mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 05:37:54 +00:00
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:
parent
34b18e9da2
commit
73eb7a8d4b
@ -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_ */
|
||||
|
@ -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;
|
||||
|
@ -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,11 +23,8 @@
|
||||
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 types support **
|
||||
@ -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();
|
||||
}
|
||||
|
@ -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); }
|
||||
|
||||
/* 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) ;
|
||||
}
|
||||
|
||||
|
||||
void Thread_base::_thread_start()
|
||||
{
|
||||
Thread_base::myself()->_thread_bootstrap();
|
||||
Thread_base::myself()->entry();
|
||||
Thread_base::myself()->_join_lock.unlock();
|
||||
Genode::sleep_forever();
|
||||
/* 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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
674
base-hw/src/core/arm/short_translation_table.h
Normal file
674
base-hw/src/core/arm/short_translation_table.h
Normal 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_ */
|
||||
|
33
base-hw/src/core/arm_v6/translation_table.h
Normal file
33
base-hw/src/core/arm_v6/translation_table.h
Normal 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_ */
|
33
base-hw/src/core/arm_v7/translation_table.h
Normal file
33
base-hw/src/core/arm_v7/translation_table.h
Normal 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_ */
|
@ -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;
|
||||
}
|
||||
|
@ -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; } }
|
||||
|
66
base-hw/src/core/core_rm_session.cc
Normal file
66
base-hw/src/core/core_rm_session.cc
Normal 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;
|
||||
}
|
@ -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_ */
|
||||
|
@ -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_ */
|
||||
|
@ -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_ */
|
||||
|
@ -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_ */
|
||||
|
61
base-hw/src/core/include/core_rm_session.h
Normal file
61
base-hw/src/core/include/core_rm_session.h
Normal 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_ */
|
46
base-hw/src/core/include/map_local.h
Normal file
46
base-hw/src/core/include/map_local.h
Normal 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_ */
|
230
base-hw/src/core/include/page_slab.h
Normal file
230
base-hw/src/core/include/page_slab.h
Normal 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_ */
|
@ -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 */
|
||||
Core_mem_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 */
|
||||
|
||||
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);
|
||||
|
@ -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:
|
||||
|
||||
Lock _lock; /* safeguard translation table and slab */
|
||||
unsigned _id;
|
||||
Native_capability _parent;
|
||||
Native_thread_id _main_thread;
|
||||
char const * const _label;
|
||||
Tlb * _tlb;
|
||||
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 **
|
||||
***************/
|
||||
|
||||
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; }
|
||||
|
||||
|
||||
/*****************************
|
||||
|
@ -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; }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -143,11 +187,11 @@ 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); }
|
||||
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,7 +228,7 @@ 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_tt_base = (addr_t) core_pd()->translation_table();
|
||||
core_pd_id = core_pd()->id();
|
||||
|
||||
/* initialize all processor objects */
|
||||
@ -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
|
||||
|
@ -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_ */
|
||||
|
@ -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)
|
||||
{
|
||||
try {
|
||||
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);
|
||||
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;
|
||||
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_ */
|
||||
|
@ -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,19 +74,39 @@ 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)
|
||||
/* 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();
|
||||
}
|
||||
}
|
||||
|
@ -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 **
|
||||
***************/
|
||||
|
@ -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 */
|
||||
using namespace Genode;
|
||||
|
||||
/* create 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());
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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!!! */
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/* 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()),
|
||||
Platform_thread::Platform_thread(const char * const label,
|
||||
Native_utcb * utcb)
|
||||
: _pd(Kernel::core_pd()->platform_pd()),
|
||||
_rm_client(0),
|
||||
_utcb_virt(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;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* \brief CPU driver for core
|
||||
* \author Martin stein
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2012-09-11
|
||||
*/
|
||||
|
||||
@ -515,17 +516,17 @@ namespace Arm
|
||||
**********************************************************/
|
||||
|
||||
uint32_t cidr; /* context ID register backup */
|
||||
uint32_t section_table; /* base address of applied section table */
|
||||
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;
|
||||
t_table = tt;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 -1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
62
base-hw/src/core/thread_support.cc
Normal file
62
base-hw/src/core/thread_support.cc
Normal 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!");
|
||||
}
|
@ -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_ */
|
||||
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
||||
|
@ -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_ */
|
||||
|
Loading…
Reference in New Issue
Block a user