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_ */
-