mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-22 20:38:09 +00:00
205 lines
4.4 KiB
C++
205 lines
4.4 KiB
C++
/*
|
|
* \brief Suplib GMM implementation
|
|
* \author Norman Feske
|
|
* \author Christian Helmuth
|
|
* \date 2020-11-09
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2020-2021 Genode Labs GmbH
|
|
*
|
|
* This file is distributed under the terms of the GNU General Public License
|
|
* version 2.
|
|
*/
|
|
|
|
#ifndef _SUP_GMM_H_
|
|
#define _SUP_GMM_H_
|
|
|
|
/* Genode includes */
|
|
#include <base/allocator_avl.h>
|
|
#include <base/attached_dataspace.h>
|
|
#include <base/mutex.h>
|
|
#include <rm_session/connection.h>
|
|
#include <vm_session/connection.h>
|
|
#include <region_map/client.h>
|
|
#include <libc/allocator.h>
|
|
|
|
/* local includes */
|
|
#include <sup.h>
|
|
|
|
|
|
namespace Sup { struct Gmm; }
|
|
|
|
/**
|
|
* Global (guest-memory) manager.(GMM)
|
|
*
|
|
* Layers in this pool are (top-down)
|
|
*
|
|
* - Page-sized allocation from Allocator_avl
|
|
* - Linear map of 32 GiB in VMM address space (Vmm_addr)
|
|
* - VirtualBox GMM chunks of GMM_CHUNK_SIZE (2 MiB) filled with pages and
|
|
* referenced with PAGEIDs (offset in linear area)
|
|
* - Slices of 128 MiB RAM dataspaces as backing store
|
|
*
|
|
* Notes
|
|
*
|
|
* - expect that guest-physical address not required here
|
|
* - NIL_GMM_CHUNKID kept unused - so offset 0 is chunk ID 1
|
|
* - we have to allocate from pool - so we need an allocator
|
|
*/
|
|
class Sup::Gmm
|
|
{
|
|
public:
|
|
|
|
struct Vmm_addr { addr_t value; };
|
|
struct Guest_addr { addr_t value; };
|
|
struct Offset { addr_t value; };
|
|
struct Bytes { size_t value; };
|
|
struct Pages { size_t value; };
|
|
struct Page_id { addr_t value; }; /* CHUNKID | PAGEIDX */
|
|
|
|
struct Protection
|
|
{
|
|
bool readable;
|
|
bool writeable;
|
|
bool executable;
|
|
|
|
bool none() const
|
|
{
|
|
return !readable && ! writeable && !executable;
|
|
}
|
|
|
|
bool operator == (Protection const &other) const
|
|
{
|
|
return readable == other.readable
|
|
&& writeable == other.writeable
|
|
&& executable == other.executable;
|
|
}
|
|
|
|
void print(Output &o) const
|
|
{
|
|
Genode::print(o, readable ? "r" : "-",
|
|
writeable ? "w" : "-",
|
|
executable ? "x" : "-");
|
|
}
|
|
};
|
|
|
|
private:
|
|
|
|
Env &_env;
|
|
|
|
Vm_connection &_vm_connection;
|
|
|
|
static constexpr Bytes _slice_size { 128*1024*1024ul };
|
|
static constexpr Bytes _map_size { 32*1024*1024*1024ul };
|
|
static constexpr auto _num_slices { _map_size.value / _slice_size.value };
|
|
|
|
Mutex _mutex { };
|
|
|
|
Dataspace_capability _slices[_num_slices];
|
|
|
|
Pages _size_pages { 0 }; /* current backing-store allocations */
|
|
Pages _reservation_pages { 0 }; /* current VMMR0_DO_GMM_UPDATE_RESERVATION pages */
|
|
Pages _alloc_ex_pages { 0 }; /* current SUPPAGEALLOCEX pages */
|
|
|
|
struct Map
|
|
{
|
|
Env &env;
|
|
|
|
Bytes const size;
|
|
|
|
Rm_connection connection { env };
|
|
|
|
Region_map_client rm { connection.create(size.value) };
|
|
|
|
Vmm_addr const base { (addr_t)env.rm().attach(rm.dataspace()) };
|
|
Vmm_addr const end { base.value + size.value - 1 };
|
|
|
|
Map(Env &env, Bytes size) : env(env), size(size) { }
|
|
|
|
} _map { _env, _map_size };
|
|
|
|
void _add_one_slice();
|
|
|
|
void _update_pool_size();
|
|
|
|
Vmm_addr _alloc_pages(Pages);
|
|
|
|
Offset _offset(Vmm_addr addr) const
|
|
{
|
|
if (addr.value < _map.base.value || addr.value > _map.end.value)
|
|
throw Out_of_range();
|
|
|
|
return Offset { addr.value - _map.base.value };
|
|
}
|
|
|
|
unsigned _slice_index(Offset offset) const
|
|
{
|
|
unsigned const index = offset.value / _slice_size.value;
|
|
|
|
if (index > _num_slices)
|
|
throw Out_of_range();
|
|
|
|
return index;
|
|
}
|
|
|
|
unsigned _slice_index(Vmm_addr addr) const
|
|
{
|
|
return _slice_index(_offset(addr));
|
|
}
|
|
|
|
Libc::Allocator _md_alloc;
|
|
Allocator_avl _alloc { &_md_alloc };
|
|
|
|
public:
|
|
|
|
struct Out_of_range : Exception { };
|
|
struct Allocation_failed : Exception { };
|
|
|
|
Gmm(Env &env, Vm_connection &);
|
|
|
|
/**
|
|
* Extend pool according to VMMR0_DO_GMM_UPDATE_RESERVATION
|
|
*/
|
|
void reservation_pages(Pages);
|
|
|
|
/**
|
|
* Allocate pages from reservation pool
|
|
*/
|
|
Vmm_addr alloc_from_reservation(Pages);
|
|
|
|
/**
|
|
* Extend pool and allocate pages
|
|
*/
|
|
Vmm_addr alloc_ex(Pages);
|
|
|
|
/**
|
|
* Free pages in pool
|
|
*/
|
|
void free(Vmm_addr, Pages);
|
|
|
|
/**
|
|
* Get page ID for VMM address inside linear area
|
|
*/
|
|
Page_id page_id(Vmm_addr);
|
|
|
|
/**
|
|
* Get 32-bit PAGEID from page ID
|
|
*/
|
|
static uint32_t page_id_as_uint32(Page_id);
|
|
|
|
/**
|
|
* Get VMM address inside linear area for page ID
|
|
*/
|
|
Vmm_addr vmm_addr(Page_id);
|
|
|
|
/**
|
|
* Make VMM memory available to the guest-physical address space
|
|
*
|
|
* \throw Out_of_range
|
|
*/
|
|
void map_to_guest(Vmm_addr, Guest_addr, Pages, Protection);
|
|
};
|
|
|
|
#endif /* _SUP_GMM_H_ */
|