From b888a26d5715ba615a9987a77ce4edee6413f94f Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Mon, 28 Apr 2014 15:40:28 +0200 Subject: [PATCH] core: extend core memory allocator * Allow to translate physical to virtual core addresses and vice versa * Eliminate race introduced by commit "core: re-design memory allocator" Ref #723 --- base-codezero/src/core/platform.cc | 7 +- base-nova/src/core/platform.cc | 8 +- base-okl4/src/core/platform.cc | 8 +- base/include/base/allocator_avl.h | 2 +- base/src/core/core_mem_alloc.cc | 27 +++- base/src/core/include/core_mem_alloc.h | 215 +++++++++++++++++++++++-- 6 files changed, 240 insertions(+), 27 deletions(-) diff --git a/base-codezero/src/core/platform.cc b/base-codezero/src/core/platform.cc index 2a9a39e86..54d758e95 100644 --- a/base-codezero/src/core/platform.cc +++ b/base-codezero/src/core/platform.cc @@ -126,13 +126,16 @@ int Platform::_init_rom_fs() ** Support for core memory management ** ****************************************/ -bool Core_mem_allocator::_map_local(addr_t virt_addr, addr_t phys_addr, unsigned size) +bool Core_mem_allocator::Mapped_mem_allocator::_map_local(addr_t virt_addr, + addr_t phys_addr, + unsigned size) { return map_local(phys_addr, virt_addr, size / get_page_size()); } -bool Core_mem_allocator::_unmap_local(addr_t virt_addr, unsigned size) +bool Core_mem_allocator::Mapped_mem_allocator::_unmap_local(addr_t virt_addr, + unsigned size) { return unmap_local(virt_addr, size / get_page_size()); } diff --git a/base-nova/src/core/platform.cc b/base-nova/src/core/platform.cc index 586227029..71b6e2fba 100644 --- a/base-nova/src/core/platform.cc +++ b/base-nova/src/core/platform.cc @@ -566,8 +566,9 @@ Platform::Platform() : ** Support for core memory management ** ****************************************/ -bool Core_mem_allocator::_map_local(addr_t virt_addr, addr_t phys_addr, - unsigned size) +bool Core_mem_allocator::Mapped_mem_allocator::_map_local(addr_t virt_addr, + addr_t phys_addr, + unsigned size) { map_local((Utcb *)Thread_base::myself()->utcb(), phys_addr, virt_addr, size / get_page_size(), @@ -576,7 +577,8 @@ bool Core_mem_allocator::_map_local(addr_t virt_addr, addr_t phys_addr, } -bool Core_mem_allocator::_unmap_local(addr_t virt_addr, unsigned size) +bool Core_mem_allocator::Mapped_mem_allocator::_unmap_local(addr_t virt_addr, + unsigned size) { unmap_local((Utcb *)Thread_base::myself()->utcb(), virt_addr, size / get_page_size()); diff --git a/base-okl4/src/core/platform.cc b/base-okl4/src/core/platform.cc index e59b62fec..18a7b0211 100644 --- a/base-okl4/src/core/platform.cc +++ b/base-okl4/src/core/platform.cc @@ -53,12 +53,14 @@ static int num_boot_module_objects; ** Support for core memory management ** ****************************************/ -bool Core_mem_allocator::_map_local(addr_t virt_addr, addr_t phys_addr, - unsigned size) { +bool Core_mem_allocator::Mapped_mem_allocator::_map_local(addr_t virt_addr, + addr_t phys_addr, + unsigned size) { return map_local(phys_addr, virt_addr, size / get_page_size()); } -bool Core_mem_allocator::_unmap_local(addr_t virt_addr, unsigned size) { +bool Core_mem_allocator::Mapped_mem_allocator::_unmap_local(addr_t virt_addr, + unsigned size) { return unmap_local(virt_addr, size / get_page_size()); } diff --git a/base/include/base/allocator_avl.h b/base/include/base/allocator_avl.h index 57d4bd93a..aa7182881 100644 --- a/base/include/base/allocator_avl.h +++ b/base/include/base/allocator_avl.h @@ -260,7 +260,7 @@ namespace Genode { template class Allocator_avl_tpl : public Allocator_avl_base { - private: + protected: /* * Pump up the Block class with custom meta-data type diff --git a/base/src/core/core_mem_alloc.cc b/base/src/core/core_mem_alloc.cc index 190184176..c6f87284b 100644 --- a/base/src/core/core_mem_alloc.cc +++ b/base/src/core/core_mem_alloc.cc @@ -14,6 +14,7 @@ /* Genode includes */ #include +#include /* local includes */ #include @@ -23,16 +24,27 @@ using namespace Genode; static const bool verbose_core_mem_alloc = false; +void * Core_mem_allocator::Mapped_avl_allocator::map_addr(void * addr) +{ + Block *b = static_cast(_find_by_address((addr_t)addr)); + + if(!b || !b->used()) return 0; + + size_t off = (addr_t)addr - b->addr(); + return (void*) (((addr_t)b->map_addr) + off); +} + + Range_allocator::Alloc_return -Core_mem_allocator::alloc_aligned(size_t size, void **out_addr, int align) +Core_mem_allocator::Mapped_mem_allocator::alloc_aligned(size_t size, void **out_addr, int align) { size_t page_rounded_size = (size + get_page_size() - 1) & get_page_mask(); void *phys_addr = 0; align = max((size_t)align, get_page_size_log2()); /* allocate physical pages */ - Alloc_return ret1 = _phys_alloc.raw()->alloc_aligned(page_rounded_size, - &phys_addr, align); + Alloc_return ret1 = _phys_alloc->alloc_aligned(page_rounded_size, + &phys_addr, align); if (!ret1.is_ok()) { PERR("Could not allocate physical memory region of size %zu\n", page_rounded_size); @@ -40,14 +52,14 @@ Core_mem_allocator::alloc_aligned(size_t size, void **out_addr, int align) } /* allocate range in core's virtual address space */ - Alloc_return ret2 = _virt_alloc.raw()->alloc_aligned(page_rounded_size, - out_addr, align); + Alloc_return ret2 = _virt_alloc->alloc_aligned(page_rounded_size, + out_addr, align); if (!ret2.is_ok()) { PERR("Could not allocate virtual address range in core of size %zu\n", page_rounded_size); /* revert physical allocation */ - _phys_alloc.raw()->free(phys_addr); + _phys_alloc->free(phys_addr); return ret2; } @@ -55,6 +67,9 @@ Core_mem_allocator::alloc_aligned(size_t size, void **out_addr, int align) printf("added core memory block of %zu bytes at virt=%p phys=%p\n", page_rounded_size, *out_addr, phys_addr); + _phys_alloc->metadata(phys_addr, { *out_addr }); + _virt_alloc->metadata(*out_addr, { phys_addr }); + /* make physical page accessible at the designated virtual address */ _map_local((addr_t)*out_addr, (addr_t)phys_addr, page_rounded_size); diff --git a/base/src/core/include/core_mem_alloc.h b/base/src/core/include/core_mem_alloc.h index 8906471c2..9cfa453e1 100644 --- a/base/src/core/include/core_mem_alloc.h +++ b/base/src/core/include/core_mem_alloc.h @@ -21,23 +21,170 @@ #include namespace Genode { + class Core_mem_translator; class Core_mem_allocator; }; +/** + * Interface of an allocator that allows to return physical addresses + * of its used virtual address ranges, and vice versa. + */ +class Genode::Core_mem_translator : public Genode::Range_allocator +{ + public: + + /** + * Returns physical address for given virtual one + * + * \param addr virtual address + */ + virtual void * phys_addr(void * addr) = 0; + + /** + * Returns virtual address for given physical one + * + * \param addr physical address + */ + virtual void * virt_addr(void * addr) = 0; +}; + + /** * Allocators for physical memory, core's virtual address space, * and core-local memory. The interface of this class is thread safe. * The class itself implements a ready-to-use memory allocator for * core that allows to allocate memory at page granularity only. */ -class Genode::Core_mem_allocator : public Genode::Range_allocator +class Genode::Core_mem_allocator : public Genode::Core_mem_translator { public: using Page_allocator = Allocator_avl_tpl; using Phys_allocator = Synchronized_range_allocator; + /** + * Metadata for allocator blocks that stores a related address + */ + struct Metadata { void * map_addr; }; + + /** + * Page-size granular allocator that links ranges to related ones. + */ + class Mapped_avl_allocator + : public Allocator_avl_tpl + { + public: + + /** + * Constructor + * + * \param md_alloc metadata allocator + */ + explicit Mapped_avl_allocator(Allocator *md_alloc) + : Allocator_avl_tpl(md_alloc) {} + + /** + * Returns related address for allocated range + * + * \param addr address within allocated range + */ + void * map_addr(void * addr); + }; + + using Synchronized_mapped_allocator = + Synchronized_range_allocator; + + /** + * Unsynchronized allocator for core-mapped memory + * + * This is an allocator of core-mapped memory. It is meant to be used as + * meta-data allocator for the other allocators and as back end for core's + * synchronized memory allocator. + */ + class Mapped_mem_allocator : public Genode::Core_mem_translator + { + private: + + Mapped_avl_allocator *_phys_alloc; + Mapped_avl_allocator *_virt_alloc; + + public: + + /** + * Constructor + * + * \param phys_alloc allocator of physical memory + * \param virt_alloc allocator of core-local virtual memory ranges + */ + + Mapped_mem_allocator(Mapped_avl_allocator *phys_alloc, + Mapped_avl_allocator *virt_alloc) + : _phys_alloc(phys_alloc), _virt_alloc(virt_alloc) { } + + /** + * Establish mapping between physical and virtual address range + * + * Note: has to be implemented by platform specific code + * + * \param virt_addr start address of virtual range + * \param phys_addr start address of physical range + * \param size size of range + */ + bool _map_local(addr_t virt_addr, addr_t phys_addr, unsigned size); + + /** + * Destroy mapping between physical and virtual address range + * + * Note: has to be implemented by platform specific code + * + * \param virt_addr start address of virtual range + * \param size size of range + */ + bool _unmap_local(addr_t virt_addr, unsigned size); + + + /*********************************** + ** Core_mem_translator interface ** + ***********************************/ + + void * phys_addr(void * addr) { + return _virt_alloc->map_addr(addr); } + + void * virt_addr(void * addr) { + return _phys_alloc->map_addr(addr); } + + + /******************************* + ** Range allocator interface ** + *******************************/ + + 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 = 0); + Alloc_return alloc_addr(size_t size, addr_t addr) { + return Alloc_return::RANGE_CONFLICT; } + void free(void *addr) {} + size_t avail() { return _phys_alloc->avail(); } + bool valid_addr(addr_t addr) { + return _virt_alloc->valid_addr(addr); } + + + /************************* + ** Allocator interface ** + *************************/ + + bool alloc(size_t size, void **out_addr) { + return alloc_aligned(size, out_addr).is_ok(); } + void free(void *addr, size_t) { free(addr); } + size_t consumed() { return _phys_alloc->consumed(); } + size_t overhead(size_t size) { + return _phys_alloc->overhead(size); } + bool need_size_for_free() const override { + return _phys_alloc->need_size_for_free(); } + }; + protected: /** @@ -52,7 +199,7 @@ class Genode::Core_mem_allocator : public Genode::Range_allocator * This allocator must only be used to allocate memory * ranges at page granularity. */ - Phys_allocator _phys_alloc; + Synchronized_mapped_allocator _phys_alloc; /** * Synchronized allocator of core's virtual memory ranges @@ -60,10 +207,20 @@ class Genode::Core_mem_allocator : public Genode::Range_allocator * This allocator must only be used to allocate memory * ranges at page granularity. */ - Phys_allocator _virt_alloc; + Synchronized_mapped_allocator _virt_alloc; - bool _map_local(addr_t virt_addr, addr_t phys_addr, unsigned size); - bool _unmap_local(addr_t virt_addr, unsigned size); + /** + * Unsynchronized core-mapped memory allocator + * + * This allocator is internally used within this class for + * allocating meta data for the other allocators. It is not + * synchronized to avoid nested locking. The lock-guarded + * access to this allocator from the outer world is + * provided via the 'Allocator' interface implemented by + * 'Core_mem_allocator'. The allocator works at byte + * granularity. + */ + Mapped_mem_allocator _mem_alloc; public: @@ -71,18 +228,41 @@ class Genode::Core_mem_allocator : public Genode::Range_allocator * Constructor */ Core_mem_allocator() - : _phys_alloc(&_lock, this), - _virt_alloc(&_lock, this) { } + : _phys_alloc(&_lock, &_mem_alloc), + _virt_alloc(&_lock, &_mem_alloc), + _mem_alloc(_phys_alloc.raw(), _virt_alloc.raw()) { } /** * Access physical-memory allocator */ - Phys_allocator *phys_alloc() { return &_phys_alloc; } + Synchronized_mapped_allocator *phys_alloc() { return &_phys_alloc; } /** * Access core's virtual-memory allocator */ - Phys_allocator *virt_alloc() { return &_virt_alloc; } + Synchronized_mapped_allocator *virt_alloc() { return &_virt_alloc; } + + /** + * Access core's local memory allocator unsynchronized + */ + Mapped_mem_allocator *raw() { return &_mem_alloc; } + + + /*********************************** + ** Core_mem_translator interface ** + ***********************************/ + + void * phys_addr(void * addr) + { + Lock::Guard lock_guard(_lock); + return _virt_alloc.raw()->map_addr(addr); + } + + void * virt_addr(void * addr) + { + Lock::Guard lock_guard(_lock); + return _phys_alloc.raw()->map_addr(addr); + } /******************************* @@ -91,11 +271,22 @@ class Genode::Core_mem_allocator : public Genode::Range_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 = 0); Alloc_return alloc_addr(size_t size, addr_t addr) { return Alloc_return::RANGE_CONFLICT; } - void free(void *addr) {} - size_t avail() { return _phys_alloc.avail(); } + + Alloc_return alloc_aligned(size_t size, void **out_addr, int align = 0) + { + Lock::Guard lock_guard(_lock); + return _mem_alloc.alloc_aligned(size, out_addr, align); + } + + void free(void *addr) + { + Lock::Guard lock_guard(_lock); + return _mem_alloc.free(addr); + } + + size_t avail() { return _phys_alloc.avail(); } bool valid_addr(addr_t addr) { return _virt_alloc.valid_addr(addr); }