core: split RAM dataspace factory from RAM service

By separating the session-interface concerns from the mechanics of the
dataspace creation, the code becomes simpler to follow, and the RAM
session can be more easily merged with the PD session in a subsequent
step.

Issue #2407
This commit is contained in:
Norman Feske 2017-05-11 15:03:03 +02:00 committed by Christian Helmuth
parent 65225a94b1
commit 4773707495
24 changed files with 384 additions and 289 deletions

View File

@ -23,6 +23,7 @@ SRC_CC += stack_area.cc \
pager_object.cc \
pd_session_component.cc \
rpc_cap_factory_l4.cc \
ram_dataspace_factory.cc \
pd_assign_pci.cc \
pd_upgrade_ram_quota.cc \
platform.cc \
@ -30,7 +31,7 @@ SRC_CC += stack_area.cc \
platform_services.cc \
platform_thread.cc \
ram_session_component.cc \
ram_session_support.cc \
ram_dataspace_support.cc \
region_map_component.cc \
region_map_support.cc \
rom_session_component.cc \
@ -59,6 +60,7 @@ vpath cpu_thread_component.cc $(GEN_CORE_DIR)
vpath pd_session_component.cc $(GEN_CORE_DIR)
vpath capability_space.cc $(GEN_CORE_DIR)
vpath rpc_cap_factory_l4.cc $(GEN_CORE_DIR)
vpath ram_dataspace_factory.cc $(GEN_CORE_DIR)
vpath core_rpc_cap_alloc.cc $(GEN_CORE_DIR)
vpath core_region_map.cc $(GEN_CORE_DIR)
vpath pd_assign_pci.cc $(GEN_CORE_DIR)

View File

@ -14,14 +14,14 @@
* under the terms of the GNU Affero General Public License version 3.
*/
#include "ram_session_component.h"
#include <ram_dataspace_factory.h>
using namespace Genode;
void Ram_session_component::_export_ram_ds(Dataspace_component *ds) { }
void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds) { }
void Ram_dataspace_factory::_export_ram_ds(Dataspace_component *ds) { }
void Ram_dataspace_factory::_revoke_ram_ds(Dataspace_component *ds) { }
void Ram_session_component::_clear_ds(Dataspace_component *ds)
void Ram_dataspace_factory::_clear_ds(Dataspace_component *ds)
{
memset((void *)ds->phys_addr(), 0, ds->size());
}

View File

@ -29,7 +29,8 @@ SRC_CC += stack_area.cc \
platform_services.cc \
platform_thread.cc \
ram_session_component.cc \
ram_session_support.cc \
ram_dataspace_support.cc \
ram_dataspace_factory.cc \
region_map_component.cc \
region_map_support.cc \
rom_session_component.cc \
@ -63,6 +64,7 @@ vpath ram_session_component.cc $(GEN_CORE_DIR)
vpath region_map_component.cc $(GEN_CORE_DIR)
vpath rom_session_component.cc $(GEN_CORE_DIR)
vpath trace_session_component.cc $(GEN_CORE_DIR)
vpath ram_dataspace_factory.cc $(GEN_CORE_DIR)
vpath signal_transmitter_proxy.cc $(GEN_CORE_DIR)
vpath signal_receiver.cc $(GEN_CORE_DIR)
vpath core_rpc_cap_alloc.cc $(GEN_CORE_DIR)

View File

@ -25,7 +25,6 @@
/* core includes */
#include <boot_modules.h>
#include <core_parent.h>
#include <platform.h>
#include <platform_thread.h>
#include <platform_pd.h>

View File

