hw: map core on demand (fix #723)

Instead of mapping all physical memory 1:1 into core/kernel's address space,
this commit limits the 1:1 mapping to the binary image, and I/O memory
regions used by the kernel only. All subsequent memory accesses of core
are done by mapping the corresponding memory on demand, and not necessarily
1:1.

This commit has several side effects:

The page table code had to be revisited completely. The kernel inserts no
longer anything into the page tables, apart from the initial translations
to have the core/kernel image available when enabling the MMU. The page
tables and higher level translation tables are no longer named Tlb, but
Translation_table instead. There is no indirection class required to define
the translation tables of a concrete SoC, the appropriated ARM specifier
is sufficient.
The ability to map core's memory the same way like it's done for all other
protection domains, makes a special treatment of core's threads (no context
area) obsolete.

Ref #567 (partly solves it)
Fix #723
Fix #1068
This commit is contained in:
Stefan Kalkowski 2014-04-28 21:31:57 +02:00 committed by Norman Feske
parent 34b18e9da2
commit 73eb7a8d4b
46 changed files with 1739 additions and 2033 deletions

View File

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

View File

@ -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;

View File

@ -1,6 +1,7 @@
/*
* \brief Thread initialization
* \author Martin stein
* \author Stefan Kalkowski
* \date 2013-02-15
*/
@ -14,6 +15,7 @@
/* Genode includes */
#include <base/thread.h>
#include <base/env.h>
#include <base/sleep.h>
/* base-hw includes */
#include <kernel/interface.h>
@ -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();
}

View File

@ -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);

View File

@ -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]);
}
}

View File

@ -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;

View File

@ -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 <util/register.h>
#include <base/printf.h>
/* base-hw includes */
#include <page_flags.h>
#include <page_slab.h>
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 <typename T>
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 <typename T>
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<Ap_0, Ap_1> { }; /* access permission */
/**
* Compose descriptor value
*/
static access_t create(Page_flags const & flags,
addr_t const pa)
{
access_t v = access_permission_bits<Small_page>(flags);
v |= memory_region_attr<Small_page>(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<<Page_table::ALIGNM_LOG2)));
enum { DOMAIN = 0 };
public:
enum {
SIZE_LOG2 = 14,
SIZE = 1 << SIZE_LOG2,
ALIGNM_LOG2 = SIZE_LOG2,
MAX_COSTS_PER_TRANSLATION = sizeof(Page_table),
MAX_PAGE_SIZE_LOG2 = 20,
MIN_PAGE_SIZE_LOG2 = 12,
};
/**
* A first level translation descriptor
*/
struct Descriptor : Register<32>
{
/**
* 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<Type_1_0, Type_1_1> { };
/**
* 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<Ap_0, Ap_1> { }; /* access permission */
/**
* Compose descriptor value
*/
static access_t create(Page_flags const & flags,
addr_t const pa)
{
access_t v = access_permission_bits<Section>(flags);
v |= memory_region_attr<Section>(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<<Section_table::ALIGNM_LOG2)));
namespace Genode { using Translation_table = Arm::Section_table; }
#endif /* _ARM__SHORT_TRANSLATION_TABLE_H_ */

View File

@ -0,0 +1,33 @@
/*
* \brief Armv6 translation table 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_V6__TRANSLATION_TABLE_H_
#define _ARM_V6__TRANSLATION_TABLE_H_
/* core includes */
#include <arm/short_translation_table.h>
template <typename T>
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_ */

View File

@ -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 <arm/short_translation_table.h>
template <typename T>
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_ */

View File

@ -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;
}

View File

@ -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 <rm_session/rm_session.h>
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; } }

View File

@ -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 <platform.h>
#include <core_rm_session.h>
#include <map_local.h>
#include <util.h>
#include <base/heap.h>
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<Dataspace_component>::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;
}

View File

@ -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 <board.h>
#include <tlb/arm_v7.h>
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_ */

View File

@ -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 <tlb/arm_v6.h>
#include <board.h>
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_ */

View File

@ -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 <board.h>
#include <tlb/arm_v7.h>
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_ */

View File

