hw: replace page table allocator with static one

Instead of organizing page tables within slab blocks and allocating such
blocks dynamically on demand, replace the page table allocator with a
simple, static alternative. The new page table allocator is dimensioned
at compile-time. When a PD runs out of page-tables, we simply flush its
current mappings, and re-use the freed tables. The only exception is
core/kernel that should not produce any page faults. Thereby it has to
be ensured that core has enough page tables to populate it's virtual
memory.

A positive side-effect of this static approach is that the accounting
of memory used for page-tables is now possible again. In the dynamic case
there was no protocol existent that solved the problem of donating memory
to core during a page fault.

Fix #1588
This commit is contained in:
Stefan Kalkowski 2015-06-16 10:59:26 +02:00 committed by Christian Helmuth
parent 3291ca59a3
commit cc58b11998
23 changed files with 407 additions and 525 deletions

View File

@ -16,7 +16,10 @@
namespace Kernel namespace Kernel
{ {
enum { DEFAULT_STACK_SIZE = 16 * 1024 }; enum {
DEFAULT_STACK_SIZE = 16 * 1024,
DEFAULT_TRANSLATION_TABLE_MAX = 128,
};
/* amount of priority bands amongst quota owners in CPU scheduling */ /* amount of priority bands amongst quota owners in CPU scheduling */
constexpr unsigned cpu_priorities = 4; constexpr unsigned cpu_priorities = 4;

View File

@ -1,83 +0,0 @@
/**
* \brief Tools for early translation tables
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2014-08-05
*/
/*
* 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 _KERNEL__EARLY_TRANSLATIONS_H_
#define _KERNEL__EARLY_TRANSLATIONS_H_
/* core includes */
#include <assert.h>
#include <page_slab.h>
#include <translation_table.h>
namespace Genode
{
/**
* Dummy back-end allocator for early translation tables
*/
class Early_translations_allocator;
/**
* Aligned slab for early translation tables
*/
class Early_translations_slab;
}
namespace Kernel
{
using Genode::Early_translations_allocator;
using Genode::Early_translations_slab;
}
class Genode::Early_translations_allocator : public Genode::Core_mem_translator
{
public:
Early_translations_allocator() { }
int add_range(addr_t base, size_t size) override { return -1; }
int remove_range(addr_t base, size_t size) override { return -1; }
Alloc_return alloc_aligned(size_t, void **, int, addr_t, addr_t) override {
return Alloc_return::RANGE_CONFLICT; }
Alloc_return alloc_addr(size_t size, addr_t addr) override {
return Alloc_return::RANGE_CONFLICT; }
void free(void *addr) override { }
size_t avail() const override { return 0; }
bool valid_addr(addr_t addr) const override { return false; }
bool alloc(size_t size, void **out_addr) override { return false; }
void free(void *addr, size_t) override { }
size_t overhead(size_t size) const override { 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; }
};
class Genode::Early_translations_slab : public Genode::Page_slab
{
public:
typedef Genode::Core_mem_translator Allocator;
enum {
ALIGN_LOG2 = Genode::Translation_table::ALIGNM_LOG2,
ALIGN = 1 << ALIGN_LOG2,
};
/**
* Constructor
*/
Early_translations_slab(Allocator * const alloc) : Page_slab(alloc) {
assert(Genode::aligned(this, ALIGN_LOG2)); }
} __attribute__((aligned(Early_translations_slab::ALIGN)));
#endif /* _KERNEL__EARLY_TRANSLATIONS_H_ */

View File

@ -16,12 +16,11 @@
#define _KERNEL__PD_H_ #define _KERNEL__PD_H_
/* core includes */ /* core includes */
#include <kernel/early_translations.h> #include <translation_table.h>
#include <kernel/cpu.h> #include <kernel/cpu.h>
#include <kernel/object.h> #include <kernel/object.h>
namespace Genode { namespace Genode {
class Page_slab;
class Platform_pd; class Platform_pd;
} }
@ -56,13 +55,15 @@ class Kernel::Mode_transition_control
private: private:
typedef Early_translations_allocator Allocator; /*
typedef Early_translations_slab Slab; * set the table allocator to the current minimum of bits-of-one-mword
* this is a limitation of the Bit_allocator used within this allocator.
* actually only one page-mapping is needed by the MTC allocator
*/
typedef Genode::Translation_table_allocator_tpl<64> Allocator;
typedef Genode::Translation_table Table; typedef Genode::Translation_table Table;
typedef Genode::Page_flags Page_flags;
Allocator _allocator; Allocator _alloc;
Slab _slab;
Table _table; Table _table;
Cpu_context _master; Cpu_context _master;
@ -101,10 +102,10 @@ class Kernel::Mode_transition_control
* Map the mode transition page to a virtual address space * Map the mode transition page to a virtual address space
* *
* \param tt translation buffer of the address space * \param tt translation buffer of the address space
* \param ram RAM donation for mapping (first try without) * \param alloc translation table allocator used for the mapping
*/ */
void map(Genode::Translation_table * tt, void map(Genode::Translation_table * tt,
Genode::Page_slab * alloc); Genode::Translation_table_allocator * alloc);
/** /**
* Continue execution of client context * Continue execution of client context

View File

@ -1,230 +0,0 @@
/*
* \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 <util/construct_at.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;
}
};
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() const
{
size_t cnt = 0;
for (List_element<Slab_block> const *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 = Genode::construct_at<Slab_block>(p);
_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;) {
List_element<Slab_block> *cur = le;
le = le->next();
if (!cur->object()->free(addr)) continue;
if (_free_slab_entries++ > (MIN_SLABS+SLABS_PER_BLOCK)
&& !cur->object()->ref_counter)
_free_slab_block(cur->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) override { return (*addr = alloc()); }
void free(void *addr, size_t) override { free(addr); }
size_t consumed() const override { return SLAB_BLOCK_SIZE * _slab_blocks_in_use(); }
size_t overhead(size_t) const override { return SLAB_BLOCK_SIZE/SLABS_PER_BLOCK; }
bool need_size_for_free() const override { return false; }
};
#endif /* _CORE__INCLUDE__PAGE_SLAB_H_ */

View File

@ -19,13 +19,17 @@
#include <translation_table.h> #include <translation_table.h>
#include <platform.h> #include <platform.h>
#include <address_space.h> #include <address_space.h>
#include <page_slab.h> #include <translation_table_allocator.h>
#include <object.h> #include <object.h>
#include <kernel/configuration.h>
#include <kernel/object.h> #include <kernel/object.h>
#include <kernel/pd.h> #include <kernel/pd.h>
namespace Hw namespace Hw
{ {
using namespace Kernel;
using namespace Genode;
/** /**
* Memory virtualization interface of a protection domain * Memory virtualization interface of a protection domain
*/ */
@ -57,14 +61,17 @@ class Hw::Address_space : public Genode::Address_space
friend class Genode::Platform; friend class Genode::Platform;
friend class Genode::Core_mem_allocator::Mapped_mem_allocator; friend class Genode::Core_mem_allocator::Mapped_mem_allocator;
using Table_allocator =
Translation_table_allocator_tpl<DEFAULT_TRANSLATION_TABLE_MAX>;
Genode::Lock _lock; /* table lock */ Genode::Lock _lock; /* table lock */
Genode::Translation_table * _tt; /* table virtual addr. */ Genode::Translation_table * _tt; /* table virt addr */
Genode::Translation_table * _tt_phys; /* table physical addr. */ Genode::Translation_table * _tt_phys; /* table phys addr */
Genode::Page_slab * _pslab; /* page table allocator */ Genode::Translation_table_allocator * _tt_alloc; /* table allocator */
Kernel::Pd * _kernel_pd; Kernel::Pd * _kernel_pd;
static inline Genode::Core_mem_allocator * _cma(); static inline Genode::Core_mem_allocator * _cma();
static inline void * _tt_alloc(); static inline void * _table_alloc();
protected: protected:
@ -74,11 +81,11 @@ class Hw::Address_space : public Genode::Address_space
* *
* \param pd pointer to kernel's pd object * \param pd pointer to kernel's pd object
* \param tt pointer to translation table * \param tt pointer to translation table
* \param slab pointer to page slab allocator * \param tt_alloc pointer to translation table allocator
*/ */
Address_space(Kernel::Pd * pd, Address_space(Kernel::Pd * pd,
Genode::Translation_table * tt, Genode::Translation_table * tt,
Genode::Page_slab * slab); Genode::Translation_table_allocator * tt_alloc);
public: public:
@ -159,9 +166,10 @@ class Genode::Platform_pd : public Hw::Address_space,
* Constructor for core pd * Constructor for core pd
* *
* \param tt translation table address * \param tt translation table address
* \param slab page table allocator * \param tt_alloc translation table allocator
*/ */
Platform_pd(Translation_table * tt, Page_slab * slab); Platform_pd(Translation_table * tt,
Translation_table_allocator * tt_alloc);
public: public:
@ -206,7 +214,7 @@ class Genode::Core_platform_pd : public Genode::Platform_pd
private: private:
static inline Translation_table * const _table(); static inline Translation_table * const _table();
static inline Page_slab * const _slab(); static inline Translation_table_allocator * const _table_alloc();
/** /**
* Establish initial one-to-one mappings for core/kernel. * Establish initial one-to-one mappings for core/kernel.

View File

@ -23,7 +23,7 @@
#include <util.h> #include <util.h>
#include <assert.h> #include <assert.h>
#include <page_flags.h> #include <page_flags.h>
#include <page_slab.h> #include <translation_table_allocator.h>
#include <cpu.h> #include <cpu.h>
namespace Genode namespace Genode
@ -412,22 +412,22 @@ class Genode::Translation_table
* \param pa physical start address of range * \param pa physical start address of range
* \param size size of range * \param size size of range
* \param flags mapping flags * \param flags mapping flags
* \param slab second level page slab allocator * \param alloc second level translation table allocator
*/ */
void _insert_second_level(unsigned i, addr_t const vo, addr_t const pa, void _insert_second_level(unsigned i, addr_t const vo, addr_t const pa,
size_t const size, Page_flags const & flags, size_t const size, Page_flags const & flags,
Page_slab * const slab) Translation_table_allocator * const alloc)
{ {
Page_table * pt = 0; Page_table * pt = 0;
switch (Descriptor::type(_entries[i])) { switch (Descriptor::type(_entries[i])) {
case Descriptor::FAULT: case Descriptor::FAULT:
{ {
if (!slab) throw Allocator::Out_of_memory(); if (!alloc) throw Allocator::Out_of_memory();
/* create and link page table */ /* create and link page table */
pt = new (slab) Page_table(); pt = new (alloc) Page_table();
Page_table * pt_phys = (Page_table*) slab->phys_addr(pt); Page_table * pt_phys = (Page_table*) alloc->phys_addr(pt);
pt_phys = pt_phys ? pt_phys : pt; /* hack for core */ pt_phys = pt_phys ? pt_phys : pt; /* hack for core */
_entries[i] = Page_table_descriptor::create(pt_phys); _entries[i] = Page_table_descriptor::create(pt_phys);
@ -441,7 +441,7 @@ class Genode::Translation_table
/* use allocator to retrieve virtual addr. of page table */ /* use allocator to retrieve virtual addr. of page table */
void * pt_phys = (void*) void * pt_phys = (void*)
Page_table_descriptor::Pa::masked(_entries[i]); Page_table_descriptor::Pa::masked(_entries[i]);
pt = (Page_table *) slab->virt_addr(pt_phys); pt = (Page_table *) alloc->virt_addr(pt_phys);
pt = pt ? pt : (Page_table *)pt_phys ; /* hack for core */ pt = pt ? pt : (Page_table *)pt_phys ; /* hack for core */
break; break;
} }
@ -481,10 +481,11 @@ class Genode::Translation_table
* \param pa base of physical backing store * \param pa base of physical backing store
* \param size size of translated region * \param size size of translated region
* \param f mapping flags * \param f mapping flags
* \param s second level page slab allocator * \param alloc second level translation table allocator
*/ */
void insert_translation(addr_t vo, addr_t pa, size_t size, void insert_translation(addr_t vo, addr_t pa, size_t size,
Page_flags const & f, Page_slab * const s) Page_flags const & f,
Translation_table_allocator * const alloc)
{ {
/* check sanity */ /* check sanity */
assert(!(vo & Page_table::Descriptor::VIRT_OFFSET_MASK) && assert(!(vo & Page_table::Descriptor::VIRT_OFFSET_MASK) &&
@ -515,7 +516,8 @@ class Genode::Translation_table
} }
default: default:
_insert_second_level(i, vo, pa, min(size, end - vo), f, s); _insert_second_level(i, vo, pa, min(size, end - vo), f,
alloc);
}; };
/* check whether we wrap */ /* check whether we wrap */
@ -533,9 +535,10 @@ class Genode::Translation_table
* *
* \param vo region offset within the tables virtual region * \param vo region offset within the tables virtual region
* \param size region size * \param size region size
* \param slab second level page slab allocator * \param alloc second level translation table allocator
*/ */
void remove_translation(addr_t vo, size_t size, Page_slab * slab) void remove_translation(addr_t vo, size_t size,
Translation_table_allocator * alloc)
{ {
/* check sanity */ /* check sanity */
assert(vo <= (vo + size)); assert(vo <= (vo + size));
@ -553,7 +556,7 @@ class Genode::Translation_table
typedef Page_table Pt; typedef Page_table Pt;
Pt * pt_phys = (Pt *) Ptd::Pa::masked(_entries[i]); Pt * pt_phys = (Pt *) Ptd::Pa::masked(_entries[i]);
Pt * pt = (Pt *) slab->virt_addr(pt_phys); Pt * pt = (Pt *) alloc->virt_addr(pt_phys);
pt = pt ? pt : pt_phys; // TODO hack for core pt = pt ? pt : pt_phys; // TODO hack for core
addr_t const pt_vo = vo - Section::Pa::masked(vo); addr_t const pt_vo = vo - Section::Pa::masked(vo);
@ -561,7 +564,7 @@ class Genode::Translation_table
if (pt->empty()) { if (pt->empty()) {
Descriptor::invalidate(_entries[i]); Descriptor::invalidate(_entries[i]);
destroy(slab, pt); destroy(alloc, pt);
} }
break; break;
} }

View File

@ -21,7 +21,7 @@
/* base-hw includes */ /* base-hw includes */
#include <page_flags.h> #include <page_flags.h>
#include <page_slab.h> #include <translation_table_allocator.h>
namespace Genode namespace Genode
{ {
@ -325,10 +325,11 @@ class Genode::Level_3_translation_table :
struct Insert_func struct Insert_func
{ {
Page_flags const & flags; Page_flags const & flags;
Page_slab * slab; Translation_table_allocator * alloc;
Insert_func(Page_flags const & flags, Insert_func(Page_flags const & flags,
Page_slab * slab) : flags(flags), slab(slab) { } Translation_table_allocator * alloc)
: flags(flags), alloc(alloc) { }
void operator () (addr_t const vo, void operator () (addr_t const vo,
addr_t const pa, addr_t const pa,
@ -354,9 +355,9 @@ class Genode::Level_3_translation_table :
struct Remove_func struct Remove_func
{ {
Page_slab * slab; Translation_table_allocator * alloc;
Remove_func(Page_slab * slab) : slab(slab) { } Remove_func(Translation_table_allocator * alloc) : alloc(alloc) { }
void operator () (addr_t const vo, void operator () (addr_t const vo,
addr_t const pa, addr_t const pa,
@ -371,11 +372,12 @@ class Genode::Level_3_translation_table :
addr_t pa, addr_t pa,
size_t size, size_t size,
Page_flags const & flags, Page_flags const & flags,
Page_slab * slab) { Translation_table_allocator * alloc) {
_range_op(vo, pa, size, Insert_func(flags, slab)); } _range_op(vo, pa, size, Insert_func(flags, alloc)); }
void remove_translation(addr_t vo, size_t size, Page_slab * slab) { void remove_translation(addr_t vo, size_t size,
_range_op(vo, 0, size, Remove_func(slab)); } Translation_table_allocator * alloc) {
_range_op(vo, 0, size, Remove_func(alloc)); }
}; };
@ -393,10 +395,11 @@ class Genode::Level_x_translation_table :
struct Insert_func struct Insert_func
{ {
Page_flags const & flags; Page_flags const & flags;
Page_slab * slab; Translation_table_allocator * alloc;
Insert_func(Page_flags const & flags, Insert_func(Page_flags const & flags,
Page_slab * slab) : flags(flags), slab(slab) { } Translation_table_allocator * alloc)
: flags(flags), alloc(alloc) { }
void operator () (addr_t const vo, void operator () (addr_t const vo,
addr_t const pa, addr_t const pa,
@ -420,11 +423,11 @@ class Genode::Level_x_translation_table :
case Descriptor::INVALID: /* no entry */ case Descriptor::INVALID: /* no entry */
{ {
if (!slab) throw Allocator::Out_of_memory(); if (!alloc) throw Allocator::Out_of_memory();
/* create and link next level table */ /* create and link next level table */
table = new (slab) ENTRY(); table = new (alloc) ENTRY();
ENTRY * phys_addr = (ENTRY*) slab->phys_addr(table); ENTRY * phys_addr = (ENTRY*) alloc->phys_addr(table);
desc = Table_descriptor::create(phys_addr ? desc = Table_descriptor::create(phys_addr ?
phys_addr : table); phys_addr : table);
} }
@ -434,7 +437,7 @@ class Genode::Level_x_translation_table :
/* use allocator to retrieve virt address of table */ /* use allocator to retrieve virt address of table */
ENTRY * phys_addr = (ENTRY*) ENTRY * phys_addr = (ENTRY*)
Table_descriptor::Next_table::masked(desc); Table_descriptor::Next_table::masked(desc);
table = (ENTRY*) slab->virt_addr(phys_addr); table = (ENTRY*) alloc->virt_addr(phys_addr);
table = table ? table : (ENTRY*)phys_addr; table = table ? table : (ENTRY*)phys_addr;
break; break;
} }
@ -447,16 +450,16 @@ class Genode::Level_x_translation_table :
/* insert translation */ /* insert translation */
table->insert_translation(vo - (vo & Base::BLOCK_MASK), table->insert_translation(vo - (vo & Base::BLOCK_MASK),
pa, size, flags, slab); pa, size, flags, alloc);
} }
}; };
struct Remove_func struct Remove_func
{ {
Page_slab * slab; Translation_table_allocator * alloc;
Remove_func(Page_slab * slab) : slab(slab) { } Remove_func(Translation_table_allocator * alloc) : alloc(alloc) { }
void operator () (addr_t const vo, void operator () (addr_t const vo,
addr_t const pa, addr_t const pa,
@ -469,13 +472,13 @@ class Genode::Level_x_translation_table :
/* use allocator to retrieve virt address of table */ /* use allocator to retrieve virt address of table */
ENTRY * phys_addr = (ENTRY*) ENTRY * phys_addr = (ENTRY*)
Table_descriptor::Next_table::masked(desc); Table_descriptor::Next_table::masked(desc);
ENTRY * table = (ENTRY*) slab->virt_addr(phys_addr); ENTRY * table = (ENTRY*) alloc->virt_addr(phys_addr);
table = table ? table : (ENTRY*)phys_addr; table = table ? table : (ENTRY*)phys_addr;
table->remove_translation(vo - (vo & Base::BLOCK_MASK), table->remove_translation(vo - (vo & Base::BLOCK_MASK),
size, slab); size, alloc);
if (!table->empty()) if (!table->empty())
break; break;
destroy(slab, table); destroy(alloc, table);
} }
case Descriptor::BLOCK: case Descriptor::BLOCK:
case Descriptor::INVALID: case Descriptor::INVALID:
@ -498,24 +501,25 @@ class Genode::Level_x_translation_table :
* \param pa base of the physical backing store * \param pa base of the physical backing store
* \param size size of the translated region * \param size size of the translated region
* \param flags mapping flags * \param flags mapping flags
* \param slab second level page slab allocator * \param alloc second level translation table allocator
*/ */
void insert_translation(addr_t vo, void insert_translation(addr_t vo,
addr_t pa, addr_t pa,
size_t size, size_t size,
Page_flags const & flags, Page_flags const & flags,
Page_slab * slab) { Translation_table_allocator * alloc) {
this->_range_op(vo, pa, size, Insert_func(flags, slab)); } this->_range_op(vo, pa, size, Insert_func(flags, alloc)); }
/** /**
* Remove translations that overlap with a given virtual region * Remove translations that overlap with a given virtual region
* *
* \param vo region offset within the tables virtual region * \param vo region offset within the tables virtual region
* \param size region size * \param size region size
* \param slab second level page slab allocator * \param alloc second level translation table allocator
*/ */
void remove_translation(addr_t vo, size_t size, Page_slab * slab) { void remove_translation(addr_t vo, size_t size,
this->_range_op(vo, 0, size, Remove_func(slab)); } Translation_table_allocator * alloc) {
this->_range_op(vo, 0, size, Remove_func(alloc)); }
}; };
namespace Genode { namespace Genode {

View File

@ -38,6 +38,8 @@ class Genode::Vm_session_component
using Translation_table = using Translation_table =
Genode::Level_1_stage_2_translation_table; Genode::Level_1_stage_2_translation_table;
using Table_allocator = Translation_table_allocator_tpl<
Kernel::DEFAULT_TRANSLATION_TABLE_MAX>;
Rpc_entrypoint *_ds_ep; Rpc_entrypoint *_ds_ep;
Range_allocator *_ram_alloc; Range_allocator *_ram_alloc;
@ -45,7 +47,7 @@ class Genode::Vm_session_component
Dataspace_capability _ds_cap; Dataspace_capability _ds_cap;
addr_t _ds_addr; addr_t _ds_addr;
Translation_table *_table; Translation_table *_table;
Page_slab *_pslab; Translation_table_allocator *_tt_alloc;
static size_t _ds_size() { static size_t _ds_size() {
return align_addr(sizeof(Cpu_state_modes), return align_addr(sizeof(Cpu_state_modes),

View File

@ -22,7 +22,7 @@
/* base-hw includes */ /* base-hw includes */
#include <page_flags.h> #include <page_flags.h>
#include <page_slab.h> #include <translation_table_allocator.h>
namespace Genode namespace Genode
{ {
@ -153,10 +153,11 @@ class Genode::Level_4_translation_table
struct Insert_func struct Insert_func
{ {
Page_flags const & flags; Page_flags const & flags;
Page_slab * slab; Translation_table_allocator * alloc;
Insert_func(Page_flags const & flags, Insert_func(Page_flags const & flags,
Page_slab * slab) : flags(flags), slab(slab) { } Translation_table_allocator * alloc)
: flags(flags), alloc(alloc) { }
void operator () (addr_t const vo, addr_t const pa, void operator () (addr_t const vo, addr_t const pa,
size_t const size, size_t const size,
@ -181,9 +182,9 @@ class Genode::Level_4_translation_table
struct Remove_func struct Remove_func
{ {
Page_slab * slab; Translation_table_allocator * alloc;
Remove_func(Page_slab * slab) : slab(slab) { } Remove_func(Translation_table_allocator * alloc) : alloc(alloc) { }
void operator () (addr_t const vo, addr_t const pa, void operator () (addr_t const vo, addr_t const pa,
size_t const size, size_t const size,
@ -247,12 +248,13 @@ class Genode::Level_4_translation_table
* \param pa base of the physical backing store * \param pa base of the physical backing store
* \param size size of the translated region * \param size size of the translated region
* \param flags mapping flags * \param flags mapping flags
* \param slab second level page slab allocator * \param alloc second level translation table allocator
*/ */
void insert_translation(addr_t vo, addr_t pa, size_t size, void insert_translation(addr_t vo, addr_t pa, size_t size,
Page_flags const & flags, Page_slab * slab) Page_flags const & flags,
Translation_table_allocator * alloc)
{ {
this->_range_op(vo, pa, size, Insert_func(flags, slab)); this->_range_op(vo, pa, size, Insert_func(flags, alloc));
} }
/** /**
@ -260,11 +262,12 @@ class Genode::Level_4_translation_table
* *
* \param vo region offset within the tables virtual region * \param vo region offset within the tables virtual region
* \param size region size * \param size region size
* \param slab second level page slab allocator * \param alloc second level translation table allocator
*/ */
void remove_translation(addr_t vo, size_t size, Page_slab * slab) void remove_translation(addr_t vo, size_t size,
Translation_table_allocator * alloc)
{ {
this->_range_op(vo, 0, size, Remove_func(slab)); this->_range_op(vo, 0, size, Remove_func(alloc));
} }
} __attribute__((aligned(1 << ALIGNM_LOG2))); } __attribute__((aligned(1 << ALIGNM_LOG2)));
@ -356,10 +359,11 @@ class Genode::Page_directory
struct Insert_func struct Insert_func
{ {
Page_flags const & flags; Page_flags const & flags;
Page_slab * slab; Translation_table_allocator * alloc;
Insert_func(Page_flags const & flags, Insert_func(Page_flags const & flags,
Page_slab * slab) : flags(flags), slab(slab) { } Translation_table_allocator * alloc)
: flags(flags), alloc(alloc) { }
void operator () (addr_t const vo, addr_t const pa, void operator () (addr_t const vo, addr_t const pa,
size_t const size, size_t const size,
@ -385,12 +389,12 @@ class Genode::Page_directory
/* we need to use a next level table */ /* we need to use a next level table */
ENTRY *table; ENTRY *table;
if (!Base_descriptor::present(desc)) { if (!Base_descriptor::present(desc)) {
if (!slab) if (!alloc)
throw Allocator::Out_of_memory(); throw Allocator::Out_of_memory();
/* create and link next level table */ /* create and link next level table */
table = new (slab) ENTRY(); table = new (alloc) ENTRY();
ENTRY * phys_addr = (ENTRY*) slab->phys_addr(table); ENTRY * phys_addr = (ENTRY*) alloc->phys_addr(table);
addr_t const pa = (addr_t)(phys_addr ? phys_addr : table); addr_t const pa = (addr_t)(phys_addr ? phys_addr : table);
desc = (typename Base_descriptor::access_t) desc = (typename Base_descriptor::access_t)
Table_descriptor::create(flags, pa); Table_descriptor::create(flags, pa);
@ -401,21 +405,21 @@ class Genode::Page_directory
Base_descriptor::merge_access_rights(desc, flags); Base_descriptor::merge_access_rights(desc, flags);
ENTRY * phys_addr = (ENTRY*) ENTRY * phys_addr = (ENTRY*)
Table_descriptor::Pa::masked(desc); Table_descriptor::Pa::masked(desc);
table = (ENTRY*) slab->virt_addr(phys_addr); table = (ENTRY*) alloc->virt_addr(phys_addr);
table = table ? table : (ENTRY*)phys_addr; table = table ? table : (ENTRY*)phys_addr;
} }
/* insert translation */ /* insert translation */
table->insert_translation(vo - (vo & PAGE_MASK), table->insert_translation(vo - (vo & PAGE_MASK),
pa, size, flags, slab); pa, size, flags, alloc);
} }
}; };
struct Remove_func struct Remove_func
{ {
Page_slab * slab; Translation_table_allocator * alloc;
Remove_func(Page_slab * slab) : slab(slab) { } Remove_func(Translation_table_allocator * alloc) : alloc(alloc) { }
void operator () (addr_t const vo, addr_t const pa, void operator () (addr_t const vo, addr_t const pa,
size_t const size, size_t const size,
@ -428,12 +432,12 @@ class Genode::Page_directory
/* use allocator to retrieve virt address of table */ /* use allocator to retrieve virt address of table */
ENTRY* phys_addr = (ENTRY*) ENTRY* phys_addr = (ENTRY*)
Table_descriptor::Pa::masked(desc); Table_descriptor::Pa::masked(desc);
ENTRY* table = (ENTRY*) slab->virt_addr(phys_addr); ENTRY* table = (ENTRY*) alloc->virt_addr(phys_addr);
table = table ? table : (ENTRY*)phys_addr; table = table ? table : (ENTRY*)phys_addr;
addr_t const table_vo = vo - (vo & PAGE_MASK); addr_t const table_vo = vo - (vo & PAGE_MASK);
table->remove_translation(table_vo, size, slab); table->remove_translation(table_vo, size, alloc);
if (table->empty()) { if (table->empty()) {
destroy(slab, table); destroy(alloc, table);
desc = 0; desc = 0;
} }
} }
@ -494,12 +498,13 @@ class Genode::Page_directory
* \param pa base of the physical backing store * \param pa base of the physical backing store
* \param size size of the translated region * \param size size of the translated region
* \param flags mapping flags * \param flags mapping flags
* \param slab second level page slab allocator * \param alloc second level translation table allocator
*/ */
void insert_translation(addr_t vo, addr_t pa, size_t size, void insert_translation(addr_t vo, addr_t pa, size_t size,
Page_flags const & flags, Page_slab * slab) Page_flags const & flags,
Translation_table_allocator * alloc)
{ {
_range_op(vo, pa, size, Insert_func(flags, slab)); _range_op(vo, pa, size, Insert_func(flags, alloc));
} }
/** /**
@ -507,11 +512,12 @@ class Genode::Page_directory
* *
* \param vo region offset within the tables virtual region * \param vo region offset within the tables virtual region
* \param size region size * \param size region size
* \param slab second level page slab allocator * \param alloc second level translation table allocator
*/ */
void remove_translation(addr_t vo, size_t size, Page_slab * slab) void remove_translation(addr_t vo, size_t size,
Translation_table_allocator * alloc)
{ {
_range_op(vo, 0, size, Remove_func(slab)); _range_op(vo, 0, size, Remove_func(alloc));
} }
} __attribute__((aligned(1 << ALIGNM_LOG2))); } __attribute__((aligned(1 << ALIGNM_LOG2)));
@ -548,10 +554,11 @@ class Genode::Pml4_table
struct Insert_func struct Insert_func
{ {
Page_flags const & flags; Page_flags const & flags;
Page_slab * slab; Translation_table_allocator * alloc;
Insert_func(Page_flags const & flags, Insert_func(Page_flags const & flags,
Page_slab * slab) : flags(flags), slab(slab) { } Translation_table_allocator * alloc)
: flags(flags), alloc(alloc) { }
void operator () (addr_t const vo, addr_t const pa, void operator () (addr_t const vo, addr_t const pa,
size_t const size, size_t const size,
@ -560,33 +567,33 @@ class Genode::Pml4_table
/* we need to use a next level table */ /* we need to use a next level table */
ENTRY *table; ENTRY *table;
if (!Descriptor::present(desc)) { if (!Descriptor::present(desc)) {
if (!slab) if (!alloc)
throw Allocator::Out_of_memory(); throw Allocator::Out_of_memory();
/* create and link next level table */ /* create and link next level table */
table = new (slab) ENTRY(); table = new (alloc) ENTRY();
ENTRY * phys_addr = (ENTRY*) slab->phys_addr(table); ENTRY * phys_addr = (ENTRY*) alloc->phys_addr(table);
addr_t const pa = (addr_t)(phys_addr ? phys_addr : table); addr_t const pa = (addr_t)(phys_addr ? phys_addr : table);
desc = Descriptor::create(flags, pa); desc = Descriptor::create(flags, pa);
} else { } else {
Descriptor::merge_access_rights(desc, flags); Descriptor::merge_access_rights(desc, flags);
ENTRY * phys_addr = (ENTRY*) ENTRY * phys_addr = (ENTRY*)
Descriptor::Pa::masked(desc); Descriptor::Pa::masked(desc);
table = (ENTRY*) slab->virt_addr(phys_addr); table = (ENTRY*) alloc->virt_addr(phys_addr);
table = table ? table : (ENTRY*)phys_addr; table = table ? table : (ENTRY*)phys_addr;
} }
/* insert translation */ /* insert translation */
addr_t const table_vo = vo - (vo & PAGE_MASK); addr_t const table_vo = vo - (vo & PAGE_MASK);
table->insert_translation(table_vo, pa, size, flags, slab); table->insert_translation(table_vo, pa, size, flags, alloc);
} }
}; };
struct Remove_func struct Remove_func
{ {
Page_slab * slab; Translation_table_allocator * alloc;
Remove_func(Page_slab * slab) : slab(slab) { } Remove_func(Translation_table_allocator * alloc) : alloc(alloc) { }
void operator () (addr_t const vo, addr_t const pa, void operator () (addr_t const vo, addr_t const pa,
size_t const size, size_t const size,
@ -596,12 +603,12 @@ class Genode::Pml4_table
/* use allocator to retrieve virt address of table */ /* use allocator to retrieve virt address of table */
ENTRY* phys_addr = (ENTRY*) ENTRY* phys_addr = (ENTRY*)
Descriptor::Pa::masked(desc); Descriptor::Pa::masked(desc);
ENTRY* table = (ENTRY*) slab->virt_addr(phys_addr); ENTRY* table = (ENTRY*) alloc->virt_addr(phys_addr);
table = table ? table : (ENTRY*)phys_addr; table = table ? table : (ENTRY*)phys_addr;
addr_t const table_vo = vo - (vo & PAGE_MASK); addr_t const table_vo = vo - (vo & PAGE_MASK);
table->remove_translation(table_vo, size, slab); table->remove_translation(table_vo, size, alloc);
if (table->empty()) { if (table->empty()) {
destroy(slab, table); destroy(alloc, table);
desc = 0; desc = 0;
} }
} }
@ -660,12 +667,13 @@ class Genode::Pml4_table
* \param pa base of the physical backing store * \param pa base of the physical backing store
* \param size size of the translated region * \param size size of the translated region
* \param flags mapping flags * \param flags mapping flags
* \param slab second level page slab allocator * \param alloc second level translation table allocator
*/ */
void insert_translation(addr_t vo, addr_t pa, size_t size, void insert_translation(addr_t vo, addr_t pa, size_t size,
Page_flags const & flags, Page_slab * slab) Page_flags const & flags,
Translation_table_allocator * alloc)
{ {
_range_op(vo, pa, size, Insert_func(flags, slab)); _range_op(vo, pa, size, Insert_func(flags, alloc));
} }
/** /**
@ -673,11 +681,12 @@ class Genode::Pml4_table
* *
* \param vo region offset within the tables virtual region * \param vo region offset within the tables virtual region
* \param size region size * \param size region size
* \param slab second level page slab allocator * \param alloc second level translation table allocator
*/ */
void remove_translation(addr_t vo, size_t size, Page_slab * slab) void remove_translation(addr_t vo, size_t size,
Translation_table_allocator * alloc)
{ {
_range_op(vo, 0, size, Remove_func(slab)); _range_op(vo, 0, size, Remove_func(alloc));
} }
} __attribute__((aligned(1 << ALIGNM_LOG2))); } __attribute__((aligned(1 << ALIGNM_LOG2)));

View File

@ -0,0 +1,161 @@
/*
* \brief Translation table allocator
* \author Stefan Kalkowski
* \date 2015-06-10
*/
/*
* Copyright (C) 2015 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__TRANSLATION_TABLE_ALLOCATOR_H_
#define _CORE__INCLUDE__TRANSLATION_TABLE_ALLOCATOR_H_
#include <base/native_types.h>
#include <base/allocator.h>
#include <util/bit_allocator.h>
#include <base/stdint.h>
#include <core_mem_alloc.h>
namespace Genode {
/**
* Translation table allocator interface
*/
class Translation_table_allocator;
/**
* Statically dimensioned translation table allocator
*
* /param TABLES count of tables the allocator provides as maximum
*/
template <unsigned TABLES> class Translation_table_allocator_tpl;
}
class Genode::Translation_table_allocator : public Genode::Allocator
{
public:
/**
* Return physical address of given virtual page address
*
* \param addr virtual page address
*/
virtual void * phys_addr(void * addr) = 0;
/**
* Return virtual address of given physical page address
*
* \param addr physical page address
*/
virtual void * virt_addr(void * addr) = 0;
};
template <unsigned TABLES>
class Genode::Translation_table_allocator_tpl
{
private:
/**
* The actual allocator interface cannot be implmented by our
* template class itself, because of its strict alignment constraints
* and therefore the impossibility to have a vtable pointer at the
* beginning of the object's layout. Therefore, we use a private
* implementation of the interface and aggregate it.
*/
class Allocator;
struct Table { uint8_t data[get_page_size()]; };
Table _tables[TABLES];
Allocator _alloc;
public:
static constexpr unsigned ALIGN= 1 << get_page_size_log2();
Translation_table_allocator_tpl() : _alloc(_tables, (addr_t)&_tables) {}
Translation_table_allocator_tpl(Core_mem_allocator *cma)
: _alloc(_tables, (addr_t)cma->phys_addr((void*)&_tables)) {}
Translation_table_allocator * alloc() { return &_alloc; }
static Translation_table_allocator_tpl *
base(Translation_table_allocator * alloc)
{
return (Translation_table_allocator_tpl*)((addr_t)alloc
- sizeof(Table)*TABLES);
}
} __attribute__((aligned(ALIGN)));
template <unsigned TABLES>
class Genode::Translation_table_allocator_tpl<TABLES>::Allocator
: public Translation_table_allocator
{
private:
Table *_tables;
Bit_allocator<TABLES> _free_tables;
addr_t _phys_addr;
/**
* Allocate a page
*
* \returns pointer to new slab, or nullptr if allocation failed
*/
void *_alloc()
{
try {
return &_tables[_free_tables.alloc()];
} catch(typename Bit_allocator<TABLES>::Out_of_indices&) {}
return nullptr;
}
/**
* Free a given page
*
* \param addr virtual address of page to free
*/
void _free(void *addr)
{
_free_tables.free(((addr_t)addr - (addr_t)_tables)
/ sizeof(Table));
}
public:
Allocator(Table * tables, addr_t phys_addr)
: _tables(tables), _phys_addr(phys_addr) {}
void * phys_addr(void * addr)
{
return (void*)((addr_t)addr - (addr_t)_tables
+ _phys_addr);
}
void * virt_addr(void * addr)
{
return (void*)((addr_t)_tables + ((addr_t)addr
- _phys_addr));
}
/************************
* Allocator interface **
************************/
bool alloc(size_t, void **addr) override {
return (*addr = _alloc()); }
void free(void *addr, size_t) override { _free(addr); }
size_t consumed() const override { return 0; }
size_t overhead(size_t) const override { return 0; }
bool need_size_for_free() const override { return false; }
};
#endif /* _CORE__INCLUDE__TRANSLATION_TABLE_ALLOCATOR_H_ */

View File

@ -17,6 +17,7 @@
#include <base/native_types.h> #include <base/native_types.h>
/* core includes */ /* core includes */
#include <assert.h>
#include <platform_pd.h> #include <platform_pd.h>
#include <kernel/ipc_node.h> #include <kernel/ipc_node.h>
#include <kernel/pd.h> #include <kernel/pd.h>

View File

@ -17,6 +17,8 @@
#include <kernel/pd.h> #include <kernel/pd.h>
/* Genode includes */ /* Genode includes */
#include <assert.h>
#include <page_flags.h>
#include <unmanaged_singleton.h> #include <unmanaged_singleton.h>
using namespace Kernel; using namespace Kernel;
@ -51,12 +53,12 @@ addr_t Mode_transition_control::_virt_user_entry()
void Mode_transition_control::map(Genode::Translation_table * tt, void Mode_transition_control::map(Genode::Translation_table * tt,
Genode::Page_slab * alloc) Genode::Translation_table_allocator * alloc)
{ {
try { try {
addr_t const phys_base = (addr_t)&_mt_begin; addr_t const phys_base = (addr_t)&_mt_begin;
tt->insert_translation(VIRT_BASE, phys_base, SIZE, tt->insert_translation(VIRT_BASE, phys_base, SIZE,
Page_flags::mode_transition(), alloc); Genode::Page_flags::mode_transition(), alloc);
} catch(...) { } catch(...) {
PERR("Inserting exception vector in page table failed!"); } PERR("Inserting exception vector in page table failed!"); }
} }
@ -90,13 +92,12 @@ void Mode_transition_control::switch_to_user(Cpu::Context * const context,
} }
Mode_transition_control::Mode_transition_control() Mode_transition_control::Mode_transition_control() : _master(&_table)
: _slab(&_allocator), _master(&_table)
{ {
assert(Genode::aligned(this, ALIGN_LOG2)); assert(Genode::aligned(this, ALIGN_LOG2));
assert(sizeof(_master) <= _master_context_size()); assert(sizeof(_master) <= _master_context_size());
assert(_size() <= SIZE); assert(_size() <= SIZE);
map(&_table, &_slab); map(&_table, _alloc.alloc());
Genode::memcpy(&_mt_master_context_begin, &_master, sizeof(_master)); Genode::memcpy(&_mt_master_context_begin, &_master, sizeof(_master));
} }

View File

@ -19,6 +19,7 @@
#include <util/construct_at.h> #include <util/construct_at.h>
/* core includes */ /* core includes */
#include <assert.h>
#include <kernel/kernel.h> #include <kernel/kernel.h>
#include <kernel/thread.h> #include <kernel/thread.h>
#include <kernel/irq.h> #include <kernel/irq.h>

View File

@ -19,10 +19,10 @@
/* core includes */ /* core includes */
#include <core_parent.h> #include <core_parent.h>
#include <page_slab.h>
#include <map_local.h> #include <map_local.h>
#include <platform.h> #include <platform.h>
#include <platform_pd.h> #include <platform_pd.h>
#include <page_flags.h>
#include <util.h> #include <util.h>
#include <pic.h> #include <pic.h>
#include <kernel/kernel.h> #include <kernel/kernel.h>
@ -106,7 +106,6 @@ static Native_region * virt_region(unsigned const i) {
static Native_region r = { VIRT_ADDR_SPACE_START, VIRT_ADDR_SPACE_SIZE }; static Native_region r = { VIRT_ADDR_SPACE_START, VIRT_ADDR_SPACE_SIZE };
return i ? 0 : &r; } return i ? 0 : &r; }
static Core_mem_allocator * _core_mem_allocator = 0;
Platform::Platform() Platform::Platform()
: :
@ -115,10 +114,6 @@ Platform::Platform()
_irq_alloc(core_mem_alloc()), _irq_alloc(core_mem_alloc()),
_vm_start(VIRT_ADDR_SPACE_START), _vm_size(VIRT_ADDR_SPACE_SIZE) _vm_start(VIRT_ADDR_SPACE_START), _vm_size(VIRT_ADDR_SPACE_SIZE)
{ {
static Page_slab pslab(&_core_mem_alloc);
Kernel::core_pd()->platform_pd()->_pslab = &pslab;
_core_mem_allocator = &_core_mem_alloc;
/* /*
* Initialise platform resource allocators. * Initialise platform resource allocators.
* Core mem alloc must come first because it is * Core mem alloc must come first because it is
@ -213,22 +208,10 @@ bool Genode::unmap_local(addr_t virt_addr, size_t num_pages)
bool Core_mem_allocator::Mapped_mem_allocator::_map_local(addr_t virt_addr, bool Core_mem_allocator::Mapped_mem_allocator::_map_local(addr_t virt_addr,
addr_t phys_addr, addr_t phys_addr,
unsigned size) unsigned size) {
{ return ::map_local(phys_addr, virt_addr, size / get_page_size()); }
Genode::Page_slab * slab = Kernel::core_pd()->platform_pd()->_pslab;
slab->backing_store(_core_mem_allocator->raw());
bool ret = ::map_local(phys_addr, virt_addr, size / get_page_size());
slab->backing_store(_core_mem_allocator);
return ret;
}
bool Core_mem_allocator::Mapped_mem_allocator::_unmap_local(addr_t virt_addr, bool Core_mem_allocator::Mapped_mem_allocator::_unmap_local(addr_t virt_addr,
unsigned size) unsigned size) {
{ return ::unmap_local(virt_addr, size / get_page_size()); }
Genode::Page_slab * slab = Kernel::core_pd()->platform_pd()->_pslab;
slab->backing_store(_core_mem_allocator->raw());
bool ret = ::unmap_local(virt_addr, size / get_page_size());
slab->backing_store(_core_mem_allocator);
return ret;
}

View File

@ -33,7 +33,7 @@ Core_mem_allocator * Hw::Address_space::_cma() {
return static_cast<Core_mem_allocator*>(platform()->core_mem_alloc()); } return static_cast<Core_mem_allocator*>(platform()->core_mem_alloc()); }
void * Hw::Address_space::_tt_alloc() void * Hw::Address_space::_table_alloc()
{ {
void * ret; void * ret;
if (!_cma()->alloc_aligned(sizeof(Translation_table), (void**)&ret, if (!_cma()->alloc_aligned(sizeof(Translation_table), (void**)&ret,
@ -50,14 +50,12 @@ bool Hw::Address_space::insert_translation(addr_t virt, addr_t phys,
for (;;) { for (;;) {
try { try {
Lock::Guard guard(_lock); Lock::Guard guard(_lock);
_tt->insert_translation(virt, phys, size, flags, _pslab); _tt->insert_translation(virt, phys, size, flags, _tt_alloc);
return true; return true;
} catch(Page_slab::Out_of_slabs) {
_pslab->alloc_slab_block();
}
}
} catch(Allocator::Out_of_memory) { } catch(Allocator::Out_of_memory) {
PWRN("Translation table needs to much RAM"); flush(platform()->vm_start(), platform()->vm_size());
}
}
} catch(...) { } catch(...) {
PERR("Invalid mapping %p -> %p (%zx)", (void*)phys, (void*)virt, size); PERR("Invalid mapping %p -> %p (%zx)", (void*)phys, (void*)virt, size);
} }
@ -70,7 +68,7 @@ void Hw::Address_space::flush(addr_t virt, size_t size)
Lock::Guard guard(_lock); Lock::Guard guard(_lock);
try { try {
if (_tt) _tt->remove_translation(virt, size, _pslab); if (_tt) _tt->remove_translation(virt, size, _tt_alloc);
/* update translation caches */ /* update translation caches */
Kernel::update_pd(_kernel_pd); Kernel::update_pd(_kernel_pd);
@ -81,25 +79,25 @@ void Hw::Address_space::flush(addr_t virt, size_t size)
Hw::Address_space::Address_space(Kernel::Pd* pd, Translation_table * tt, Hw::Address_space::Address_space(Kernel::Pd* pd, Translation_table * tt,
Page_slab * slab) Translation_table_allocator * tt_alloc)
: _tt(tt), _tt_phys(tt), _pslab(slab), _kernel_pd(pd) { } : _tt(tt), _tt_phys(tt), _tt_alloc(tt_alloc), _kernel_pd(pd) { }
Hw::Address_space::Address_space(Kernel::Pd * pd) Hw::Address_space::Address_space(Kernel::Pd * pd)
: _tt(construct_at<Translation_table>(_tt_alloc())), : _tt(construct_at<Translation_table>(_table_alloc())),
_tt_phys(reinterpret_cast<Translation_table*>(_cma()->phys_addr(_tt))), _tt_phys(reinterpret_cast<Translation_table*>(_cma()->phys_addr(_tt))),
_pslab(new (_cma()) Page_slab(_cma())), _tt_alloc((new (_cma()) Table_allocator(_cma()))->alloc()),
_kernel_pd(pd) _kernel_pd(pd)
{ {
Lock::Guard guard(_lock); Lock::Guard guard(_lock);
Kernel::mtc()->map(_tt, _pslab); Kernel::mtc()->map(_tt, _tt_alloc);
} }
Hw::Address_space::~Address_space() Hw::Address_space::~Address_space()
{ {
flush(platform()->vm_start(), platform()->vm_size()); flush(platform()->vm_start(), platform()->vm_size());
destroy(_cma(), _pslab); destroy(_cma(), Table_allocator::base(_tt_alloc));
destroy(_cma(), _tt); destroy(_cma(), _tt);
} }
@ -151,8 +149,9 @@ int Platform_pd::assign_parent(Native_capability parent)
} }
Platform_pd::Platform_pd(Translation_table * tt, Page_slab * slab) Platform_pd::Platform_pd(Translation_table * tt,
: Hw::Address_space(kernel_object(), tt, slab), Translation_table_allocator * alloc)
: Hw::Address_space(kernel_object(), tt, alloc),
Kernel_object<Kernel::Pd>(false, tt, this), Kernel_object<Kernel::Pd>(false, tt, this),
_label("core") { } _label("core") { }
@ -180,13 +179,19 @@ Translation_table * const Core_platform_pd::_table()
} }
Page_slab * const Core_platform_pd::_slab() Translation_table_allocator * const Core_platform_pd::_table_alloc()
{ {
using Slab = Kernel::Early_translations_slab; /**
using Allocator = Kernel::Early_translations_allocator; * Core's translation table allocator should contain as much tables
* needed to populate the whole virtual memory available to core.
return unmanaged_singleton<Slab, * By now, we do not cover the limitation of core's virtula memory
Slab::ALIGN>(unmanaged_singleton<Allocator>()); * when opening e.g. sessions on behalf of clients. Therefore, for
* the time being the number of tables is set to some reasonable
* high number.
*/
using Pa = Translation_table_allocator_tpl<1024>;
static Pa * pa = unmanaged_singleton<Pa, Pa::ALIGN>();
return pa->alloc();
} }
@ -199,9 +204,7 @@ void Core_platform_pd::_map(addr_t start, addr_t end, bool io_mem)
size_t size = round_page(end) - start; size_t size = round_page(end) - start;
try { try {
_table()->insert_translation(start, start, size, flags, _slab()); _table()->insert_translation(start, start, size, flags, _table_alloc());
} catch(Page_slab::Out_of_slabs) {
PERR("Not enough page slabs");
} catch(Allocator::Out_of_memory) { } catch(Allocator::Out_of_memory) {
PERR("Translation table needs to much RAM"); PERR("Translation table needs to much RAM");
} catch(...) { } catch(...) {
@ -212,10 +215,10 @@ void Core_platform_pd::_map(addr_t start, addr_t end, bool io_mem)
Core_platform_pd::Core_platform_pd() Core_platform_pd::Core_platform_pd()
: Platform_pd(_table(), _slab()) : Platform_pd(_table(), _table_alloc())
{ {
/* map exception vector for core */ /* map exception vector for core */
Kernel::mtc()->map(_table(), _slab()); Kernel::mtc()->map(_table(), _table_alloc());
/* map core's program image */ /* map core's program image */
_map((addr_t)&_prog_img_beg, (addr_t)&_prog_img_end, false); _map((addr_t)&_prog_img_beg, (addr_t)&_prog_img_end, false);

View File

@ -13,6 +13,7 @@
*/ */
/* core includes */ /* core includes */
#include <assert.h>
#include <platform_thread.h> #include <platform_thread.h>
#include <platform_pd.h> #include <platform_pd.h>
#include <core_env.h> #include <core_env.h>

View File

@ -13,6 +13,7 @@
*/ */
/* core includes */ /* core includes */
#include <assert.h>
#include <kernel/cpu.h> #include <kernel/cpu.h>
#include <kernel/kernel.h> #include <kernel/kernel.h>
#include <kernel/pd.h> #include <kernel/pd.h>

View File

@ -15,6 +15,7 @@
#include <util/bit_allocator.h> #include <util/bit_allocator.h>
/* core includes */ /* core includes */
#include <assert.h>
#include <kernel/pd.h> #include <kernel/pd.h>
using Asid_allocator = Genode::Bit_allocator<256>; using Asid_allocator = Genode::Bit_allocator<256>;

View File

@ -13,6 +13,7 @@
*/ */
/* core includes */ /* core includes */
#include <assert.h>
#include <kernel/thread.h> #include <kernel/thread.h>
#include <kernel/pd.h> #include <kernel/pd.h>
#include <kernel/kernel.h> #include <kernel/kernel.h>

View File

@ -34,3 +34,14 @@ Vm_session_component::Vm_session_component(Rpc_entrypoint *ds_ep,
{ {
_ds.assign_core_local_addr(core_env()->rm_session()->attach(_ds_cap)); _ds.assign_core_local_addr(core_env()->rm_session()->attach(_ds_cap));
} }
Vm_session_component::~Vm_session_component()
{
/* dissolve VM dataspace from service entry point */
_ds_ep->dissolve(&_ds);
/* free region in allocator */
core_env()->rm_session()->detach(_ds.core_local_addr());
platform()->ram_alloc()->free((void*)_ds.phys_addr());
}

View File

@ -11,6 +11,7 @@
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
#include <assert.h>
#include <platform_pd.h> #include <platform_pd.h>
#include <kernel/vm.h> #include <kernel/vm.h>

View File

@ -39,13 +39,8 @@ void Vm_session_component::_attach(addr_t phys_addr, addr_t vm_addr, size_t size
Page_flags pflags = Page_flags::apply_mapping(true, CACHED, false); Page_flags pflags = Page_flags::apply_mapping(true, CACHED, false);
try { try {
for (;;) _table->insert_translation(vm_addr, phys_addr, size, pflags, _tt_alloc);
try {
_table->insert_translation(vm_addr, phys_addr, size, pflags, _pslab);
return; return;
} catch(Page_slab::Out_of_slabs) {
_pslab->alloc_slab_block();
}
} catch(Allocator::Out_of_memory) { } catch(Allocator::Out_of_memory) {
PERR("Translation table needs to much RAM"); PERR("Translation table needs to much RAM");
} catch(...) { } catch(...) {
@ -73,7 +68,7 @@ void Vm_session_component::attach_pic(addr_t vm_addr)
void Vm_session_component::detach(addr_t vm_addr, size_t size) { void Vm_session_component::detach(addr_t vm_addr, size_t size) {
_table->remove_translation(vm_addr, size, _pslab); } _table->remove_translation(vm_addr, size, _tt_alloc); }
Vm_session_component::Vm_session_component(Rpc_entrypoint *ds_ep, Vm_session_component::Vm_session_component(Rpc_entrypoint *ds_ep,
@ -95,5 +90,20 @@ Vm_session_component::Vm_session_component(Rpc_entrypoint *ds_ep,
} }
_table = construct_at<Translation_table>(tt); _table = construct_at<Translation_table>(tt);
_pslab = new (cma) Page_slab(cma); _tt_alloc = (new (cma) Table_allocator(cma))->alloc();
}
Vm_session_component::~Vm_session_component()
{
/* dissolve VM dataspace from service entry point */
_ds_ep->dissolve(&_ds);
/* free region in allocator */
core_env()->rm_session()->detach(_ds.core_local_addr());
platform()->ram_alloc()->free((void*)_ds.phys_addr());
/* free guest-to-host page tables */
destroy(platform()->core_mem_alloc(), _table);
destroy(platform()->core_mem_alloc(), Table_allocator::base(_tt_alloc));
} }

View File

@ -42,14 +42,3 @@ void Vm_session_component::pause(void)
if (Kernel_object<Kernel::Vm>::_cap.valid()) if (Kernel_object<Kernel::Vm>::_cap.valid())
Kernel::pause_vm(kernel_object()); Kernel::pause_vm(kernel_object());
} }
Vm_session_component::~Vm_session_component()
{
/* dissolve VM dataspace from service entry point */
_ds_ep->dissolve(&_ds);
/* free region in allocator */
core_env()->rm_session()->detach(_ds.core_local_addr());
platform()->ram_alloc()->free((void*)_ds.phys_addr());
}