@ -12,7 +12,7 @@
*/
/* core-local includes */
#include <ram_session_component.h>
#include <ram_dataspace_factory.h>
#include <map_local.h>
namespace Fiasco {
@ -21,11 +21,11 @@ namespace Fiasco {
using namespace Genode;
void Ram_session_component::_export_ram_ds(Dataspace_component *ds) { }
void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds) { }
void Ram_dataspace_factory::_export_ram_ds(Dataspace_component *ds) { }
void Ram_dataspace_factory::_revoke_ram_ds(Dataspace_component *ds) { }
void Ram_session_component::_clear_ds(Dataspace_component *ds)
void Ram_dataspace_factory::_clear_ds(Dataspace_component *ds)
{
memset((void *)ds->phys_addr(), 0, ds->size());

View File

@ -37,11 +37,12 @@ SRC_CC += platform_pd.cc
SRC_CC += platform_thread.cc
SRC_CC += stack_area.cc
SRC_CC += ram_session_component.cc
SRC_CC += ram_session_support.cc
SRC_CC += ram_dataspace_support.cc
SRC_CC += region_map_component.cc
SRC_CC += rom_session_component.cc
SRC_CC += trace_session_component.cc
SRC_CC += signal_receiver.cc
SRC_CC += ram_dataspace_factory.cc
SRC_CC += signal_transmitter_noinit.cc
SRC_CC += thread_start.cc
SRC_CC += env.cc

View File

@ -18,7 +18,6 @@
/* core includes */
#include <boot_modules.h>
#include <hw/memory_region.h>
#include <core_parent.h>
#include <map_local.h>
#include <platform.h>
#include <platform_pd.h>

View File

@ -5,7 +5,7 @@
* \date 2012-02-12
*
* TODO: this file is almost identical to
* base-okl4/src/core/ram_session_support.cc, we should merge them
* base-okl4/src/core/ram_dataspace_support.cc, we should merge them
*/
/*
@ -19,16 +19,16 @@
#include <base/log.h>
/* core includes */
#include <ram_session_component.h>
#include <ram_dataspace_factory.h>
#include <platform.h>
#include <map_local.h>
using namespace Genode;
void Ram_session_component::_export_ram_ds(Dataspace_component *ds) { }
void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds) { }
void Ram_dataspace_factory::_export_ram_ds(Dataspace_component *ds) { }
void Ram_dataspace_factory::_revoke_ram_ds(Dataspace_component *ds) { }
void Ram_session_component::_clear_ds (Dataspace_component * ds)
void Ram_dataspace_factory::_clear_ds (Dataspace_component * ds)
{
size_t page_rounded_size = (ds->size() + get_page_size() - 1) & get_page_mask();

View File

@ -9,7 +9,7 @@ SRC_CC = main.cc \
platform_thread.cc \
platform_services.cc \
ram_session_component.cc \
ram_session_support.cc \
ram_dataspace_support.cc \
rom_session_component.cc \
cpu_session_component.cc \
cpu_session_support.cc \
@ -21,6 +21,7 @@ SRC_CC = main.cc \
native_cpu_component.cc \
capability_space.cc \
rpc_cap_factory_l4.cc \
ram_dataspace_factory.cc \
core_rpc_cap_alloc.cc \
io_mem_session_component.cc \
signal_source_component.cc \
@ -54,6 +55,7 @@ vpath cpu_thread_component.cc $(GEN_CORE_DIR)
vpath pd_upgrade_ram_quota.cc $(GEN_CORE_DIR)
vpath capability_space.cc $(GEN_CORE_DIR)
vpath rpc_cap_factory_l4.cc $(GEN_CORE_DIR)
vpath ram_dataspace_factory.cc $(GEN_CORE_DIR)
vpath platform_services.cc $(GEN_CORE_DIR)
vpath signal_source_component.cc $(GEN_CORE_DIR)
vpath signal_transmitter_proxy.cc $(GEN_CORE_DIR)

View File

@ -18,7 +18,7 @@
#include <base/snprintf.h>
/* local includes */
#include <ram_session_component.h>
#include <ram_dataspace_factory.h>
#include <resource_path.h>
/* base-internal includes */
@ -33,7 +33,7 @@ using namespace Genode;
static int ram_ds_cnt = 0; /* counter for creating unique dataspace IDs */
void Ram_session_component::_export_ram_ds(Dataspace_component *ds)
void Ram_dataspace_factory::_export_ram_ds(Dataspace_component *ds)
{
char fname[Linux_dataspace::FNAME_LEN];
@ -56,7 +56,7 @@ void Ram_session_component::_export_ram_ds(Dataspace_component *ds)
}
void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds)
void Ram_dataspace_factory::_revoke_ram_ds(Dataspace_component *ds)
{
int const fd = Capability_space::ipc_cap_data(ds->fd()).dst.socket;
if (fd != -1)
@ -64,4 +64,4 @@ void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds)
}
void Ram_session_component::_clear_ds(Dataspace_component *ds) { }
void Ram_dataspace_factory::_clear_ds(Dataspace_component *ds) { }

View File

@ -28,12 +28,13 @@ SRC_CC += stack_area.cc \
pd_upgrade_ram_quota.cc \
pd_assign_pci.cc \
rpc_cap_factory.cc \
ram_dataspace_factory.cc \
platform.cc \
platform_pd.cc \
platform_services.cc \
platform_thread.cc \
ram_session_component.cc \
ram_session_support.cc \
ram_dataspace_support.cc \
region_map_component.cc \
region_map_support.cc \
rom_session_component.cc \
@ -66,6 +67,7 @@ vpath io_port_session_component.cc $(GEN_CORE_DIR)/spec/x86
vpath io_port_session_support.cc $(GEN_CORE_DIR)/spec/x86
vpath io_mem_session_component.cc $(GEN_CORE_DIR)
vpath io_mem_session_support.cc $(GEN_CORE_DIR)
vpath ram_dataspace_factory.cc $(GEN_CORE_DIR)
vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath core_mem_alloc.cc $(GEN_CORE_DIR)
vpath default_log.cc $(GEN_CORE_DIR)

