genode/base-nova/include/base/pager.h

288 lines
6.7 KiB
C++

/*
* \brief Paging-server framework
* \author Norman Feske
* \date 2006-04-28
*/
/*
* 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 _INCLUDE__BASE__PAGER_H_
#define _INCLUDE__BASE__PAGER_H_
#include <base/thread.h>
#include <base/object_pool.h>
#include <base/ipc_pager.h>
#include <base/capability.h>
#include <cap_session/cap_session.h>
#include <pager/capability.h>
namespace Genode {
class Pager_entrypoint;
/*
* On NOVA, each pager object is an EC that corresponds to one user thread.
*/
class Pager_object : public Object_pool<Pager_object>::Entry,
Thread_base
{
private:
void entry() { }
void start() { }
unsigned long _badge; /* used for debugging */
/**
* User-level signal handler registered for this pager object via
* 'Cpu_session::exception_handler()'.
*/
Signal_context_capability _exception_sigh;
/**
* Portal selector for object cleanup/destruction
*/
addr_t _pt_cleanup;
addr_t _initial_esp;
addr_t _initial_eip;
addr_t _client_exc_pt_sel;
addr_t _client_exc_vcpu;
struct
{
struct Thread_state thread;
addr_t sel_client_ec;
enum {
VALID = 0x1U,
DEAD = 0x2U,
SINGLESTEP = 0x4U,
CLIENT_CANCEL = 0x8U,
SIGNAL_SM = 0x10U,
};
uint8_t _status;
/* convenience function to access pause/recall state */
inline bool is_valid() { return _status & VALID; }
inline void mark_valid() { _status |= VALID; }
inline void mark_invalid() { _status &= ~VALID; }
inline bool is_client_cancel() { return _status & CLIENT_CANCEL; }
inline void mark_client_cancel() { _status |= CLIENT_CANCEL; }
inline void unmark_client_cancel() { _status &= ~CLIENT_CANCEL; }
inline void mark_dead() { _status |= DEAD; }
inline bool is_dead() { return _status & DEAD; }
inline bool singlestep() { return _status & SINGLESTEP; }
inline void mark_signal_sm() { _status |= SIGNAL_SM; }
inline bool has_signal_sm() { return _status & SIGNAL_SM; }
} _state;
Thread_capability _thread_cap;
void _copy_state(Nova::Utcb * utcb);
/**
* Semaphore selector to synchronize pause/state/resume operations
*/
addr_t sm_state_notify() { return _pt_cleanup + 1; }
static void _page_fault_handler();
static void _startup_handler();
static void _invoke_handler();
static void _recall_handler();
__attribute__((regparm(1)))
static void _exception_handler(addr_t portal_id);
static Nova::Utcb * _check_handler(Thread_base *&, Pager_object *&);
public:
Pager_object(unsigned long badge, Affinity::Location location);
virtual ~Pager_object();
unsigned long badge() const { return _badge; }
virtual int pager(Ipc_pager &ps) = 0;
/**
* Assign user-level exception handler for the pager object
*/
void exception_handler(Signal_context_capability sigh)
{
_exception_sigh = sigh;
}
/**
* Return base of initial portal window
*/
addr_t ec_sel() { return _tid.ec_sel; }
/**
* Return base of initial portal window
*/
addr_t exc_pt_sel() { return _tid.exc_pt_sel; }
addr_t exc_pt_sel_client() { return _client_exc_pt_sel; }
addr_t exc_pt_vcpu() { return _client_exc_vcpu; }
/**
* Set initial stack pointer used by the startup handler
*/
addr_t initial_esp() { return _initial_esp; }
void initial_esp(addr_t esp) { _initial_esp = esp; }
/**
* Set initial instruction pointer used by the startup handler
*/
void initial_eip(addr_t eip) { _initial_eip = eip; }
/**
* Continue execution of pager object
*/
void wake_up();
/**
* Notify exception handler about the occurrence of an exception
*/
bool submit_exception_signal()
{
if (!_exception_sigh.valid()) return false;
Signal_transmitter transmitter(_exception_sigh);
transmitter.submit();
return true;
}
/**
* Return entry point address
*/
addr_t handler_address()
{
return reinterpret_cast<addr_t>(_invoke_handler);
}
/**
* Return semaphore to block on until state of a recall is
* available.
*/
Native_capability notify_sm()
{
if (_state.is_valid() || _state.is_dead())
return Native_capability();
return Native_capability(sm_state_notify());
}
/**
* Copy thread state of recalled thread.
*/
bool copy_thread_state(Thread_state * state_dst)
{
if (!state_dst || !_state.is_valid())
return false;
*state_dst = _state.thread;
return true;
}
/**
* Cancel blocking in a lock so that recall exception can take
* place.
*/
void client_cancel_blocking();
uint8_t client_recall();
void client_set_ec(addr_t ec) { _state.sel_client_ec = ec; }
inline void single_step(bool on)
{
if (on)
_state._status |= _state.SINGLESTEP;
else
_state._status &= ~_state.SINGLESTEP;
}
/**
* Remember thread cap so that rm_session can tell thread that
* rm_client is gone.
*/
Thread_capability thread_cap() { return _thread_cap; } const
void thread_cap(Thread_capability cap) { _thread_cap = cap; }
/**
* Make sure nobody is in the handler anymore by doing an IPC to a
* local cap pointing to same serving thread (if not running in the
* context of the serving thread). When the call returns
* we know that nobody is handled by this object anymore, because
* all remotely available portals had been revoked beforehand.
*/
void cleanup_call();
/**
* Open receive window for initial portals for vCPU.
*/
void prepare_vCPU_portals()
{
_client_exc_vcpu = cap_map()->insert(Nova::NUM_INITIAL_VCPU_PT_LOG2);
Nova::Utcb *utcb = reinterpret_cast<Nova::Utcb *>(Thread_base::utcb());
utcb->crd_rcv = Nova::Obj_crd(_client_exc_vcpu, Nova::NUM_INITIAL_VCPU_PT_LOG2);
}
};
/**
* Dummy pager activation
*
* Because on NOVA each pager object can be invoked separately,
* there is no central pager activation.
*/
class Pager_activation_base { };
template <unsigned STACK_SIZE>
class Pager_activation : public Pager_activation_base
{ };
/**
* Dummy pager entrypoint
*/
class Pager_entrypoint : public Object_pool<Pager_object>
{
private:
Cap_session *_cap_session;
public:
Pager_entrypoint(Cap_session *cap_session,
Pager_activation_base *a = 0)
: _cap_session(cap_session) { }
/**
* Return capability for 'Pager_object'
*/
Pager_capability manage(Pager_object *obj);
/**
* Dissolve 'Pager_object' from entry point
*/
void dissolve(Pager_object *obj);
};
}
#endif /* _INCLUDE__BASE__PAGER_H_ */