hw: allocate core's page-tables outside of binary

Moreover, be strict when calculating the page-table requirements of
core, which is architecture specific, and declare the virtual memory
requirements of core architecture-wise.

Ref #1588
This commit is contained in:
Stefan Kalkowski 2015-06-25 15:53:39 +02:00 committed by Christian Helmuth
parent 3ee2997198
commit 8abd70e6e7
10 changed files with 241 additions and 137 deletions

View File

@ -16,7 +16,7 @@
#define _KERNEL__PD_H_
/* core includes */
#include <translation_table.h>
#include <translation_table_allocator_tpl.h>
#include <kernel/cpu.h>
#include <kernel/object.h>

View File

@ -22,9 +22,11 @@
/* base-hw includes */
#include <kernel/log.h>
#include <kernel/configuration.h>
#include <kernel/core_interface.h>
/* core includes */
#include <translation_table_allocator_tpl.h>
#include <platform_generic.h>
#include <core_rm_session.h>
#include <core_mem_alloc.h>
@ -121,6 +123,20 @@ namespace Genode {
static void setup_irq_mode(unsigned irq_number, unsigned trigger,
unsigned polarity);
/**
* Return address of cores translation table allocator
*/
static addr_t core_translation_tables();
/**
* Return size of cores translation table allocator
*/
static constexpr size_t core_translation_tables_size()
{
return round_page(sizeof(Translation_table_allocator_tpl<
Translation_table::CORE_TRANS_TABLE_COUNT>));
}
/********************************
** Platform_generic interface **
********************************/

View File

@ -279,11 +279,15 @@ class Genode::Translation_table
public:
enum {
SIZE_LOG2 = 14,
SIZE = 1 << SIZE_LOG2,
ALIGNM_LOG2 = SIZE_LOG2,
MAX_PAGE_SIZE_LOG2 = 20,
MIN_PAGE_SIZE_LOG2 = 12,
SIZE_LOG2 = 14,
SIZE = 1 << SIZE_LOG2,
ALIGNM_LOG2 = SIZE_LOG2,
MAX_PAGE_SIZE_LOG2 = 20,
MIN_PAGE_SIZE_LOG2 = 12,
TABLE_LEVEL_X_VIRT_SIZE = 1 << MAX_PAGE_SIZE_LOG2,
TABLE_LEVEL_X_SIZE_LOG2 = MIN_PAGE_SIZE_LOG2,
CORE_VM_AREA_SIZE = 1024 * 1024 * 1024,
CORE_TRANS_TABLE_COUNT = CORE_VM_AREA_SIZE / TABLE_LEVEL_X_VIRT_SIZE,
};
/**

View File

@ -522,7 +522,25 @@ class Genode::Level_x_translation_table :
this->_range_op(vo, 0, size, Remove_func(alloc)); }
};
namespace Genode {
class Translation_table : public Level_1_stage_1_translation_table { }; }
namespace Genode {
class Translation_table;
}
class Genode::Translation_table : public Level_1_stage_1_translation_table
{
public:
enum {
TABLE_LEVEL_X_SIZE_LOG2 = SIZE_LOG2_4KB,
TABLE_LEVEL_X_ENTRIES = (1 << SIZE_LOG2_4KB) / sizeof(addr_t),
CORE_VM_AREA_SIZE = 1024 * 1024 * 1024,
SIZE_1GB = 1 << SIZE_LOG2_1GB,
CORE_LEVEL_2_TT_COUNT = ((uint64_t)CORE_VM_AREA_SIZE +
SIZE_1GB - 1) / SIZE_1GB,
CORE_TRANS_TABLE_COUNT = CORE_LEVEL_2_TT_COUNT +
CORE_LEVEL_2_TT_COUNT *
TABLE_LEVEL_X_ENTRIES,
};
};
#endif /* _ARM_V7__LONG_TRANSLATION_TABLE_H_ */

View File

@ -21,6 +21,7 @@
#include <assert.h>
/* base-hw includes */
#include <util.h>
#include <page_flags.h>
#include <translation_table_allocator.h>
@ -634,6 +635,14 @@ class Genode::Pml4_table
}
}
protected:
/**
* Return how many entries of an alignment fit into region
*/
static constexpr size_t _count(size_t region, size_t alignment) {
return align_addr<size_t>(region, alignment) / (1UL << alignment); }
public:
static constexpr size_t MIN_PAGE_SIZE_LOG2 = SIZE_LOG2_4KB;
@ -690,7 +699,23 @@ class Genode::Pml4_table
}
} __attribute__((aligned(1 << ALIGNM_LOG2)));
namespace Genode {
class Translation_table : public Pml4_table { }; }
class Translation_table;
}
class Genode::Translation_table : public Pml4_table
{
public:
enum {
TABLE_LEVEL_X_SIZE_LOG2 = SIZE_LOG2_4KB,
CORE_VM_AREA_SIZE = 1024 * 1024 * 1024,
CORE_TRANS_TABLE_COUNT =
_count(CORE_VM_AREA_SIZE, SIZE_LOG2_512GB)
+ _count(CORE_VM_AREA_SIZE, SIZE_LOG2_1GB)
+ _count(CORE_VM_AREA_SIZE, SIZE_LOG2_2MB)
};
};
#endif /* _TRANSLATION_TABLE_H_ */