@ -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 <drivers/trustzone.h>
/* core includes */
#include <board.h>
#include <tlb/arm_v7.h>
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_ */

View File

@ -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 <rm_session/rm_session.h>
#include <base/rpc_server.h>
/* core includes */
#include <dataspace_component.h>
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_ */

View File

@ -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 <base/printf.h>
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_ */

View File

@ -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 <base/allocator.h>
#include <base/stdint.h>
#include <util/list.h>
#include <util/bit_allocator.h>
#include <core_mem_alloc.h>
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<SLABS_PER_BLOCK> indices;
List_element<Slab_block> 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<List_element<Slab_block> > _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<Slab_block> *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<Slab_block> *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<Slab_block> *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_ */

View File

@ -1,6 +1,7 @@
/*
* \brief Platform interface
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2011-12-21
*/
@ -25,6 +26,8 @@
/* core includes */
#include <platform_generic.h>
#include <core_rm_session.h>
#include <core_mem_alloc.h>
namespace Genode {
@ -33,16 +36,23 @@ namespace Genode {
*/
class Platform : public Platform_generic
{
typedef Synchronized_range_allocator<Allocator_avl> 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);

View File

@ -20,25 +20,15 @@
#include <root/root.h>
/* Core includes */
#include <tlb.h>
#include <translation_table.h>
#include <platform.h>
#include <platform_thread.h>
#include <address_space.h>
#include <page_slab.h>
#include <kernel/kernel.h>
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<Core_mem_allocator*>(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; }
/*****************************

View File

@ -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> _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; }
};
}

View File

@ -30,19 +30,23 @@
#include <trustzone.h>
#include <timer.h>
#include <pic.h>
#include <map_local.h>
/* base includes */
#include <base/allocator_avl.h>
#include <unmanaged_singleton.h>
#include <base/native_types.h>
/* base-hw includes */
#include <kernel/irq.h>
#include <kernel/perf_counter.h>
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<Core_tlb, tlb_align>();
return unmanaged_singleton<Core_pd>(core_tlb);
Simple_allocator * sa = unmanaged_singleton<Simple_allocator>();
Ttable * tt = unmanaged_singleton<Ttable, tt_align>();
Genode::Page_slab * slab = unmanaged_singleton<Genode::Page_slab,
tt_align>(sa);
return unmanaged_singleton<Core_pd>(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

View File

@ -17,6 +17,9 @@
#include <kernel/pd.h>
namespace Kernel { Pd * core_pd(); }
namespace Kernel {
Pd * core_pd();
Mode_transition_control * mtc();
}
#endif /* _KERNEL__KERNEL_H_ */

View File

@ -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 <kernel/configuration.h>
#include <kernel/object.h>
#include <kernel/processor.h>
#include <tlb.h>
#include <translation_table.h>
#include <assert.h>
#include <page_slab.h>
/* 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<Pd, MAX_PDS, Pd_ids, pd_ids, pd_pool>
{
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<Pd, MAX_PDS, Pd_ids, pd_ids, pd_pool>
/**
* 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<Pd, MAX_PDS, Pd_ids, pd_ids, pd_pool>
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<Pd, MAX_PDS, Pd_ids, pd_ids, pd_pool>
** 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_ */

View File

@ -14,6 +14,7 @@
/* core includes */
#include <kernel/processor.h>
#include <kernel/processor_pool.h>
#include <kernel/thread.h>
#include <kernel/irq.h>
#include <pic.h>
@ -27,6 +28,16 @@ namespace Kernel
Timer * timer();
}
using Tlb_list_item = Genode::List_element<Processor_client>;
using Tlb_list = Genode::List<Tlb_list_item>;
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<Processor_client> * 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<Processor_client> * 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();
}
}

View File

@ -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<Genode::List_element<Processor_client> >;
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 **
***************/

View File

@ -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);
}

View File

@ -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 <board.h>
#include <tlb/arm_v7.h>
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_ */

View File

@ -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 <board.h>
#include <tlb/arm_v7.h>
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_ */

View File

