genode/base/src/core/include/rm_session_component.h
Norman Feske 5fe29e8e4a Express affinities via Cartesian coordinates
This patch introduces new types for expressing CPU affinities. Instead
of dealing with physical CPU numbers, affinities are expressed as
rectangles in a grid of virtual CPU nodes. This clears the way to
conveniently assign sets of adjacent CPUs to subsystems, each of them
managing their respective viewport of the coordinate space.

By using 2D Cartesian coordinates, the locality of CPU nodes can be
modeled for different topologies such as SMP (simple Nx1 grid), grids of
NUMA nodes, or ring topologies.
2013-08-13 17:08:24 +02:00

373 lines
11 KiB
C++

/*
* \brief RM session interface
* \author Christian Helmuth
* \author Norman Feske
* \date 2006-07-17
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__RM_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__RM_SESSION_COMPONENT_H_
/* Genode includes */
#include <base/stdint.h>
#include <base/lock.h>
#include <base/capability.h>
#include <base/pager.h>
#include <base/allocator_avl.h>
#include <base/allocator_guard.h>
#include <base/sync_allocator.h>
#include <base/signal.h>
#include <base/rpc_server.h>
#include <util/list.h>
#include <util/fifo.h>
/* core includes */
#include <platform.h>
#include <dataspace_component.h>
#include <util.h>
#include <address_space.h>
namespace Genode {
class Dataspace_component;
class Rm_session_component;
class Rm_client;
/**
* Representation of a single entry of a region-manager session
*
* Each 'Rm_region' is associated with one dataspace and makes a portion
* of this dataspace visible in a address space of a region-manager session.
* All 'Rm_regions' to which one and the same dataspace is attached to, are
* organized in a linked list. The head of the list is a member of the
* 'Dataspace_component'.
*/
class Rm_region : public List<Rm_region>::Element
{
private:
addr_t _base;
size_t _size;
bool _write;
Dataspace_component *_dsc;
off_t _off;
Rm_session_component *_session; /* corresponding region manager
session */
public:
/**
* Default constructor - invalid region
*/
Rm_region() { }
Rm_region(addr_t base, size_t size, bool write,
Dataspace_component *dsc, off_t offset,
Rm_session_component *session)
: _base(base), _size(size), _write(write),
_dsc(dsc), _off(offset), _session(session) { }
/***************
** Accessors **
***************/
addr_t base() const { return _base; }
size_t size() const { return _size; }
bool write() const { return _write; }
Dataspace_component* dataspace() const { return _dsc; }
off_t offset() const { return _off; }
Rm_session_component* session() const { return _session; }
};
/**
* Member of faulter list
*
* Each 'Rm_client' can fault not only at the RM session that it is member
* of but also on any other RM session used as a nested dataspace. If a
* 'Rm_client' faults, it gets enqueued at the leaf RM session that
* detected the fault and waits for this RM session to resolve the fault.
* For example, the dataspace manager that resolves the faults for the
* nested dataspace exported to its client. Because each RM session must
* be able to handle faults by arbitrary clients (not only its own
* clients), it maintains the list head of faulters.
*/
class Rm_faulter : public Fifo<Rm_faulter>::Element
{
private:
Pager_object *_pager_object;
Lock _lock;
Rm_session_component *_faulting_rm_session;
Rm_session::State _fault_state;
public:
/**
* Constructor
*
* \param Pager_object pager object that corresponds to the faulter
*
* Currently, there is only one pager in core.
*/
Rm_faulter(Pager_object *pager_object) :
_pager_object(pager_object), _faulting_rm_session(0) { }
/**
* Assign fault state
*/
void fault(Rm_session_component *faulting_rm_session,
Rm_session::State fault_state);
/**
* Disassociate faulter from the faulted region-manager session
*
* This function must be called when destructing region-manager
* sessions to prevent dangling pointers in '_faulters' lists.
*/
void dissolve_from_faulting_rm_session(Rm_session_component *);
/**
* Return true if page fault occurred in specified address range
*/
bool fault_in_addr_range(addr_t addr, size_t size) {
return (_fault_state.addr >= addr) && (_fault_state.addr <= addr + size - 1); }
/**
* Return fault state as exported via the rm-session interface
*/
Rm_session::State fault_state() { return _fault_state; }
/**
* Wake up faulter by answering the pending page fault
*/
void continue_after_resolved_fault();
};
/**
* Member role of region manager session
*
* A region-manager session can be used as address space for any number
* of threads (region-manager clients). This class represents the client's
* role as member of this address space.
*/
class Rm_member : public List<Rm_client>
{
private:
Rm_session_component *_rm_session;
public:
/**
* Constructor
*/
Rm_member(Rm_session_component *rm_session): _rm_session(rm_session) { }
/**
* Return region-manager session that the RM client is member of
*/
Rm_session_component *member_rm_session() { return _rm_session; }
};
class Rm_client : public Pager_object, public Rm_member, public Rm_faulter,
public List<Rm_client>::Element
{
private:
Weak_ptr<Address_space> _address_space;
public:
/**
* Constructor
*
* \param session RM session to which the client belongs
* \param badge pager-object badge used of identifying the client
* when a page-fault occurs
* \param location affinity to physical CPU
*/
Rm_client(Rm_session_component *session, unsigned long badge,
Weak_ptr<Address_space> &address_space,
Affinity::Location location)
:
Pager_object(badge, location), Rm_member(session),
Rm_faulter(this), _address_space(address_space) { }
int pager(Ipc_pager &pager);
/**
* Flush memory mappings for the specified virtual address range
*/
void unmap(addr_t core_local_base, addr_t virt_base, size_t size);
bool has_same_address_space(Rm_client const &other)
{
return other._address_space == _address_space;
}
};
class Rm_session_component : public Rpc_object<Rm_session>
{
private:
Rpc_entrypoint *_ds_ep;
Rpc_entrypoint *_thread_ep;
Rpc_entrypoint *_session_ep;
Allocator_guard _md_alloc;
Signal_transmitter _fault_notifier; /* notification mechanism for
region-manager faults */
/*********************
** Paging facility **
*********************/
class Rm_region_ref : public List<Rm_region_ref>::Element
{
private:
Rm_region *_region;
public:
Rm_region_ref(Rm_region *region) : _region(region) { }
Rm_region* region() const { return _region; }
};
class Rm_dataspace_component : public Dataspace_component
{
private:
Native_capability _rm_session_cap;
public:
/**
* Constructor
*/
Rm_dataspace_component(size_t size)
:
Dataspace_component(size, 0, false, false, 0)
{ _managed = true; }
/***********************************
** Dataspace component interface **
***********************************/
Native_capability sub_rm_session() { return _rm_session_cap; }
void sub_rm_session(Native_capability _cap) { _rm_session_cap = _cap; }
};
typedef Synchronized_allocator<Tslab<Rm_client, 1024> > Client_slab_alloc;
Client_slab_alloc _client_slab; /* backing store for
client structures, synchronized */
Tslab<Rm_region_ref, 1024> _ref_slab; /* backing store for
region list */
Allocator_avl_tpl<Rm_region> _map; /* region map for attach,
detach, pagefaults */
List<Rm_region_ref> _regions; /* region list for destruction */
Fifo<Rm_faulter> _faulters; /* list of threads that faulted at
the region-manager session and wait
for fault resolution */
List<Rm_client> _clients; /* list of RM clients using this RM
session */
Lock _lock; /* lock for map and list */
Pager_entrypoint *_pager_ep;
Rm_dataspace_component _ds; /* dataspace representation of region map */
Dataspace_capability _ds_cap;
public:
/**
* Constructor
*/
Rm_session_component(Rpc_entrypoint *ds_ep,
Rpc_entrypoint *thread_ep,
Rpc_entrypoint *session_ep,
Allocator *md_alloc,
size_t ram_quota,
Pager_entrypoint *pager_ep,
addr_t vm_start,
size_t vm_size);
~Rm_session_component();
class Fault_area;
/**
* Reversely lookup dataspace and offset matching the specified address
*
* \return true lookup succeeded
*/
bool reverse_lookup(addr_t dst_base,
Fault_area *dst_fault_region,
Dataspace_component **src_dataspace,
Fault_area *src_fault_region,
Rm_session_component **sub_rm_session);
/**
* Register fault
*
* This function is called by the pager to schedule a page fault
* for resolution.
*
* \param faulter faulting region-manager client
* \param pf_addr page-fault address
* \param pf_type type of page fault (read/write/execute)
*/
void fault(Rm_faulter *faulter, addr_t pf_addr,
Rm_session::Fault_type pf_type);
/**
* Dissolve faulter from region-manager session
*/
void discard_faulter(Rm_faulter *faulter, bool do_lock);
List<Rm_client> *clients() { return &_clients; }
/**
* Return the dataspace representation of this session
*/
Rm_dataspace_component *dataspace_component() { return &_ds; }
/**
* Register quota donation at allocator guard
*/
void upgrade_ram_quota(size_t ram_quota) { _md_alloc.upgrade(ram_quota); }
/**************************************
** Region manager session interface **
**************************************/
Local_addr attach (Dataspace_capability, size_t, off_t, bool, Local_addr, bool);
void detach (Local_addr);
Pager_capability add_client (Thread_capability);
void remove_client (Pager_capability);
void fault_handler (Signal_context_capability handler);
State state ();
Dataspace_capability dataspace () { return _ds_cap; }
};
}
#endif /* _CORE__INCLUDE__RM_SESSION_COMPONENT_H_ */