From 0a89d8dbb454356d30bc7b5565667a8325fe1b7f Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Wed, 8 Aug 2012 17:12:10 +0200 Subject: [PATCH] NOVA: extend cpu_session for base-nova --- base-nova/include/nova_cpu_session/client.h | 81 +++++++++ .../include/nova_cpu_session/connection.h | 40 +++++ .../nova_cpu_session/nova_cpu_session.h | 46 ++++++ base-nova/src/core/cpu_session_extension.cc | 43 +++++ .../src/core/include/cpu_session_component.h | 156 ++++++++++++++++++ base-nova/src/core/include/platform_thread.h | 17 +- base-nova/src/core/platform_thread.cc | 76 ++++++--- base-nova/src/core/target.inc | 3 +- 8 files changed, 432 insertions(+), 30 deletions(-) create mode 100644 base-nova/include/nova_cpu_session/client.h create mode 100644 base-nova/include/nova_cpu_session/connection.h create mode 100644 base-nova/include/nova_cpu_session/nova_cpu_session.h create mode 100644 base-nova/src/core/cpu_session_extension.cc create mode 100644 base-nova/src/core/include/cpu_session_component.h diff --git a/base-nova/include/nova_cpu_session/client.h b/base-nova/include/nova_cpu_session/client.h new file mode 100644 index 0000000000..0bc1ecd684 --- /dev/null +++ b/base-nova/include/nova_cpu_session/client.h @@ -0,0 +1,81 @@ +/* + * \brief Client-side cpu session NOVA extension + * \author Alexander Boettcher + * \date 2012-07-27 + */ + +/* + * Copyright (C) 2012-2012 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__NOVA_CPU_SESSION__CLIENT_H_ +#define _INCLUDE__NOVA_CPU_SESSION__CLIENT_H_ + +#include +#include + +namespace Genode { + + struct Nova_cpu_session_client : Rpc_client + { + explicit Nova_cpu_session_client(Cpu_session_capability session) + : Rpc_client(static_cap_cast(session)) { } + + Thread_capability create_thread(Name const &name, addr_t utcb = 0) { + return call(name, utcb); } + + Ram_dataspace_capability utcb(Thread_capability thread) { + return call(thread); } + + + void kill_thread(Thread_capability thread) { + call(thread); } + + Thread_capability first() { + return call(); } + + Thread_capability next(Thread_capability curr) { + return call(curr); } + + int set_pager(Thread_capability thread, Pager_capability pager) { + return call(thread, pager); } + + int start(Thread_capability thread, addr_t ip, addr_t sp) { + return call(thread, ip, sp); } + + void pause(Thread_capability thread) { + call(thread); } + + void resume(Thread_capability thread) { + call(thread); } + + void cancel_blocking(Thread_capability thread) { + call(thread); } + + int state(Thread_capability thread, Thread_state *dst_state) { + return call(thread, dst_state); } + + void exception_handler(Thread_capability thread, Signal_context_capability handler) { + call(thread, handler); } + + void single_step(Thread_capability thread, bool enable) { + call(thread, enable); } + + Native_capability native_cap(Thread_capability cap) { + return call(cap); } + + int start_exc_base_vcpu(Thread_capability thread, addr_t ip, + addr_t sp, addr_t exc_base) + { + return call(thread, ip, sp, + exc_base); + } + + + }; +} + +#endif /* _INCLUDE__NOVA_CPU_SESSION__CLIENT_H_ */ diff --git a/base-nova/include/nova_cpu_session/connection.h b/base-nova/include/nova_cpu_session/connection.h new file mode 100644 index 0000000000..1398dec5bf --- /dev/null +++ b/base-nova/include/nova_cpu_session/connection.h @@ -0,0 +1,40 @@ +/* + * \brief Connection to NOVA specific CPU service + * \author Alexander Boettcher + * \date 2012-07-27 + */ + +/* + * Copyright (C) 2012-2012 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__NOVA_CPU_SESSION__CONNECTION_H_ +#define _INCLUDE__NOVA_CPU_SESSION__CONNECTION_H_ + +#include +#include + +namespace Genode { + + struct Nova_cpu_connection : Connection, Nova_cpu_session_client + { + /** + * Constructor + * + * \param label initial session label + * \param priority designated priority of all threads created + * with this CPU session + */ + Nova_cpu_connection(const char *label = "", long priority = DEFAULT_PRIORITY) + : + Connection( + session("priority=0x%lx, ram_quota=32K, label=\"%s\"", + priority, label)), + Nova_cpu_session_client(cap()) { } + }; +} + +#endif /* _INCLUDE__NOVA_CPU_SESSION__CONNECTION_H_ */ diff --git a/base-nova/include/nova_cpu_session/nova_cpu_session.h b/base-nova/include/nova_cpu_session/nova_cpu_session.h new file mode 100644 index 0000000000..a99c140280 --- /dev/null +++ b/base-nova/include/nova_cpu_session/nova_cpu_session.h @@ -0,0 +1,46 @@ +/* + * \brief Cpu session interface extension for NOVA + * \author Alexander Boettcher + * \date 2012-07-27 + */ + +/* + * Copyright (C) 2012-2012 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__NOVA_CPU_SESSION__NOVA_CPU_SESSION_H_ +#define _INCLUDE__NOVA_CPU_SESSION__NOVA_CPU_SESSION_H_ + +#include +#include + +namespace Genode { + + struct Nova_cpu_session : Cpu_session + { + virtual ~Nova_cpu_session() { } + + virtual int + start_exc_base_vcpu(Thread_capability thread, addr_t ip, + addr_t sp, addr_t exc_base) = 0; + virtual + Native_capability native_cap(Thread_capability cap) = 0; + + /********************* + ** RPC declaration ** + *********************/ + + GENODE_RPC(Rpc_start_exc_base_vcpu, int, start_exc_base_vcpu, + Thread_capability, addr_t, addr_t, addr_t); + GENODE_RPC(Rpc_native_cap, Native_capability, native_cap, + Thread_capability); + + GENODE_RPC_INTERFACE_INHERIT(Cpu_session, Rpc_native_cap, + Rpc_start_exc_base_vcpu); + }; +} + +#endif /* _INCLUDE__NOVA_CPU_SESSION__NOVA_CPU_SESSION_H_ */ diff --git a/base-nova/src/core/cpu_session_extension.cc b/base-nova/src/core/cpu_session_extension.cc new file mode 100644 index 0000000000..48439d1f4e --- /dev/null +++ b/base-nova/src/core/cpu_session_extension.cc @@ -0,0 +1,43 @@ +/** + * \brief Core implementation of the CPU session interface extension + * \author Alexander Boettcher + * \date 2012-07-27 + */ + +/* + * Copyright (C) 2012-2012 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. + */ + +/* Genode includes */ +#include + +/* Core includes */ +#include + +using namespace Genode; + +Native_capability +Cpu_session_component::native_cap(Thread_capability thread_cap) +{ + Cpu_thread_component *thread = _lookup_thread(thread_cap); + if (!thread) + return Native_capability(0, 0); + + return thread->platform_thread()->native_cap(); +} + +int +Cpu_session_component::start_exc_base_vcpu(Thread_capability thread_cap, + addr_t ip, addr_t sp, + addr_t exc_base) +{ + Cpu_thread_component *thread = _lookup_thread(thread_cap); + if (!thread) return -1; + + return thread->platform_thread()->start((void *)ip, (void *)sp, exc_base); +} + + diff --git a/base-nova/src/core/include/cpu_session_component.h b/base-nova/src/core/include/cpu_session_component.h new file mode 100644 index 0000000000..e3b9a0d17d --- /dev/null +++ b/base-nova/src/core/include/cpu_session_component.h @@ -0,0 +1,156 @@ +/* + * \brief Core-specific instance of the CPU session/thread interfaces + * \author Christian Helmuth + * \author Alexander Boettcher + * \date 2006-07-17 + */ + +/* + * Copyright (C) 2006-2012 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__CPU_SESSION_COMPONENT_H_ +#define _CORE__INCLUDE__CPU_SESSION_COMPONENT_H_ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include +#include + +/* core includes */ +#include + +namespace Genode { + + /** + * RPC interface of CPU thread + * + * We make 'Cpu_thread' a RPC object only to be able to lookup CPU threads + * from thread capabilities supplied as arguments to CPU-session functions. + * A CPU thread does not provide an actual RPC interface. + */ + struct Cpu_thread + { + GENODE_RPC_INTERFACE(); + }; + + + class Cpu_thread_component : public Rpc_object, + public List::Element + { + private: + + Platform_thread _platform_thread; + + bool _bound; /* pd binding flag */ + + public: + + Cpu_thread_component(const char *name, unsigned priority, addr_t) + : _platform_thread(name, priority), _bound(false) { } + + + /************************ + ** Accessor functions ** + ************************/ + + inline Platform_thread * platform_thread() { return &_platform_thread; } + inline bool bound() const { return _bound; } + inline void bound(bool b) { _bound = b; } + }; + + + class Cpu_session_component : public Rpc_object + { + private: + + /** + * Allocator used for managing the CPU threads associated with the + * CPU session + */ + typedef Tslab Cpu_thread_allocator; + + Rpc_entrypoint *_thread_ep; + Pager_entrypoint *_pager_ep; + Allocator_guard _md_alloc; /* guarded meta-data allocator */ + Cpu_thread_allocator _thread_alloc; /* meta-data allocator */ + Lock _thread_alloc_lock; /* protect alloc access */ + List _thread_list; + Lock _thread_list_lock; /* protect thread list */ + unsigned _priority; /* priority of threads + created with this + session */ + + /** + * Lookup thread in CPU session by its capability + * + * \retval NULL thread capability is invalid or + * does not belong to the CPU session + */ + Cpu_thread_component *_lookup_thread(Thread_capability thread) { + return dynamic_cast + (_thread_ep->obj_by_cap(thread)); } + + /** + * Raw thread-killing functionality + * + * This function is called from the 'kill_thread' function and + * the destructor. Each these functions grab the list lock + * by themselves and call this function to perform the actual + * killing. + */ + void _unsynchronized_kill_thread(Cpu_thread_component *thread); + + public: + + /** + * Constructor + */ + Cpu_session_component(Rpc_entrypoint *thread_ep, + Pager_entrypoint *pager_ep, + Allocator *md_alloc, const char *args); + + /** + * Destructor + */ + ~Cpu_session_component(); + + + /*************************** + ** CPU session interface ** + ***************************/ + + Thread_capability create_thread(Name const &, addr_t); + Ram_dataspace_capability utcb(Thread_capability thread); + + void kill_thread(Thread_capability); + Thread_capability first(); + Thread_capability next(Thread_capability); + int set_pager(Thread_capability, Pager_capability); + int start(Thread_capability, addr_t, addr_t); + void pause(Thread_capability thread_cap); + void resume(Thread_capability thread_cap); + void cancel_blocking(Thread_capability); + int name(Thread_capability, char *, size_t); + int state(Thread_capability, Thread_state *); + void exception_handler(Thread_capability, Signal_context_capability); + + + /*********************************** + ** NOVA specific extensions ** + ***********************************/ + + int start_exc_base_vcpu(Thread_capability, addr_t, + addr_t, addr_t); + Native_capability native_cap(Thread_capability); + }; +} + +#endif /* _CORE__INCLUDE__CPU_SESSION_COMPONENT_H_ */ diff --git a/base-nova/src/core/include/platform_thread.h b/base-nova/src/core/include/platform_thread.h index 3c0fa50db4..974b449686 100644 --- a/base-nova/src/core/include/platform_thread.h +++ b/base-nova/src/core/include/platform_thread.h @@ -31,7 +31,11 @@ namespace Genode { Platform_pd *_pd; Pager_object *_pager; bool _is_main_thread; - int _id; + addr_t _id_base; + unsigned _cpu_no; + + addr_t _sel_ec() { return _id_base; } + addr_t _sel_sc() { return _id_base + 1; } public: @@ -41,7 +45,7 @@ namespace Genode { * Constructor */ Platform_thread(const char *name = 0, unsigned priority = 0, - addr_t utcb = 0, int thread_id = THREAD_INVALID); + int thread_id = THREAD_INVALID); /** * Destructor @@ -53,12 +57,11 @@ namespace Genode { * * \param ip instruction pointer to start at * \param sp stack pointer to use - * \param cpu_no target cpu * * \retval 0 successful * \retval -1 thread could not be started */ - int start(void *ip, void *sp, unsigned int cpu_no = 0); + int start(void *ip, void *sp, addr_t exc_base = ~0UL); /** * Pause this thread @@ -119,6 +122,12 @@ namespace Genode { { _pd = pd, _is_main_thread = is_main_thread; } + + Native_capability native_cap() + { + return Native_capability(_sel_ec(), 0); + } + }; } diff --git a/base-nova/src/core/platform_thread.cc b/base-nova/src/core/platform_thread.cc index 8ddebf096d..9655950156 100644 --- a/base-nova/src/core/platform_thread.cc +++ b/base-nova/src/core/platform_thread.cc @@ -39,7 +39,7 @@ void Platform_thread::set_cpu(unsigned int cpu_no) } -int Platform_thread::start(void *ip, void *sp, unsigned int cpu_no) +int Platform_thread::start(void *ip, void *sp, addr_t exc_base) { using namespace Nova; @@ -48,13 +48,32 @@ int Platform_thread::start(void *ip, void *sp, unsigned int cpu_no) return -1; } - enum { PD_EC_CPU_NO = 0, PD_UTCB = 0x6000000 }; + if (!_pd) { + PERR("protection domain undefined"); + return -2; + } + enum { PD_UTCB = 0x6000000 }; _pager->initial_eip((addr_t)ip); + if (!_is_main_thread) { + addr_t initial_sp = reinterpret_cast(sp); + addr_t utcb = round_page(initial_sp); - if (!_is_main_thread || !_pd) { - _pager->initial_esp((addr_t)sp); - return 0; + _pager->initial_esp(initial_sp); + if (exc_base == ~0UL) { + PERR("exception base not specified"); + return -3; + } + + /* ip == 0 means that caller will use the thread as worker */ + bool thread_global = ip; + uint8_t res = create_ec(_sel_ec(), _pd->pd_sel(), _cpu_no, + utcb, initial_sp, + exc_base, thread_global); + if (res) + PERR("creation of new thread failed %u", res); + + return res ? -4 : 0; } /* @@ -67,32 +86,38 @@ int Platform_thread::start(void *ip, void *sp, unsigned int cpu_no) int res = map_local((Nova::Utcb *)Thread_base::myself()->utcb(), Obj_crd(_pd->parent_pt_sel(), 0), Obj_crd(_pager->exc_pt_sel() + PT_SEL_PARENT, 0)); - if (res) + if (res) { PERR("could not locally remap parent portal"); + return -5; + } - Obj_crd initial_pts(_pager->exc_pt_sel(), Nova::NUM_INITIAL_PT_LOG2); + Obj_crd initial_pts(_pager->exc_pt_sel(), Nova::NUM_INITIAL_PT_LOG2, + 1 << 4); - int pd_sel = cap_selector_allocator()->pd_sel(); - int pd0_sel = _pager->exc_pt_sel() + Nova::PD_SEL; + addr_t pd_sel = cap_selector_allocator()->pd_sel(); + addr_t pd0_sel = _pager->exc_pt_sel() + Nova::PD_SEL; _pd->assign_pd(pd0_sel); res = create_pd(pd0_sel, pd_sel, initial_pts); - if (res) + if (res) { PERR("create_pd returned %d", res); - - int ec_sel = cap_selector_allocator()->alloc(); - int sc_sel = cap_selector_allocator()->alloc(); + return -6; + } enum { THREAD_GLOBAL = true }; - res = create_ec(ec_sel, pd0_sel, PD_EC_CPU_NO, PD_UTCB, 0, 0, + res = create_ec(_sel_ec(), pd0_sel, _cpu_no, PD_UTCB, 0, 0, THREAD_GLOBAL); - if (res) - PDBG("create_ec returned %d", res); + if (res) { + PERR("create_ec returned %d", res); + return -7; + } - res = create_sc(sc_sel, pd0_sel, ec_sel, Qpd()); - if (res) + res = create_sc(_sel_sc(), pd0_sel, _sel_ec(), Qpd()); + if (res) { PERR("create_sc returned %d", res); + return -8; + } return 0; } @@ -106,7 +131,10 @@ void Platform_thread::pause() void Platform_thread::resume() { - PDBG("not implemented"); + uint8_t res = Nova::create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(), + Nova::Qpd()); + if (res) + PDBG("create_sc returned %u", res); } @@ -123,15 +151,13 @@ void Platform_thread::cancel_blocking() { PWRN("not implemented"); } unsigned long Platform_thread::pager_object_badge() const { - return _pd ? ((_pd->id() << 16) || _id) : ~0; + return ~0UL; } -static int id_cnt; - - -Platform_thread::Platform_thread(const char *name, unsigned, addr_t, int thread_id) -: _pd(0), _id(++id_cnt) { } +Platform_thread::Platform_thread(const char *name, unsigned, int thread_id) +: _pd(0), _id_base(cap_selector_allocator()->alloc(1)), + _cpu_no(0) { } Platform_thread::~Platform_thread() diff --git a/base-nova/src/core/target.inc b/base-nova/src/core/target.inc index 7e348e77dd..090c27aa55 100644 --- a/base-nova/src/core/target.inc +++ b/base-nova/src/core/target.inc @@ -32,7 +32,8 @@ SRC_CC = \ main_thread.cc \ context_area.cc \ echo.cc \ - dump_alloc.cc + dump_alloc.cc \ + cpu_session_extension.cc INC_DIR = $(REP_DIR)/src/core/include \ $(GEN_CORE_DIR)/include