2011-12-22 15:19:25 +00:00
|
|
|
/*
|
|
|
|
* \brief Paging-server framework
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2006-04-28
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2013-01-10 20:44:47 +00:00
|
|
|
* Copyright (C) 2006-2013 Genode Labs GmbH
|
2011-12-22 15:19:25 +00:00
|
|
|
*
|
|
|
|
* 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;
|
|
|
|
|
2012-08-24 08:25:24 +00:00
|
|
|
/**
|
|
|
|
* Portal selector for object cleanup/destruction
|
|
|
|
*/
|
|
|
|
addr_t _pt_cleanup;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Semaphore selector to synchronize pause/state/resume operations
|
|
|
|
*/
|
|
|
|
addr_t _sm_state_notify;
|
2011-12-22 15:19:25 +00:00
|
|
|
|
|
|
|
addr_t _initial_esp;
|
|
|
|
addr_t _initial_eip;
|
|
|
|
|
2012-08-24 08:25:24 +00:00
|
|
|
struct {
|
|
|
|
struct Thread_state thread;
|
2012-08-22 10:10:04 +00:00
|
|
|
addr_t sel_client_ec;
|
2012-08-24 08:25:24 +00:00
|
|
|
bool valid;
|
|
|
|
bool dead;
|
2012-08-23 10:43:19 +00:00
|
|
|
bool singlestep;
|
2012-08-24 08:25:24 +00:00
|
|
|
} _state;
|
|
|
|
|
2012-11-29 12:37:30 +00:00
|
|
|
Thread_capability _thread_cap;
|
|
|
|
|
2012-08-24 08:25:24 +00:00
|
|
|
void _copy_state(Nova::Utcb * utcb);
|
|
|
|
|
2011-12-22 15:19:25 +00:00
|
|
|
static void _page_fault_handler();
|
|
|
|
static void _startup_handler();
|
|
|
|
static void _invoke_handler();
|
2012-08-24 08:25:24 +00:00
|
|
|
static void _recall_handler();
|
2011-12-22 15:19:25 +00:00
|
|
|
|
2012-08-23 09:02:31 +00:00
|
|
|
__attribute__((regparm(1)))
|
|
|
|
static void _exception_handler(addr_t portal_id);
|
|
|
|
|
|
|
|
static Nova::Utcb * _check_handler(Thread_base *&, Pager_object *&);
|
2011-12-22 15:19:25 +00:00
|
|
|
public:
|
|
|
|
|
|
|
|
Pager_object(unsigned long badge);
|
|
|
|
|
|
|
|
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
|
|
|
|
*/
|
2012-08-08 12:23:13 +00:00
|
|
|
addr_t ec_sel() { return _tid.ec_sel; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return base of initial portal window
|
|
|
|
*/
|
|
|
|
addr_t exc_pt_sel() { return _tid.exc_pt_sel; }
|
2011-12-22 15:19:25 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Set initial stack pointer used by the startup handler
|
|
|
|
*/
|
|
|
|
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
|
|
|
|
*/
|
2012-08-24 08:25:24 +00:00
|
|
|
bool submit_exception_signal()
|
2011-12-22 15:19:25 +00:00
|
|
|
{
|
2012-08-24 08:25:24 +00:00
|
|
|
if (!_exception_sigh.valid()) return false;
|
2011-12-22 15:19:25 +00:00
|
|
|
|
|
|
|
Signal_transmitter transmitter(_exception_sigh);
|
|
|
|
transmitter.submit();
|
2012-08-24 08:25:24 +00:00
|
|
|
|
|
|
|
return true;
|
2011-12-22 15:19:25 +00:00
|
|
|
}
|
2012-08-08 12:23:13 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Return entry point address
|
|
|
|
*/
|
|
|
|
addr_t handler_address()
|
|
|
|
{
|
2012-08-24 08:25:24 +00:00
|
|
|
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.valid)
|
|
|
|
return Native_capability::invalid_cap();
|
|
|
|
if (_state.dead)
|
|
|
|
return Native_capability::invalid_cap();
|
|
|
|
|
|
|
|
return Native_capability(_sm_state_notify);
|
2012-08-08 12:23:13 +00:00
|
|
|
}
|
2012-08-24 08:25:24 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Copy thread state of recalled thread.
|
|
|
|
*/
|
|
|
|
int copy_thread_state(Thread_state * state_dst)
|
|
|
|
{
|
|
|
|
if (!state_dst || !_state.valid) return -1;
|
|
|
|
|
|
|
|
*state_dst = _state.thread;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Cancel blocking in a lock so that recall exception can take
|
|
|
|
* place.
|
|
|
|
*/
|
2012-08-22 10:10:04 +00:00
|
|
|
void client_cancel_blocking();
|
|
|
|
|
|
|
|
uint8_t client_recall();
|
|
|
|
void client_set_ec(addr_t ec) { _state.sel_client_ec = ec; }
|
2012-08-23 10:43:19 +00:00
|
|
|
|
|
|
|
void single_step(bool on) { _state.singlestep = on; }
|
2012-11-29 12:37:30 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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; }
|
2011-12-22 15:19:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Dummy pager activation
|
|
|
|
*
|
|
|
|
* Because on NOVA each pager object can be invoked separately,
|
|
|
|
* there is no central pager activation.
|
|
|
|
*/
|
|
|
|
class Pager_activation_base { };
|
|
|
|
|
|
|
|
|
2012-06-19 13:54:41 +00:00
|
|
|
template <unsigned STACK_SIZE>
|
2011-12-22 15:19:25 +00:00
|
|
|
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_ */
|