From 657dd5faadff179a6bed837374613d68a33ae443 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Fri, 8 Jul 2016 16:38:48 +0200 Subject: [PATCH] sel4: support region fault manager outside core rm_fault.run works Issue #2044 --- repos/base-sel4/lib/mk/core.mk | 4 +- repos/base-sel4/src/core/include/ipc_pager.h | 28 +-- repos/base-sel4/src/core/include/pager.h | 187 +++++++++++++++++++ repos/base-sel4/src/core/pager.cc | 91 +++++++-- 4 files changed, 270 insertions(+), 40 deletions(-) create mode 100644 repos/base-sel4/src/core/include/pager.h diff --git a/repos/base-sel4/lib/mk/core.mk b/repos/base-sel4/lib/mk/core.mk index 005ba3a357..0113717390 100644 --- a/repos/base-sel4/lib/mk/core.mk +++ b/repos/base-sel4/lib/mk/core.mk @@ -35,8 +35,7 @@ SRC_CC += \ dump_alloc.cc \ stack_area.cc \ capability_space.cc \ - pager.cc \ - pager_ep.cc + pager.cc LIBS += core_printf base-common syscall @@ -64,5 +63,4 @@ vpath dataspace_component.cc $(GEN_CORE_DIR) vpath core_mem_alloc.cc $(GEN_CORE_DIR) vpath core_rpc_cap_alloc.cc $(GEN_CORE_DIR) vpath dump_alloc.cc $(GEN_CORE_DIR) -vpath pager_ep.cc $(GEN_CORE_DIR) vpath %.cc $(REP_DIR)/src/core diff --git a/repos/base-sel4/src/core/include/ipc_pager.h b/repos/base-sel4/src/core/include/ipc_pager.h index a66759f6c4..3245b3be88 100644 --- a/repos/base-sel4/src/core/include/ipc_pager.h +++ b/repos/base-sel4/src/core/include/ipc_pager.h @@ -75,6 +75,7 @@ namespace Genode { private: addr_t _last; /* faulted thread ID */ + addr_t _reply_sel; /* selector to save reply cap */ addr_t _pf_addr; /* page-fault address */ addr_t _pf_ip; /* instruction pointer of faulter */ bool _pf_write; /* true on write fault */ @@ -116,21 +117,7 @@ namespace Genode { /** * Set destination for next reply */ - void set_reply_dst(Native_capability pager_object) { - _last = pager_object.local_name(); } - - /** - * Answer call without sending a mapping - * - * This function is used to acknowledge local calls from one of - * core's region-manager sessions. - */ - void acknowledge_wakeup(); - - /** - * Returns true if the last request was send from a core thread - */ - bool request_from_core() { return false; } + void reply_save_caller(addr_t sel) { _reply_sel = sel; } /** * Return badge for faulting thread @@ -141,17 +128,6 @@ namespace Genode { * Return true if page fault was a write fault */ bool write_fault() const { return _pf_write; } - - /** - * Return true if last fault was an exception - */ - bool exception() const - { - /* - * Reflection of exceptions is not supported on this platform. - */ - return false; - } }; } diff --git a/repos/base-sel4/src/core/include/pager.h b/repos/base-sel4/src/core/include/pager.h new file mode 100644 index 0000000000..7c6785de0d --- /dev/null +++ b/repos/base-sel4/src/core/include/pager.h @@ -0,0 +1,187 @@ +/* + * \brief Paging-server framework + * \author Norman Feske + * \author Christian Helmuth + * \author Stefan Kalkowski + * \date 2006-04-28 + */ + +/* + * Copyright (C) 2006-2015 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__PAGER_H_ +#define _CORE__INCLUDE__PAGER_H_ + +/* Genode includes */ +#include +#include +#include +#include +#include + +/* core-local includes */ +#include +#include + +namespace Genode { + + /** + * Special server object for paging + * + * A 'Pager_object' is very similar to a 'Rpc_object'. It is just a + * special implementation for page-fault handling, which does not allow to + * define a "badge" for pager capabilities. + */ + class Pager_object; + + /** + * Paging entry point + */ + class Pager_entrypoint; + + enum { PAGER_EP_STACK_SIZE = sizeof(addr_t) * 2048 }; +} + + +class Genode::Pager_object : public Object_pool::Entry +{ + protected: + + /** + * Local name for this pager object + */ + unsigned long _badge; + + Cpu_session_capability _cpu_session_cap; + Thread_capability _thread_cap; + Genode::Cap_sel _reply_cap; + + /** + * User-level signal handler registered for this pager object via + * 'Cpu_session::exception_handler()'. + */ + Signal_context_capability _exception_sigh; + + public: + + /** + * Contains information about exception state of corresponding thread. + */ + Thread_state state; + + /** + * Constructor + * + * \param location affinity of paged thread to physical CPU + */ + Pager_object(Cpu_session_capability cpu_sesion, Thread_capability thread, + unsigned long badge, Affinity::Location location); + + ~Pager_object(); + + unsigned long badge() const { return _badge; } + + unsigned long reply_cap_sel() const { return _reply_cap.value(); } + + /** + * Interface to be implemented by a derived class + * + * \param ps 'Ipc_pager' stream + * + * Returns !0 on error and pagefault will not be answered. + */ + virtual int pager(Ipc_pager &ps) = 0; + + /** + * Wake up the faulter + */ + void wake_up(); + + /** + * Assign user-level exception handler for the pager object + */ + void exception_handler(Signal_context_capability sigh) + { + _exception_sigh = sigh; + } + + /** + * Notify exception handler about the occurrence of an exception + */ + void submit_exception_signal() + { + if (!_exception_sigh.valid()) return; + + Signal_transmitter transmitter(_exception_sigh); + transmitter.submit(); + } + + /** + * Return CPU session that was used to created the thread + */ + Cpu_session_capability cpu_session_cap() const { return _cpu_session_cap; } + + /** + * Return thread capability + * + * This function enables the destructor of the thread's + * address-space region map to kill the thread. + */ + Thread_capability thread_cap() const { return _thread_cap; } + + /* + * Note in the thread state that an unresolved page + * fault occurred. + */ + void unresolved_page_fault_occurred(); +}; + + +class Genode::Pager_entrypoint : public Object_pool, + public Thread_deprecated +{ + private: + + Ipc_pager _pager; + Rpc_cap_factory _cap_factory; + + Untyped_capability _pager_object_cap(unsigned long badge); + + public: + + /** + * Constructor + * + * \param cap_factory factory for creating capabilities + * for the pager objects managed by this + * entry point + */ + Pager_entrypoint(Rpc_cap_factory &cap_factory) + : + Thread_deprecated("pager_ep"), + _cap_factory(cap_factory) + { start(); } + + /** + * Associate Pager_object with the entry point + */ + Pager_capability manage(Pager_object *obj); + + /** + * Dissolve Pager_object from entry point + */ + void dissolve(Pager_object *obj); + + + /********************** + ** Thread interface ** + **********************/ + + void entry(); +}; + +#endif /* _CORE__INCLUDE__PAGER_H_ */ diff --git a/repos/base-sel4/src/core/pager.cc b/repos/base-sel4/src/core/pager.cc index 925e6acf4f..67f87d43c9 100644 --- a/repos/base-sel4/src/core/pager.cc +++ b/repos/base-sel4/src/core/pager.cc @@ -11,13 +11,11 @@ * under the terms of the GNU General Public License version 2. */ -/* Genode includes */ -#include - /* core includes */ #include #include #include +#include /* base-internal includes */ #include @@ -53,8 +51,18 @@ struct Fault_info ** IPC pager ** ***************/ + void Ipc_pager::wait_for_fault() { + if (_last && _reply_sel) { + seL4_CNode const service = seL4_CapInitThreadCNode; + seL4_Word const index = _reply_sel; + uint8_t const depth = 32; + int ret = seL4_CNode_SaveCaller(service, index, depth); + if (ret != seL4_NoError) + Genode::error("saving reply cap failed with ", ret); + } + _reply_sel = 0; _last = 0; reply_and_wait_for_fault(); } @@ -91,22 +99,35 @@ void Ipc_pager::reply_and_wait_for_fault() } -void Ipc_pager::acknowledge_wakeup() -{ - PDBG("not implemented"); -} - - -Ipc_pager::Ipc_pager() : _last(0) { } +Ipc_pager::Ipc_pager() : _last(0), _reply_sel(0) { } /****************** ** Pager object ** ******************/ +Pager_object::Pager_object(Cpu_session_capability cpu_sesion, + Thread_capability thread, + unsigned long badge, Affinity::Location location) +: + _badge(badge), _cpu_session_cap(cpu_sesion), _thread_cap(thread), + _reply_cap(platform_specific()->core_sel_alloc().alloc()) +{ } + + +Pager_object::~Pager_object() +{ + seL4_CNode_Delete(seL4_CapInitThreadCNode, _reply_cap.value(), 32); + platform_specific()->core_sel_alloc().free(_reply_cap); + /* invalidate reply cap for Pager_object::wait_for_fault() _reply_sel */ + _reply_cap = Cap_sel(0); +} + + void Pager_object::wake_up() { - PDBG("not implemented"); + seL4_MessageInfo_t const send_msg = seL4_MessageInfo_new(0, 0, 0, 0); + seL4_Send(_reply_cap.value(), send_msg); } @@ -133,3 +154,51 @@ Untyped_capability Pager_entrypoint::_pager_object_cap(unsigned long badge) return Capability_space::create_rpc_obj_cap(ep_cap, nullptr, rpc_obj_key); } + +void Pager_entrypoint::dissolve(Pager_object *obj) +{ + using Pool = Object_pool; + + if (obj) Pool::remove(obj); +} + + +Pager_capability Pager_entrypoint::manage(Pager_object *obj) +{ + Native_capability cap = _pager_object_cap(obj->badge()); + + /* add server object to object pool */ + obj->cap(cap); + insert(obj); + + /* return capability that uses the object id as badge */ + return reinterpret_cap_cast(cap); +} + + +void Pager_entrypoint::entry() +{ + using Pool = Object_pool; + + bool reply_pending = false; + + while (1) { + + if (reply_pending) + _pager.reply_and_wait_for_fault(); + else + _pager.wait_for_fault(); + + reply_pending = false; + + Pool::apply(_pager.badge(), [&] (Pager_object *obj) { + if (!obj) + return; + + /* send reply if page-fault handling succeeded */ + reply_pending = !obj->pager(_pager); + if (!reply_pending) + _pager.reply_save_caller(obj->reply_cap_sel()); + }); + } +}