diff --git a/base/include/drivers/cpu/cortex_a9/core.h b/base/include/drivers/cpu/cortex_a9/core.h index 9917460211..e8d98ac3b3 100644 --- a/base/include/drivers/cpu/cortex_a9/core.h +++ b/base/include/drivers/cpu/cortex_a9/core.h @@ -48,23 +48,25 @@ namespace Genode /* timer */ PRIVATE_TIMER_MMIO_BASE = Board::CORTEX_A9_PRIVATE_MEM_BASE + 0x600, PRIVATE_TIMER_MMIO_SIZE = 0x10, - PRIVATE_TIMER_IRQ = 29, - TIMER_MMIO = PRIVATE_TIMER_MMIO_BASE, - TIMER_IRQ = PRIVATE_TIMER_IRQ, + PRIVATE_TIMER_IRQ = 29, + PRIVATE_TIMER_CLK = PERIPH_CLK }; /** - * Exceotion type IDs + * CPU local timer module */ - enum Exception_type + class Private_timer : public Cortex_a9_timer { - RESET = 1, - UNDEFINED_INSTRUCTION = 2, - SUPERVISOR_CALL = 3, - PREFETCH_ABORT = 4, - DATA_ABORT = 5, - INTERRUPT_REQUEST = 6, - FAST_INTERRUPT_REQUEST = 7, + public: + + enum { IRQ = PRIVATE_TIMER_IRQ }; + + /** + * Constructor + */ + Private_timer() : + Cortex_a9_timer(PRIVATE_TIMER_MMIO_BASE) + { } }; typedef Cortex_a9_timer Timer; @@ -170,10 +172,7 @@ namespace Genode */ struct Contextidr : Register<32> { - struct Asid : Bitfield<0,8> /* ID part used by MMU */ - { - enum { MAX = MASK }; - }; + struct Asid : Bitfield<0,8> { }; /* ID part used by MMU */ struct Procid : Bitfield<8,24> { }; /* ID part used by debug/trace */ /** @@ -286,8 +285,8 @@ namespace Genode /** * Translation table base register 0 * - * Typically for process specific spaces, references first level table - * with a size between 128B and 16KB according to TTBCR.N + * Typically for process specific spaces, references first level + * table with a size between 128B and 16KB according to 'Ttbcr::N'. */ struct Ttbr0 : Register<32> { @@ -356,22 +355,22 @@ namespace Genode */ struct Cpsr : Register<32> { - struct M : Bitfield<0,5> /* processor mode */ + struct M : Bitfield<0,5> /* processor mode */ { - enum { /* , */ - USER = 0b10000, /* 0, application code */ - FIQ = 0b10001, /* 1, entered at fast interrupt */ - IRQ = 0b10010, /* 1, entered at normal interrupt */ - SUPERVISOR = 0b10011, /* 1, most kernel code */ - MONITOR = 0b10110, /* 1, a secure mode, switch sec./non-sec. */ - ABORT = 0b10111, /* 1, entered at aborts */ + enum { /* , */ + USER = 0b10000, /* 0, application code */ + FIQ = 0b10001, /* 1, entered at fast interrupt */ + IRQ = 0b10010, /* 1, entered at normal interrupt */ + SUPERVISOR = 0b10011, /* 1, most kernel code */ + MONITOR = 0b10110, /* 1, a secure mode, switch sec./non-sec. */ + ABORT = 0b10111, /* 1, entered at aborts */ UNDEFINED = 0b11011, /* 1, entered at instruction-related error */ SYSTEM = 0b11111, /* 1, applications that require privileged */ }; }; - struct F : Bitfield<6,1> { }; /* fast interrupt request disable */ - struct I : Bitfield<7,1> { }; /* interrupt request disable */ - struct A : Bitfield<8,1> { }; /* asynchronous abort disable */ + struct F : Bitfield<6,1> { }; /* fast interrupt request disable */ + struct I : Bitfield<7,1> { }; /* interrupt request disable */ + struct A : Bitfield<8,1> { }; /* asynchronous abort disable */ /** * Read whole register @@ -415,35 +414,189 @@ namespace Genode */ struct Context { - /* general purpose registers, offset 0*4 .. 15*4 */ - uint32_t - r0, r1, r2, r3, r4, r5, r6, r7, - r8, r9, r10, r11, r12, sp, lr, pc; + enum { + MAX_GPR = 15, + MAX_CPU_EXCEPTION = 7, + }; - /* special registers, offset 16*4 .. 17*4 */ - uint32_t psr, contextidr; + /** + * Native exception types + */ + enum Cpu_exception { + RESET = 1, + UNDEFINED_INSTRUCTION = 2, + SUPERVISOR_CALL = 3, + PREFETCH_ABORT = 4, + DATA_ABORT = 5, + INTERRUPT_REQUEST = 6, + FAST_INTERRUPT_REQUEST = 7, + }; - /* additional state info, offset 18*4 .. 19*4 */ - uint32_t exception_type, section_table; + /* general purpose register backups, offsets 0*4 .. 15*4 */ + uint32_t r0, r1, r2, r3, r4, r5, r6, r7, + r8, r9, r10, r11, r12, r13, r14, r15; + + uint32_t psr; /* program status register backup, offset 16*4 */ + uint32_t contextidr; /* contextidr register backup, offset 17*4 */ + uint32_t cpu_exception; /* native type of last exception, + * offset 18*4 */ + uint32_t section_table; /* base address of applied section table, + * offset 19*4 */ + + /** + * Read a general purpose register + * + * \param id ID of the targeted register + * \param r Holds register value if this returns 1 + */ + bool get_gpr(unsigned id, unsigned & r) const + { + if (id > MAX_GPR) return 0; + r = *(&r0 + id); + return 1; + } + + /** + * Override a general purpose register + * + * \param id ID of the targeted register + * \param r Has been written to register if this returns 1 + */ + bool set_gpr(unsigned id, unsigned const r) + { + if (id > MAX_GPR) return 0; + *(&r0 + id) = r; + return 1; + } /*************** ** Accessors ** ***************/ - void software_tlb(Section_table * const st) - { section_table = (addr_t)st; } + void software_tlb(Section_table * const st) { + section_table = (addr_t)st; } - Section_table * software_tlb() { return (Section_table *)section_table; } + Section_table * software_tlb() const { + return (Section_table *)section_table; } - void instruction_ptr(addr_t const p) { pc = p; } + void instruction_ptr(addr_t const p) { r15 = p; } - addr_t instruction_ptr() { return pc; } + addr_t instruction_ptr() const { return r15; } - void return_ptr(addr_t const p) { lr = p; } + void return_ptr(addr_t const p) { r14 = p; } - void stack_ptr(addr_t const p) { sp = p; } + void stack_ptr(addr_t const p) { r13 = p; } - void pd_id(unsigned long const id) { contextidr = id; } + void protection_domain(unsigned const id) { contextidr = id; } + }; + + /** + * An usermode execution state + */ + struct User_context : Context + { + /** + * Constructor + */ + User_context() + { + /* Execute in usermode with IRQ's enabled and FIQ's and + * asynchronous aborts disabled */ + psr = Cpsr::M::bits(Cpsr::M::USER) | Cpsr::F::bits(1) | + Cpsr::I::bits(0) | Cpsr::A::bits(1); + } + + /*************************************************** + ** Communication between user and context holder ** + ***************************************************/ + + void user_arg_0(unsigned const arg) { r0 = arg; } + void user_arg_1(unsigned const arg) { r1 = arg; } + void user_arg_2(unsigned const arg) { r2 = arg; } + void user_arg_3(unsigned const arg) { r3 = arg; } + void user_arg_4(unsigned const arg) { r4 = arg; } + void user_arg_5(unsigned const arg) { r5 = arg; } + void user_arg_6(unsigned const arg) { r6 = arg; } + void user_arg_7(unsigned const arg) { r7 = arg; } + unsigned user_arg_0() const { return r0; } + unsigned user_arg_1() const { return r1; } + unsigned user_arg_2() const { return r2; } + unsigned user_arg_3() const { return r3; } + unsigned user_arg_4() const { return r4; } + unsigned user_arg_5() const { return r5; } + unsigned user_arg_6() const { return r6; } + unsigned user_arg_7() const { return r7; } + + /** + * Determine wich type of exception occured on this context lastly + * + * \return 0 If the exception is unknown by the kernel + * 1 If the exception is an interrupt + * 2 If the exception is a pagefault + * 3 If the exception is a syscall + */ + unsigned exception() const + { + /* map all CPU-exception types to kernel-exception types */ + enum { INVALID = 0, INTERRUPT = 1, PAGEFAULT = 2, SYSCALL = 3 }; + static unsigned cpu_excpt_to_excpt[MAX_CPU_EXCEPTION + 1] = { + INVALID, /* 0 */ + INVALID, /* 1 */ + INVALID, /* 2 */ + SYSCALL, /* 3 */ + PAGEFAULT, /* 4 */ + PAGEFAULT, /* 5 */ + INTERRUPT, /* 6 */ + INVALID /* 7 */ + }; + /* determine exception type */ + if (cpu_exception > MAX_CPU_EXCEPTION) return INVALID; + return cpu_excpt_to_excpt[cpu_exception]; + } + + /** + * Does a pagefault exist and originate from a lack of translation? + * + * \param va Holds the virtual fault-address if this + * function returns 1 + * \param w Indicates wether the fault was caused by a write + * access if this function returns 1 + */ + bool translation_miss(addr_t & va, bool & w) const + { + /* determine fault type */ + switch (cpu_exception) + { + case PREFETCH_ABORT: { + + /* check if fault was caused by a translation miss */ + Ifsr::Fault_status const fs = Ifsr::fault_status(); + if(fs == Ifsr::SECTION_TRANSLATION_FAULT || + fs == Ifsr::PAGE_TRANSLATION_FAULT) + { + /* fetch fault data */ + w = 0; + va = Ifar::read(); + return 1; + } + return 0; } + case DATA_ABORT: { + + /* check if fault was caused by translation miss */ + Dfsr::Fault_status const fs = Dfsr::fault_status(); + if(fs == Dfsr::SECTION_TRANSLATION_FAULT || + fs == Dfsr::PAGE_TRANSLATION_FAULT) + { + /* fetch fault data */ + Dfsr::access_t const dfsr = Dfsr::read(); + w = Dfsr::Wnr::get(dfsr); + va = Dfar::read(); + return 1; + } + return 0; } + default: return 0; + } + } }; /** @@ -541,7 +694,7 @@ namespace Genode /** * Invalidate all entries of the branch predictor array * - * Must be inline to avoid dependence on the branch predictor + * Must be inline to avoid dependence on the branch predictor. */ __attribute__((always_inline)) inline static void flush_branch_prediction() { @@ -560,51 +713,6 @@ namespace Genode :: [asid]"r"(Contextidr::Asid::masked(process_id)) : ); flush_branch_prediction(); } - - /** - * Does a pagefault exist and originate from a lack of translation? - * - * \param c CPU Context that triggered the page fault - * \param va holds the virtual fault-address if this - * function returns 1 - * \param w indicates whether the fault was caused by a write access - * if this function returns 1 - */ - static bool translation_miss(Context * c, addr_t & va, bool & w) - { - /* determine fault type */ - switch (c->exception_type) - { - case PREFETCH_ABORT: { - - /* is fault caused by translation miss? */ - Ifsr::Fault_status const fs = Ifsr::fault_status(); - if(fs == Ifsr::SECTION_TRANSLATION_FAULT || - fs == Ifsr::PAGE_TRANSLATION_FAULT) - { - /* fetch fault data */ - w = 0; - va = Ifar::read(); - return 1; - } - return 0; } - case DATA_ABORT: { - - /* is fault caused by translation miss? */ - Dfsr::Fault_status const fs = Dfsr::fault_status(); - if(fs == Dfsr::SECTION_TRANSLATION_FAULT || - fs == Dfsr::PAGE_TRANSLATION_FAULT) - { - /* fetch fault data */ - Dfsr::access_t const dfsr = Dfsr::read(); - w = Dfsr::Wnr::get(dfsr); - va = Dfar::read(); - return 1; - } - return 0; } - default: return 0; - } - } }; } diff --git a/base/include/drivers/cpu/cortex_a9/section_table.h b/base/include/drivers/cpu/cortex_a9/section_table.h index 4aa10f5eb8..87eddb7d26 100644 --- a/base/include/drivers/cpu/cortex_a9/section_table.h +++ b/base/include/drivers/cpu/cortex_a9/section_table.h @@ -34,8 +34,12 @@ namespace Genode */ struct Ap_1_0_bitfield { - enum { KERNEL_AND_USER_NO_ACCESS = 0, - KERNEL_AND_USER_SAME_ACCESS = 3 }; + enum { + KERNEL_AND_USER_NO_ACCESS = 0, + USER_NO_ACCESS = 1, + USER_RO_ACCESS = 2, + KERNEL_AND_USER_SAME_ACCESS = 3 + }; }; /** @@ -43,10 +47,49 @@ namespace Genode */ struct Ap_2_bitfield { - enum { KERNEL_RW_OR_NO_ACCESS = 0, - KERNEL_RO_ACCESS = 1 }; + enum { + KERNEL_RW_OR_NO_ACCESS = 0, + KERNEL_RO_ACCESS = 1 + }; }; + + /** + * Permission configuration according to given access rights + * + * \param T targeted translation-table-descriptor type + * \param w see 'Section_table::insert_translation' + * \param x see 'Section_table::insert_translation' + * \param k see 'Section_table::insert_translation' + * + * \return descriptor value with requested perms and the rest left zero + */ + template + static typename T::access_t access_permission_bits(bool const w, + bool const x, + bool const k) + { + /* lookup table for AP bitfield values according to 'w' and 'k' */ + typedef typename T::Ap_1_0 Ap_1_0; + typedef typename T::Ap_2 Ap_2; + static typename T::access_t const ap_bits[2][2] = {{ + Ap_1_0::bits(Ap_1_0::USER_RO_ACCESS) | /* -- */ + Ap_2::bits(Ap_2::KERNEL_RW_OR_NO_ACCESS), + + Ap_1_0::bits(Ap_1_0::USER_NO_ACCESS) | /* -k */ + Ap_2::bits(Ap_2::KERNEL_RO_ACCESS) }, { + + Ap_1_0::bits(Ap_1_0::KERNEL_AND_USER_SAME_ACCESS) | /* w- */ + Ap_2::bits(Ap_2::KERNEL_RW_OR_NO_ACCESS), + + Ap_1_0::bits(Ap_1_0::USER_NO_ACCESS) | /* wk */ + Ap_2::bits(Ap_2::KERNEL_RW_OR_NO_ACCESS) } + }; + /* combine XN and AP bitfield values according to 'w', 'x' and 'k' */ + typedef typename T::Xn Xn; + return Xn::bits(!x) | ap_bits[w][k]; + } + /** * Cortex A9 second level translation table * @@ -111,17 +154,23 @@ namespace Genode static void type(access_t & v, Type const t) { switch (t) { - case FAULT: + + case FAULT: { + Type_1::set(v, 0); Type_2::set(v, 0); - break; - case SMALL_PAGE: + break; } + + case SMALL_PAGE: { + Type_1::set(v, 1); - break; - case LARGE_PAGE: + break; } + + case LARGE_PAGE: { + Type_1::set(v, 0); Type_2::set(v, 1); - break; + break; } } } @@ -196,42 +245,12 @@ namespace Genode struct S : Bitfield<10, 1> { }; /* shareable bit */ struct Ng : Bitfield<11, 1> { }; /* not global bit */ struct Pa_31_12 : Bitfield<12, 20> { }; /* physical address bits [31:12] */ - - /** - * Permission configuration according to given access rights - * - * \param r readability - * \param w writeability - * \param x executability - * \return descriptor value configured with appropriate - * access permissions and the rest left zero - */ - static access_t access_permission_bits(bool const r, - bool const w, - bool const x) - { - access_t v = Xn::bits(!x); - if (r) { - v |= Ap_1_0::bits(Ap_1_0::KERNEL_AND_USER_SAME_ACCESS); - if(w) v |= Ap_2::bits(Ap_2::KERNEL_RW_OR_NO_ACCESS); - else v |= Ap_2::bits(Ap_2::KERNEL_RO_ACCESS); - } - else if (w) { - PDBG("Write only translations not supported"); - while (1) ; - } - else { - v |= Ap_1_0::bits(Ap_1_0::KERNEL_AND_USER_NO_ACCESS) - | Ap_2::bits(Ap_2::KERNEL_RO_ACCESS); - } - return v; - } }; /* * Table payload * - * Attention: Must be the only member of this class + * Must be the only member of this class */ Descriptor::access_t _entries[SIZE/sizeof(Descriptor::access_t)]; @@ -240,10 +259,12 @@ namespace Genode /** * Get entry index by virtual offset * - * \param i is overridden with the resulting index - * \param vo virtual offset relative to the virtual table base - * \retval <0 if virtual offset couldn't be resolved, - * in this case 'i' reside invalid + * \param i is overridden with the resulting index + * \param vo virtual offset relative to the virtual table base + * + * \retval 0 on success + * \retval <0 If virtual offset couldn't be resolved. + * In this case 'i' reside invalid */ int _index_by_vo (unsigned long & i, addr_t const vo) const { @@ -266,8 +287,8 @@ namespace Genode { /* check table alignment */ if (!aligned((addr_t)this, ALIGNM_LOG2) - || (addr_t)this != (addr_t)_entries) { - + || (addr_t)this != (addr_t)_entries) + { PDBG("Insufficient table alignment"); while (1) ; } @@ -289,25 +310,25 @@ namespace Genode /** * Insert one atomic translation into this table * - * \param vo offset of the virtual region represented - * by the translation within the virtual - * region represented by this table - * \param pa base of the physical backing store - * \param size_log2 log2(Size of the translated region), - * must be supported by this table - * \param r shall one can read trough this translation - * \param w shall one can write trough this translation - * \param x shall one can execute trough this - * translation + * \param vo offset of the virtual region represented + * by the translation within the virtual + * region represented by this table + * \param pa base of the physical backing store + * \param size_log2 log2(Size of the translated region), + * must be supported by this table + * \param w see 'Section_table::insert_translation' + * \param x see 'Section_table::insert_translation' + * \param k see 'Section_table::insert_translation' + * \param g see 'Section_table::insert_translation' * - * This method overrides an existing translation in case that it - * spans the the same virtual range and is not a link to another - * table level. + * This method overrides an existing translation in case + * that it spans the the same virtual range and is not + * a link to another table level. */ - void insert_translation (addr_t const vo, addr_t const pa, - unsigned long const size_log2, - bool const r, bool const w, bool const x, - bool const global) + void insert_translation(addr_t const vo, addr_t const pa, + unsigned long const size_log2, + bool const w, bool const x, + bool const k, bool const g) { /* validate virtual address */ unsigned long i; @@ -315,25 +336,32 @@ namespace Genode PDBG("Invalid virtual offset"); while (1) ; } - /* select descriptor type by the translation size */ - if (size_log2 == Small_page::VIRT_SIZE_LOG2) { + if (size_log2 == Small_page::VIRT_SIZE_LOG2) + { + /* compose new descriptor value */ + Descriptor::access_t entry = + access_permission_bits(w, x, k) + | Small_page::Ng::bits(!g) + | Small_page::Pa_31_12::masked(pa); + Descriptor::type(entry, Descriptor::SMALL_PAGE); - /* - * Can we write to the targeted entry? - */ - if (Descriptor::valid(_entries[i]) && - Descriptor::type(_entries[i]) != Descriptor::SMALL_PAGE) + /* check if we can we write to the targeted entry */ + if (Descriptor::valid(_entries[i])) { + /* + * It's possible that multiple threads fault at the + * same time on the same translation, thus we need + * this check. + */ + if (_entries[i] == entry) return; + + /* never modify existing translations */ PDBG("Couldn't override entry"); while (1) ; } - - /* compose descriptor */ - _entries[i] = Small_page::access_permission_bits(r, w, x) - | Small_page::Ng::bits(!global) - | Small_page::Pa_31_12::masked(pa); - Descriptor::type(_entries[i], Descriptor::SMALL_PAGE); + /* override table entry with new descriptor value */ + _entries[i] = entry; return; } PDBG("Translation size not supported"); @@ -343,9 +371,9 @@ namespace Genode /** * Remove translations, wich overlap with a given virtual region * - * \param vo offset of the virtual region within the region - * represented by this table - * \param size region size + * \param vo offset of the virtual region within the region + * represented by this table + * \param size region size */ void remove_region (addr_t const vo, size_t const size) { @@ -354,21 +382,13 @@ namespace Genode unsigned long i; while (1) { - /* - * Is anything left over to remove? - */ + /* check if anything is left over to remove */ if (residual_vo >= vo + size) return; - /* - * Does the residual region overlap with the region - * represented by this table? - */ + /* check if residual region overlaps with table */ if (_index_by_vo(i, residual_vo)) return; - /* - * Update current entry and recalculate the residual - * region. - */ + /* update current entry and recalculate residual region */ switch (Descriptor::type(_entries[i])) { case Descriptor::FAULT: @@ -514,8 +534,7 @@ namespace Genode }; /** - * References a second level translation table for the virtual - * region it represents + * Link to a second level translation table */ struct Page_table_descriptor : Descriptor { @@ -578,58 +597,26 @@ namespace Genode struct Ng : Bitfield<17, 1> { }; /* not global bit */ struct Ns : Bitfield<19, 1> { }; /* non-secure bit */ struct Pa_31_20 : Bitfield<20, 12> { }; /* physical address bits [31:20] */ - - /** - * Permission configuration according to given access rights - * - * \param r readability - * \param w writeability - * \param x executability - * \return descriptor value configured with appropriate - * access permissions and the rest left zero - */ - static access_t access_permission_bits(bool const r, - bool const w, - bool const x) - { - access_t v = Xn::bits(!x); - if (r) { - v |= Ap_1_0::bits(Ap_1_0::KERNEL_AND_USER_SAME_ACCESS); - if(w) v |= Ap_2::bits(Ap_2::KERNEL_RW_OR_NO_ACCESS); - else v |= Ap_2::bits(Ap_2::KERNEL_RO_ACCESS); - } - else if (w) { - PDBG("Write only sections not supported"); - while (1) ; - } - else { - v |= Ap_1_0::bits(Ap_1_0::KERNEL_AND_USER_NO_ACCESS) - | Ap_2::bits(Ap_2::KERNEL_RW_OR_NO_ACCESS); - } - return v; - } }; - /* - * Table payload - * - * Attention: Must be the first member of this class - */ + /* table payload, must be the first member of this class */ Descriptor::access_t _entries[SIZE/sizeof(Descriptor::access_t)]; enum { MAX_INDEX = sizeof(_entries) / sizeof(_entries[0]) - 1 }; - /* is this table dedicated to secure mode or to non-secure mode */ + /* if this table dedicated to secure mode or to non-secure mode */ bool _secure; /** * Get entry index by virtual offset * - * \param i is overridden with the resulting index - * \param vo offset within the virtual region represented - * by this table - * \retval <0 if virtual offset couldn't be resolved, - * in this case 'i' reside invalid + * \param i is overridden with the resulting index + * \param vo offset within the virtual region represented + * by this table + * + * \retval 0 on success + * \retval <0 if virtual offset couldn't be resolved, + * in this case 'i' reside invalid */ int _index_by_vo(unsigned long & i, addr_t const vo) const { @@ -647,8 +634,8 @@ namespace Genode { /* check table alignment */ if (!aligned((addr_t)this, ALIGNM_LOG2) - || (addr_t)this != (addr_t)_entries) { - + || (addr_t)this != (addr_t)_entries) + { PDBG("Insufficient table alignment"); while (1) ; } @@ -670,40 +657,45 @@ namespace Genode /** * Insert one atomic translation into this table * - * \param vo offset of the virtual region represented - * by the translation within the virtual - * region represented by this table - * \param pa base of the physical backing store - * \param size_log2 size log2 of the translated region - * \param r shall one can read trough this translation - * \param w shall one can write trough this translation - * \param x shall one can execute trough this translation - * \param global shall the translation apply to all - * address spaces - * \param extra_space If > 0, it must point to a portion of - * size-aligned memory space wich may be used - * furthermore by the table for the incurring - * administrative costs of the translation. - * To determine the amount of additionally - * needed memory one can instrument this - * method with 'extra_space' set to 0. - * The so donated memory may be regained by - * using the method 'regain_memory'. - * \retval 0 translation successfully inserted - * \retval >0 translation not inserted, the return value - * is the size log2 of additional size-aligned - * space that is needed to do the translation. - * This occurs solely when 'extra_space' is 0. + * \param vo offset of the virtual region represented + * by the translation within the virtual + * region represented by this table + * \param pa base of the physical backing store + * \param size_log2 size log2 of the translated region + * \param w if one can write trough this translation + * \param x if one can execute trough this translation + * \param k If set to 1, the given permissions apply + * in kernel mode, while in user mode this + * translations grants no type of access. + * If set to 0, the given permissions apply + * in user mode, while in kernel mode this + * translation grants any type of access. + * \param g if the translation applies to all spaces + * \param extra_space If > 0, it must point to a portion of + * size-aligned memory space wich may be used + * furthermore by the table for the incurring + * administrative costs of the translation. + * To determine the amount of additionally + * needed memory one can instrument this + * method with 'extra_space' set to 0. + * The so donated memory may be regained by + * using the method 'regain_memory'. + * + * \retval 0 translation successfully inserted + * \retval >0 Translation not inserted, the return value + * is the size log2 of additional size-aligned + * space that is needed to do the translation. + * This occurs solely when 'extra_space' is 0. * * This method overrides an existing translation in case that it * spans the the same virtual range and is not a link to another * table level. */ - unsigned long insert_translation (addr_t const vo, addr_t const pa, - unsigned long const size_log2, - bool const r, bool const w, - bool const x, bool const global, - void * const extra_space = 0) + unsigned long insert_translation(addr_t const vo, addr_t const pa, + unsigned long const size_log2, + bool const w, bool const x, + bool const k, bool const g, + void * const extra_space = 0) { /* validate virtual address */ unsigned long i; @@ -713,34 +705,23 @@ namespace Genode } /* select descriptor type by translation size */ - if (size_log2 < Section::VIRT_SIZE_LOG2) { - + if (size_log2 < Section::VIRT_SIZE_LOG2) + { + /* check if an appropriate page table already exists */ Page_table * pt; - - /* - * Does an appropriate page table already exist? - */ if (Descriptor::type(_entries[i]) == Descriptor::PAGE_TABLE) { pt = (Page_table *)(addr_t) Page_table_descriptor::Pa_31_10::masked(_entries[i]); } - - /* - * Is there some extra space to create a page table? - */ - else if (extra_space) { - - /* - * Can we write to the targeted entry? - */ + /* check if we have enough memory for the page table */ + else if (extra_space) + { + /* check if we can write to the targeted entry */ if (Descriptor::valid(_entries[i])) { PDBG ("Couldn't override entry"); while (1) ; } - /* - * Create and link page table. The page table checks - * alignment by itself. - */ + /* create and link page table */ pt = new (extra_space) Page_table(); _entries[i] = Page_table_descriptor::Ns::bits(!_secure) | Page_table_descriptor::Pa_31_10::masked((addr_t)pt); @@ -751,27 +732,35 @@ namespace Genode /* insert translation */ pt->insert_translation(vo - Section::Pa_31_20::masked(vo), - pa, size_log2, r, w, x, global); + pa, size_log2, w, x, k, g); return 0; } - if (size_log2 == Section::VIRT_SIZE_LOG2) { + if (size_log2 == Section::VIRT_SIZE_LOG2) + { + /* compose section descriptor */ + Descriptor::access_t entry = + access_permission_bits
(w, x, k) + | Section::Ns::bits(!_secure) + | Section::Ng::bits(!g) + | Section::Pa_31_20::masked(pa); + Descriptor::type(entry, Descriptor::SECTION); - /* - * Can we write to the targeted entry? - */ - if (Descriptor::valid(_entries[i]) && - Descriptor::type(_entries[i]) != Descriptor::SECTION) + /* check if we can we write to the targeted entry */ + if (Descriptor::valid(_entries[i])) { + /* + * It's possible that multiple threads fault at the + * same time on the same translation, thus we need + * this check. + */ + if (_entries[i] == entry) return 0; + + /* never modify existing translations */ PDBG("Couldn't override entry"); while (1) ; } - - /* compose section descriptor */ - _entries[i] = Section::access_permission_bits(r, w, x) - | Section::Ns::bits(!_secure) - | Section::Ng::bits(!global) - | Section::Pa_31_20::masked(pa); - Descriptor::type(_entries[i], Descriptor::SECTION); + /* override the table entry */ + _entries[i] = entry; return 0; } PDBG("Translation size not supported"); @@ -781,9 +770,9 @@ namespace Genode /** * Remove translations, wich overlap with a given virtual region * - * \param vo offset of the virtual region within the region - * represented by this table - * \param size region size + * \param vo offset of the virtual region within the region + * represented by this table + * \param size region size */ void remove_region (addr_t const vo, size_t const size) { @@ -792,21 +781,13 @@ namespace Genode unsigned long i; while (1) { - /* - * Is anything left over to remove? - */ + /* check if anything is left over to remove */ if (residual_vo >= vo + size) return; - /* - * Does the residual region overlap with the region - * represented by this table? - */ + /* check if the residual region overlaps with this table */ if (_index_by_vo(i, residual_vo)) return; - /* - * Update current entry and recalculate the residual - * region. - */ + /* update current entry and recalculate residual region */ switch (Descriptor::type(_entries[i])) { case Descriptor::FAULT: @@ -850,21 +831,22 @@ namespace Genode /** * Get a portion of memory that is no longer used by this table * - * \param base base of regained memory portion if method returns 1 - * \param s size of regained memory portion if method returns 1 + * \param base base of regained mem portion if method returns 1 + * \param s size of regained mem portion if method returns 1 + * + * \retval 0 no more memory to regain */ bool regain_memory (void * & base, size_t & s) { /* walk through all entries */ for (unsigned i = 0; i <= MAX_INDEX; i++) { - if (Descriptor::type(_entries[i]) == Descriptor::PAGE_TABLE) { - + if (Descriptor::type(_entries[i]) == Descriptor::PAGE_TABLE) + { Page_table * const pt = (Page_table *) (addr_t)Page_table_descriptor::Pa_31_10::masked(_entries[i]); - - if (pt->empty()) { - + if (pt->empty()) + { /* we've found an useless page table */ Descriptor::invalidate(_entries[i]); base = (void *)pt;