View File

@ -14,11 +14,7 @@
#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 {
@ -26,13 +22,6 @@ 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;
}
@ -55,107 +44,4 @@ class Genode::Translation_table_allocator : public Genode::Allocator
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

@ -0,0 +1,140 @@
/*
* \brief Translation table allocator template implementation
* \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_TPL_H_
#define _CORE__INCLUDE__TRANSLATION_TABLE_ALLOCATOR_TPL_H_
#include <base/stdint.h>
#include <util/bit_allocator.h>
#include <core_mem_alloc.h>
#include <translation_table.h>
#include <translation_table_allocator.h>
namespace Genode {
/**
* Statically dimensioned translation table allocator
*
* /param TABLES count of tables the allocator provides as maximum
*/
template <unsigned TABLES> class Translation_table_allocator_tpl;
}
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 {
enum { SIZE = 1 << Translation_table::TABLE_LEVEL_X_SIZE_LOG2 };
uint8_t data[SIZE];
};
Table _tables[TABLES];
Allocator _alloc;
public:
static constexpr unsigned ALIGN = Table::SIZE;
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_TPL_H_ */

View File

@ -33,13 +33,14 @@ namespace Genode
/**
* Round down to the minimal page-size alignment
*/
inline addr_t trunc_page(addr_t addr) { return addr & get_page_mask(); }
constexpr addr_t trunc_page(addr_t addr) {
return addr & get_page_mask(); }
/**
* Round up to the minimal page-size alignment
*/
inline addr_t round_page(addr_t addr)
constexpr addr_t round_page(addr_t addr)
{ return trunc_page(addr + get_page_size() - 1); }

View File

@ -86,6 +86,14 @@ static void init_alloc(Range_allocator * const alloc,
** Platform **
**************/
addr_t Platform::core_translation_tables()
{
size_t sz = max((size_t)Translation_table::TABLE_LEVEL_X_SIZE_LOG2,
get_page_size_log2());
return align_addr<addr_t>((addr_t)&_boot_modules_binaries_end, sz);
}
Native_region * Platform::_core_only_ram_regions(unsigned const i)
{
static Native_region _r[] =
@ -97,7 +105,10 @@ Native_region * Platform::_core_only_ram_regions(unsigned const i)
/* boot modules */
{ (addr_t)&_boot_modules_binaries_begin,
(size_t)((addr_t)&_boot_modules_binaries_end -
(addr_t)&_boot_modules_binaries_begin) }
(addr_t)&_boot_modules_binaries_begin) },
/* translation table allocator */
{ core_translation_tables(), core_translation_tables_size() }
};
return i < sizeof(_r)/sizeof(_r[0]) ? &_r[i] : 0;
}

View File

@ -181,17 +181,15 @@ Translation_table * const Core_platform_pd::_table()
Translation_table_allocator * const Core_platform_pd::_table_alloc()
{
/**
* Core's translation table allocator should contain as much tables
* needed to populate the whole virtual memory available to core.
* By now, we do not cover the limitation of core's virtula memory
* 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();
constexpr size_t count = Genode::Translation_table::CORE_TRANS_TABLE_COUNT;
using Allocator = Translation_table_allocator_tpl<count>;
static Allocator * alloc = nullptr;
if (!alloc) {
void * base = (void*) Platform::core_translation_tables();
alloc = construct_at<Allocator>(base);
}
return alloc->alloc();
}
@ -223,6 +221,11 @@ Core_platform_pd::Core_platform_pd()
/* map core's program image */
_map((addr_t)&_prog_img_beg, (addr_t)&_prog_img_end, false);
/* map core's page table allocator */
_map(Platform::core_translation_tables(),
Platform::core_translation_tables() +
Platform::core_translation_tables_size(), false);
/* map core's mmio regions */
Native_region * r = Platform::_core_only_mmio_regions(0);
for (unsigned i = 0; r;