View File

@ -15,7 +15,7 @@
#include <base/thread.h>
/* core includes */
#include <ram_session_component.h>
#include <ram_dataspace_factory.h>
#include <platform.h>
#include <util.h>
#include <nova_util.h>
@ -26,7 +26,7 @@
using namespace Genode;
void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds) { }
void Ram_dataspace_factory::_revoke_ram_ds(Dataspace_component *ds) { }
static inline void * alloc_region(Dataspace_component *ds, const size_t size)
@ -49,7 +49,7 @@ static inline void * alloc_region(Dataspace_component *ds, const size_t size)
}
void Ram_session_component::_clear_ds(Dataspace_component *ds)
void Ram_dataspace_factory::_clear_ds(Dataspace_component *ds)
{
size_t page_rounded_size = align_addr(ds->size(), get_page_size_log2());
@ -74,7 +74,7 @@ void Ram_session_component::_clear_ds(Dataspace_component *ds)
}
void Ram_session_component::_export_ram_ds(Dataspace_component *ds) {
void Ram_dataspace_factory::_export_ram_ds(Dataspace_component *ds) {
size_t page_rounded_size = align_addr(ds->size(), get_page_size_log2());

View File

@ -28,12 +28,13 @@ SRC_CC += stack_area.cc \
pd_upgrade_ram_quota.cc \
pd_assign_pci.cc \
rpc_cap_factory_l4.cc \
ram_dataspace_factory.cc \
platform.cc \
platform_pd.cc \
platform_services.cc \
platform_thread.cc \
ram_session_component.cc \
ram_session_support.cc \
ram_dataspace_support.cc \
region_map_component.cc \
region_map_support.cc \
rom_session_component.cc \
@ -56,6 +57,7 @@ vpath cpu_session_support.cc $(GEN_CORE_DIR)
vpath cpu_thread_component.cc $(GEN_CORE_DIR)
vpath capability_space.cc $(GEN_CORE_DIR)
vpath rpc_cap_factory_l4.cc $(GEN_CORE_DIR)
vpath ram_dataspace_factory.cc $(GEN_CORE_DIR)
vpath pd_session_component.cc $(GEN_CORE_DIR)
vpath pd_upgrade_ram_quota.cc $(GEN_CORE_DIR)
vpath pd_assign_pci.cc $(GEN_CORE_DIR)

View File

@ -20,7 +20,7 @@
/* core includes */
#include <platform.h>
#include <map_local.h>
#include <ram_session_component.h>
#include <ram_dataspace_factory.h>
/* OKL4 includes */
namespace Okl4 { extern "C" {
@ -29,10 +29,10 @@ namespace Okl4 { extern "C" {
using namespace Genode;
void Ram_session_component::_export_ram_ds(Dataspace_component *ds) { }
void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds) { }
void Ram_dataspace_factory::_export_ram_ds(Dataspace_component *ds) { }
void Ram_dataspace_factory::_revoke_ram_ds(Dataspace_component *ds) { }
void Ram_session_component::_clear_ds (Dataspace_component *ds)
void Ram_dataspace_factory::_clear_ds (Dataspace_component *ds)
{
size_t page_rounded_size = (ds->size() + get_page_size() - 1) & get_page_mask();

View File

@ -21,6 +21,7 @@ SRC_CC = stack_area.cc \
main.cc \
pd_session_component.cc \
rpc_cap_factory_l4.cc \
ram_dataspace_factory.cc \
pd_assign_pci.cc \
pd_upgrade_ram_quota.cc \
pager.cc \
@ -31,7 +32,7 @@ SRC_CC = stack_area.cc \
platform_services.cc \
platform_thread.cc \
ram_session_component.cc \
ram_session_support.cc \
ram_dataspace_support.cc \
region_map_component.cc \
region_map_support.cc \
rom_session_component.cc \
@ -57,6 +58,7 @@ vpath pd_assign_pci.cc $(GEN_CORE_DIR)
vpath pd_upgrade_ram_quota.cc $(GEN_CORE_DIR)
vpath region_map_component.cc $(GEN_CORE_DIR)
vpath rpc_cap_factory_l4.cc $(GEN_CORE_DIR)
vpath ram_dataspace_factory.cc $(GEN_CORE_DIR)
vpath capability_space.cc $(GEN_CORE_DIR)
vpath io_mem_session_component.cc $(GEN_CORE_DIR)
vpath io_mem_session_support.cc $(GEN_CORE_DIR)

View File

@ -14,14 +14,14 @@
* under the terms of the GNU Affero General Public License version 3.
*/
#include "ram_session_component.h"
#include <ram_dataspace_factory.h>
using namespace Genode;
void Ram_session_component::_export_ram_ds(Dataspace_component *ds) { }
void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds) { }
void Ram_dataspace_factory::_export_ram_ds(Dataspace_component *) { }
void Ram_dataspace_factory::_revoke_ram_ds(Dataspace_component *) { }
void Ram_session_component::_clear_ds(Dataspace_component *ds)
void Ram_dataspace_factory::_clear_ds(Dataspace_component *ds)
{
memset((void *)ds->phys_addr(), 0, ds->size());
}

View File

@ -3,13 +3,14 @@ GEN_CORE_DIR = $(BASE_DIR)/src/core
SRC_CC += \
main.cc \
ram_session_component.cc \
ram_session_support.cc \
ram_dataspace_support.cc \
rom_session_component.cc \
cpu_session_component.cc \
cpu_session_support.cc \
cpu_thread_component.cc \
pd_session_component.cc \
rpc_cap_factory.cc \
ram_dataspace_factory.cc \
pd_assign_pci.cc \
pd_upgrade_ram_quota.cc \
io_mem_session_component.cc \
@ -62,6 +63,7 @@ vpath platform_services.cc $(GEN_CORE_DIR)/spec/x86
vpath trace_session_component.cc $(GEN_CORE_DIR)
vpath signal_transmitter_proxy.cc $(GEN_CORE_DIR)
vpath signal_receiver.cc $(GEN_CORE_DIR)
vpath ram_dataspace_factory.cc $(GEN_CORE_DIR)
vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath core_mem_alloc.cc $(GEN_CORE_DIR)
vpath core_rpc_cap_alloc.cc $(GEN_CORE_DIR)

View File

@ -12,7 +12,7 @@
*/
/* core includes */
#include <ram_session_component.h>
#include <ram_dataspace_factory.h>
#include <platform.h>
#include <map_local.h>
#include <untyped_memory.h>
@ -20,7 +20,7 @@
using namespace Genode;
void Ram_session_component::_export_ram_ds(Dataspace_component *ds)
void Ram_dataspace_factory::_export_ram_ds(Dataspace_component *ds)
{
size_t const page_rounded_size = (ds->size() + get_page_size() - 1) & get_page_mask();
size_t const num_pages = page_rounded_size >> get_page_size_log2();
@ -29,7 +29,7 @@ void Ram_session_component::_export_ram_ds(Dataspace_component *ds)
}
void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds)
void Ram_dataspace_factory::_revoke_ram_ds(Dataspace_component *ds)
{
size_t const page_rounded_size = (ds->size() + get_page_size() - 1) & get_page_mask();
@ -37,7 +37,7 @@ void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds)
}
void Ram_session_component::_clear_ds (Dataspace_component *ds)
void Ram_dataspace_factory::_clear_ds (Dataspace_component *ds)
{
size_t const page_rounded_size = (ds->size() + get_page_size() - 1) & get_page_mask();

View File

@ -66,7 +66,7 @@ class Genode::Core_env : public Env_deprecated
Session::Diag{false},
*platform()->ram_alloc(),
_region_map,
Ram_session_component::any_phys_range())
Ram_dataspace_factory::any_phys_range())
{
_ram_session.init_ram_account();
}

View File

@ -0,0 +1,117 @@
/*
* \brief RAM dataspace factory
* \author Norman Feske
* \date 2017-05-11
*/
/*
* Copyright (C) 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__RAM_DATASPACE_FACTORY_H_
#define _CORE__INCLUDE__RAM_DATASPACE_FACTORY_H_
/* Genode includes */
#include <base/heap.h>
#include <base/tslab.h>
/* base-internal includes */
#include <base/internal/page_size.h>
/* core includes */
#include <dataspace_component.h>
namespace Genode { class Ram_dataspace_factory; }
class Genode::Ram_dataspace_factory : public Ram_allocator,
public Dataspace_owner
{
public:
struct Phys_range { addr_t start, end; };
static Phys_range any_phys_range() { return { 0UL, ~0UL }; }
/*
* Dimension '_ds_slab' such that slab blocks (including the
* meta-data overhead of the sliced-heap blocks) are page sized.
*/
static constexpr size_t SLAB_BLOCK_SIZE =
get_page_size() - Sliced_heap::meta_data_size();
private:
Rpc_entrypoint &_ep;
Range_allocator &_phys_alloc;
Phys_range const _phys_range;
/*
* Statically allocated initial slab block for '_ds_slab', needed to
* untangle the hen-and-egg problem of allocating the meta data for
* core's RAM allocator from itself. I also saves the allocation
* of one dataspace (along with a dataspace capability) per session.
*/
uint8_t _initial_sb[SLAB_BLOCK_SIZE];
Tslab<Dataspace_component, SLAB_BLOCK_SIZE> _ds_slab;
/********************************************
** Platform-implemented support functions **
********************************************/
struct Core_virtual_memory_exhausted : Exception { };
/**
* Export RAM dataspace as shared memory block
*
* \throw Core_virtual_memory_exhausted
*/
void _export_ram_ds(Dataspace_component *ds);
/**
* Revert export of RAM dataspace
*/
void _revoke_ram_ds(Dataspace_component *ds);
/**
* Zero-out content of dataspace
*/
void _clear_ds(Dataspace_component *ds);
public:
Ram_dataspace_factory(Rpc_entrypoint &ep,
Range_allocator &phys_alloc,
Phys_range phys_range,
Region_map &local_rm,
Sliced_heap &sliced_heap)
:
_ep(ep), _phys_alloc(phys_alloc), _phys_range(phys_range),
_ds_slab(sliced_heap, _initial_sb)
{ }
~Ram_dataspace_factory()
{
while (Dataspace_component *ds = _ds_slab.first_object())
free(static_cap_cast<Ram_dataspace>(
static_cap_cast<Dataspace>(ds->cap())));
}
/*****************************
** Ram_allocator interface **
*****************************/
Ram_dataspace_capability alloc(size_t, Cache_attribute) override;
void free(Ram_dataspace_capability) override;
size_t dataspace_size(Ram_dataspace_capability ds) const override;
};
#endif /* _CORE__INCLUDE__RAM_DATASPACE_FACTORY_H_ */

View File

@ -34,8 +34,8 @@ namespace Genode {
addr_t const size = Arg_string::find_arg(args, "phys_size").ulong_value(0);
addr_t const end = start + size - 1;
return (start <= end) ? Ram_session_component::Phys_range { start, end }
: Ram_session_component::any_phys_range();
return (start <= end) ? Ram_dataspace_factory::Phys_range { start, end }
: Ram_dataspace_factory::any_phys_range();
}
protected:

View File

@ -15,96 +15,34 @@
#define _CORE__INCLUDE__RAM_SESSION_COMPONENT_H_
/* Genode includes */
#include <util/list.h>
#include <base/heap.h>
#include <base/tslab.h>
#include <base/session_object.h>
#include <base/allocator_guard.h>
#include <base/synced_allocator.h>
#include <base/session_label.h>
/* core includes */
#include <dataspace_component.h>
#include <util.h>
#include <ram_dataspace_factory.h>
#include <account.h>
namespace Genode { class Ram_session_component; }
class Genode::Ram_session_component : public Session_object<Ram_session>,
public Dataspace_owner
class Genode::Ram_session_component : public Session_object<Ram_session>
{
public:
struct Phys_range { addr_t start, end; };
static Phys_range any_phys_range() { return { 0UL, ~0UL }; }
private:
class Invalid_dataspace : public Exception { };
/*
* Dimension 'Ds_slab' such that slab blocks (including the
* meta-data overhead of the sliced-heap blocks) are page sized.
*/
static constexpr size_t SBS = get_page_size() - Sliced_heap::meta_data_size();
using Ds_slab = Tslab<Dataspace_component, SBS>;
Rpc_entrypoint &_ep;
Range_allocator &_phys_alloc;
Constrained_ram_allocator _constrained_md_ram_alloc;
Constructible<Sliced_heap> _sliced_heap;
/*
* Statically allocated initial slab block for '_ds_slab', needed to
* untangle the hen-and-egg problem of allocating the meta data for
* core's RAM allocator from itself. I also saves the allocation
* of one dataspace (along with a dataspace capability) per session.
*/
uint8_t _initial_sb[SBS];
Constructible<Ds_slab> _ds_slab;
Phys_range const _phys_range;
Sliced_heap _sliced_heap;
Constructible<Account<Ram_quota> > _ram_account;
/**
* Free dataspace
*/
void _free_ds(Dataspace_capability ds_cap);
/********************************************
** Platform-implemented support functions **
********************************************/
struct Core_virtual_memory_exhausted : Exception { };
/**
* Export RAM dataspace as shared memory block
*
* \throw Core_virtual_memory_exhausted
*/
void _export_ram_ds(Dataspace_component *ds);
/**
* Revert export of RAM dataspace
*/
void _revoke_ram_ds(Dataspace_component *ds);
/**
* Zero-out content of dataspace
*/
void _clear_ds(Dataspace_component *ds);
Ram_dataspace_factory _ram_ds_factory;
public:
typedef Ram_dataspace_factory::Phys_range Phys_range;
Ram_session_component(Rpc_entrypoint &ep,
Resources resources,
Session_label const &label,
@ -113,8 +51,6 @@ class Genode::Ram_session_component : public Session_object<Ram_session>,
Region_map &local_rm,
Phys_range phys_range);
~Ram_session_component();
/**
* Initialize RAM account without providing a reference account
*
@ -124,15 +60,6 @@ class Genode::Ram_session_component : public Session_object<Ram_session>,
*/
void init_ram_account() { _ram_account.construct(*this, _label); }
/**
* Get physical address of the RAM that backs a dataspace
*
* \param ds targeted dataspace
*
* \throw Invalid_dataspace
*/
addr_t phys_addr(Ram_dataspace_capability ds);
/*****************************
** Ram_allocator interface **
@ -142,7 +69,7 @@ class Genode::Ram_session_component : public Session_object<Ram_session>,
void free(Ram_dataspace_capability) override;
size_t dataspace_size(Ram_dataspace_capability ds) const override;
size_t dataspace_size(Ram_dataspace_capability) const override;
/***************************

View File

@ -0,0 +1,175 @@
/*
* \brief Core-internal RAM-dataspace factory
* \author Norman Feske
* \date 2006-05-19
*/
/*
* Copyright (C) 2006-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.
*/
/* Genode includes */
#include <base/log.h>
/* core includes */
#include <ram_dataspace_factory.h>
using namespace Genode;
Ram_dataspace_capability
Ram_dataspace_factory::alloc(size_t ds_size, Cache_attribute cached)
{
/* zero-sized dataspaces are not allowed */
if (!ds_size) return Ram_dataspace_capability();
/* dataspace allocation granularity is page size */
ds_size = align_addr(ds_size, 12);
/*
* Allocate physical backing store
*
* As an optimization for the use of large mapping sizes, we try to
* align the dataspace in physical memory naturally (size-aligned).
* If this does not work, we subsequently weaken the alignment constraint
* until the allocation succeeds.
*/
void *ds_addr = 0;
bool alloc_succeeded = false;
/*
* If no physical constraint exists, try to allocate physical memory at
* high locations (3G for 32-bit / 4G for 64-bit platforms) in order to
* preserve lower physical regions for device drivers, which may have DMA
* constraints.
*/
if (_phys_range.start == 0 && _phys_range.end == ~0UL) {
addr_t const high_start = (sizeof(void *) == 4 ? 3UL : 4UL) << 30;
for (size_t align_log2 = log2(ds_size); align_log2 >= 12; align_log2--) {
if (_phys_alloc.alloc_aligned(ds_size, &ds_addr, align_log2,
high_start, _phys_range.end).ok()) {
alloc_succeeded = true;
break;
}
}
}
/* apply constraints or re-try because higher memory allocation failed */
if (!alloc_succeeded) {
for (size_t align_log2 = log2(ds_size); align_log2 >= 12; align_log2--) {
if (_phys_alloc.alloc_aligned(ds_size, &ds_addr, align_log2,
_phys_range.start, _phys_range.end).ok()) {
alloc_succeeded = true;
break;
}
}
}
/*
* Helper to release the allocated physical memory whenever we leave the
* scope via an exception.
*/
struct Phys_alloc_guard
{
Range_allocator &phys_alloc;
void * const ds_addr;
bool ack = false;
Phys_alloc_guard(Range_allocator &phys_alloc, void *ds_addr)
: phys_alloc(phys_alloc), ds_addr(ds_addr) { }
~Phys_alloc_guard() { if (!ack) phys_alloc.free(ds_addr); }
} phys_alloc_guard(_phys_alloc, ds_addr);
/*
* Normally, init's quota equals the size of physical memory and this quota
* is distributed among the processes. As we check the quota before
* allocating, the allocation should always succeed in theory. However,
* fragmentation could cause a failing allocation.
*/
if (!alloc_succeeded) {
error("out of physical memory while allocating ", ds_size, " bytes ",
"in range [", Hex(_phys_range.start), "-", Hex(_phys_range.end), "]");
throw Out_of_ram();
}
/*
* For non-cached RAM dataspaces, we mark the dataspace as write
* combined and expect the pager to evaluate this dataspace property
* when resolving page faults.
*
* \throw Out_of_ram
* \throw Out_of_caps
*/
Dataspace_component * const ds = new (_ds_slab)
Dataspace_component(ds_size, (addr_t)ds_addr, cached, true, this);
/* create native shared memory representation of dataspace */
try { _export_ram_ds(ds); }
catch (Core_virtual_memory_exhausted) {
warning("could not export RAM dataspace of size ", ds->size());
/* cleanup unneeded resources */
destroy(_ds_slab, ds);
throw Out_of_ram();
}
/*
* Fill new dataspaces with zeros. For non-cached RAM dataspaces, this
* function must also make sure to flush all cache lines related to the
* address range used by the dataspace.
*/
_clear_ds(ds);
Dataspace_capability result = _ep.manage(ds);
phys_alloc_guard.ack = true;
return static_cap_cast<Ram_dataspace>(result);
}
void Ram_dataspace_factory::free(Ram_dataspace_capability ds_cap)
{
Dataspace_component *ds = nullptr;
_ep.apply(ds_cap, [&] (Dataspace_component *c)
{
if (!c) return;
if (!c->owner(this)) return;
ds = c;
size_t const ds_size = ds->size();
/* tell entry point to forget the dataspace */
_ep.dissolve(ds);
/* remove dataspace from all RM sessions */
ds->detach_from_rm_sessions();
/* destroy native shared memory representation */
_revoke_ram_ds(ds);
/* free physical memory that was backing the dataspace */
_phys_alloc.free((void *)ds->phys_addr(), ds_size);
});
/* call dataspace destructor and free memory */
if (ds)
destroy(_ds_slab, ds);
}
size_t Ram_dataspace_factory::dataspace_size(Ram_dataspace_capability ds_cap) const
{
size_t result = 0;
_ep.apply(ds_cap, [&] (Dataspace_component *c) {
if (c && c->owner(this))
result = c->size(); });
return result;
}

View File

@ -13,7 +13,6 @@
/* Genode includes */
#include <base/log.h>
#include <util/arg_string.h>
/* core includes */
#include <ram_session_component.h>
@ -21,53 +20,8 @@
using namespace Genode;
addr_t Ram_session_component::phys_addr(Ram_dataspace_capability ds)
{
auto lambda = [] (Dataspace_component *dsc) {
if (!dsc) throw Invalid_dataspace();
return dsc->phys_addr();
};
return _ep.apply(ds, lambda);
}
void Ram_session_component::_free_ds(Dataspace_capability ds_cap)
{
Dataspace_component *ds = nullptr;
_ep.apply(ds_cap, [&] (Dataspace_component *c)
{
if (!c) return;
if (!c->owner(this)) return;
ds = c;
size_t ds_size = ds->size();
/* tell entry point to forget the dataspace */
_ep.dissolve(ds);
/* remove dataspace from all RM sessions */
ds->detach_from_rm_sessions();
/* destroy native shared memory representation */
_revoke_ram_ds(ds);
/* free physical memory that was backing the dataspace */
_phys_alloc.free((void *)ds->phys_addr(), ds_size);
_ram_account->replenish(Ram_quota{ds_size});
});
/* call dataspace destructors and free memory */
if (ds) {
destroy(*_ds_slab, ds);
Cap_quota_guard::replenish(Cap_quota{1});
}
}
Ram_dataspace_capability Ram_session_component::alloc(size_t ds_size, Cache_attribute cached)
Ram_dataspace_capability
Ram_session_component::alloc(size_t ds_size, Cache_attribute cached)
{
/* zero-sized dataspaces are not allowed */
if (!ds_size) return Ram_dataspace_capability();
@ -91,7 +45,8 @@ Ram_dataspace_capability Ram_session_component::alloc(size_t ds_size, Cache_attr
* account does not have enough room for the meta data.
*/
{
Ram_quota_guard::Reservation sbs_ram_costs(*this, Ram_quota{SBS});
Ram_quota const overhead { Ram_dataspace_factory::SLAB_BLOCK_SIZE };
Ram_quota_guard::Reservation sbs_ram_costs(*this, overhead);
}
/*
@ -100,114 +55,39 @@ Ram_dataspace_capability Ram_session_component::alloc(size_t ds_size, Cache_attr
Cap_quota_guard::Reservation dataspace_cap_costs(*this, Cap_quota{1});
/*
* Allocate physical backing store
*
* As an optimization for the use of large mapping sizes, we try to
* align the dataspace in physical memory naturally (size-aligned).
* If this does not work, we subsequently weaken the alignment constraint
* until the allocation succeeds.
*/
void *ds_addr = 0;
bool alloc_succeeded = false;
/*
* If no physical constraint exists, try to allocate physical memory at
* high locations (3G for 32-bit / 4G for 64-bit platforms) in order to
* preserve lower physical regions for device drivers, which may have DMA
* constraints.
*/
if (_phys_range.start == 0 && _phys_range.end == ~0UL) {
addr_t const high_start = (sizeof(void *) == 4 ? 3UL : 4UL) << 30;
for (size_t align_log2 = log2(ds_size); align_log2 >= 12; align_log2--) {
if (_phys_alloc.alloc_aligned(ds_size, &ds_addr, align_log2,
high_start, _phys_range.end).ok()) {
alloc_succeeded = true;
break;
}
}
}
/* apply constraints or re-try because higher memory allocation failed */
if (!alloc_succeeded) {
for (size_t align_log2 = log2(ds_size); align_log2 >= 12; align_log2--) {
if (_phys_alloc.alloc_aligned(ds_size, &ds_addr, align_log2,
_phys_range.start, _phys_range.end).ok()) {
alloc_succeeded = true;
break;
}
}
}
/*
* Helper to release the allocated physical memory whenever we leave the
* scope via an exception.
*/
struct Phys_alloc_guard
{
Range_allocator &phys_alloc;
void * const ds_addr;
bool ack = false;
Phys_alloc_guard(Range_allocator &phys_alloc, void *ds_addr)
: phys_alloc(phys_alloc), ds_addr(ds_addr) { }
~Phys_alloc_guard() { if (!ack) phys_alloc.free(ds_addr); }
} phys_alloc_guard(_phys_alloc, ds_addr);
/*
* Normally, init's quota equals the size of physical memory and this quota
* is distributed among the processes. As we check the quota before
* allocating, the allocation should always succeed in theory. However,
* fragmentation could cause a failing allocation.
*/
if (!alloc_succeeded) {
error("out of physical memory while allocating ", ds_size, " bytes ",
"in range [", Hex(_phys_range.start), "-", Hex(_phys_range.end), "]");
throw Out_of_ram();
}
/*
* For non-cached RAM dataspaces, we mark the dataspace as write
* combined and expect the pager to evaluate this dataspace property
* when resolving page faults.
* Allocate physical dataspace
*
* \throw Out_of_ram
* \throw Out_of_caps
*/
Dataspace_component *ds = new (*_ds_slab)
Dataspace_component(ds_size, (addr_t)ds_addr, cached, true, this);
/* create native shared memory representation of dataspace */
try { _export_ram_ds(ds); }
catch (Core_virtual_memory_exhausted) {
warning("could not export RAM dataspace of size ", ds->size());
/* cleanup unneeded resources */
destroy(*_ds_slab, ds);
throw Out_of_ram();
}
Ram_dataspace_capability ram_ds = _ram_ds_factory.alloc(ds_size, cached);
/*
* Fill new dataspaces with zeros. For non-cached RAM dataspaces, this
* function must also make sure to flush all cache lines related to the
* address range used by the dataspace.
* We returned from '_ram_ds_factory.alloc' with a valid dataspace.
*/
_clear_ds(ds);
Dataspace_capability result = _ep.manage(ds);
dataspace_ram_costs.acknowledge();
dataspace_cap_costs.acknowledge();
phys_alloc_guard.ack = true;
return static_cap_cast<Ram_dataspace>(result);
return ram_ds;
}
void Ram_session_component::free(Ram_dataspace_capability ds_cap)
{
_free_ds(ds_cap);
if (this->cap() == ds_cap)
return;
size_t const size = _ram_ds_factory.dataspace_size(ds_cap);
if (size == 0)
return;
_ram_ds_factory.free(ds_cap);
/* physical memory */
_ram_account->replenish(Ram_quota{size});
/* capability of the dataspace RPC object */
Cap_quota_guard::replenish(Cap_quota{1});
}
@ -216,12 +96,7 @@ size_t Ram_session_component::dataspace_size(Ram_dataspace_capability ds_cap) co
if (this->cap() == ds_cap)
return 0;
size_t result = 0;
_ep.apply(ds_cap, [&] (Dataspace_component *c) {
if (c && c->owner(this))
result = c->size(); });
return result;
return _ram_ds_factory.dataspace_size(ds_cap);
}
@ -284,19 +159,7 @@ Ram_session_component::Ram_session_component(Rpc_entrypoint &ep,
:
Session_object(ep, resources, label, diag),
_ep(ep),
_phys_alloc(phys_alloc),
_constrained_md_ram_alloc(*this, *this, *this),
_phys_range(phys_range)
{
_sliced_heap.construct(_constrained_md_ram_alloc, local_rm);
_ds_slab.construct(*_sliced_heap, _initial_sb);
}
Ram_session_component::~Ram_session_component()
{
/* destroy all dataspaces */
Ds_slab &ds_slab = *_ds_slab;
for (Dataspace_component *ds; (ds = ds_slab.first_object());
_free_ds(ds->cap()));
}
_sliced_heap(_constrained_md_ram_alloc, local_rm),
_ram_ds_factory(ep, phys_alloc, phys_range, local_rm, _sliced_heap)
{ }