@ -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 <core_parent.h>
#include <page_slab.h>
#include <map_local.h>
#include <platform.h>
#include <pic.h>
#include <platform_pd.h>
#include <util.h>
#include <pic.h>
#include <kernel/kernel.h>
#include <translation_table.h>
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;
}

View File

@ -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!!! */
}

View File

@ -17,6 +17,9 @@
#include <platform_pd.h>
#include <core_env.h>
#include <rm_session_component.h>
#include <map_local.h>
#include <kernel/pd.h>
/* kernel includes */
#include <kernel/kernel.h>
@ -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<Ram_session_component *>(core_env()->ram_session());
assert(ram);
ram->free(_utcb);
}
Ram_session_component * const ram =
dynamic_cast<Ram_session_component *>(core_env()->ram_session());
assert(ram);
ram->free(_utcb);
/* release from pager */
if (_rm_client) {
Pager_object * const object = dynamic_cast<Pager_object *>(_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;
}

View File

@ -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;
}
/**

View File

@ -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/printf.h>
/* base-hw includes */
#include <kernel/core_interface.h>
/* core includes */
#include <ram_session_component.h>
#include <platform.h>
#include <map_local.h>
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);
}

View File

@ -20,24 +20,11 @@
#include <platform.h>
#include <platform_pd.h>
#include <platform_thread.h>
#include <tlb.h>
#include <translation_table.h>
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<Update_pd_data *>(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<<sl2, &ram,
sl2).is_ok();
if (!ram_ok) {
PWRN("failed to allocate additional RAM for TLB");
return -1;
}
/* try to translate again with extra RAM */
sl2 = tlb->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;
}

View File

@ -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 <tlb/arm_v6.h>
#include <board.h>
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_ */

View File

@ -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

View File

@ -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 <base/thread.h>
#include <base/env.h>
#include <kernel/log.h>
/* core includes */
#include <platform.h>
#include <platform_thread.h>
#include <kernel/kernel.h>
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 *>(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();
}

View File

@ -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 <base/thread.h>
#include <base/sleep.h>
#include <base/env.h>
/* core includes */
#include <platform.h>
#include <platform_thread.h>
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!");
}

View File

@ -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 <util/register.h>
#include <base/printf.h>
/* base-hw includes */
#include <placement_new.h>
#include <tlb/page_flags.h>
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 <typename T>
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 <typename T>
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<Ap_0, Ap_1> { }; /* access permission */
/**
* Compose descriptor value
*/
static access_t create(Page_flags const & flags,
addr_t const pa)
{
access_t v = access_permission_bits<Small_page>(flags);
v |= memory_region_attr<Small_page>(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<<Page_table::ALIGNM_LOG2)));
/**
* First level translation table
*/
class Section_table
{
enum {
_16KB_LOG2 = 14,
_1MB_LOG2 = 20,
_16MB_LOG2 = 24,
DOMAIN = 0,
};
public:
enum {
SIZE_LOG2 = _16KB_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),
MAX_COSTS_PER_TRANSLATION = sizeof(Page_table),
MAX_PAGE_SIZE_LOG2 = 20,
MIN_PAGE_SIZE_LOG2 = 12,
};
/**
* A first level translation descriptor
*/
struct Descriptor : Register<32>
{
/**
* 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<Type_1_0, Type_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; }
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<Ap_0, Ap_1> { }; /* access permission */
/**
* Compose descriptor value
*/
static access_t create(Page_flags const & flags,
addr_t const pa)
{
access_t v = access_permission_bits<Section>(flags);
v |= memory_region_attr<Section>(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 <typename ST>
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 <typename ST>
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<<Section_table::ALIGNM_LOG2)));
}
#endif /* _TLB__ARM_H_ */

View File

@ -1,107 +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_V6_H_
#define _TLB__ARM_V6_H_
/* core includes */
#include <tlb/arm.h>
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 <typename T>
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_ */

View File

@ -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 <tlb/arm.h>
#include <processor_driver.h>
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 <typename T>
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_ */

View File

@ -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 <board.h>
#include <tlb/arm_v7.h>
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_ */

View File

@ -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 <drivers/trustzone.h>
/* core includes */
#include <board.h>
#include <tlb/arm_v7.h>
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_ */