/* * \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 #include #include #include #include #include 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::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(_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(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 class Pager_activation : public Pager_activation_base { }; /** * Dummy pager entrypoint */ class Pager_entrypoint : public Object_pool { 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_ */