From 84c5437437622a15a5f85e06bcbaf3256a84d3be Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Wed, 13 May 2015 11:15:58 +0200 Subject: [PATCH] sel4: initialization of non-main threads --- repos/base-sel4/include/base/native_types.h | 21 +++++--- .../src/base/internal/capability_space_sel4.h | 4 +- repos/base-sel4/src/base/ipc/ipc.cc | 19 +++++-- .../src/base/thread/thread_bootstrap.cc | 7 ++- .../base-sel4/src/base/thread/thread_init.cc | 6 --- .../base-sel4/src/core/include/platform_pd.h | 6 --- .../src/core/include/platform_thread.h | 15 +++++- .../base-sel4/src/core/include/thread_sel4.h | 2 + repos/base-sel4/src/core/platform_pd.cc | 28 ++++++----- repos/base-sel4/src/core/platform_thread.cc | 49 ++++++++++++++++++- 10 files changed, 116 insertions(+), 41 deletions(-) diff --git a/repos/base-sel4/include/base/native_types.h b/repos/base-sel4/include/base/native_types.h index 1157aa6f71..cd6c1eb36c 100644 --- a/repos/base-sel4/include/base/native_types.h +++ b/repos/base-sel4/include/base/native_types.h @@ -108,17 +108,22 @@ namespace Genode { bool valid() const; }; - class Native_utcb + struct Native_utcb { - private: + /** + * On seL4, the UTCB is called IPC buffer. We use one page + * for each IPC buffer. + */ + enum { IPC_BUFFER_SIZE = 4096 }; - /** - * On seL4, the UTCB is called IPC buffer. We use one page - * for each IPC buffer. - */ - enum { IPC_BUFFER_SIZE = 4096 }; + union { - addr_t _utcb[IPC_BUFFER_SIZE/sizeof(addr_t)]; + addr_t raw[IPC_BUFFER_SIZE/sizeof(addr_t)]; + + struct { + addr_t ep_sel; + }; + }; }; struct Native_config diff --git a/repos/base-sel4/src/base/internal/capability_space_sel4.h b/repos/base-sel4/src/base/internal/capability_space_sel4.h index 82b5aa5d2a..ee6695d69d 100644 --- a/repos/base-sel4/src/base/internal/capability_space_sel4.h +++ b/repos/base-sel4/src/base/internal/capability_space_sel4.h @@ -215,10 +215,8 @@ class Genode::Capability_space_sel4 { Lock::Guard guard(_lock); - if (!_is_core_managed(data) && !data.dec_ref()) { - PDBG("remove cap"); + if (!_is_core_managed(data) && !data.dec_ref()) _remove(data); - } } void inc_ref(Data &data) diff --git a/repos/base-sel4/src/base/ipc/ipc.cc b/repos/base-sel4/src/base/ipc/ipc.cc index b9e6212f69..c8ff768de7 100644 --- a/repos/base-sel4/src/base/ipc/ipc.cc +++ b/repos/base-sel4/src/base/ipc/ipc.cc @@ -136,7 +136,22 @@ static void decode_seL4_message(umword_t badge, Rpc_obj_key const rpc_obj_key(seL4_GetMR(MR_IDX_CAPS + i)); - if (!rpc_obj_key.valid()) { + /* + * Detect passing of invalid capabilities as arguments + * + * The second condition of the check handles the case where a non-RPC + * object capability as passed as RPC argument as done by the + * 'Cap_session::alloc' RPC function. Here, the entrypoint capability + * is not an RPC-object capability but a raw seL4 endpoint selector. + * + * XXX Technically, a message may contain one invalid capability + * followed by a valid one. This check would still wrongly regard + * the first capability as a valid one. A better approach would + * be to introduce another state to Rpc_obj_key, which would + * denote a valid capability that is not an RPC-object capability. + * Hence it is meaningless as a key. + */ + if (!rpc_obj_key.valid() && seL4_MessageInfo_get_extraCaps(msg_info) == 0) { dst_msg.append_cap(Native_capability()); continue; } @@ -193,8 +208,6 @@ static void decode_seL4_message(umword_t badge, ASSERT(delegated); - ASSERT(delegated); - Native_capability arg_cap = Capability_space::lookup(rpc_obj_key); if (arg_cap.valid()) { diff --git a/repos/base-sel4/src/base/thread/thread_bootstrap.cc b/repos/base-sel4/src/base/thread/thread_bootstrap.cc index 531b81d0ec..f47c97336b 100644 --- a/repos/base-sel4/src/base/thread/thread_bootstrap.cc +++ b/repos/base-sel4/src/base/thread/thread_bootstrap.cc @@ -29,4 +29,9 @@ void prepare_reinit_main_thread() { prepare_init_main_thread(); } ** Thread_base ** *****************/ -void Genode::Thread_base::_thread_bootstrap() { } +void Genode::Thread_base::_thread_bootstrap() +{ + if (tid().ep_sel == 0) { + tid().ep_sel = _context->utcb.ep_sel; + } +} diff --git a/repos/base-sel4/src/base/thread/thread_init.cc b/repos/base-sel4/src/base/thread/thread_init.cc index 51c53f5b0f..e28c2c0394 100644 --- a/repos/base-sel4/src/base/thread/thread_init.cc +++ b/repos/base-sel4/src/base/thread/thread_init.cc @@ -21,10 +21,4 @@ using namespace Genode; void Thread_base::_init_platform_thread(size_t, Type type) { - /* - * XXX initialize the 'Native_thread' structure with the thread's - * tcb_sel, ep_sel. - */ - - PDBG("not implemented"); } diff --git a/repos/base-sel4/src/core/include/platform_pd.h b/repos/base-sel4/src/core/include/platform_pd.h index 8537c50d5e..44162c758a 100644 --- a/repos/base-sel4/src/core/include/platform_pd.h +++ b/repos/base-sel4/src/core/include/platform_pd.h @@ -63,12 +63,8 @@ class Genode::Platform_pd : public Address_space Sel_alloc _sel_alloc; Lock _sel_alloc_lock; - bool _initial_ipc_buffer_mapped = false; - public: - enum { INITIAL_IPC_BUFFER_VIRT = 0x1000 }; - /** * Constructors */ @@ -123,8 +119,6 @@ class Genode::Platform_pd : public Address_space size_t cspace_size_log2() { return CSPACE_SIZE_LOG2; } void install_mapping(Mapping const &mapping); - - void map_ipc_buffer_of_initial_thread(addr_t ipc_buffer_phys); }; #endif /* _CORE__INCLUDE__PLATFORM_PD_H_ */ diff --git a/repos/base-sel4/src/core/include/platform_thread.h b/repos/base-sel4/src/core/include/platform_thread.h index 2457ea5789..00ff3fecdb 100644 --- a/repos/base-sel4/src/core/include/platform_thread.h +++ b/repos/base-sel4/src/core/include/platform_thread.h @@ -41,19 +41,32 @@ class Genode::Platform_thread : public List::Element String<128> _name; + /** + * Virtual address of the IPC buffer within the PDs address space + * + * The value is 0 for the PD's main thread. For all other threads, + * the value is somewhere within the context area. + */ + addr_t const _utcb; + Thread_info _info; unsigned const _pager_obj_sel; /* - * Allocated when the thread is started + * Selectors within the PD's CSpace + * + * Allocated when the thread is started. */ unsigned _fault_handler_sel = 0; + unsigned _ep_sel = 0; friend class Platform_pd; Platform_pd *_pd = nullptr; + enum { INITIAL_IPC_BUFFER_VIRT = 0x1000 }; + public: /** diff --git a/repos/base-sel4/src/core/include/thread_sel4.h b/repos/base-sel4/src/core/include/thread_sel4.h index f688d560ee..2ca1ac5e3f 100644 --- a/repos/base-sel4/src/core/include/thread_sel4.h +++ b/repos/base-sel4/src/core/include/thread_sel4.h @@ -36,6 +36,8 @@ namespace Genode { addr_t ipc_buffer_phys = 0; + inline void write_thread_info_to_ipc_buffer(unsigned pd_ep_sel); + Thread_info() { } inline void init(addr_t const utcb_virt_addr); diff --git a/repos/base-sel4/src/core/platform_pd.cc b/repos/base-sel4/src/core/platform_pd.cc index d114fb8f8d..75fba92bdc 100644 --- a/repos/base-sel4/src/core/platform_pd.cc +++ b/repos/base-sel4/src/core/platform_pd.cc @@ -57,6 +57,23 @@ int Platform_pd::bind_thread(Platform_thread *thread) ASSERT(thread); thread->_pd = this; + + /* + * Map IPC buffer + * + * XXX The mapping of the IPC buffer could be evicted from the PD's + * 'Vm_space'. In contrast to mapping that are created as a result of + * the RM-session's page-fault resolution, the IPC buffer's mapping + * won't be recoverable once flushed. For this reason, it is important + * to attach the UTCB as a dataspace to the context-area to make the RM + * session aware to the mapping. This code is missing. + */ + if (thread->_utcb) { + _vm_space.map(thread->_info.ipc_buffer_phys, thread->_utcb, 1); + } else { + _vm_space.map(thread->_info.ipc_buffer_phys, thread->INITIAL_IPC_BUFFER_VIRT, 1); + } + return 0; } @@ -116,17 +133,6 @@ void Platform_pd::install_mapping(Mapping const &mapping) } -void Platform_pd::map_ipc_buffer_of_initial_thread(addr_t ipc_buffer_phys) -{ - if (_initial_ipc_buffer_mapped) - return; - - _vm_space.map(ipc_buffer_phys, INITIAL_IPC_BUFFER_VIRT, 1); - - _initial_ipc_buffer_mapped = true; -} - - Platform_pd::Platform_pd(Allocator * md_alloc, size_t ram_quota, char const *, signed pd_id, bool create) : diff --git a/repos/base-sel4/src/core/platform_thread.cc b/repos/base-sel4/src/core/platform_thread.cc index ee5cc5b0bc..8a2495eadc 100644 --- a/repos/base-sel4/src/core/platform_thread.cc +++ b/repos/base-sel4/src/core/platform_thread.cc @@ -75,6 +75,38 @@ void Genode::install_mapping(Mapping const &mapping, unsigned long pager_object_ } +/******************************************************** + ** Utilities to support the Platform_thread interface ** + ********************************************************/ + +static void prepopulate_ipc_buffer(addr_t ipc_buffer_phys, unsigned ep_sel) +{ + /* IPC buffer is one page */ + size_t const page_rounded_size = get_page_size(); + + /* allocate range in core's virtual address space */ + void *virt_addr; + if (!platform()->region_alloc()->alloc(page_rounded_size, &virt_addr)) { + PERR("could not allocate virtual address range in core of size %zd\n", + page_rounded_size); + return; + } + + /* map the IPC buffer to core-local virtual addresses */ + map_local(ipc_buffer_phys, (addr_t)virt_addr, 1); + + /* populate IPC buffer with thread information */ + Native_utcb &utcb = *(Native_utcb *)virt_addr; + utcb.ep_sel = ep_sel; + + /* unmap IPC buffer from core */ + unmap_local((addr_t)virt_addr, 1); + + /* free core's virtual address space */ + platform()->region_alloc()->free(virt_addr, page_rounded_size); +} + + /******************************* ** Platform_thread interface ** *******************************/ @@ -94,7 +126,19 @@ int Platform_thread::start(void *ip, void *sp, unsigned int cpu_no) _pd->cspace_cnode().copy(platform_specific()->core_cnode(), pager_sel, _fault_handler_sel); - _pd->map_ipc_buffer_of_initial_thread(_info.ipc_buffer_phys); + /* allocate endpoint selector in the PD's CSpace */ + _ep_sel = _pd->alloc_sel(); + + /* install the thread's endpoint selector to the PD's CSpace */ + _pd->cspace_cnode().copy(platform_specific()->core_cnode(), _info.ep_sel, + _ep_sel); + + /* + * Populate the thread's IPC buffer with initial information about the + * thread. Once started, the thread picks up this information in the + * 'Thread_base::_thread_bootstrap' method. + */ + prepopulate_ipc_buffer(_info.ipc_buffer_phys, _ep_sel); /* bind thread to PD and CSpace */ seL4_CapData_t const guard_cap_data = @@ -161,10 +205,11 @@ Platform_thread::Platform_thread(size_t, const char *name, unsigned priority, addr_t utcb) : _name(name), + _utcb(utcb), _pager_obj_sel(platform_specific()->alloc_core_sel()) { - _info.init(Platform_pd::INITIAL_IPC_BUFFER_VIRT); + _info.init(_utcb ? _utcb : INITIAL_IPC_BUFFER_VIRT); platform_thread_registry().insert(*this); }