diff --git a/base-hw/include/base/native_types.h b/base-hw/include/base/native_types.h index 3d829d1f4..69f30ff40 100644 --- a/base-hw/include/base/native_types.h +++ b/base-hw/include/base/native_types.h @@ -1,6 +1,7 @@ /* * \brief Basic Genode types * \author Martin Stein + * \author Stefan Kalkowski * \date 2012-01-02 */ @@ -317,23 +318,12 @@ class Genode::Native_utcb namespace Genode { - enum { - VIRT_ADDR_SPACE_START = 0x1000, - VIRT_ADDR_SPACE_SIZE = 0xfffef000, - }; + static constexpr addr_t VIRT_ADDR_SPACE_START = 0x1000; + static constexpr size_t VIRT_ADDR_SPACE_SIZE = 0xfffef000; - /** - * Return virtual UTCB location of main threads - */ - inline Native_utcb * main_thread_utcb() - { - enum { - VAS_TOP = VIRT_ADDR_SPACE_START + VIRT_ADDR_SPACE_SIZE, - UTCB = VAS_TOP - sizeof(Native_utcb), - UTCB_ALIGNED = UTCB & ~((1 << MIN_MAPPING_SIZE_LOG2) - 1), - }; - return (Native_utcb *)UTCB_ALIGNED; - } + static constexpr Native_utcb * UTCB_MAIN_THREAD = (Native_utcb *) + ((VIRT_ADDR_SPACE_START + VIRT_ADDR_SPACE_SIZE - sizeof(Native_utcb)) + & ~((1 << MIN_MAPPING_SIZE_LOG2) - 1)); } #endif /* _BASE__NATIVE_TYPES_H_ */ diff --git a/base-hw/include/base/pager.h b/base-hw/include/base/pager.h index f0924927f..00af36013 100644 --- a/base-hw/include/base/pager.h +++ b/base-hw/include/base/pager.h @@ -93,7 +93,7 @@ class Genode::Ipc_pager */ struct Fault_thread_regs { - addr_t tlb; + addr_t pd; addr_t ip; addr_t addr; addr_t writes; diff --git a/base-hw/src/base/thread/thread_bootstrap.cc b/base-hw/src/base/thread/thread_bootstrap.cc index 8b74d4476..9d9002f55 100644 --- a/base-hw/src/base/thread/thread_bootstrap.cc +++ b/base-hw/src/base/thread/thread_bootstrap.cc @@ -1,6 +1,7 @@ /* * \brief Thread initialization * \author Martin stein + * \author Stefan Kalkowski * \date 2013-02-15 */ @@ -14,6 +15,7 @@ /* Genode includes */ #include #include +#include /* base-hw includes */ #include @@ -21,10 +23,7 @@ using namespace Genode; Ram_dataspace_capability _main_thread_utcb_ds; - -Native_thread_id _main_thread_id; - -namespace Genode { Rm_session * env_context_area_rm_session(); } +Native_thread_id _main_thread_id; /************************** @@ -64,43 +63,25 @@ void prepare_reinit_main_thread() { prepare_init_main_thread(); } ** Thread_base ** *****************/ +extern Native_utcb* main_thread_utcb(); + +Native_utcb * Thread_base::utcb() +{ + if (this) { return &_context->utcb; } + return main_thread_utcb(); +} + + +void Thread_base::_thread_start() +{ + Thread_base::myself()->_thread_bootstrap(); + Thread_base::myself()->entry(); + Thread_base::myself()->_join_lock.unlock(); + Genode::sleep_forever(); +} + void Thread_base::_thread_bootstrap() { Native_utcb * const utcb = Thread_base::myself()->utcb(); _tid.thread_id = utcb->start_info()->thread_id(); } - - -void Thread_base::_init_platform_thread(Type type) -{ - /* if no cpu session is given, use it from the environment */ - if (!_cpu_session) - _cpu_session = env()->cpu_session(); - - /* nothing platform specific to do if this is not a special thread */ - if (type == NORMAL) - { - /* create server object */ - char buf[48]; - name(buf, sizeof(buf)); - _thread_cap = _cpu_session->create_thread(buf, (addr_t)&_context->utcb); - return; - } - - /* if we got reinitialized we have to get rid of the old UTCB */ - size_t const utcb_size = sizeof(Native_utcb); - addr_t const context_area = Native_config::context_area_virtual_base(); - addr_t const utcb_new = (addr_t)&_context->utcb - context_area; - Rm_session * const rm = env_context_area_rm_session(); - if (type == REINITIALIZED_MAIN) { rm->detach(utcb_new); } - - /* remap initial main-thread UTCB according to context-area spec */ - try { rm->attach_at(_main_thread_utcb_ds, utcb_new, utcb_size); } - catch(...) { - PERR("failed to re-map UTCB"); - while (1) ; - } - /* adjust initial object state in case of a main thread */ - tid().thread_id = _main_thread_id; - _thread_cap = env()->parent()->main_thread_cap(); -} diff --git a/base-hw/src/base/thread_support.cc b/base-hw/src/base/thread_support.cc index 5468b1608..99c305a32 100644 --- a/base-hw/src/base/thread_support.cc +++ b/base-hw/src/base/thread_support.cc @@ -1,6 +1,7 @@ /** * \brief Platform specific parts of the thread API * \author Martin Stein + * \author Stefan Kalkowski * \date 2012-02-12 */ @@ -21,29 +22,50 @@ using namespace Genode; namespace Genode { Rm_session * env_context_area_rm_session(); } +extern Ram_dataspace_capability _main_thread_utcb_ds; +extern Native_thread_id _main_thread_id; + + +/** + * Return virtual UTCB location of main threads + */ +Native_utcb * main_thread_utcb() { return UTCB_MAIN_THREAD; } + /***************** ** Thread_base ** *****************/ -Native_utcb * Thread_base::utcb() +void Thread_base::_init_platform_thread(Type type) { - if (this) { return &_context->utcb; } - return main_thread_utcb(); -} + if (type == NORMAL) { return; } + /* if we got reinitialized we have to get rid of the old UTCB */ + size_t const utcb_size = sizeof(Native_utcb); + addr_t const context_area = Native_config::context_area_virtual_base(); + addr_t const utcb_new = (addr_t)&_context->utcb - context_area; + Rm_session * const rm = env_context_area_rm_session(); + if (type == REINITIALIZED_MAIN) { rm->detach(utcb_new); } -void Thread_base::_thread_start() -{ - Thread_base::myself()->_thread_bootstrap(); - Thread_base::myself()->entry(); - Thread_base::myself()->_join_lock.unlock(); - Genode::sleep_forever(); + /* remap initial main-thread UTCB according to context-area spec */ + try { rm->attach_at(_main_thread_utcb_ds, utcb_new, utcb_size); } + catch(...) { + PERR("failed to re-map UTCB"); + while (1) ; + } + /* adjust initial object state in case of a main thread */ + tid().thread_id = _main_thread_id; + _thread_cap = env()->parent()->main_thread_cap(); } void Thread_base::_deinit_platform_thread() { + if (!_cpu_session) + _cpu_session = env()->cpu_session(); + + _cpu_session->kill_thread(_thread_cap); + /* detach userland thread-context */ size_t const size = sizeof(_context->utcb); addr_t utcb = Context_allocator::addr_to_base(_context) + @@ -51,8 +73,6 @@ void Thread_base::_deinit_platform_thread() Native_config::context_area_virtual_base(); env_context_area_rm_session()->detach(utcb); - /* destroy server object */ - _cpu_session->kill_thread(_thread_cap); if (_pager_cap.valid()) { env()->rm_session()->remove_client(_pager_cap); } @@ -61,6 +81,14 @@ void Thread_base::_deinit_platform_thread() void Thread_base::start() { + if (!_cpu_session) + _cpu_session = env()->cpu_session(); + + /* create server object */ + char buf[48]; + name(buf, sizeof(buf)); + _thread_cap = _cpu_session->create_thread(buf, (addr_t)&_context->utcb); + /* assign thread to protection domain */ env()->pd_session()->bind_thread(_thread_cap); diff --git a/base-hw/src/core/arm/cpu_support.cc b/base-hw/src/core/arm/cpu_support.cc index 695c73e50..dd10cdd85 100644 --- a/base-hw/src/core/arm/cpu_support.cc +++ b/base-hw/src/core/arm/cpu_support.cc @@ -1,6 +1,7 @@ /* * \brief CPU specific implementations of core * \author Martin Stein + * \author Stefan Kalkowski * \date 2013-11-11 */ @@ -25,7 +26,7 @@ using namespace Kernel; Thread_cpu_support::Thread_cpu_support(Thread * const t) : _fault(t), - _fault_tlb(0), + _fault_pd(0), _fault_addr(0), _fault_writes(0), _fault_signal(0) @@ -57,7 +58,7 @@ addr_t Thread::* Thread::_reg(addr_t const id) const /* [15] */ (addr_t Thread::*)&Thread::ip, /* [16] */ (addr_t Thread::*)&Thread::cpsr, /* [17] */ (addr_t Thread::*)&Thread::cpu_exception, - /* [18] */ (addr_t Thread::*)&Thread::_fault_tlb, + /* [18] */ (addr_t Thread::*)&Thread::_fault_pd, /* [19] */ (addr_t Thread::*)&Thread::_fault_addr, /* [20] */ (addr_t Thread::*)&Thread::_fault_writes, /* [21] */ (addr_t Thread::*)&Thread::_fault_signal @@ -79,7 +80,7 @@ void Thread::_mmu_exception() { _unschedule(AWAITS_RESUME); if (in_fault(_fault_addr, _fault_writes)) { - _fault_tlb = (addr_t)_pd->tlb(); + _fault_pd = (addr_t)_pd->platform_pd(); _fault_signal = _fault.signal_context_id(); _fault.submit(); return; @@ -113,4 +114,4 @@ addr_t const * cpu_state_regs() { return _cpu_state_regs; } size_t cpu_state_regs_length() { return sizeof(_cpu_state_regs)/sizeof(_cpu_state_regs[0]); -} \ No newline at end of file +} diff --git a/base-hw/src/core/arm/cpu_support.h b/base-hw/src/core/arm/cpu_support.h index 13f27e848..6db65c718 100644 --- a/base-hw/src/core/arm/cpu_support.h +++ b/base-hw/src/core/arm/cpu_support.h @@ -27,7 +27,7 @@ class Kernel::Thread_cpu_support protected: Thread_event _fault; - addr_t _fault_tlb; + addr_t _fault_pd; addr_t _fault_addr; addr_t _fault_writes; addr_t _fault_signal; diff --git a/base-hw/src/core/arm/short_translation_table.h b/base-hw/src/core/arm/short_translation_table.h new file mode 100644 index 000000000..042d37671 --- /dev/null +++ b/base-hw/src/core/arm/short_translation_table.h @@ -0,0 +1,674 @@ +/* + * \brief Short descriptor translation table definitions + * \author Martin Stein + * \author Stefan Kalkowski + * \date 2012-02-22 + */ + +/* + * Copyright (C) 2012-2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _ARM__SHORT_TRANSLATION_TABLE_H_ +#define _ARM__SHORT_TRANSLATION_TABLE_H_ + +/* Genode includes */ +#include +#include + +/* base-hw includes */ +#include +#include + +namespace Arm +{ + using namespace Genode; + + /** + * Check if 'p' is aligned to 1 << 'alignm_log2' + */ + inline bool aligned(addr_t const a, size_t const alignm_log2) { + return a == ((a >> alignm_log2) << alignm_log2); } + + /** + * Return permission configuration according to given mapping flags + * + * \param T targeted translation-table-descriptor type + * \param flags mapping flags + * + * \return descriptor value with AP and XN set and the rest left zero + */ + template + static typename T::access_t + access_permission_bits(Page_flags const & flags) + { + typedef typename T::Xn Xn; + typedef typename T::Ap Ap; + typedef typename T::access_t access_t; + bool const w = flags.writeable; + bool const p = flags.privileged; + access_t ap; + if (w) { if (p) { ap = Ap::bits(0b001); } + else { ap = Ap::bits(0b011); } + } else { if (p) { ap = Ap::bits(0b101); } + else { ap = Ap::bits(0b010); } + } + return Xn::bits(!flags.executable) | ap; + } + + /** + * Memory region attributes for the translation descriptor 'T' + */ + template + static typename T::access_t + memory_region_attr(Page_flags const & flags); + + class Section_table; +} + +/** + * First level translation table + */ +class Arm::Section_table +{ + public: + + /*************************** + ** Exception definitions ** + ***************************/ + + class Double_insertion {}; + class Misaligned {}; + class Invalid_range {}; + + private: + + /** + * Second level translation table + */ + class Page_table + { + public: + + enum { + SIZE_LOG2 = 10, + SIZE = 1 << SIZE_LOG2, + ALIGNM_LOG2 = SIZE_LOG2, + }; + + /** + * Common descriptor structure + */ + struct Descriptor : Register<32> + { + /** + * Descriptor types + */ + enum Type { FAULT, SMALL_PAGE }; + + enum { + VIRT_SIZE_LOG2 = 12, + VIRT_SIZE = 1 << VIRT_SIZE_LOG2, + VIRT_OFFSET_MASK = (1 << VIRT_SIZE_LOG2) - 1, + VIRT_BASE_MASK = ~(VIRT_OFFSET_MASK), + }; + + struct Type_0 : Bitfield<0, 2> { }; + struct Type_1 : Bitfield<1, 1> { }; + + /** + * Get descriptor type of 'v' + */ + static Type type(access_t const v) + { + access_t const t0 = Type_0::get(v); + if (t0 == 0) { return FAULT; } + access_t const t1 = Type_1::get(v); + if (t1 == 1) return SMALL_PAGE; + return FAULT; + } + + /** + * Set descriptor type of 'v' + */ + static void type(access_t & v, Type const t) + { + switch (t) { + case FAULT: + Type_0::set(v, 0); + return; + case SMALL_PAGE: + Type_1::set(v, 1); + return; + } + } + + /** + * Invalidate descriptor 'v' + */ + static void invalidate(access_t & v) { type(v, FAULT); } + + /** + * Return if descriptor 'v' is valid + */ + static bool valid(access_t & v) { + return type(v) != FAULT; } + }; + + /** + * Small page descriptor structure + */ + struct Small_page : Descriptor + { + struct Xn : Bitfield<0, 1> { }; /* execute never */ + struct B : Bitfield<2, 1> { }; /* mem region attr. */ + struct C : Bitfield<3, 1> { }; /* mem region attr. */ + struct Ap_0 : Bitfield<4, 2> { }; /* access permission */ + struct Tex : Bitfield<6, 3> { }; /* mem region attr. */ + struct Ap_1 : Bitfield<9, 1> { }; /* access permission */ + struct S : Bitfield<10, 1> { }; /* shareable bit */ + struct Ng : Bitfield<11, 1> { }; /* not global bit */ + struct Pa : Bitfield<12, 20> { }; /* physical base */ + + struct Ap : Bitset_2 { }; /* access permission */ + + /** + * Compose descriptor value + */ + static access_t create(Page_flags const & flags, + addr_t const pa) + { + access_t v = access_permission_bits(flags); + v |= memory_region_attr(flags); + v |= Ng::bits(!flags.global); + v |= S::bits(1); + v |= Pa::masked(pa); + Descriptor::type(v, Descriptor::SMALL_PAGE); + return v; + } + }; + + private: + + /* + * Table payload + * + * Must be the only member of this class + */ + Descriptor::access_t _entries[SIZE/sizeof(Descriptor::access_t)]; + + enum { MAX_INDEX = sizeof(_entries) / sizeof(_entries[0]) - 1 }; + + /** + * Get entry index by virtual offset + * + * \param i is overridden with the index if call returns 0 + * \param vo virtual offset relative to the virtual table base + * + * \retval 0 on success + * \retval <0 translation failed + */ + bool _index_by_vo (unsigned & i, addr_t const vo) const + { + if (vo > max_virt_offset()) return false; + i = vo >> Descriptor::VIRT_SIZE_LOG2; + return true; + } + + public: + + /** + * Constructor + */ + Page_table() + { + if (!aligned((addr_t)this, ALIGNM_LOG2)) + throw Misaligned(); + + /* start with an empty table */ + memset(&_entries, 0, sizeof(_entries)); + } + + /** + * Maximum virtual offset that can be translated by this table + */ + static addr_t max_virt_offset() + { + return (MAX_INDEX << Descriptor::VIRT_SIZE_LOG2) + + (Descriptor::VIRT_SIZE - 1); + } + + /** + * 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 size of the translated region + * \param flags mapping flags + * + * This method overrides an existing translation in case + * that it spans the the same virtual range otherwise it + * throws a Double_insertion. + */ + void insert_translation(addr_t vo, + addr_t pa, + size_t size, + Page_flags const & flags) + { + constexpr size_t sz = Descriptor::VIRT_SIZE; + + for (unsigned i; (size > 0) && _index_by_vo (i, vo); + size = (size < sz) ? 0 : size - sz, vo += sz, pa += sz) { + + if (Descriptor::valid(_entries[i]) && + _entries[i] != Small_page::create(flags, pa)) + throw Double_insertion(); + + /* compose new descriptor value */ + _entries[i] = Small_page::create(flags, pa); + } + } + + /** + * Remove translations that overlap with a given virtual region + * + * \param vo region offset within the tables virtual region + * \param size region size + */ + void remove_translation(addr_t vo, size_t size) + { + constexpr size_t sz = Descriptor::VIRT_SIZE; + + for (unsigned i; (size > 0) && _index_by_vo(i, vo); + size = (size < sz) ? 0 : size - sz, vo += sz) { + + switch (Descriptor::type(_entries[i])) { + + case Descriptor::SMALL_PAGE: + { + Descriptor::invalidate(_entries[i]); + } + + default: ; + } + } + } + + /** + * Does this table solely contain invalid entries + */ + bool empty() + { + for (unsigned i = 0; i <= MAX_INDEX; i++) + if (Descriptor::valid(_entries[i])) return false; + return true; + } + + } __attribute__((aligned(1< + { + /** + * Descriptor types + */ + enum Type { FAULT, PAGE_TABLE, SECTION }; + + enum { + VIRT_SIZE_LOG2 = 20, + VIRT_SIZE = 1 << VIRT_SIZE_LOG2, + VIRT_OFFSET_MASK = (1 << VIRT_SIZE_LOG2) - 1, + VIRT_BASE_MASK = ~VIRT_OFFSET_MASK, + }; + + struct Type_0 : Bitfield<0, 2> { }; + struct Type_1_0 : Bitfield<1, 1> { }; + struct Type_1_1 : Bitfield<18, 1> { }; + struct Type_1 : Bitset_2 { }; + + /** + * Get descriptor type of 'v' + */ + static Type type(access_t const v) + { + switch (Type_0::get(v)) { + case 0: return FAULT; + case 1: return PAGE_TABLE; + } + + switch (Type_1::get(v)) { + case 1: return SECTION; + } + + return FAULT; + } + + /** + * Set descriptor type of 'v' + */ + static void type(access_t & v, Type const t) + { + switch (t) { + case FAULT: + Type_0::set(v, 0); + return; + case PAGE_TABLE: + Type_0::set(v, 1); + return; + case SECTION: + Type_1::set(v, 1); + return; + } + } + + /** + * Invalidate descriptor 'v' + */ + static void invalidate(access_t & v) { type(v, FAULT); } + + /** + * Return if descriptor 'v' is valid + */ + static bool valid(access_t & v) { return type(v) != FAULT; } + + static inline Type align(addr_t vo, size_t size) + { + return ((vo & VIRT_OFFSET_MASK) || size < VIRT_SIZE) + ? PAGE_TABLE : SECTION; + } + }; + + /** + * Link to a second level translation table + */ + struct Page_table_descriptor : Descriptor + { + struct Domain : Bitfield<5, 4> { }; /* domain */ + struct Pa : Bitfield<10, 22> { }; /* physical base */ + + /** + * Compose descriptor value + */ + static access_t create(Page_table * const pt) + { + access_t v = Domain::bits(DOMAIN) | + Pa::masked((addr_t)pt); + Descriptor::type(v, Descriptor::PAGE_TABLE); + return v; + } + }; + + /** + * Section translation descriptor + */ + struct Section : Descriptor + { + struct B : Bitfield<2, 1> { }; /* mem. region attr. */ + struct C : Bitfield<3, 1> { }; /* mem. region attr. */ + struct Xn : Bitfield<4, 1> { }; /* execute never bit */ + struct Domain : Bitfield<5, 4> { }; /* domain */ + struct Ap_0 : Bitfield<10, 2> { }; /* access permission */ + struct Tex : Bitfield<12, 3> { }; /* mem. region attr. */ + struct Ap_1 : Bitfield<15, 1> { }; /* access permission */ + struct S : Bitfield<16, 1> { }; /* shared */ + struct Ng : Bitfield<17, 1> { }; /* not global */ + struct Pa : Bitfield<20, 12> { }; /* physical base */ + struct Ap : Bitset_2 { }; /* access permission */ + + /** + * Compose descriptor value + */ + static access_t create(Page_flags const & flags, + addr_t const pa) + { + access_t v = access_permission_bits
(flags); + v |= memory_region_attr
(flags); + v |= Domain::bits(DOMAIN); + v |= S::bits(1); + v |= Ng::bits(!flags.global); + v |= Pa::masked(pa); + Descriptor::type(v, Descriptor::SECTION); + return v; + } + }; + + protected: + + /* 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 }; + + /** + * 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 on success + * \retval <0 if virtual offset couldn't be resolved, + * in this case 'i' reside invalid + */ + bool _index_by_vo(unsigned & i, addr_t const vo) const + { + if (vo > max_virt_offset()) return false; + i = vo >> Descriptor::VIRT_SIZE_LOG2; + return true; + } + + /** + * Insert a second level translation at the given entry index + * + * \param i the related index + * \param vo virtual start address of range + * \param pa physical start address of range + * \param size size of range + * \param flags mapping flags + * \param slab second level page slab allocator + */ + void _insert_second_level(unsigned i, + addr_t const vo, + addr_t const pa, + size_t const size, + Page_flags const & flags, + Page_slab * slab) + { + Page_table * pt = 0; + switch (Descriptor::type(_entries[i])) { + + case Descriptor::FAULT: + { + if (!slab) throw Allocator::Out_of_memory(); + + /* create and link page table */ + pt = new (slab) Page_table(); + Page_table * pt_phys = (Page_table*) slab->phys_addr(pt); + pt_phys = pt_phys ? pt_phys : pt; /* hack for core */ + _entries[i] = Page_table_descriptor::create(pt_phys); + } + + case Descriptor::PAGE_TABLE: + { + /* use allocator to retrieve virtual address of page table */ + void * pt_phys = (void*) + Page_table_descriptor::Pa::masked(_entries[i]); + pt = (Page_table *) slab->virt_addr(pt_phys); + pt = pt ? pt : (Page_table *)pt_phys ; /* hack for core */ + break; + } + + default: + { + throw Double_insertion(); + } + }; + + /* insert translation */ + pt->insert_translation(vo - Section::Pa::masked(vo), + pa, size, flags); + } + + public: + + /** + * Placement new + */ + void * operator new (size_t, void * p) { return p; } + + /** + * Constructor + */ + Section_table() + { + if (!aligned((addr_t)this, ALIGNM_LOG2)) + throw Misaligned(); + + /* start with an empty table */ + memset(&_entries, 0, sizeof(_entries)); + } + + /** + * Maximum virtual offset that can be translated by this table + */ + static addr_t max_virt_offset() + { + return (MAX_INDEX << Descriptor::VIRT_SIZE_LOG2) + + (Descriptor::VIRT_SIZE - 1); + } + + /** + * Insert translations 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 size of the translated region + * \param flags mapping flags + * \param slab second level page slab allocator + */ + void insert_translation(addr_t vo, + addr_t pa, + size_t size, + Page_flags const & flags, + Page_slab * slab) + { + /* sanity check */ + if ((vo & Page_table::Descriptor::VIRT_OFFSET_MASK) + || size < Page_table::Descriptor::VIRT_SIZE) + throw Invalid_range(); + + for (unsigned i; (size > 0) && _index_by_vo (i, vo);) { + + addr_t end = (vo + Descriptor::VIRT_SIZE) + & Descriptor::VIRT_BASE_MASK; + + /* decide granularity of entry that can be inserted */ + switch (Descriptor::align(vo, size)) { + + case Descriptor::SECTION: + { + if (Descriptor::valid(_entries[i]) && + _entries[i] != Section::create(flags, pa)) + throw Double_insertion(); + _entries[i] = Section::create(flags, pa); + break; + } + + default: + { + _insert_second_level(i, vo, pa, min(size, end-vo), flags, slab); + } + }; + + /* check whether we wrap */ + if (end < vo) return; + + size_t sz = end - vo; + size = (size > sz) ? size - sz : 0; + vo += sz; + pa += sz; + } + } + + /** + * Remove translations that overlap with a given virtual region + * + * \param vo region offset within the tables virtual region + * \param size region size + * \param slab second level page slab allocator + */ + void remove_translation(addr_t vo, size_t size, Page_slab * slab) + { + if (vo > (vo + size)) throw Invalid_range(); + + for (unsigned i; (size > 0) && _index_by_vo(i, vo);) { + + addr_t end = (vo + Descriptor::VIRT_SIZE) + & Descriptor::VIRT_BASE_MASK; + + switch (Descriptor::type(_entries[i])) { + + case Descriptor::PAGE_TABLE: + { + typedef Page_table_descriptor Ptd; + typedef Page_table Pt; + + Pt * pt_phys = (Pt *) Ptd::Pa::masked(_entries[i]); + Pt * pt = (Pt *) slab->virt_addr(pt_phys); + pt = pt ? pt : pt_phys; // TODO hack for core + + addr_t const pt_vo = vo - Section::Pa::masked(vo); + pt->remove_translation(pt_vo, min(size, end-vo)); + + if (pt->empty()) { + Descriptor::invalidate(_entries[i]); + destroy(slab, pt); + } + break; + } + + default: + { + Descriptor::invalidate(_entries[i]); + } + } + + /* check whether we wrap */ + if (end < vo) return; + + size_t sz = end - vo; + size = (size > sz) ? size - sz : 0; + vo += sz; + } + } +} __attribute__((aligned(1< + +template +static typename T::access_t +Arm::memory_region_attr(Page_flags const & flags) +{ + typedef typename T::Tex Tex; + typedef typename T::C C; + typedef typename T::B B; + if(flags.device) { return 0; } + if(flags.cacheable) { return Tex::bits(5) | B::bits(1); } + return Tex::bits(6) | C::bits(1); +} + +#endif /* _ARM_V6__TRANSLATION_TABLE_H_ */ diff --git a/base-hw/src/core/arm_v7/translation_table.h b/base-hw/src/core/arm_v7/translation_table.h new file mode 100644 index 000000000..613298162 --- /dev/null +++ b/base-hw/src/core/arm_v7/translation_table.h @@ -0,0 +1,33 @@ +/* + * \brief Armv7 translation table definitions for core + * \author Martin Stein + * \author Stefan Kalkowski + * \date 2012-02-22 + */ + +/* + * Copyright (C) 2012-2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _ARM_V7__TRANSLATION_TABLE_H_ +#define _ARM_V7__TRANSLATION_TABLE_H_ + +/* core includes */ +#include + +template +static typename T::access_t +Arm::memory_region_attr(Page_flags const & flags) +{ + typedef typename T::Tex Tex; + typedef typename T::C C; + typedef typename T::B B; + if (flags.device) { return Tex::bits(2); } + if (flags.cacheable) { return Tex::bits(5) | B::bits(1); } + return Tex::bits(6) | C::bits(1); +} + +#endif /* _ARM_V7__TRANSLATION_TABLE_H_ */ diff --git a/base-hw/src/core/arndale/platform_support.cc b/base-hw/src/core/arndale/platform_support.cc index f57b1c026..f197c2f39 100644 --- a/base-hw/src/core/arndale/platform_support.cc +++ b/base-hw/src/core/arndale/platform_support.cc @@ -47,6 +47,7 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i) { { Board::GIC_CPU_MMIO_BASE, Board::GIC_CPU_MMIO_SIZE }, { Board::MCT_MMIO_BASE, Board::MCT_MMIO_SIZE }, + { Board::UART_2_MMIO_BASE, 0x1000 }, }; return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0; } diff --git a/base-hw/src/core/context_area.cc b/base-hw/src/core/context_area.cc deleted file mode 100644 index 0d64567c8..000000000 --- a/base-hw/src/core/context_area.cc +++ /dev/null @@ -1,28 +0,0 @@ -/* - * \brief Support code for the thread API - * \author Martin Stein - * \date 2013-05-07 - */ - -/* - * Copyright (C) 2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -/* Genode includes */ -#include - -using namespace Genode; - -/** - * Return single instance of the context-area RM-session - * - * In base-hw core this object is never used because contexts - * get allocated through the phys-mem allocator. Anyways the - * accessor must exist because generic main-thread startup calls - * it to ensure that common allocations do not steal context area. - */ -namespace Genode { Rm_session * env_context_area_rm_session() { return 0; } } - diff --git a/base-hw/src/core/core_rm_session.cc b/base-hw/src/core/core_rm_session.cc new file mode 100644 index 000000000..21b9fc7a3 --- /dev/null +++ b/base-hw/src/core/core_rm_session.cc @@ -0,0 +1,66 @@ +/* + * \brief hw-specific implementation of core-local RM session + * \author Norman Feske + * \author Stefan Kalkowski + * \date 2014-02-26 + * + * Taken from OKL4-specific imlementation + */ + +/* + * Copyright (C) 2014 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* core includes */ +#include +#include +#include +#include +#include + +using namespace Genode; + +Rm_session::Local_addr +Core_rm_session::attach(Dataspace_capability ds_cap, size_t size, + off_t offset, bool use_local_addr, + Rm_session::Local_addr, bool executable) +{ + Object_pool::Guard ds(_ds_ep->lookup_and_lock(ds_cap)); + if (!ds) + throw Invalid_dataspace(); + + if (size == 0) + size = ds->size(); + + size_t page_rounded_size = (size + get_page_size() - 1) & get_page_mask(); + + if (use_local_addr) { + PERR("Parameter 'use_local_addr' not supported within core"); + return 0; + } + + if (offset) { + PERR("Parameter 'offset' not supported within core"); + return 0; + } + + /* allocate range in core's virtual address space */ + void *virt_addr; + if (!platform()->region_alloc()->alloc_aligned(page_rounded_size, + &virt_addr, + get_page_size_log2()).is_ok()) { + PERR("Could not allocate virtual address range in core of size %zd\n", + page_rounded_size); + return false; + } + + /* map the dataspace's physical pages to corresponding virtual addresses */ + unsigned num_pages = page_rounded_size >> get_page_size_log2(); + if (!map_local(ds->phys_addr(), (addr_t)virt_addr, num_pages)) + return 0; + + return virt_addr; +} diff --git a/base-hw/src/core/exynos5/tlb.h b/base-hw/src/core/exynos5/tlb.h deleted file mode 100644 index 63abccc02..000000000 --- a/base-hw/src/core/exynos5/tlb.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * \brief Translation lookaside buffer - * \author Martin Stein - * \date 2012-04-23 - */ - -/* - * Copyright (C) 2012 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _EXYNOS5__TLB_H_ -#define _EXYNOS5__TLB_H_ - -/* core includes */ -#include -#include - -namespace Genode -{ - class Tlb : public Arm_v7::Section_table { }; - - /** - * Translation lookaside buffer of core - */ - class Core_tlb : public Tlb - { - public: - - /** - * Constructor - ensures that core never gets a pagefault - */ - Core_tlb() - { - using namespace Genode; - map_core_area(Board::RAM_0_BASE, Board::RAM_0_SIZE, 0); - map_core_area(Board::MMIO_0_BASE, Board::MMIO_0_SIZE, 1); - } - }; -} - -#endif /* _EXYNOS5__TLB_H_ */ - diff --git a/base-hw/src/core/imx31/tlb.h b/base-hw/src/core/imx31/tlb.h deleted file mode 100644 index 279bc3233..000000000 --- a/base-hw/src/core/imx31/tlb.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * \brief Translation lookaside buffer - * \author Norman Feske - * \author Martin stein - * \date 2012-08-30 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _IMX31__TLB_H_ -#define _IMX31__TLB_H_ - -/* core includes */ -#include -#include - -namespace Genode -{ - class Tlb : public Arm_v6::Section_table { }; - - /** - * Translation lookaside buffer of core - */ - class Core_tlb : public Tlb - { - public: - - /** - * Constructor - ensures that core never gets a pagefault - */ - Core_tlb() - { - map_core_area(Board::RAM_0_BASE, Board::RAM_0_SIZE, 0); - map_core_area(Board::MMIO_0_BASE, Board::MMIO_0_SIZE, 1); - } - }; -} - -#endif /* _IMX31__TLB_H_ */ - diff --git a/base-hw/src/core/imx53/no_trustzone/tlb.h b/base-hw/src/core/imx53/no_trustzone/tlb.h deleted file mode 100644 index a088a4093..000000000 --- a/base-hw/src/core/imx53/no_trustzone/tlb.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * \brief Translation lookaside buffer - * \author Stefan Kalkowski - * \author Martin Stein - * \date 2012-10-24 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _IMX53__TLB_H_ -#define _IMX53__TLB_H_ - -/* core includes */ -#include -#include - -namespace Genode -{ - class Tlb : public Arm_v7::Section_table { }; - - /** - * Translation lookaside buffer of core - */ - class Core_tlb : public Tlb - { - public: - - /** - * Constructor - ensures that core never gets a pagefault - */ - Core_tlb() - { - map_core_area(Board::RAM0_BASE, Board::RAM0_SIZE, 0); - map_core_area(Board::RAM1_BASE, Board::RAM1_SIZE, 0); - map_core_area(Board::MMIO_BASE, Board::MMIO_SIZE, 1); - } - }; -} - -#endif /* _IMX53__TLB_H_ */ - diff --git a/base-hw/src/core/imx53/trustzone/tlb.h b/base-hw/src/core/imx53/trustzone/tlb.h deleted file mode 100644 index 344d80809..000000000 --- a/base-hw/src/core/imx53/trustzone/tlb.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * \brief Translation lookaside buffer - * \author Stefan Kalkowski - * \author Martin Stein - * \date 2012-10-24 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _IMX53__TLB_H_ -#define _IMX53__TLB_H_ - -#include - -/* core includes */ -#include -#include - -namespace Genode -{ - class Tlb : public Arm_v7::Section_table { }; - - /** - * Translation lookaside buffer of core - */ - class Core_tlb : public Tlb - { - public: - - /** - * Constructor - ensures that core never gets a pagefault - */ - Core_tlb() - { - map_core_area(Trustzone::SECURE_RAM_BASE, - Trustzone::SECURE_RAM_SIZE, 0); - map_core_area(Board::MMIO_BASE, Board::MMIO_SIZE, 1); - map_core_area(Trustzone::VM_STATE_BASE, - Trustzone::VM_STATE_SIZE, 1); - } - }; -} - -#endif /* _IMX53__TLB_H_ */ - diff --git a/base-hw/src/core/include/core_rm_session.h b/base-hw/src/core/include/core_rm_session.h new file mode 100644 index 000000000..58a7e000a --- /dev/null +++ b/base-hw/src/core/include/core_rm_session.h @@ -0,0 +1,61 @@ +/* + * \brief OKL4-specific core-local region manager session + * \author Norman Feske + * \author Stefan Kalkowski + * \date 2009-04-02 + */ + +/* + * Copyright (C) 2009-2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _CORE__INCLUDE__CORE_RM_SESSION_H_ +#define _CORE__INCLUDE__CORE_RM_SESSION_H_ + +/* Genode includes */ +#include +#include + +/* core includes */ +#include + +namespace Genode { + + /** + * Region manager that uses the physical dataspace + * addresses directly as virtual addresses. + */ + class Core_rm_session : public Rm_session + { + private: + + Rpc_entrypoint *_ds_ep; + + public: + + Core_rm_session(Rpc_entrypoint *ds_ep): _ds_ep(ds_ep) { } + + Local_addr attach(Dataspace_capability ds_cap, size_t size=0, + off_t offset=0, bool use_local_addr = false, + Local_addr local_addr = 0, + bool executable = false); + + void detach(Local_addr) { } + + Pager_capability add_client(Thread_capability thread) { + return Pager_capability(); } + + void remove_client(Pager_capability) { } + + void fault_handler(Signal_context_capability handler) { } + + State state() { return State(); } + + Dataspace_capability dataspace() { return Dataspace_capability(); } + }; +} + +#endif /* _CORE__INCLUDE__CORE_RM_SESSION_H_ */ diff --git a/base-hw/src/core/include/map_local.h b/base-hw/src/core/include/map_local.h new file mode 100644 index 000000000..96b37b40d --- /dev/null +++ b/base-hw/src/core/include/map_local.h @@ -0,0 +1,46 @@ +/* + * \brief Core-local mapping + * \author Stefan Kalkowski + * \date 2014-02-26 + */ + +/* + * Copyright (C) 2014 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _CORE__INCLUDE__MAP_LOCAL_H_ +#define _CORE__INCLUDE__MAP_LOCAL_H_ + +/* Genode includes */ +#include + +namespace Genode { + + /** + * Map physical pages to core-local virtual address range + * + * \param from_phys physical source address + * \param to_virt core-local destination address + * \param num_pages number of pages to map + * \param io_mem true if it's memory mapped I/O (uncached) + * + * \return true on success + */ + bool map_local(addr_t from_phys, addr_t to_virt, size_t num_pages, + bool io_mem = false); + + /** + * Unmap pages from core's address space + * + * \param virt_addr first core-local address to unmap, must be page-aligned + * \param num_pages number of pages to unmap + * + * \return true on success + */ + bool unmap_local(addr_t virt_addr, size_t num_pages); +} + +#endif /* _CORE__INCLUDE__MAP_LOCAL_H_ */ diff --git a/base-hw/src/core/tlb/page_flags.h b/base-hw/src/core/include/page_flags.h similarity index 100% rename from base-hw/src/core/tlb/page_flags.h rename to base-hw/src/core/include/page_flags.h diff --git a/base-hw/src/core/include/page_slab.h b/base-hw/src/core/include/page_slab.h new file mode 100644 index 000000000..d74dba6ba --- /dev/null +++ b/base-hw/src/core/include/page_slab.h @@ -0,0 +1,230 @@ +/* + * \brief Slab allocator with aligned slab entries + * \author Stefan Kalkowski + * \date 2014-03-04 + */ + +/* + * Copyright (C) 2014 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _CORE__INCLUDE__PAGE_SLAB_H_ +#define _CORE__INCLUDE__PAGE_SLAB_H_ + +#include +#include +#include +#include + +#include + +namespace Genode { + class Page_slab; +} + +/** + * Slab allocator returning aligned slab entries for page table descriptors. + */ +class Genode::Page_slab : public Genode::Allocator +{ + protected: + + static constexpr unsigned MIN_SLABS = 6; + static constexpr unsigned SLAB_SIZE = get_page_size(); + static constexpr unsigned SLABS_PER_BLOCK = 8 * sizeof(addr_t); + static constexpr unsigned ALIGN_LOG2 = get_page_size_log2(); + + /** + * A slab block holding a fixed amount of slabs + */ + struct Slab_block + { + uint8_t data[SLAB_SIZE*SLABS_PER_BLOCK]; + Bit_allocator indices; + List_element list_elem; + size_t ref_counter; + + Slab_block() : list_elem(this), ref_counter(0) {} + + /** + * Alloc a free block + */ + void* alloc() + { + ref_counter++; + size_t off = indices.alloc() * SLAB_SIZE; + return (void*)((Genode::addr_t)&data + off); + } + + /** + * Free given slab + * + * \param addr address of slab to free + * \return true if slab is part of this block, and got freed + */ + bool free(void *addr) + { + if (addr < &data || addr > &indices) return false; + ref_counter--; + size_t off = (addr_t)addr - (addr_t)&data; + indices.free(off / SLAB_SIZE); + return true; + } + + void * operator new (size_t, void * p) { return p; } + }; + + Slab_block _initial_sb __attribute__((aligned(1 << ALIGN_LOG2))); /* + first slab block is part of allocator to solve hen-egg problems */ + + List > _b_list; /* list of slab blocks */ + Core_mem_translator *_backing_store; /* block allocator */ + size_t _free_slab_entries; /* free slabs */ + bool _in_alloc; /* in block allocation */ + + /** + * Frees a given slab block + * + * \param b address of slab block to free + */ + void _free_slab_block(Slab_block * b) + { + if (b == &_initial_sb) return; + + _b_list.remove(&b->list_elem); + destroy(_backing_store, b); + _free_slab_entries -= SLABS_PER_BLOCK; + } + + /** + * Returns number of used slab blocks + */ + size_t _slab_blocks_in_use() + { + size_t cnt = 0; + for (List_element *le = _b_list.first(); + le; le = le->next(), cnt++) ; + return cnt; + } + + public: + + class Out_of_slabs {}; + + static constexpr size_t SLAB_BLOCK_SIZE = sizeof(Slab_block); + + /** + * Constructor + * + * \param backing_store allocator for additional slab blocks + */ + Page_slab(Core_mem_translator *backing_store) + : _backing_store(backing_store), _free_slab_entries(SLABS_PER_BLOCK), + _in_alloc(false) { _b_list.insert(&_initial_sb.list_elem); } + + ~Page_slab() + { + while (_b_list.first() && (_b_list.first() != &_initial_sb.list_elem)) + _free_slab_block(_b_list.first()->object()); + } + + /** + * Set allocator used for slab blocks + */ + void backing_store(Core_mem_translator *cma) { _backing_store = cma; } + + /** + * Allocate additional slab blocks + * + * \throw Out_of_memory when no slab block could be allocated + */ + void alloc_slab_block() + { + void *p; + if (!_backing_store->alloc_aligned(sizeof(Slab_block), &p, + ALIGN_LOG2).is_ok()) { + throw Out_of_memory(); + } + Slab_block *b = new (p) Slab_block(); + _b_list.insert(&b->list_elem); + _free_slab_entries += SLABS_PER_BLOCK; + _in_alloc = false; + } + + /** + * Allocate a slab + * + * \throw Out_of_slabs when new slab blocks need to be allocated + * \returns pointer to new slab, or zero if allocation failed + */ + void *alloc() + { + if (_free_slab_entries <= MIN_SLABS && !_in_alloc) { + _in_alloc = true; + throw Out_of_slabs(); + } + + void * ret = 0; + for (List_element *le = _b_list.first(); + le; le = le->next()) { + if (le->object()->ref_counter == SLABS_PER_BLOCK) + continue; + + ret = le->object()->alloc(); + _free_slab_entries--; + return ret; + } + return ret; + } + + /** + * Free a given slab + * + * As a side effect empty slab block might get freed + * + * \param addr address of slab to free + */ + void free(void *addr) + { + for (List_element *le = _b_list.first(); + le; le = le->next()) { + if (!le->object()->free(addr)) continue; + + if (_free_slab_entries++ > (MIN_SLABS+SLABS_PER_BLOCK) + && !le->object()->ref_counter) + _free_slab_block(le->object()); + } + } + + /** + * Return physical address of given slab address + * + * \param addr slab address + */ + void * phys_addr(void * addr) { + return _backing_store->phys_addr(addr); } + + /** + * Return slab address of given physical address + * + * \param addr physical address + */ + void * virt_addr(void * addr) { + return _backing_store->virt_addr(addr); } + + + /************************ + * Allocator interface ** + ************************/ + + bool alloc(size_t, void **addr) { return (*addr = alloc()); } + void free(void *addr, size_t) { free(addr); } + size_t consumed() { return SLAB_BLOCK_SIZE * _slab_blocks_in_use(); } + size_t overhead(size_t) { return SLAB_BLOCK_SIZE/SLABS_PER_BLOCK; } + bool need_size_for_free() const override { return false; } +}; + +#endif /* _CORE__INCLUDE__PAGE_SLAB_H_ */ diff --git a/base-hw/src/core/include/platform.h b/base-hw/src/core/include/platform.h index cb272a587..3c2cfd366 100644 --- a/base-hw/src/core/include/platform.h +++ b/base-hw/src/core/include/platform.h @@ -1,6 +1,7 @@ /* * \brief Platform interface * \author Martin Stein + * \author Stefan Kalkowski * \date 2011-12-21 */ @@ -25,6 +26,8 @@ /* core includes */ #include +#include +#include namespace Genode { @@ -33,16 +36,23 @@ namespace Genode { */ class Platform : public Platform_generic { - typedef Synchronized_range_allocator Phys_allocator; + typedef Core_mem_allocator::Phys_allocator Phys_allocator; - Phys_allocator _core_mem_alloc; /* core-accessible memory */ - Phys_allocator _io_mem_alloc; /* MMIO allocator */ - Phys_allocator _io_port_alloc; /* I/O port allocator */ - Phys_allocator _irq_alloc; /* IRQ allocator */ - Rom_fs _rom_fs; /* ROM file system */ + Core_mem_allocator _core_mem_alloc; /* core-accessible memory */ + Phys_allocator _io_mem_alloc; /* MMIO allocator */ + Phys_allocator _irq_alloc; /* IRQ allocator */ + Rom_fs _rom_fs; /* ROM file system */ - addr_t _vm_start; /* base of virtual address space */ - size_t _vm_size; /* size of virtual address space */ + /* + * Virtual-memory range for non-core address spaces. + * The virtual memory layout of core is maintained in + * '_core_mem_alloc.virt_alloc()'. + */ + addr_t _vm_start; + size_t _vm_size; + + + public: /** * Get one of the consecutively numbered available resource regions @@ -79,8 +89,6 @@ namespace Genode { */ static unsigned * _irq(unsigned const i); - public: - /** * Constructor */ @@ -91,13 +99,18 @@ namespace Genode { ** Platform_generic interface ** ********************************/ - inline Range_allocator * core_mem_alloc() { return &_core_mem_alloc; } + inline Range_allocator * core_mem_alloc() { + return &_core_mem_alloc; } - inline Range_allocator * ram_alloc() { return &_core_mem_alloc; } + inline Range_allocator * ram_alloc() { + return _core_mem_alloc.phys_alloc(); } + + inline Range_allocator * region_alloc() { + return _core_mem_alloc.virt_alloc(); } inline Range_allocator * io_mem_alloc() { return &_io_mem_alloc; } - inline Range_allocator * io_port_alloc() { return &_io_port_alloc; } + inline Range_allocator * io_port_alloc() { return 0; } inline Range_allocator * irq_alloc() { return &_irq_alloc; } @@ -114,13 +127,6 @@ namespace Genode { bool supports_direct_unmap() const { return 1; } - inline Range_allocator * region_alloc() - { - Kernel::log() << __PRETTY_FUNCTION__ << "not implemented\n"; - while (1) ; - return 0; - } - Affinity::Space affinity_space() const { return Affinity::Space(PROCESSORS); diff --git a/base-hw/src/core/include/platform_pd.h b/base-hw/src/core/include/platform_pd.h index 23eb56358..87f1354ee 100644 --- a/base-hw/src/core/include/platform_pd.h +++ b/base-hw/src/core/include/platform_pd.h @@ -20,25 +20,15 @@ #include /* Core includes */ -#include +#include #include #include #include +#include +#include namespace Genode { - /** - * Regain all administrative memory that isn't used anymore by 'tlb' - */ - inline void regain_ram_from_tlb(Tlb * tlb) - { - size_t s; - void * base; - while (tlb->regain_memory(base, s)) { - platform()->ram_alloc()->free(base, s); - } - } - class Platform_thread; /** @@ -48,42 +38,59 @@ namespace Genode { protected: - unsigned _id; - Native_capability _parent; - Native_thread_id _main_thread; - char const * const _label; - Tlb * _tlb; + Lock _lock; /* safeguard translation table and slab */ + unsigned _id; + Native_capability _parent; + Native_thread_id _main_thread; + char const * const _label; + Translation_table * _tt; /* translation table virtual addr. */ + Translation_table * _tt_phys; /* translation table physical addr. */ + uint8_t _kernel_pd[sizeof(Kernel::Pd)]; + Page_slab * _pslab; /* page table allocator */ public: /** * Constructor for core pd + * + * \param tt translation table address + * \param slab page table allocator */ - Platform_pd(Tlb * tlb) - : _main_thread(0), _label("core"), _tlb(tlb) { } + Platform_pd(Translation_table * tt, Page_slab * slab) + : _main_thread(0), _label("core"), _tt(tt), + _tt_phys(tt), _pslab(slab) { } /** - * Constructor + * Constructor for non-core pd + * + * \param label name of protection domain */ Platform_pd(char const *label) : _main_thread(0), _label(label) { - /* get some aligned space for the kernel object */ - void * kernel_pd = 0; - Range_allocator * ram = platform()->ram_alloc(); - bool kernel_pd_ok = - ram->alloc_aligned(Kernel::pd_size(), &kernel_pd, - Kernel::pd_alignment_log2()).is_ok(); - if (!kernel_pd_ok) { + Lock::Guard guard(_lock); + + Core_mem_allocator * cma = + static_cast(platform()->core_mem_alloc()); + void *tt; + + /* get some aligned space for the translation table */ + if (!cma->alloc_aligned(sizeof(Translation_table), (void**)&tt, + Translation_table::ALIGNM_LOG2).is_ok()) { PERR("failed to allocate kernel object"); throw Root::Quota_exceeded(); } + + _tt = new (tt) Translation_table(); + _tt_phys = (Translation_table*) cma->phys_addr(_tt); + _pslab = new (cma) Page_slab(cma); + Kernel::mtc()->map(_tt, _pslab); + /* create kernel object */ - _id = Kernel::new_pd(kernel_pd, this); + _id = Kernel::new_pd(&_kernel_pd, this); if (!_id) { PERR("failed to create kernel object"); throw Root::Unavailable(); } - _tlb = (Tlb *)kernel_pd; } /** @@ -109,6 +116,14 @@ namespace Genode return t->join_pd(this, 0, Address_space::weak_ptr()); } + + /** + * Unbind thread 't' from protection domain + */ + void unbind_thread(Platform_thread *t) { + t->join_pd(nullptr, false, Address_space::weak_ptr()); } + + /** * Assign parent interface to protection domain */ @@ -127,8 +142,13 @@ namespace Genode ** Accessors ** ***************/ - unsigned const id() { return _id; } - char const * const label() { return _label; } + Lock * lock() { return &_lock; } + unsigned const id() { return _id; } + char const * const label() { return _label; } + Page_slab * page_slab() { return _pslab; } + Translation_table * translation_table() { return _tt; } + Translation_table * translation_table_phys() { return _tt_phys; } + void page_slab(Page_slab *pslab) { _pslab = pslab; } /***************************** diff --git a/base-hw/src/core/include/platform_thread.h b/base-hw/src/core/include/platform_thread.h index 1dfc8ceff..e56e823d0 100644 --- a/base-hw/src/core/include/platform_thread.h +++ b/base-hw/src/core/include/platform_thread.h @@ -34,6 +34,7 @@ namespace Genode { class Thread_state; class Rm_client; class Platform_thread; + class Platform_pd; /** * Userland interface for the management of kernel thread-objects @@ -42,15 +43,13 @@ namespace Genode { { enum { LABEL_MAX_LEN = 32 }; - size_t _stack_size; Platform_pd * _pd; Weak_ptr _address_space; unsigned _id; Rm_client * _rm_client; - Native_utcb * _utcb_phys; - Native_utcb * _utcb_virt; - Tlb * _tlb; - Ram_dataspace_capability _utcb; + Native_utcb * _utcb_core_addr; /* UTCB address in core */ + Native_utcb * _utcb_pd_addr; /* UTCB address in pd */ + Ram_dataspace_capability _utcb; /* UTCB dataspace */ char _label[LABEL_MAX_LEN]; char _kernel_thread[sizeof(Kernel::Thread)]; @@ -81,10 +80,10 @@ namespace Genode { /** * Constructor for core threads * - * \param stack_size initial size of the stack * \param label debugging label + * \param utcb virtual address of UTCB within core */ - Platform_thread(size_t const stack_size, const char * const label); + Platform_thread(const char * const label, Native_utcb * utcb); /** * Constructor for threads outside of core @@ -182,13 +181,7 @@ namespace Genode { Native_thread_id id() const { return _id; } - size_t stack_size() const { return _stack_size; } - - Native_utcb * utcb_virt() const { return _utcb_virt; } - Ram_dataspace_capability utcb() const { return _utcb; } - - Tlb * tlb() const { return _tlb; } }; } diff --git a/base-hw/src/core/kernel/kernel.cc b/base-hw/src/core/kernel/kernel.cc index 86ee77433..15778ae35 100644 --- a/base-hw/src/core/kernel/kernel.cc +++ b/base-hw/src/core/kernel/kernel.cc @@ -30,19 +30,23 @@ #include #include #include +#include /* base includes */ +#include #include +#include /* base-hw includes */ #include #include - using namespace Kernel; extern Genode::Native_thread_id _main_thread_id; extern "C" void CORE_MAIN(); extern void * _start_secondary_processors; +extern int _prog_img_beg; +extern int _prog_img_end; Genode::Native_utcb * _main_thread_utcb; @@ -55,7 +59,6 @@ namespace Kernel /* import Genode types */ typedef Genode::umword_t umword_t; - typedef Genode::Core_tlb Core_tlb; typedef Genode::Core_thread_id Core_thread_id; } @@ -95,24 +98,65 @@ namespace Kernel */ Pd * core_pd() { + using Ttable = Genode::Translation_table; + constexpr int tt_align = 1 << Ttable::ALIGNM_LOG2; + /** - * Core protection-domain + * Dummy page slab backend allocator for bootstrapping only */ - struct Core_pd : public Platform_pd, public Pd + struct Simple_allocator : Genode::Core_mem_translator { - /** - * Constructor - */ - Core_pd(Tlb * const tlb) - : Platform_pd(tlb), - Pd(tlb, this) + Simple_allocator() { } + + int add_range(addr_t base, size_t size) { return -1; } + int remove_range(addr_t base, size_t size) { return -1; } + Alloc_return alloc_aligned(size_t size, void **out_addr, int align) { + return Alloc_return::RANGE_CONFLICT; } + Alloc_return alloc_addr(size_t size, addr_t addr) { + return Alloc_return::RANGE_CONFLICT; } + void free(void *addr) {} + size_t avail() { return 0; } + bool valid_addr(addr_t addr) { return false; } + bool alloc(size_t size, void **out_addr) { return false; } + void free(void *addr, size_t) { } + size_t overhead(size_t size) { return 0; } + bool need_size_for_free() const override { return false; } + + void * phys_addr(void * addr) { return addr; } + void * virt_addr(void * addr) { return addr; } + }; + + struct Core_pd : Platform_pd, Pd + { + Core_pd(Ttable * tt, Genode::Page_slab * slab) + : Platform_pd(tt, slab), + Pd(tt, this) { + using namespace Genode; + Platform_pd::_id = Pd::id(); + + /* map exception vector for core */ + Kernel::mtc()->map(tt, slab); + + /* map core's program image */ + addr_t start = trunc_page((addr_t)&_prog_img_beg); + addr_t end = round_page((addr_t)&_prog_img_end); + map_local(start, start, (end-start) / get_page_size()); + + /* map core's mmio regions */ + Native_region * r = Platform::_core_only_mmio_regions(0); + for (unsigned i = 0; r; + r = Platform::_core_only_mmio_regions(++i)) + map_local(r->base, r->base, r->size / get_page_size(), true); } }; - constexpr int tlb_align = 1 << Core_tlb::ALIGNM_LOG2; - Core_tlb * core_tlb = unmanaged_singleton(); - return unmanaged_singleton(core_tlb); + + Simple_allocator * sa = unmanaged_singleton(); + Ttable * tt = unmanaged_singleton(); + Genode::Page_slab * slab = unmanaged_singleton(sa); + return unmanaged_singleton(tt, slab); } /** @@ -142,12 +186,12 @@ namespace Kernel /** * Get attributes of the kernel objects */ - size_t thread_size() { return sizeof(Thread); } - size_t pd_size() { return sizeof(Tlb) + sizeof(Pd); } - size_t signal_context_size() { return sizeof(Signal_context); } - size_t signal_receiver_size() { return sizeof(Signal_receiver); } - unsigned pd_alignment_log2() { return Tlb::ALIGNM_LOG2; } - size_t vm_size() { return sizeof(Vm); } + size_t thread_size() { return sizeof(Thread); } + size_t signal_context_size() { return sizeof(Signal_context); } + size_t signal_receiver_size() { return sizeof(Signal_receiver); } + size_t vm_size() { return sizeof(Vm); } + unsigned pd_alignm_log2() { return Genode::Translation_table::ALIGNM_LOG2; } + size_t pd_size() { return sizeof(Genode::Translation_table) + sizeof(Pd); } enum { STACK_SIZE = 64 * 1024 }; @@ -160,7 +204,7 @@ namespace Kernel return s; } - addr_t core_tlb_base; + addr_t core_tt_base; unsigned core_pd_id; } @@ -184,8 +228,8 @@ extern "C" void init_kernel_uniprocessor() ************************************************************************/ /* calculate in advance as needed later when data writes aren't allowed */ - core_tlb_base = core_pd()->tlb()->base(); - core_pd_id = core_pd()->id(); + core_tt_base = (addr_t) core_pd()->translation_table(); + core_pd_id = core_pd()->id(); /* initialize all processor objects */ processor_pool(); @@ -216,7 +260,7 @@ extern "C" void init_kernel_multiprocessor() Processor::init_phys_kernel(); /* switch to core address space */ - Processor::init_virt_kernel(core_tlb_base, core_pd_id); + Processor::init_virt_kernel(core_tt_base, core_pd_id); /************************************ ** Now it's safe to use 'cmpxchg' ** @@ -307,9 +351,6 @@ extern "C" void kernel() Processor_client * const old_occupant = scheduler->occupant(); old_occupant->exception(processor_id); - /* check for TLB maintainance requirements */ - processor->flush_tlb(); - /* * The processor local as well as remote exception-handling may have * changed the scheduling of the local activities. Hence we must update the diff --git a/base-hw/src/core/kernel/kernel.h b/base-hw/src/core/kernel/kernel.h index 0c6531dab..0b582d899 100644 --- a/base-hw/src/core/kernel/kernel.h +++ b/base-hw/src/core/kernel/kernel.h @@ -17,6 +17,9 @@ #include -namespace Kernel { Pd * core_pd(); } +namespace Kernel { + Pd * core_pd(); + Mode_transition_control * mtc(); +} #endif /* _KERNEL__KERNEL_H_ */ diff --git a/base-hw/src/core/kernel/pd.h b/base-hw/src/core/kernel/pd.h index 1ab3d50ad..e3429785d 100644 --- a/base-hw/src/core/kernel/pd.h +++ b/base-hw/src/core/kernel/pd.h @@ -1,6 +1,7 @@ /* * \brief Kernel backend for protection domains * \author Martin Stein + * \author Stefan Kalkowski * \date 2012-11-30 */ @@ -21,8 +22,9 @@ #include #include #include -#include +#include #include +#include /* structure of the mode transition */ extern int _mt_begin; @@ -148,7 +150,7 @@ class Kernel::Mode_transition_control public: enum { - SIZE_LOG2 = Tlb::MIN_PAGE_SIZE_LOG2, + SIZE_LOG2 = Genode::Translation_table::MIN_PAGE_SIZE_LOG2, SIZE = 1 << SIZE_LOG2, VIRT_BASE = Processor::EXCEPTION_ENTRY, VIRT_END = VIRT_BASE + SIZE, @@ -185,17 +187,18 @@ class Kernel::Mode_transition_control /** * Map the mode transition page to a virtual address space * - * \param tlb translation buffer of the address space + * \param tt translation buffer of the address space * \param ram RAM donation for mapping (first try without) - * - * \return RAM-donation size that is needed to do the mapping */ - size_t map(Tlb * tlb, addr_t ram = 0) + void map(Genode::Translation_table * tt, + Genode::Page_slab * alloc) { - addr_t const phys_base = (addr_t)&_mt_begin; - return tlb->insert_translation(VIRT_BASE, phys_base, SIZE_LOG2, - Page_flags::mode_transition(), - (void *)ram); + try { + addr_t const phys_base = (addr_t)&_mt_begin; + tt->insert_translation(VIRT_BASE, phys_base, SIZE, + Page_flags::mode_transition(), alloc); + } catch(...) { + PERR("Inserting exception vector in page table failed!"); } } /** @@ -227,11 +230,14 @@ class Kernel::Pd : public Object { private: - Tlb * const _tlb; - Platform_pd * const _platform_pd; + Genode::Translation_table * const _tt; + Platform_pd * const _platform_pd; /* keep ready memory for size-aligned extra costs at construction */ - enum { EXTRA_RAM_SIZE = 2 * Tlb::MAX_COSTS_PER_TRANSLATION }; + enum { + EXTRA_RAM_SIZE = 2 * Genode::Translation_table::MAX_COSTS_PER_TRANSLATION + }; + char _extra_ram[EXTRA_RAM_SIZE]; public: @@ -239,33 +245,12 @@ class Kernel::Pd : public Object /** * Constructor * - * \param tlb translation lookaside buffer of the PD + * \param tt translation lookaside buffer of the PD * \param platform_pd core object of the PD */ - Pd(Tlb * const tlb, Platform_pd * const platform_pd) - : - _tlb(tlb), _platform_pd(platform_pd) - { - /* try to add translation for mode transition region */ - unsigned const slog2 = mtc()->map(tlb); - - /* extra ram needed to translate mode transition region */ - if (slog2) - { - /* get size aligned extra ram */ - addr_t const ram = (addr_t)&_extra_ram; - addr_t const ram_end = ram + sizeof(_extra_ram); - addr_t const aligned_ram = (ram_end - (1 << slog2)) & - ~((1 << slog2) - 1); - addr_t const aligned_ram_end = aligned_ram + (1 << slog2); - - /* check attributes of aligned extra ram */ - assert(aligned_ram >= ram && aligned_ram_end <= ram_end) - - /* translate mode transition region globally */ - mtc()->map(tlb, aligned_ram); - } - } + Pd(Genode::Translation_table * const tt, + Platform_pd * const platform_pd) + : _tt(tt), _platform_pd(platform_pd) { } /** * Destructor @@ -278,7 +263,7 @@ class Kernel::Pd : public Object void admit(Processor::Context * const c) { c->protection_domain(id()); - c->tlb(tlb()->base()); + c->translation_table((addr_t)translation_table()); } @@ -286,9 +271,10 @@ class Kernel::Pd : public Object ** Accessors ** ***************/ - Tlb * tlb() const { return _tlb; } - Platform_pd * platform_pd() const { return _platform_pd; } + + Genode::Translation_table * translation_table() const { + return _tt; } }; #endif /* _KERNEL__PD_H_ */ diff --git a/base-hw/src/core/kernel/processor.cc b/base-hw/src/core/kernel/processor.cc index a51c0693e..431408c46 100644 --- a/base-hw/src/core/kernel/processor.cc +++ b/base-hw/src/core/kernel/processor.cc @@ -14,6 +14,7 @@ /* core includes */ #include +#include #include #include #include @@ -27,6 +28,16 @@ namespace Kernel Timer * timer(); } +using Tlb_list_item = Genode::List_element; +using Tlb_list = Genode::List; + + +static Tlb_list *tlb_list() +{ + static Tlb_list tlb_list; + return &tlb_list; +} + void Kernel::Processor_client::_interrupt(unsigned const processor_id) { @@ -63,20 +74,40 @@ void Kernel::Processor_client::_schedule() { __processor->schedule(this); } void Kernel::Processor_client::tlb_to_flush(unsigned pd_id) { - /* initialize pd and reference counter, and remove client from scheduler */ + /* initialize pd and reference counters, and remove client from scheduler */ _flush_tlb_pd_id = pd_id; - _flush_tlb_ref_cnt = PROCESSORS; + for (unsigned i = 0; i < PROCESSORS; i++) + _flush_tlb_ref_cnt[i] = false; _unschedule(); + + /* find the last working item in the TLB work queue */ + Tlb_list_item * last = tlb_list()->first(); + while (last && last->next()) last = last->next(); + + /* insert new work item at the end of the work list */ + tlb_list()->insert(&_flush_tlb_li, last); + + /* enforce kernel entry of other processors */ + for (unsigned i = 0; i < PROCESSORS; i++) + pic()->trigger_ip_interrupt(i); + + processor_pool()->processor(Processor::executing_id())->flush_tlb(); } void Kernel::Processor_client::flush_tlb_by_id() { + /* flush TLB on current processor and adjust ref counter */ Processor::flush_tlb_by_pid(_flush_tlb_pd_id); + _flush_tlb_ref_cnt[Processor::executing_id()] = true; - /* if reference counter reaches zero, add client to scheduler again */ - if (--_flush_tlb_ref_cnt == 0) - _schedule(); + /* check whether all processors are done */ + for (unsigned i = 0; i < PROCESSORS; i++) + if (!_flush_tlb_ref_cnt[i]) return; + + /* remove work item from the list and re-schedule thread */ + tlb_list()->remove(&_flush_tlb_li); + _schedule(); } @@ -122,26 +153,12 @@ void Kernel::Processor_client::_yield() } -void Kernel::Processor::flush_tlb(Processor_client * const client) -{ - /* find the last working item in the TLB work queue */ - Genode::List_element * last = _ipi_scheduler.first(); - while (last && last->next()) last = last->next(); - - /* insert new work item at the end of the work list */ - _ipi_scheduler.insert(&client->_flush_tlb_li, last); - - /* enforce kernel entry of the corresponding processor */ - pic()->trigger_ip_interrupt(_id); -} - - void Kernel::Processor::flush_tlb() { /* iterate through the list of TLB work items, and proceed them */ - for (Genode::List_element * cli = _ipi_scheduler.first(); cli; - cli = _ipi_scheduler.first()) { - cli->object()->flush_tlb_by_id(); - _ipi_scheduler.remove(cli); + for (Tlb_list_item * cli = tlb_list()->first(); cli;) { + Tlb_list_item * current = cli; + cli = current->next(); + current->object()->flush_tlb_by_id(); } } diff --git a/base-hw/src/core/kernel/processor.h b/base-hw/src/core/kernel/processor.h index 356790948..6b33c5eb1 100644 --- a/base-hw/src/core/kernel/processor.h +++ b/base-hw/src/core/kernel/processor.h @@ -51,9 +51,7 @@ class Kernel::Processor_client : public Processor_scheduler::Item List_item _flush_tlb_li; /* TLB maintainance work list item */ unsigned _flush_tlb_pd_id; /* id of pd that TLB entries are flushed */ - unsigned _flush_tlb_ref_cnt; /* reference counter */ - - friend class Processor; + bool _flush_tlb_ref_cnt[PROCESSORS]; /* reference counters */ /** * Handle an interrupt exception that occured during execution @@ -104,7 +102,7 @@ class Kernel::Processor_client : public Processor_scheduler::Item virtual void proceed(unsigned const processor_id) = 0; /** - * Sets the pd id, which TLB entries should be flushed + * Enqueues TLB maintainance work into queue of the processors * * \param pd_id protection domain kernel object's id */ @@ -142,11 +140,8 @@ class Kernel::Processor : public Processor_driver { private: - using Ipi_scheduler = Genode::List >; - unsigned const _id; Processor_scheduler _scheduler; - Ipi_scheduler _ipi_scheduler; bool _ip_interrupt_pending; public: @@ -162,6 +157,11 @@ class Kernel::Processor : public Processor_driver _id(id), _scheduler(idle_client), _ip_interrupt_pending(false) { } + /** + * Perform outstanding TLB maintainance work + */ + void flush_tlb(); + /** * Notice that the inter-processor interrupt isn't pending anymore */ @@ -174,6 +174,7 @@ class Kernel::Processor : public Processor_driver * available. */ _ip_interrupt_pending = false; + flush_tlb(); } /** @@ -184,19 +185,6 @@ class Kernel::Processor : public Processor_driver void schedule(Processor_client * const client); - /** - * Add processor client to the TLB maintainance queue of the processor - * - * \param client targeted client - */ - void flush_tlb(Processor_client * const client); - - /** - * Perform outstanding TLB maintainance work - */ - void flush_tlb(); - - /*************** ** Accessors ** ***************/ diff --git a/base-hw/src/core/kernel/thread.cc b/base-hw/src/core/kernel/thread.cc index 5291ed3d2..e6941c0b3 100644 --- a/base-hw/src/core/kernel/thread.cc +++ b/base-hw/src/core/kernel/thread.cc @@ -172,8 +172,7 @@ void Thread::init(Processor * const processor, Pd * const pd, /* join protection domain */ _pd = pd; - addr_t const tlb = _pd->tlb()->base(); - User_context::init_thread(tlb, pd_id()); + User_context::init_thread((addr_t)_pd->translation_table(), pd_id()); /* print log message */ if (START_VERBOSE) { @@ -243,11 +242,13 @@ char const * Kernel::Thread::pd_label() const void Thread::_call_new_pd() { - /* create translation lookaside buffer and protection domain */ - void * p = (void *)user_arg_1(); - Tlb * const tlb = new (p) Tlb(); - p = (void *)((addr_t)p + sizeof(Tlb)); - Pd * const pd = new (p) Pd(tlb, (Platform_pd *)user_arg_2()); + using namespace Genode; + + /* create protection domain */ + void * p = (void *) user_arg_1(); + Platform_pd * ppd = (Platform_pd *) user_arg_2(); + Translation_table * tt = ppd->translation_table_phys(); + Pd * const pd = new (p) Pd(tt, ppd); user_arg_0(pd->id()); } @@ -262,10 +263,8 @@ void Thread::_call_bin_pd() user_arg_0(-1); return; } - /* destruct translation lookaside buffer and protection domain */ - Tlb * const tlb = pd->tlb(); + /* destruct protection domain */ pd->~Pd(); - tlb->~Tlb(); /* clean up buffers of memory management */ Processor::flush_tlb_by_pid(pd->id()); @@ -326,7 +325,7 @@ void Thread::_call_start_thread() /* start thread */ Native_utcb * const utcb = (Native_utcb *)user_arg_4(); thread->init(processor, pd, utcb, 1); - user_arg_0((Call_ret)thread->_pd->tlb()); + user_arg_0((Call_ret)thread->_pd->translation_table()); } @@ -538,10 +537,6 @@ void Thread::_call_access_thread_regs() void Thread::_call_update_pd() { tlb_to_flush(user_arg_1()); - - /* inform other processors */ - for (unsigned i = 0; i < PROCESSORS; i++) - Kernel::processor_pool()->processor(i)->flush_tlb(this); } diff --git a/base-hw/src/core/panda/tlb.h b/base-hw/src/core/panda/tlb.h deleted file mode 100644 index d8b3a0b06..000000000 --- a/base-hw/src/core/panda/tlb.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * \brief Transtaltion lookaside buffer - * \author Martin Stein - * \date 2012-04-23 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _PANDA__TLB_H_ -#define _PANDA__TLB_H_ - -/* core includes */ -#include -#include - -namespace Genode -{ - class Tlb : public Arm_v7::Section_table { }; - - /** - * Transtaltion lookaside buffer of core - */ - class Core_tlb : public Tlb - { - private: - - /** - * On Pandaboard the L2 cache needs to be disabled by a - * TrustZone hypervisor call - */ - void _disable_outer_l2_cache() - { - asm volatile ( - "stmfd sp!, {r0-r12} \n" - "mov r0, #0 \n" - "ldr r12, =0x102 \n" - "dsb \n" - "smc #0 \n" - "ldmfd sp!, {r0-r12}"); - } - - public: - - /** - * Constructor - ensures that core never gets a pagefault - */ - Core_tlb() - { - using namespace Genode; - - /* - * Disable L2-cache by now, or we get into deep trouble with the MMU - * not using the L2 cache - */ - _disable_outer_l2_cache(); - - map_core_area(Board::RAM_0_BASE, Board::RAM_0_SIZE, 0); - map_core_area(Board::MMIO_0_BASE, Board::MMIO_0_SIZE, 1); - map_core_area(Board::MMIO_1_BASE, Board::MMIO_1_SIZE, 1); - } - }; -} - -#endif /* _PANDA__TLB_H_ */ - diff --git a/base-hw/src/core/pbxa9/tlb.h b/base-hw/src/core/pbxa9/tlb.h deleted file mode 100644 index 1e297f6cd..000000000 --- a/base-hw/src/core/pbxa9/tlb.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * \brief Translation lookaside buffer - * \author Martin Stein - * \date 2012-04-23 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _PBXA9__TLB_H_ -#define _PBXA9__TLB_H_ - -/* core includes */ -#include -#include - -namespace Genode -{ - class Tlb : public Arm_v7::Section_table { }; - - /** - * Translation lookaside buffer of core - */ - class Core_tlb : public Tlb - { - public: - - /** - * Constructor - ensures that core never gets a pagefault - */ - Core_tlb() - { - using namespace Genode; - map_core_area(Board::RAM_0_BASE, Board::RAM_0_SIZE, 0); - map_core_area(Board::RAM_1_BASE, Board::RAM_1_SIZE, 0); - map_core_area(Board::MMIO_0_BASE, Board::MMIO_0_SIZE, 1); - map_core_area(Board::MMIO_1_BASE, Board::MMIO_1_SIZE, 1); - } - }; -} - -#endif /* _PBXA9__TLB_H_ */ - diff --git a/base-hw/src/core/platform.cc b/base-hw/src/core/platform.cc index d04c8c522..61181e14d 100644 --- a/base-hw/src/core/platform.cc +++ b/base-hw/src/core/platform.cc @@ -1,6 +1,7 @@ /* * \brief Platform implementation specific for hw * \author Martin Stein + * \author Stefan Kalkowski * \date 2011-12-21 */ @@ -18,9 +19,14 @@ /* core includes */ #include +#include +#include #include -#include +#include #include +#include +#include +#include using namespace Genode; @@ -86,12 +92,6 @@ Native_region * Platform::_core_only_ram_regions(unsigned const i) { static Native_region _r[] = { - /* avoid null pointers */ - { 0, 1 }, - - /* mode transition region */ - { Kernel::mode_transition_base(), Kernel::mode_transition_size() }, - /* core image */ { (addr_t)&_prog_img_beg, (size_t)((addr_t)&_prog_img_end - (addr_t)&_prog_img_beg) }, @@ -103,22 +103,32 @@ Native_region * Platform::_core_only_ram_regions(unsigned const i) return i < sizeof(_r)/sizeof(_r[0]) ? &_r[i] : 0; } +static Native_region * virt_region(unsigned const i) { + static Native_region r = { VIRT_ADDR_SPACE_START, VIRT_ADDR_SPACE_SIZE }; + return i ? 0 : &r; } + +static Core_mem_allocator * _core_mem_allocator = 0; Platform::Platform() : - _core_mem_alloc(0), - _io_mem_alloc(core_mem_alloc()), _io_port_alloc(core_mem_alloc()), + _io_mem_alloc(core_mem_alloc()), _irq_alloc(core_mem_alloc()), _vm_start(VIRT_ADDR_SPACE_START), _vm_size(VIRT_ADDR_SPACE_SIZE) { + static Page_slab pslab(&_core_mem_alloc); + Kernel::core_pd()->platform_pd()->page_slab(&pslab); + _core_mem_allocator = &_core_mem_alloc; + /* * Initialise platform resource allocators. * Core mem alloc must come first because it is * used by the other allocators. */ enum { VERBOSE = 0 }; - unsigned const psl2 = get_page_size_log2(); - init_alloc(&_core_mem_alloc, _ram_regions, _core_only_ram_regions, psl2); + init_alloc(_core_mem_alloc.phys_alloc(), _ram_regions, + _core_only_ram_regions, get_page_size_log2()); + init_alloc(_core_mem_alloc.virt_alloc(), virt_region, + _core_only_ram_regions, get_page_size_log2()); /* make interrupts available to the interrupt allocator */ for (unsigned i = 0; i < Kernel::Pic::MAX_INTERRUPT_ID; i++) @@ -139,11 +149,16 @@ Platform::Platform() Rom_module(header->base, header->size, (const char*)header->name); _rom_fs.insert(rom_module); } + /* print ressource summary */ if (VERBOSE) { - printf("Core memory allocator\n"); + printf("Core virtual memory allocator\n"); printf("---------------------\n"); - _core_mem_alloc.raw()->dump_addr_tree(); + _core_mem_alloc.virt_alloc()->raw()->dump_addr_tree(); + printf("\n"); + printf("RAM memory allocator\n"); + printf("---------------------\n"); + _core_mem_alloc.phys_alloc()->raw()->dump_addr_tree(); printf("\n"); printf("IO memory allocator\n"); printf("-------------------\n"); @@ -171,3 +186,76 @@ void Core_parent::exit(int exit_value) while (1) ; } + +/**************************************** + ** Support for core memory management ** + ****************************************/ + +bool Genode::map_local(addr_t from_phys, addr_t to_virt, size_t num_pages, bool io_mem) +{ + Translation_table *tt = Kernel::core_pd()->translation_table(); + const Page_flags flags = Page_flags::map_core_area(io_mem); + + try { + for (unsigned i = 0; i < 2; i++) { + try { + Lock::Guard guard(*Kernel::core_pd()->platform_pd()->lock()); + + tt->insert_translation(to_virt, from_phys, + num_pages * get_page_size(), flags, + Kernel::core_pd()->platform_pd()->page_slab()); + return true; + } catch(Page_slab::Out_of_slabs) { + Kernel::core_pd()->platform_pd()->page_slab()->alloc_slab_block(); + } + } + } catch(Allocator::Out_of_memory) { + PERR("Translation table needs to much RAM"); + } catch(...) { + PERR("Invalid mapping %p -> %p (%zx)", (void*)from_phys, (void*)to_virt, + get_page_size() * num_pages); + } + return false; +} + + +bool Genode::unmap_local(addr_t virt_addr, size_t num_pages) +{ + try { + Lock::Guard guard(*Kernel::core_pd()->platform_pd()->lock()); + + Translation_table *tt = Kernel::core_pd()->translation_table(); + tt->remove_translation(virt_addr, num_pages * get_page_size(), + Kernel::core_pd()->platform_pd()->page_slab()); + + /* update translation caches of all processors */ + Kernel::update_pd(Kernel::core_pd()->id()); + return true; + } catch(...) { + PERR("tried to remove invalid region!"); + } + return false; +} + + +bool Core_mem_allocator::Mapped_mem_allocator::_map_local(addr_t virt_addr, + addr_t phys_addr, + unsigned size) +{ + Genode::Page_slab * slab = Kernel::core_pd()->platform_pd()->page_slab(); + slab->backing_store(_core_mem_allocator->raw()); + bool ret = ::map_local(phys_addr, virt_addr, size / get_page_size(), false); + slab->backing_store(_core_mem_allocator); + return ret; +} + + +bool Core_mem_allocator::Mapped_mem_allocator::_unmap_local(addr_t virt_addr, + unsigned size) +{ + Genode::Page_slab * slab = Kernel::core_pd()->platform_pd()->page_slab(); + slab->backing_store(_core_mem_allocator->raw()); + bool ret = ::unmap_local(virt_addr, size / get_page_size()); + slab->backing_store(_core_mem_allocator); + return ret; +} diff --git a/base-hw/src/core/platform_pd.cc b/base-hw/src/core/platform_pd.cc index 615478529..c813deac6 100644 --- a/base-hw/src/core/platform_pd.cc +++ b/base-hw/src/core/platform_pd.cc @@ -1,6 +1,7 @@ /* * \brief Protection-domain facility * \author Martin Stein + * \author Stefan Kalkowski * \date 2012-02-12 */ @@ -18,10 +19,15 @@ using namespace Genode; Platform_pd::~Platform_pd() { - _tlb->remove_region(platform()->vm_start(), platform()->vm_size()); - regain_ram_from_tlb(_tlb); + Lock::Guard guard(_lock); + if (Kernel::bin_pd(_id)) { PERR("failed to destruct protection domain at kernel"); } + + _tt->remove_translation(platform()->vm_start(), platform()->vm_size(), + _pslab); + + /* TODO: destroy page slab and translation table!!! */ } diff --git a/base-hw/src/core/platform_thread.cc b/base-hw/src/core/platform_thread.cc index c3951787a..8493abf0a 100644 --- a/base-hw/src/core/platform_thread.cc +++ b/base-hw/src/core/platform_thread.cc @@ -17,6 +17,9 @@ #include #include #include +#include + +#include /* kernel includes */ #include @@ -51,19 +54,16 @@ Platform_thread::~Platform_thread() /* the RM client may be destructed before platform thread */ if (_rm_client) { Rm_session_component * const rm = _rm_client->member_rm_session(); - rm->detach(_utcb_virt); + rm->detach(_utcb_pd_addr); } } + /* free UTCB */ - if (_pd == Kernel::core_pd()->platform_pd()) { - Range_allocator * const ram = platform()->ram_alloc(); - ram->free(_utcb_phys, sizeof(Native_utcb)); - } else { - Ram_session_component * const ram = - dynamic_cast(core_env()->ram_session()); - assert(ram); - ram->free(_utcb); - } + Ram_session_component * const ram = + dynamic_cast(core_env()->ram_session()); + assert(ram); + ram->free(_utcb); + /* release from pager */ if (_rm_client) { Pager_object * const object = dynamic_cast(_rm_client); @@ -78,29 +78,27 @@ Platform_thread::~Platform_thread() } -Platform_thread::Platform_thread(size_t const stack_size, - const char * const label) -: - _stack_size(stack_size), - _pd(Kernel::core_pd()->platform_pd()), - _rm_client(0), - _utcb_virt(0), - _main_thread(0) +Platform_thread::Platform_thread(const char * const label, + Native_utcb * utcb) +: _pd(Kernel::core_pd()->platform_pd()), + _rm_client(0), + _utcb_core_addr(utcb), + _utcb_pd_addr(utcb), + _main_thread(0) { strncpy(_label, label, LABEL_MAX_LEN); /* create UTCB for a core thread */ - Range_allocator * const ram = platform()->ram_alloc(); - if (!ram->alloc_aligned(sizeof(Native_utcb), (void **)&_utcb_phys, - MIN_MAPPING_SIZE_LOG2).is_ok()) - { + void *utcb_phys; + if (!platform()->ram_alloc()->alloc(sizeof(Native_utcb), &utcb_phys)) { PERR("failed to allocate UTCB"); throw Cpu_session::Out_of_metadata(); } - _utcb_virt = _utcb_phys; + map_local((addr_t)utcb_phys, (addr_t)_utcb_core_addr, + sizeof(Native_utcb) / get_page_size()); /* set-up default start-info */ - _utcb_virt->core_start_info()->init(Processor_driver::primary_id()); + _utcb_core_addr->core_start_info()->init(Processor_driver::primary_id()); /* create kernel object */ _id = Kernel::new_thread(_kernel_thread, Kernel::Priority::MAX, _label); @@ -115,10 +113,9 @@ Platform_thread::Platform_thread(const char * const label, unsigned const virt_prio, addr_t const utcb) : - _stack_size(0), _pd(nullptr), _rm_client(0), - _utcb_virt((Native_utcb *)utcb), + _utcb_pd_addr((Native_utcb *)utcb), _main_thread(0) { strncpy(_label, label, LABEL_MAX_LEN); @@ -136,7 +133,7 @@ Platform_thread::Platform_thread(const char * const label, PERR("failed to allocate UTCB"); throw Cpu_session::Out_of_metadata(); } - _utcb_phys = (Native_utcb *)ram->phys_addr(_utcb); + _utcb_core_addr = (Native_utcb *)core_env()->rm_session()->attach(_utcb); /* create kernel object */ enum { MAX_PRIO = Kernel::Priority::MAX }; @@ -157,6 +154,7 @@ int Platform_thread::join_pd(Platform_pd * pd, bool const main_thread, PERR("thread already in another protection domain"); return -1; } + /* join protection domain */ _pd = pd; _main_thread = main_thread; @@ -178,13 +176,13 @@ int Platform_thread::start(void * const ip, void * const sp) { /* attach UTCB in case of a main thread */ if (_main_thread) { - _utcb_virt = main_thread_utcb(); + _utcb_pd_addr = UTCB_MAIN_THREAD; if (!_rm_client) { PERR("invalid RM client"); return -1; }; Rm_session_component * const rm = _rm_client->member_rm_session(); - try { rm->attach(_utcb, 0, 0, true, _utcb_virt, 0); } + try { rm->attach(_utcb, 0, 0, true, _utcb_pd_addr, 0); } catch (...) { PERR("failed to attach UTCB"); return -1; @@ -207,9 +205,8 @@ int Platform_thread::start(void * const ip, void * const sp) else { processor_id = Processor_driver::primary_id(); } /* start executing new thread */ - _utcb_phys->start_info()->init(_id, _utcb); - _tlb = Kernel::start_thread(_id, processor_id, _pd->id(), _utcb_phys); - if (!_tlb) { + _utcb_core_addr->start_info()->init(_id, _utcb); + if (!Kernel::start_thread(_id, processor_id, _pd->id(), _utcb_core_addr)) { PERR("failed to start thread"); return -1; } diff --git a/base-hw/src/core/processor_driver/arm.h b/base-hw/src/core/processor_driver/arm.h index 0d8bf092d..0fecf6ada 100644 --- a/base-hw/src/core/processor_driver/arm.h +++ b/base-hw/src/core/processor_driver/arm.h @@ -1,6 +1,7 @@ /* * \brief CPU driver for core * \author Martin stein + * \author Stefan Kalkowski * \date 2012-09-11 */ @@ -514,18 +515,18 @@ namespace Arm ** files. So take care if you attempt to change them. ** **********************************************************/ - uint32_t cidr; /* context ID register backup */ - uint32_t section_table; /* base address of applied section table */ + uint32_t cidr; /* context ID register backup */ + uint32_t t_table; /* base address of applied translation table */ /** * Get base of assigned translation lookaside buffer */ - addr_t tlb() const { return section_table; } + addr_t translation_table() const { return t_table; } /** * Assign translation lookaside buffer */ - void tlb(addr_t const st) { section_table = st; } + void translation_table(addr_t const tt) { t_table = tt; } /** * Assign protection domain @@ -567,13 +568,13 @@ namespace Arm /** * Initialize thread context * - * \param tlb physical base of appropriate page table + * \param tt physical base of appropriate translation table * \param pd_id kernel name of appropriate protection domain */ - void init_thread(addr_t const tlb, unsigned const pd_id) + void init_thread(addr_t const tt, unsigned const pd_id) { - cidr = pd_id; - section_table = tlb; + cidr = pd_id; + t_table = tt; } /** diff --git a/base-hw/src/core/ram_session_support.cc b/base-hw/src/core/ram_session_support.cc index 5c78bf4a9..2aabc8953 100644 --- a/base-hw/src/core/ram_session_support.cc +++ b/base-hw/src/core/ram_session_support.cc @@ -1,7 +1,11 @@ /* * \brief Export RAM dataspace as shared memory object (dummy) * \author Martin Stein + * \author Stefan Kalkowski * \date 2012-02-12 + * + * TODO: this file is almost identical to + * base-okl4/src/core/ram_session_support.cc, we should merge them */ /* @@ -14,26 +18,47 @@ /* Genode includes */ #include -/* base-hw includes */ -#include - /* core includes */ #include +#include +#include using namespace Genode; - void Ram_session_component::_export_ram_ds(Dataspace_component *ds) { } - - void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds) { } - void Ram_session_component::_clear_ds (Dataspace_component * ds) { - memset((void *)ds->phys_addr(), 0, ds->size()); + size_t page_rounded_size = (ds->size() + get_page_size() - 1) & get_page_mask(); - /* make the new DS-content visible to other PDs */ - Kernel::update_data_region(ds->phys_addr(), ds->size()); + /* allocate range in core's virtual address space */ + void *virt_addr; + if (!platform()->region_alloc()->alloc(page_rounded_size, &virt_addr)) { + PERR("could not allocate virtual address range in core of size %zd\n", + page_rounded_size); + return; + } + + /* map the dataspace's physical pages to corresponding virtual addresses */ + size_t num_pages = page_rounded_size >> get_page_size_log2(); + if (!map_local(ds->phys_addr(), (addr_t)virt_addr, num_pages)) { + PERR("core-local memory mapping failed"); + return; + } + + /* clear dataspace */ + memset(virt_addr, 0, page_rounded_size); + + /* uncached dataspaces need to be flushed */ + if (ds->write_combined()) + Kernel::update_data_region((addr_t)virt_addr, page_rounded_size); + + /* unmap dataspace from core */ + if (!unmap_local((addr_t)virt_addr, num_pages)) + PERR("could not unmap core-local address range at %p", virt_addr); + + /* free core's virtual address space */ + platform()->region_alloc()->free(virt_addr, page_rounded_size); } diff --git a/base-hw/src/core/rm_session_support.cc b/base-hw/src/core/rm_session_support.cc index a3fd21c3e..7e5593c65 100644 --- a/base-hw/src/core/rm_session_support.cc +++ b/base-hw/src/core/rm_session_support.cc @@ -20,24 +20,11 @@ #include #include #include -#include +#include using namespace Genode; -/************************************** - ** Helpers for processor broadcasts ** - **************************************/ - -struct Update_pd_data { unsigned const pd_id; }; - -void update_pd(void * const data) -{ - auto const d = reinterpret_cast(data); - Kernel::update_pd(d->pd_id); -} - - /*************** ** Rm_client ** ***************/ @@ -46,22 +33,19 @@ void Rm_client::unmap(addr_t, addr_t virt_base, size_t size) { /* remove mapping from the translation table of the thread that we serve */ Platform_thread * const pt = (Platform_thread *)badge(); - if (!pt) { - PWRN("failed to get platform thread of RM client"); + if (!pt || !pt->pd()) return; + + Lock::Guard guard(*pt->pd()->lock()); + + Translation_table * const tt = pt->pd()->translation_table(); + if (!tt) { + PWRN("failed to get translation table of RM client"); return; } - Tlb * const tlb = pt->tlb(); - if (!tlb) { - PWRN("failed to get page table of RM client"); - return; - } - tlb->remove_region(virt_base, size); + tt->remove_translation(virt_base, size,pt->pd()->page_slab()); /* update translation caches of all processors */ Kernel::update_pd(pt->pd()->id()); - - /* try to get back released memory from the translation table */ - regain_ram_from_tlb(tlb); } @@ -72,37 +56,36 @@ void Rm_client::unmap(addr_t, addr_t virt_base, size_t size) int Pager_activation_base::apply_mapping() { /* prepare mapping */ - Tlb * const tlb = (Tlb *)_fault.tlb; + Platform_pd * const pd = (Platform_pd*)_fault.pd; + + Lock::Guard guard(*pd->lock()); + + Translation_table * const tt = pd->translation_table(); + Page_slab * page_slab = pd->page_slab(); + Page_flags const flags = Page_flags::apply_mapping(_mapping.writable, _mapping.write_combined, _mapping.io_mem); - /* insert mapping into TLB */ - unsigned sl2; - sl2 = tlb->insert_translation(_mapping.virt_address, _mapping.phys_address, - _mapping.size_log2, flags); - if (sl2) - { - /* try to get some natural aligned RAM */ - void * ram; - bool ram_ok = platform()->ram_alloc()->alloc_aligned(1<insert_translation(_mapping.virt_address, - _mapping.phys_address, - _mapping.size_log2, flags, ram); - if (sl2) { - PWRN("TLB needs to much RAM"); - regain_ram_from_tlb(tlb); - return -1; + /* insert mapping into translation table */ + try { + for (unsigned retry = 0; retry < 2; retry++) { + try { + tt->insert_translation(_mapping.virt_address, _mapping.phys_address, + 1 << _mapping.size_log2, flags, page_slab); + return 0; + } catch(Page_slab::Out_of_slabs) { + page_slab->alloc_slab_block(); + } } + } catch(Allocator::Out_of_memory) { + PERR("Translation table needs to much RAM"); + } catch(...) { + PERR("Invalid mapping %p -> %p (%zx)", (void*)_mapping.phys_address, + (void*)_mapping.virt_address, 1 << _mapping.size_log2); } - return 0; + return -1; } diff --git a/base-hw/src/core/rpi/tlb.h b/base-hw/src/core/rpi/tlb.h deleted file mode 100644 index 32e0c4d91..000000000 --- a/base-hw/src/core/rpi/tlb.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * \brief Translation lookaside buffer - * \author Norman Feske - * \author Martin stein - * \date 2012-08-30 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _RPI__TLB_H_ -#define _RPI__TLB_H_ - -/* core includes */ -#include -#include - -namespace Genode -{ - class Tlb : public Arm_v6::Section_table { }; - - /** - * Translation lookaside buffer of core - */ - class Core_tlb : public Tlb - { - public: - - /** - * Constructor - ensures that core never gets a pagefault - */ - Core_tlb() - { - map_core_area(Board::RAM_0_BASE, Board::RAM_0_SIZE, 0); - map_core_area(Board::MMIO_0_BASE, Board::MMIO_0_SIZE, 1); - } - }; -} - -#endif /* _RPI__TLB_H_ */ - diff --git a/base-hw/src/core/target.inc b/base-hw/src/core/target.inc index f41e750fa..21043e345 100644 --- a/base-hw/src/core/target.inc +++ b/base-hw/src/core/target.inc @@ -29,6 +29,8 @@ INC_DIR += $(REP_DIR)/src/core \ SRC_CC += console.cc \ cpu_session_component.cc \ cpu_session_support.cc \ + core_rm_session.cc \ + core_mem_alloc.cc \ dataspace_component.cc \ dump_alloc.cc \ io_mem_session_component.cc \ @@ -47,6 +49,7 @@ SRC_CC += console.cc \ signal_session_component.cc \ trace_session_component.cc \ thread.cc \ + thread_support.cc \ kernel/kernel.cc \ kernel/thread.cc \ kernel/vm.cc \ @@ -75,8 +78,11 @@ vpath rm_session_component.cc $(BASE_DIR)/src/core vpath rom_session_component.cc $(BASE_DIR)/src/core vpath trace_session_component.cc $(BASE_DIR)/src/core vpath dump_alloc.cc $(BASE_DIR)/src/core +vpath context_area.cc $(BASE_DIR)/src/core +vpath core_mem_alloc.cc $(BASE_DIR)/src/core vpath console.cc $(REP_DIR)/src/base vpath pager.cc $(REP_DIR)/src/base vpath _main.cc $(BASE_DIR)/src/platform +vpath thread.cc $(BASE_DIR)/src/base/thread vpath % $(REP_DIR)/src/core diff --git a/base-hw/src/core/thread.cc b/base-hw/src/core/thread.cc deleted file mode 100644 index 0ad8b0923..000000000 --- a/base-hw/src/core/thread.cc +++ /dev/null @@ -1,116 +0,0 @@ -/* - * \brief Implementation of Thread API interface for core - * \author Martin Stein - * \date 2012-01-25 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -/* Genode includes */ -#include -#include -#include - -/* core includes */ -#include -#include -#include - -using namespace Genode; - -extern Genode::Native_utcb * _main_thread_utcb; - -namespace Kernel { unsigned core_id(); } - - -Native_utcb * Thread_base::utcb() -{ - if (this) { return _tid.platform_thread->utcb_virt(); } - return _main_thread_utcb; -} - - -Thread_base * Thread_base::myself() -{ - /* get thread ident from the aligned base of the stack */ - int dummy = 0; - addr_t sp = (addr_t)(&dummy); - enum { SP_MASK = ~((1 << CORE_STACK_ALIGNM_LOG2) - 1) }; - Core_thread_id id = *(Core_thread_id *)((addr_t)sp & SP_MASK); - return (Thread_base *)id; -} - - -void Thread_base::_thread_start() -{ - /* this is never called by the main thread */ - Thread_base::myself()->_thread_bootstrap(); - Thread_base::myself()->entry(); -} - - -Thread_base::Thread_base(const char * const label, size_t const stack_size, Type) -{ - _tid.platform_thread = new (platform()->core_mem_alloc()) - Platform_thread(stack_size, label); -} - - -Thread_base::~Thread_base() -{ - Kernel::log() << __PRETTY_FUNCTION__ << "not implemented\n"; - while (1) ; -} - - -void Thread_base::start() -{ - /* allocate stack memory that fullfills the constraints for core stacks */ - size_t const size = _tid.platform_thread->stack_size(); - if (size > (1 << CORE_STACK_ALIGNM_LOG2) - sizeof(Core_thread_id)) { - PERR("stack size does not fit stack alignment of core"); - return; - } - void * base; - Platform * const p = static_cast(platform()); - Range_allocator * const alloc = p->core_mem_alloc(); - if (alloc->alloc_aligned(size, &base, CORE_STACK_ALIGNM_LOG2).is_error()) { - PERR("failed to allocate stack memory"); - return; - } - /* provide thread ident at the aligned base of the stack */ - *(Core_thread_id *)base = (Core_thread_id)this; - - /* set affinity of thread */ - Platform_thread * const platform_thread = _tid.platform_thread; - unsigned const processor_id = utcb()->core_start_info()->processor_id(); - Affinity::Location location(processor_id, 0, 1, 1); - platform_thread->affinity(location); - - /* start thread with stack pointer at the top of stack */ - void * sp = (void *)((addr_t)base + size); - void * ip = (void *)&_thread_start; - if (platform_thread->start(ip, sp)) { - PERR("failed to start thread"); - alloc->free(base, size); - return; - } -} - - -void Thread_base::join() -{ - _join_lock.lock(); -} - - -void Thread_base::cancel_blocking() -{ - _tid.platform_thread->cancel_blocking(); -} - diff --git a/base-hw/src/core/thread_support.cc b/base-hw/src/core/thread_support.cc new file mode 100644 index 000000000..e543c8e4f --- /dev/null +++ b/base-hw/src/core/thread_support.cc @@ -0,0 +1,62 @@ +/* + * \brief Implementation of Thread API interface for core + * \author Stefan Kalkowski + * \author Martin Stein + * \date 2014-02-27 + */ + +/* + * Copyright (C) 2014 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Genode includes */ +#include +#include +#include + +/* core includes */ +#include +#include + +using namespace Genode; + +extern Genode::Native_utcb * _main_thread_utcb; + +Native_utcb * main_thread_utcb() { + return _main_thread_utcb; } + + +void Thread_base::start() +{ + /* start thread with stack pointer at the top of stack */ + if (_tid.platform_thread->start((void *)&_thread_start, stack_top())) + PERR("failed to start thread"); +} + + +void Thread_base::cancel_blocking() +{ + _tid.platform_thread->cancel_blocking(); +} + + +void Thread_base::_deinit_platform_thread() +{ + /* destruct platform thread */ + destroy(platform()->core_mem_alloc(), _tid.platform_thread); +} + + +void Thread_base::_init_platform_thread(Type type) +{ + /* create platform thread */ + _tid.platform_thread = new (platform()->core_mem_alloc()) + Platform_thread(_context->name, &_context->utcb); + + if (type == NORMAL) { return; } + + PWRN("not implemented!"); +} diff --git a/base-hw/src/core/tlb/arm.h b/base-hw/src/core/tlb/arm.h deleted file mode 100644 index 11d5843be..000000000 --- a/base-hw/src/core/tlb/arm.h +++ /dev/null @@ -1,825 +0,0 @@ -/* - * \brief TLB driver for core - * \author Martin Stein - * \date 2012-02-22 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _TLB__ARM_H_ -#define _TLB__ARM_H_ - -/* Genode includes */ -#include -#include - -/* base-hw includes */ -#include -#include - -namespace Arm -{ - using namespace Genode; - - /** - * Check if 'p' is aligned to 1 << 'alignm_log2' - */ - inline bool aligned(addr_t const a, size_t const alignm_log2) { - return a == ((a >> alignm_log2) << alignm_log2); } - - /** - * Return permission configuration according to given mapping flags - * - * \param T targeted translation-table-descriptor type - * \param flags mapping flags - * - * \return descriptor value with AP and XN set and the rest left zero - */ - template - static typename T::access_t - access_permission_bits(Page_flags const & flags) - { - typedef typename T::Xn Xn; - typedef typename T::Ap Ap; - typedef typename T::access_t access_t; - bool const w = flags.writeable; - bool const p = flags.privileged; - access_t ap; - if (w) { if (p) { ap = Ap::bits(0b001); } - else { ap = Ap::bits(0b011); } - } else { if (p) { ap = Ap::bits(0b101); } - else { ap = Ap::bits(0b010); } - } - return Xn::bits(!flags.executable) | ap; - } - - /** - * Memory region attributes for the translation descriptor 'T' - */ - template - static typename T::access_t - memory_region_attr(Page_flags const & flags); - - /** - * Second level translation table - */ - class Page_table - { - enum { - _1KB_LOG2 = 10, - _4KB_LOG2 = 12, - _64KB_LOG2 = 16, - _1MB_LOG2 = 20, - }; - - public: - - enum { - SIZE_LOG2 = _1KB_LOG2, - SIZE = 1 << SIZE_LOG2, - ALIGNM_LOG2 = SIZE_LOG2, - - VIRT_SIZE_LOG2 = _1MB_LOG2, - VIRT_SIZE = 1 << VIRT_SIZE_LOG2, - VIRT_BASE_MASK = ~((1 << VIRT_SIZE_LOG2) - 1), - }; - - protected: - - /** - * Common descriptor structure - */ - struct Descriptor : Register<32> - { - /** - * Descriptor types - */ - enum Type { FAULT, SMALL_PAGE }; - - struct Type_0 : Bitfield<0, 2> { }; - struct Type_1 : Bitfield<1, 1> { }; - - /** - * Get descriptor type of 'v' - */ - static Type type(access_t const v) - { - access_t const t0 = Type_0::get(v); - if (t0 == 0) { return FAULT; } - access_t const t1 = Type_1::get(v); - if (t1 == 1) return SMALL_PAGE; - return FAULT; - } - - /** - * Set descriptor type of 'v' - */ - static void type(access_t & v, Type const t) - { - switch (t) { - case FAULT: - Type_0::set(v, 0); - return; - case SMALL_PAGE: - Type_1::set(v, 1); - return; - } - } - - /** - * Invalidate descriptor 'v' - */ - static void invalidate(access_t & v) { type(v, FAULT); } - - /** - * Return if descriptor 'v' is valid - */ - static bool valid(access_t & v) { return type(v) != FAULT; } - }; - - /** - * Represents an untranslated virtual region - */ - struct Fault : Descriptor - { - enum { - VIRT_SIZE_LOG2 = _4KB_LOG2, - VIRT_SIZE = 1 << VIRT_SIZE_LOG2, - VIRT_BASE_MASK = ~((1 << VIRT_SIZE_LOG2) - 1) - }; - }; - - /** - * Small page descriptor structure - */ - struct Small_page : Descriptor - { - enum { - VIRT_SIZE_LOG2 = _4KB_LOG2, - VIRT_SIZE = 1 << VIRT_SIZE_LOG2, - VIRT_OFFSET_MASK = (1 << VIRT_SIZE_LOG2) - 1, - VIRT_BASE_MASK = ~(VIRT_OFFSET_MASK), - }; - - struct Xn : Bitfield<0, 1> { }; /* execute never */ - struct B : Bitfield<2, 1> { }; /* mem region attr. */ - struct C : Bitfield<3, 1> { }; /* mem region attr. */ - struct Ap_0 : Bitfield<4, 2> { }; /* access permission */ - struct Tex : Bitfield<6, 3> { }; /* mem region attr. */ - struct Ap_1 : Bitfield<9, 1> { }; /* access permission */ - struct S : Bitfield<10, 1> { }; /* shareable bit */ - struct Ng : Bitfield<11, 1> { }; /* not global bit */ - struct Pa_31_12 : Bitfield<12, 20> { }; /* physical base */ - - struct Ap : Bitset_2 { }; /* access permission */ - - /** - * Compose descriptor value - */ - static access_t create(Page_flags const & flags, - addr_t const pa) - { - access_t v = access_permission_bits(flags); - v |= memory_region_attr(flags); - v |= Ng::bits(!flags.global); - v |= S::bits(1); - v |= Pa_31_12::masked(pa); - Descriptor::type(v, Descriptor::SMALL_PAGE); - return v; - } - }; - - /* - * Table payload - * - * Must be the only member of this class - */ - Descriptor::access_t _entries[SIZE/sizeof(Descriptor::access_t)]; - - enum { MAX_INDEX = sizeof(_entries) / sizeof(_entries[0]) - 1 }; - - /** - * Get entry index by virtual offset - * - * \param i is overridden with the index if call returns 0 - * \param vo virtual offset relative to the virtual table base - * - * \retval 0 on success - * \retval <0 translation failed - */ - int _index_by_vo (unsigned & i, addr_t const vo) const - { - if (vo > max_virt_offset()) return -1; - i = vo >> Small_page::VIRT_SIZE_LOG2; - return 0; - } - - public: - - /** - * Constructor - */ - Page_table() - { - /* check table alignment */ - if (!aligned((addr_t)this, ALIGNM_LOG2) || - (addr_t)this != (addr_t)_entries) - { - PDBG("Insufficient table alignment"); - while (1) ; - } - /* start with an empty table */ - for (unsigned i = 0; i <= MAX_INDEX; i++) - Descriptor::invalidate(_entries[i]); - } - - /** - * Maximum virtual offset that can be translated by this table - */ - static addr_t max_virt_offset() - { - return (MAX_INDEX << Small_page::VIRT_SIZE_LOG2) - + (Small_page::VIRT_SIZE - 1); - } - - /** - * 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 flags mapping flags - * - * 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, - size_t const size_log2, - Page_flags const & flags) - { - /* validate virtual address */ - unsigned i; - if (_index_by_vo (i, vo)) { - PDBG("Invalid virtual offset"); - while (1) ; - } - /* select descriptor type by the translation size */ - if (size_log2 == Small_page::VIRT_SIZE_LOG2) - { - /* compose new descriptor value */ - Descriptor::access_t const entry = - Small_page::create(flags, pa); - - /* 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) ; - } - /* override table entry with new descriptor value */ - _entries[i] = entry; - return; - } - PDBG("Translation size not supported"); - while (1) ; - } - - /** - * Remove translations that overlap with a given virtual region - * - * \param vo region offset within the tables virtual region - * \param size region size - */ - void remove_region(addr_t vo, size_t const size) - { - addr_t const ve = vo + size; - unsigned i; - while (1) - { - if (vo >= ve) { return; } - if (_index_by_vo(i, vo)) { return; } - addr_t next_vo; - switch (Descriptor::type(_entries[i])) { - - case Descriptor::FAULT: { - - vo &= Fault::VIRT_BASE_MASK; - next_vo = vo + Fault::VIRT_SIZE; - break; } - - case Descriptor::SMALL_PAGE: { - - vo &= Small_page::VIRT_BASE_MASK; - Descriptor::invalidate(_entries[i]); - next_vo = vo + Small_page::VIRT_SIZE; - break; } - } - if (next_vo < vo) { return; } - vo = next_vo; - } - } - - /** - * Does this table solely contain invalid entries - */ - bool empty() - { - for (unsigned i = 0; i <= MAX_INDEX; i++) { - if (Descriptor::valid(_entries[i])) return false; - } - return true; - } - - /** - * Get next translation size log2 by area constraints - * - * \param vo virtual offset within this table - * \param s area size - */ - static unsigned - translation_size_l2(addr_t const vo, size_t const s) - { - off_t const o = vo & Small_page::VIRT_OFFSET_MASK; - if (!o && s >= Small_page::VIRT_SIZE) - return Small_page::VIRT_SIZE_LOG2; - PDBG("Insufficient alignment or size"); - while (1) ; - } - - } __attribute__((aligned(1< - { - /** - * Descriptor types - */ - enum Type { FAULT, PAGE_TABLE, SECTION }; - - struct Type_0 : Bitfield<0, 2> { }; - struct Type_1_0 : Bitfield<1, 1> { }; - struct Type_1_1 : Bitfield<18, 1> { }; - struct Type_1 : Bitset_2 { }; - - /** - * Get descriptor type of 'v' - */ - static Type type(access_t const v) - { - access_t const t0 = Type_0::get(v); - if (t0 == 0) { return FAULT; } - if (t0 == 1) { return PAGE_TABLE; } - access_t const t1 = Type_1::get(v); - if (t1 == 1) { return SECTION; } - return FAULT; - } - - /** - * Set descriptor type of 'v' - */ - static void type(access_t & v, Type const t) - { - switch (t) { - case FAULT: - Type_0::set(v, 0); - return; - case PAGE_TABLE: - Type_0::set(v, 1); - return; - case SECTION: - Type_1::set(v, 1); - return; - } - } - - /** - * Invalidate descriptor 'v' - */ - static void invalidate(access_t & v) { type(v, FAULT); } - - /** - * Return if descriptor 'v' is valid - */ - static bool valid(access_t & v) { return type(v) != FAULT; } - }; - - /** - * Represents an untranslated virtual region - */ - struct Fault : Descriptor - { - enum { - VIRT_SIZE_LOG2 = _1MB_LOG2, - VIRT_SIZE = 1 << VIRT_SIZE_LOG2, - VIRT_BASE_MASK = ~((1 << VIRT_SIZE_LOG2) - 1) - }; - }; - - /** - * Link to a second level translation table - */ - struct Page_table_descriptor : Descriptor - { - struct Domain : Bitfield<5, 4> { }; /* domain */ - struct Pa_31_10 : Bitfield<10, 22> { }; /* physical base */ - - /** - * Compose descriptor value - */ - static access_t create(Page_table * const pt) - { - access_t v = Domain::bits(DOMAIN) | - Pa_31_10::masked((addr_t)pt); - Descriptor::type(v, Descriptor::PAGE_TABLE); - return v; - } - }; - - /** - * Section translation descriptor - */ - struct Section : Descriptor - { - enum { - VIRT_SIZE_LOG2 = _1MB_LOG2, - VIRT_SIZE = 1 << VIRT_SIZE_LOG2, - VIRT_OFFSET_MASK = (1 << VIRT_SIZE_LOG2) - 1, - VIRT_BASE_MASK = ~(VIRT_OFFSET_MASK), - }; - - struct B : Bitfield<2, 1> { }; /* mem. region attr. */ - struct C : Bitfield<3, 1> { }; /* mem. region attr. */ - struct Xn : Bitfield<4, 1> { }; /* execute never bit */ - struct Domain : Bitfield<5, 4> { }; /* domain */ - struct Ap_0 : Bitfield<10, 2> { }; /* access permission */ - struct Tex : Bitfield<12, 3> { }; /* mem. region attr. */ - struct Ap_1 : Bitfield<15, 1> { }; /* access permission */ - struct S : Bitfield<16, 1> { }; /* shared */ - struct Ng : Bitfield<17, 1> { }; /* not global */ - struct Pa_31_20 : Bitfield<20, 12> { }; /* physical base */ - - struct Ap : Bitset_2 { }; /* access permission */ - - /** - * Compose descriptor value - */ - static access_t create(Page_flags const & flags, - addr_t const pa) - { - access_t v = access_permission_bits
(flags); - v |= memory_region_attr
(flags); - v |= Domain::bits(DOMAIN); - v |= S::bits(1); - v |= Ng::bits(!flags.global); - v |= Pa_31_20::masked(pa); - Descriptor::type(v, Descriptor::SECTION); - return v; - } - }; - - protected: - - /* 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 }; - - /** - * 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 on success - * \retval <0 if virtual offset couldn't be resolved, - * in this case 'i' reside invalid - */ - int _index_by_vo(unsigned & i, addr_t const vo) const - { - if (vo > max_virt_offset()) return -1; - i = vo >> Section::VIRT_SIZE_LOG2; - return 0; - } - - public: - - /** - * Placement new - */ - void * operator new (size_t, void * p) { return p; } - - /** - * Constructor - */ - Section_table() - { - /* check for appropriate positioning of the table */ - if (!aligned((addr_t)this, ALIGNM_LOG2) - || (addr_t)this != (addr_t)_entries) - { - PDBG("Insufficient table alignment"); - while (1) ; - } - /* start with an empty table */ - for (unsigned i = 0; i <= MAX_INDEX; i++) - Descriptor::invalidate(_entries[i]); - } - - /** - * Maximum virtual offset that can be translated by this table - */ - static addr_t max_virt_offset() - { - return (MAX_INDEX << Section::VIRT_SIZE_LOG2) - + (Section::VIRT_SIZE - 1); - } - - /** - * Insert one atomic translation into this table - * - * \param ST platform specific section-table type - * \param st platform specific section 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 flags mapping flags - * \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. - */ - template - size_t insert_translation(addr_t const vo, addr_t const pa, - size_t const size_log2, - Page_flags const & flags, - ST * const st, - void * const extra_space = 0) - { - typedef typename ST::Section Section; - typedef typename ST::Page_table_descriptor Page_table_descriptor; - - /* validate virtual address */ - unsigned i; - if (_index_by_vo (i, vo)) { - PDBG("Invalid virtual offset"); - while (1) ; - } - /* select descriptor type by translation size */ - if (size_log2 < Section::VIRT_SIZE_LOG2) - { - /* check if an appropriate page table already exists */ - Page_table * pt; - if (Descriptor::type(_entries[i]) == Descriptor::PAGE_TABLE) { - pt = (Page_table *)(addr_t) - Page_table_descriptor::Pa_31_10::masked(_entries[i]); - } - /* 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 */ - pt = new (extra_space) Page_table(); - _entries[i] = Page_table_descriptor::create(pt, st); - } - /* request additional memory to create a page table */ - else return Page_table::SIZE_LOG2; - - /* insert translation */ - pt->insert_translation(vo - Section::Pa_31_20::masked(vo), - pa, size_log2, flags); - return 0; - } - if (size_log2 == Section::VIRT_SIZE_LOG2) - { - /* compose section descriptor */ - Descriptor::access_t const entry = - Section::create(flags, pa, st); - - /* 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) ; - } - /* override the table entry */ - _entries[i] = entry; - return 0; - } - PDBG("Translation size not supported"); - while (1) ; - } - - /** - * Remove translations that overlap with a given virtual region - * - * \param vo region offset within the tables virtual region - * \param size region size - */ - void remove_region(addr_t vo, size_t const size) - { - addr_t const ve = vo + size; - unsigned i; - while (1) - { - if (vo >= ve) { return; } - if (_index_by_vo(i, vo)) { return; } - addr_t next_vo; - switch (Descriptor::type(_entries[i])) { - - case Descriptor::FAULT: { - - vo &= Fault::VIRT_BASE_MASK; - next_vo = vo + Fault::VIRT_SIZE; - break; } - - case Descriptor::PAGE_TABLE: { - - typedef Page_table_descriptor Ptd; - typedef Page_table Pt; - - vo &= Pt::VIRT_BASE_MASK; - Pt * const pt = (Pt *)Ptd::Pa_31_10::masked(_entries[i]); - addr_t const pt_vo = vo - Section::Pa_31_20::masked(vo); - pt->remove_region(pt_vo, ve - vo); - next_vo = vo + Pt::VIRT_SIZE; - break; } - - case Descriptor::SECTION: { - - vo &= Section::VIRT_BASE_MASK; - Descriptor::invalidate(_entries[i]); - next_vo = vo + Section::VIRT_SIZE; - break; } - } - if (next_vo < vo) { return; } - vo = next_vo; - } - } - - /** - * Get base address for hardware table walk - */ - addr_t base() const { return (addr_t)_entries; } - - /** - * Get a portion of memory that is no longer used by this table - * - * \param base base of regained mem portion if method returns 1 - * \param s size of regained mem portion if method returns 1 - * - * \retval 1 successfully regained memory - * \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) - { - Page_table * const pt = (Page_table *) - (addr_t)Page_table_descriptor::Pa_31_10::masked(_entries[i]); - if (pt->empty()) - { - /* we've found an useless page table */ - Descriptor::invalidate(_entries[i]); - base = (void *)pt; - s = sizeof(Page_table); - return true; - } - } - } - return false; - } - - /** - * Get next translation size log2 by area constraints - * - * \param vo virtual offset within this table - * \param s area size - */ - static unsigned - translation_size_l2(addr_t const vo, size_t const s) - { - off_t const o = vo & Section::VIRT_OFFSET_MASK; - if (!o && s >= Section::VIRT_SIZE) - return Section::VIRT_SIZE_LOG2; - return Page_table::translation_size_l2(o, s); - } - - /** - * Insert translations for given area, do not permit displacement - * - * \param vo virtual offset within this table - * \param s area size - * \param flags mapping flags - */ - template - void map_core_area(addr_t vo, size_t s, bool io_mem, ST * st) - { - /* initialize parameters */ - Page_flags const flags = Page_flags::map_core_area(io_mem); - unsigned tsl2 = translation_size_l2(vo, s); - size_t ts = 1 << tsl2; - - /* walk through the area and map all offsets */ - while (1) - { - /* map current offset without displacement */ - if(st->insert_translation(vo, vo, tsl2, flags)) { - PDBG("Displacement not permitted"); - return; - } - /* update parameters for next round or exit */ - vo += ts; - s = ts < s ? s - ts : 0; - if (!s) return; - tsl2 = translation_size_l2(vo, s); - ts = 1 << tsl2; - } - } - - } __attribute__((aligned(1< - -namespace Arm_v6 -{ - using namespace Genode; - - /** - * First level translation table - */ - class Section_table; -} - -class Arm_v6::Section_table : public Arm::Section_table -{ - private: - - typedef Arm::Section_table Base; - - public: - - /** - * Link to second level translation-table - */ - struct Page_table_descriptor : Base::Page_table_descriptor - { - /** - * Compose descriptor value - */ - static access_t create(Arm::Page_table * const pt, Section_table *) - { - return Base::Page_table_descriptor::create(pt); - } - }; - - /** - * Section translation descriptor - */ - struct Section : Base::Section - { - /** - * Compose descriptor value - */ - static access_t create(Page_flags const & flags, - addr_t const pa, Section_table *) - { - return Base::Section::create(flags, pa); - } - }; - - /** - * Insert one atomic translation into this table - * - * For details see 'Base::insert_translation' - */ - size_t insert_translation(addr_t const vo, addr_t const pa, - size_t const size_l2, - Page_flags const & f, - void * const p = 0) - { - return Base::insert_translation(vo, pa, size_l2, f, this, p); - } - - /** - * Insert translations for given area, do not permit displacement - * - * \param vo virtual offset within this table - * \param s area size - * \param io_mem wether the area maps MMIO - */ - void map_core_area(addr_t vo, size_t s, bool const io_mem) - { - Base::map_core_area(vo, s, io_mem, this); - } -}; - - -template -static typename T::access_t -Arm::memory_region_attr(Page_flags const & flags) -{ - typedef typename T::Tex Tex; - typedef typename T::C C; - typedef typename T::B B; - if(flags.device) { return 0; } - if(flags.cacheable) { return Tex::bits(5) | B::bits(1); } - return Tex::bits(6) | C::bits(1); -} - - -#endif /* _TLB__ARM_V6_H_ */ diff --git a/base-hw/src/core/tlb/arm_v7.h b/base-hw/src/core/tlb/arm_v7.h deleted file mode 100644 index 52ae2ccdd..000000000 --- a/base-hw/src/core/tlb/arm_v7.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * \brief TLB driver for core - * \author Martin Stein - * \date 2012-02-22 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _TLB__ARM_V7_H_ -#define _TLB__ARM_V7_H_ - -/* core includes */ -#include -#include - -namespace Arm_v7 -{ - /** - * First level translation table - */ - class Section_table; -} - -class Arm_v7::Section_table : public Arm::Section_table -{ - private: - - typedef Arm::Section_table Base; - typedef Genode::addr_t addr_t; - typedef Genode::size_t size_t; - - public: - - /** - * Link to second level translation-table - */ - struct Page_table_descriptor : Base::Page_table_descriptor - { - struct Ns : Bitfield<3, 1> { }; /* non-secure bit */ - - /** - * Compose descriptor value - */ - static access_t create(Arm::Page_table * const pt, - Section_table * const st) - { - access_t const ns = Ns::bits(!st->secure()); - return Base::Page_table_descriptor::create(pt) | ns; - } - }; - - /** - * Section translation descriptor - */ - struct Section : Base::Section - { - struct Ns : Bitfield<19, 1> { }; /* non-secure bit */ - - /** - * Compose descriptor value - */ - static access_t create(Page_flags const & flags, - addr_t const pa, Section_table * const st) - { - access_t const ns = Ns::bits(!st->secure()); - return Base::Section::create(flags, pa) | ns; - } - }; - - protected: - - /* if this table is dedicated to secure mode or to non-secure mode */ - bool const _secure; - - public: - - /** - * Constructor - */ - Section_table() : _secure(Processor_driver::secure_mode()) { } - - /** - * Insert one atomic translation into this table - * - * For details see 'Base::insert_translation' - */ - size_t insert_translation(addr_t const vo, addr_t const pa, - size_t const size_log2, - Page_flags const & flags, - void * const p = 0) - { - return Base::insert_translation(vo, pa, size_log2, flags, this, p); - } - - /** - * Insert translations for given area, do not permit displacement - * - * \param vo virtual offset within this table - * \param s area size - * \param io_mem wether the area maps MMIO - */ - void map_core_area(addr_t vo, size_t s, bool const io_mem) - { - Base::map_core_area(vo, s, io_mem, this); - } - - - /*************** - ** Accessors ** - ***************/ - - bool secure() const { return _secure; } -}; - - -template -static typename T::access_t -Arm::memory_region_attr(Page_flags const & flags) -{ - typedef typename T::Tex Tex; - typedef typename T::C C; - typedef typename T::B B; - if (flags.device) { return Tex::bits(2); } - if (flags.cacheable) { return Tex::bits(5) | B::bits(1); } - return Tex::bits(6) | C::bits(1); -} - - -#endif /* _TLB__ARM_V7_H_ */ diff --git a/base-hw/src/core/vea9x4/no_trustzone/tlb.h b/base-hw/src/core/vea9x4/no_trustzone/tlb.h deleted file mode 100644 index 471b14294..000000000 --- a/base-hw/src/core/vea9x4/no_trustzone/tlb.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * \brief Translation lookaside buffer - * \author Martin Stein - * \date 2012-04-23 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _VEA9X4__TLB_H_ -#define _VEA9X4__TLB_H_ - -/* core includes */ -#include -#include - -namespace Genode -{ - class Tlb : public Arm_v7::Section_table { }; - - /** - * Translation lookaside buffer of core - */ - class Core_tlb : public Tlb - { - public: - - /** - * Constructor - ensures that core never gets a pagefault - */ - Core_tlb() - { - map_core_area(Board::RAM_0_BASE, Board::RAM_0_SIZE, 0); - map_core_area(Board::RAM_1_BASE, Board::RAM_1_SIZE, 0); - map_core_area(Board::RAM_2_BASE, Board::RAM_2_SIZE, 0); - map_core_area(Board::RAM_3_BASE, Board::RAM_3_SIZE, 0); - map_core_area(Board::MMIO_0_BASE, Board::MMIO_0_SIZE, 1); - map_core_area(Board::MMIO_1_BASE, Board::MMIO_1_SIZE, 1); - } - }; -} - -#endif /* _VEA9X4__TLB_H_ */ - diff --git a/base-hw/src/core/vea9x4/trustzone/tlb.h b/base-hw/src/core/vea9x4/trustzone/tlb.h deleted file mode 100644 index 6f7261caa..000000000 --- a/base-hw/src/core/vea9x4/trustzone/tlb.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * \brief Translation lookaside buffer - * \author Martin Stein - * \author Stefan Kalkowski - * \date 2012-04-23 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _VEA9X4__TLB_H_ -#define _VEA9X4__TLB_H_ - -#include - -/* core includes */ -#include -#include - -namespace Genode -{ - class Tlb : public Arm_v7::Section_table { }; - - /** - * Translation lookaside buffer of core - */ - class Core_tlb : public Tlb - { - public: - - /** - * Constructor - ensures that core never gets a pagefault - */ - Core_tlb() - { - map_core_area(Trustzone::SECURE_RAM_BASE, Trustzone::SECURE_RAM_SIZE, 0); - map_core_area(Board::MMIO_0_BASE, Board::MMIO_0_SIZE, 1); - map_core_area(Board::MMIO_1_BASE, Board::MMIO_1_SIZE, 1); - map_core_area(Trustzone::VM_STATE_BASE, Trustzone::VM_STATE_SIZE, 1); - } - }; -} - -#endif /* _VEA9X4__TLB_H_ */ -