/* * \brief Allocator infrastructure for core * \author Norman Feske * \author Stefan Kalkowski * \date 2009-10-12 */ /* * Copyright (C) 2009-2017 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ #ifndef _CORE__INCLUDE__CORE_MEM_ALLOC_H_ #define _CORE__INCLUDE__CORE_MEM_ALLOC_H_ #include #include #include #include namespace Genode { class Core_mem_translator; class Core_mem_allocator; struct Metadata; class Mapped_mem_allocator; class Mapped_avl_allocator; using Page_allocator = Allocator_avl_tpl; using Phys_allocator = Synced_range_allocator; using Synced_mapped_allocator = Synced_range_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; }; /** * Metadata for allocator blocks that stores a related address */ struct Genode::Metadata { void * map_addr; }; /** * Page-size granular allocator that links ranges to related ones. */ class Genode::Mapped_avl_allocator : public Genode::Allocator_avl_tpl { friend class Mapped_mem_allocator; 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); }; /** * 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 Genode::Mapped_mem_allocator : public Genode::Core_mem_translator { private: Mapped_avl_allocator *_phys_alloc; Mapped_avl_allocator *_virt_alloc; /* * Noncopyable */ Mapped_mem_allocator(Mapped_mem_allocator const &); Mapped_mem_allocator &operator = (Mapped_mem_allocator const &); public: /** * Constructor * * \param phys_alloc allocator of physical memory * \param virt_alloc allocator of core-local virtual memory ranges */ Mapped_mem_allocator(Synced_mapped_allocator &phys_alloc, Synced_mapped_allocator &virt_alloc) : _phys_alloc(&phys_alloc._alloc), _virt_alloc(&virt_alloc._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 phys_addr start address of physical range * \param size size of range */ bool _unmap_local(addr_t virt_addr, addr_t phys_addr, unsigned size); /*********************************** ** Core_mem_translator interface ** ***********************************/ void * phys_addr(void * addr) override { return _virt_alloc->map_addr(addr); } void * virt_addr(void * addr) override { return _phys_alloc->map_addr(addr); } /******************************* ** Range allocator interface ** *******************************/ int add_range(addr_t, size_t) override { return -1; } int remove_range(addr_t, size_t) override { return -1; } Alloc_return alloc_aligned(size_t, void **, int, addr_t from = 0, addr_t to = ~0UL) override; Alloc_return alloc_addr(size_t, addr_t) override { return Alloc_return::RANGE_CONFLICT; } void free(void *) override; size_t avail() const override { return _phys_alloc->avail(); } bool valid_addr(addr_t addr) const override { return _virt_alloc->valid_addr(addr); } /************************* ** Allocator interface ** *************************/ bool alloc(size_t size, void **out_addr) override { return alloc_aligned(size, out_addr, log2(sizeof(addr_t))).ok(); } void free(void *addr, size_t) override; size_t consumed() const override { return _phys_alloc->consumed(); } size_t overhead(size_t size) const override { return _phys_alloc->overhead(size); } bool need_size_for_free() const override { return _phys_alloc->need_size_for_free(); } }; /** * 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::Core_mem_translator { protected: /** * Lock used for synchronization of all operations on the * embedded allocators. */ Lock _lock { }; /** * Synchronized allocator of physical memory ranges * * This allocator must only be used to allocate memory * ranges at page granularity. */ Synced_mapped_allocator _phys_alloc; /** * Synchronized allocator of core's virtual memory ranges * * This allocator must only be used to allocate memory * ranges at page granularity. */ Synced_mapped_allocator _virt_alloc; /** * 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: /** * Constructor */ Core_mem_allocator() : _phys_alloc(_lock, &_mem_alloc), _virt_alloc(_lock, &_mem_alloc), _mem_alloc(_phys_alloc, _virt_alloc) { } /** * Access physical-memory allocator */ Synced_mapped_allocator &phys_alloc() { return _phys_alloc; } /** * Access core's virtual-memory allocator */ Synced_mapped_allocator &virt_alloc() { return _virt_alloc; } /*********************************** ** Core_mem_translator interface ** ***********************************/ void * phys_addr(void * addr) override { return _virt_alloc()->map_addr(addr); } void * virt_addr(void * addr) override { return _phys_alloc()->map_addr(addr); } /******************************* ** Range allocator interface ** *******************************/ int add_range(addr_t, size_t) override { return -1; } int remove_range(addr_t, size_t) override { return -1; } Alloc_return alloc_addr(size_t, addr_t) override { return Alloc_return::RANGE_CONFLICT; } Alloc_return alloc_aligned(size_t size, void **out_addr, int align, addr_t from = 0, addr_t to = ~0UL) override { Lock::Guard lock_guard(_lock); return _mem_alloc.alloc_aligned(size, out_addr, align, from, to); } void free(void *addr) override { Lock::Guard lock_guard(_lock); return _mem_alloc.free(addr); } size_t avail() const override { return _phys_alloc.avail(); } bool valid_addr(addr_t addr) const override { return _virt_alloc.valid_addr(addr); } /************************* ** Allocator interface ** *************************/ bool alloc(size_t size, void **out_addr) override { return alloc_aligned(size, out_addr, log2(sizeof(addr_t))).ok(); } void free(void *addr, size_t size) override { Lock::Guard lock_guard(_lock); return _mem_alloc.free(addr, size); } size_t consumed() const override { return _phys_alloc.consumed(); } size_t overhead(size_t size) const override { return _phys_alloc.overhead(size); } bool need_size_for_free() const override { return _phys_alloc.need_size_for_free(); } }; #endif /* _CORE__INCLUDE__CORE_MEM_ALLOC_H_ */