From 8abd70e6e704421cfce2defa545c1486168e4cac Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Thu, 25 Jun 2015 15:53:39 +0200 Subject: [PATCH] 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 --- repos/base-hw/src/core/include/kernel/pd.h | 2 +- repos/base-hw/src/core/include/platform.h | 16 ++ .../spec/arm/short_translation_table.h | 14 +- .../spec/arm_v7/long_translation_table.h | 22 ++- .../include/spec/x86_64/translation_table.h | 27 +++- .../include/translation_table_allocator.h | 114 -------------- .../include/translation_table_allocator_tpl.h | 140 ++++++++++++++++++ repos/base-hw/src/core/include/util.h | 5 +- repos/base-hw/src/core/platform.cc | 13 +- repos/base-hw/src/core/platform_pd.cc | 25 ++-- 10 files changed, 241 insertions(+), 137 deletions(-) create mode 100644 repos/base-hw/src/core/include/translation_table_allocator_tpl.h diff --git a/repos/base-hw/src/core/include/kernel/pd.h b/repos/base-hw/src/core/include/kernel/pd.h index 345a02822c..455de7bdda 100644 --- a/repos/base-hw/src/core/include/kernel/pd.h +++ b/repos/base-hw/src/core/include/kernel/pd.h @@ -16,7 +16,7 @@ #define _KERNEL__PD_H_ /* core includes */ -#include +#include #include #include diff --git a/repos/base-hw/src/core/include/platform.h b/repos/base-hw/src/core/include/platform.h index 8fddac816e..aeefd03688 100644 --- a/repos/base-hw/src/core/include/platform.h +++ b/repos/base-hw/src/core/include/platform.h @@ -22,9 +22,11 @@ /* base-hw includes */ #include +#include #include /* core includes */ +#include #include #include #include @@ -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 ** ********************************/ diff --git a/repos/base-hw/src/core/include/spec/arm/short_translation_table.h b/repos/base-hw/src/core/include/spec/arm/short_translation_table.h index 526165491d..5743132cd5 100644 --- a/repos/base-hw/src/core/include/spec/arm/short_translation_table.h +++ b/repos/base-hw/src/core/include/spec/arm/short_translation_table.h @@ -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, }; /** diff --git a/repos/base-hw/src/core/include/spec/arm_v7/long_translation_table.h b/repos/base-hw/src/core/include/spec/arm_v7/long_translation_table.h index 6347b238af..dd91071adb 100644 --- a/repos/base-hw/src/core/include/spec/arm_v7/long_translation_table.h +++ b/repos/base-hw/src/core/include/spec/arm_v7/long_translation_table.h @@ -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_ */ diff --git a/repos/base-hw/src/core/include/spec/x86_64/translation_table.h b/repos/base-hw/src/core/include/spec/x86_64/translation_table.h index 3e8a8e9e35..144b30ea03 100644 --- a/repos/base-hw/src/core/include/spec/x86_64/translation_table.h +++ b/repos/base-hw/src/core/include/spec/x86_64/translation_table.h @@ -21,6 +21,7 @@ #include /* base-hw includes */ +#include #include #include @@ -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(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_ */ diff --git a/repos/base-hw/src/core/include/translation_table_allocator.h b/repos/base-hw/src/core/include/translation_table_allocator.h index 10fc4f6de6..83b6e9466b 100644 --- a/repos/base-hw/src/core/include/translation_table_allocator.h +++ b/repos/base-hw/src/core/include/translation_table_allocator.h @@ -14,11 +14,7 @@ #ifndef _CORE__INCLUDE__TRANSLATION_TABLE_ALLOCATOR_H_ #define _CORE__INCLUDE__TRANSLATION_TABLE_ALLOCATOR_H_ -#include #include -#include -#include -#include 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 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 -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 -class Genode::Translation_table_allocator_tpl::Allocator -: public Translation_table_allocator -{ - private: - - Table *_tables; - Bit_allocator _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::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_ */ diff --git a/repos/base-hw/src/core/include/translation_table_allocator_tpl.h b/repos/base-hw/src/core/include/translation_table_allocator_tpl.h new file mode 100644 index 0000000000..e223d73e3f --- /dev/null +++ b/repos/base-hw/src/core/include/translation_table_allocator_tpl.h @@ -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 +#include +#include +#include +#include + +namespace Genode { + + /** + * Statically dimensioned translation table allocator + * + * /param TABLES count of tables the allocator provides as maximum + */ + template class Translation_table_allocator_tpl; +} + + +template +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 +class Genode::Translation_table_allocator_tpl::Allocator +: public Translation_table_allocator +{ + private: + + Table *_tables; + Bit_allocator _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::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_ */ diff --git a/repos/base-hw/src/core/include/util.h b/repos/base-hw/src/core/include/util.h index 05e5b3e32d..5bdc53d6f8 100644 --- a/repos/base-hw/src/core/include/util.h +++ b/repos/base-hw/src/core/include/util.h @@ -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); } diff --git a/repos/base-hw/src/core/platform.cc b/repos/base-hw/src/core/platform.cc index 9a39b39b0c..90c8776139 100644 --- a/repos/base-hw/src/core/platform.cc +++ b/repos/base-hw/src/core/platform.cc @@ -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)&_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; } diff --git a/repos/base-hw/src/core/platform_pd.cc b/repos/base-hw/src/core/platform_pd.cc index aef6c9dac9..3f3d6d4487 100644 --- a/repos/base-hw/src/core/platform_pd.cc +++ b/repos/base-hw/src/core/platform_pd.cc @@ -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(); - return pa->alloc(); + constexpr size_t count = Genode::Translation_table::CORE_TRANS_TABLE_COUNT; + using Allocator = Translation_table_allocator_tpl; + + static Allocator * alloc = nullptr; + if (!alloc) { + void * base = (void*) Platform::core_translation_tables(); + alloc = construct_at(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;