mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-23 15:32:25 +00:00
361557e1f0
Issue #5227
156 lines
3.9 KiB
C++
156 lines
3.9 KiB
C++
/*
|
|
* \brief Page table allocator
|
|
* \author Stefan Kalkowski
|
|
* \author Johannes Schlatow
|
|
* \date 2015-06-10
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2015-2023 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 _INCLUDE__CPU__PAGE_TABLE_ALLOCATOR_H_
|
|
#define _INCLUDE__CPU__PAGE_TABLE_ALLOCATOR_H_
|
|
|
|
#include <util/bit_allocator.h>
|
|
#include <util/construct_at.h>
|
|
|
|
namespace Genode {
|
|
template <Genode::size_t TABLE_SIZE> class Page_table_allocator;
|
|
struct Out_of_tables {};
|
|
}
|
|
|
|
template <Genode::size_t TABLE_SIZE>
|
|
class Genode::Page_table_allocator
|
|
{
|
|
protected:
|
|
|
|
using addr_t = Genode::addr_t;
|
|
using size_t = Genode::size_t;
|
|
|
|
addr_t const _virt_addr;
|
|
addr_t const _phys_addr;
|
|
size_t const _size;
|
|
|
|
template <typename TABLE> addr_t _offset(TABLE & table) {
|
|
return (addr_t)&table - _virt_addr; }
|
|
|
|
void * _index(unsigned idx) {
|
|
return (void*)(_virt_addr + TABLE_SIZE*idx); }
|
|
|
|
virtual unsigned _alloc() = 0;
|
|
virtual void _free(unsigned idx) = 0;
|
|
|
|
public:
|
|
|
|
template <unsigned COUNT> class Array;
|
|
|
|
Page_table_allocator(addr_t virt_addr, addr_t phys_addr, size_t size)
|
|
: _virt_addr(virt_addr), _phys_addr(phys_addr), _size(size) { }
|
|
|
|
virtual ~Page_table_allocator() { }
|
|
|
|
template <typename TABLE>
|
|
void with_table(addr_t phys_addr, auto const &match_fn, auto const &no_match_fn)
|
|
{
|
|
static_assert((sizeof(TABLE) == TABLE_SIZE), "unexpected size");
|
|
|
|
if (phys_addr >= _phys_addr && phys_addr < _phys_addr + _size)
|
|
match_fn(*(TABLE*)(_virt_addr + (phys_addr - _phys_addr)));
|
|
else
|
|
no_match_fn();
|
|
}
|
|
|
|
template <typename TABLE> addr_t construct()
|
|
{
|
|
static_assert((sizeof(TABLE) == TABLE_SIZE), "unexpected size");
|
|
TABLE & table = *Genode::construct_at<TABLE>(_index(_alloc()));
|
|
return _offset(table) + _phys_addr;
|
|
}
|
|
|
|
template <typename TABLE> void destruct(addr_t phys_addr)
|
|
{
|
|
static_assert((sizeof(TABLE) == TABLE_SIZE), "unexpected size");
|
|
|
|
with_table<TABLE>(phys_addr,
|
|
[&] (TABLE & table) {
|
|
table.~TABLE();
|
|
_free((unsigned)(_offset(table) / sizeof(TABLE)));
|
|
},
|
|
[&] {
|
|
Genode::error("Trying to destruct foreign table at ", Genode::Hex(phys_addr));
|
|
});
|
|
}
|
|
|
|
size_t size() const { return _size; }
|
|
};
|
|
|
|
|
|
template <Genode::size_t TABLE_SIZE>
|
|
template <unsigned COUNT>
|
|
class Genode::Page_table_allocator<TABLE_SIZE>::Array
|
|
{
|
|
public:
|
|
|
|
class Allocator;
|
|
|
|
private:
|
|
|
|
struct Table { Genode::uint8_t data[TABLE_SIZE]; };
|
|
|
|
Table _tables[COUNT];
|
|
Allocator _alloc;
|
|
|
|
public:
|
|
|
|
Array() : _alloc((Table*)&_tables, (addr_t)&_tables, COUNT * TABLE_SIZE) {}
|
|
|
|
explicit Array(auto phys_addr)
|
|
: _alloc(_tables, phys_addr((void*)_tables), COUNT * TABLE_SIZE) { }
|
|
|
|
Page_table_allocator<TABLE_SIZE> & alloc() { return _alloc; }
|
|
};
|
|
|
|
|
|
template <Genode::size_t TABLE_SIZE>
|
|
template <unsigned COUNT>
|
|
class Genode::Page_table_allocator<TABLE_SIZE>::Array<COUNT>::Allocator
|
|
:
|
|
public Genode::Page_table_allocator<TABLE_SIZE>
|
|
{
|
|
private:
|
|
|
|
using Bit_allocator = Genode::Bit_allocator<COUNT>;
|
|
using Array = Page_table_allocator<TABLE_SIZE>::Array<COUNT>;
|
|
|
|
Bit_allocator _free_tables { };
|
|
|
|
unsigned _alloc() override
|
|
{
|
|
try {
|
|
return (unsigned)_free_tables.alloc();
|
|
} catch (typename Bit_allocator::Out_of_indices&) {}
|
|
throw Out_of_tables();
|
|
}
|
|
|
|
void _free(unsigned idx) override { _free_tables.free(idx); }
|
|
|
|
public:
|
|
|
|
Allocator(Table * tables, addr_t phys_addr, size_t size)
|
|
: Page_table_allocator((addr_t)tables, phys_addr, size) {}
|
|
|
|
Allocator(addr_t phys_addr, addr_t virt_addr, size_t size)
|
|
: Page_table_allocator(virt_addr, phys_addr, size),
|
|
_free_tables(static_cast<Allocator*>(&reinterpret_cast<Array*>(virt_addr)->alloc())->_free_tables)
|
|
{
|
|
static_assert(!__is_polymorphic(Bit_allocator),
|
|
"base class needs to be non-virtual");
|
|
}
|
|
};
|
|
|
|
#endif /* _INCLUDE__CPU__PAGE_TABLE_ALLOCATOR_H_ */
|