sel4: use notification objects for Genode::Lock

Fixes #1717
Issue #2044
This commit is contained in:
Alexander Boettcher 2016-07-20 12:02:23 +02:00 committed by Christian Helmuth
parent 1472c0629b
commit bee0e11049
15 changed files with 160 additions and 55 deletions

View File

@ -66,6 +66,26 @@ class Genode::Cnode_base
void copy(Cnode_base const &from, Index idx) { copy(from, idx, idx); }
/**
* Mint selector from another CNode
*/
void mint(Cnode_base const &from, Index from_idx, Index to_idx)
{
seL4_CNode const service = sel().value();
seL4_Word const dest_index = to_idx.value();
uint8_t const dest_depth = size_log2();
seL4_CNode const src_root = from.sel().value();
seL4_Word const src_index = from_idx.value();
uint8_t const src_depth = from.size_log2();
seL4_CapRights const rights = seL4_AllRights;
seL4_CapData_t const badge = seL4_CapData_Badge_new(to_idx.value());
int const ret = seL4_CNode_Mint(service, dest_index, dest_depth,
src_root, src_index, src_depth,
rights, badge);
ASSERT(ret == seL4_NoError);
}
/**
* Delete selector from CNode
*/

View File

@ -59,6 +59,7 @@ class Genode::Platform_thread : public List<Platform_thread>::Element
*/
Cap_sel _fault_handler_sel { 0 };
Cap_sel _ep_sel { 0 };
Cap_sel _lock_sel { 0 };
friend class Platform_pd;

View File

@ -34,6 +34,7 @@ namespace Genode {
{
Cap_sel tcb_sel { 0 };
Cap_sel ep_sel { 0 };
Cap_sel lock_sel { 0 };
addr_t ipc_buffer_phys = 0;
@ -42,6 +43,8 @@ namespace Genode {
Thread_info() { }
inline void init(addr_t const utcb_virt_addr);
inline void destruct();
};
/**
@ -69,6 +72,10 @@ void Genode::Thread_info::init(addr_t const utcb_virt_addr)
ep_sel = platform.core_sel_alloc().alloc();
create<Endpoint_kobj>(phys_alloc, platform.core_cnode().sel(), ep_sel);
/* allocate asynchronous object within core's CSpace */
lock_sel = platform.core_sel_alloc().alloc();
create<Notification_kobj>(phys_alloc, platform.core_cnode().sel(), lock_sel);
/* assign IPC buffer to thread */
{
/* determine page frame selector of the allocated IPC buffer */
@ -85,6 +92,30 @@ void Genode::Thread_info::init(addr_t const utcb_virt_addr)
}
void Genode::Thread_info::destruct()
{
if (lock_sel.value()) {
seL4_CNode_Delete(seL4_CapInitThreadCNode, lock_sel.value(), 32);
platform_specific()->core_sel_alloc().free(lock_sel);
}
if (ep_sel.value()) {
seL4_CNode_Delete(seL4_CapInitThreadCNode, ep_sel.value(), 32);
platform_specific()->core_sel_alloc().free(ep_sel);
}
if (tcb_sel.value()) {
seL4_CNode_Delete(seL4_CapInitThreadCNode, tcb_sel.value(), 32);
platform_specific()->core_sel_alloc().free(tcb_sel);
}
if (ipc_buffer_phys) {
Platform &platform = *platform_specific();
Range_allocator &phys_alloc = *platform.ram_alloc();
Untyped_memory::convert_to_untyped_frames(ipc_buffer_phys, 4096);
Untyped_memory::free_page(phys_alloc, ipc_buffer_phys);
}
}
void Genode::start_sel4_thread(Cap_sel tcb_sel, addr_t ip, addr_t sp)
{
/* set register values for the instruction pointer and stack pointer */

View File

@ -430,6 +430,22 @@ Platform::Platform()
_core_page_table_registry,
"core")
{
/* create notification object for Genode::Lock used by this first thread */
Cap_sel lock_sel (INITIAL_SEL_LOCK);
Cap_sel core_sel = _core_sel_alloc.alloc();
create<Notification_kobj>(*ram_alloc(), core_cnode().sel(), core_sel);
/* mint a copy of the notification object with badge of lock_sel */
_core_cnode.mint(_core_cnode, core_sel, lock_sel);
/* test signal/wakeup once */
seL4_Word sender;
seL4_Signal(lock_sel.value());
seL4_Wait(lock_sel.value(), &sender);
ASSERT(sender == INITIAL_SEL_LOCK);
/* I/O port allocator (only meaningful for x86) */
_io_port_alloc.add_range(0, 0x10000);

View File

@ -61,11 +61,17 @@ bool Platform_pd::bind_thread(Platform_thread *thread)
thread->_fault_handler_sel = alloc_sel();
/* allocate endpoint selector in the PD's CSpace */
thread->_ep_sel = alloc_sel();
/* allocate asynchronous selector used for locks in the PD's CSpace */
thread->_lock_sel = thread->_utcb ? alloc_sel() : Cap_sel(INITIAL_SEL_LOCK);
} catch (Platform_pd::Sel_bit_alloc::Out_of_indices) {
if (thread->_fault_handler_sel.value()) {
free_sel(thread->_fault_handler_sel);
thread->_fault_handler_sel = Cap_sel(0);
}
if (thread->_ep_sel.value()) {
free_sel(thread->_ep_sel);
thread->_ep_sel = Cap_sel(0);
}
return false;
}
@ -95,6 +101,11 @@ void Platform_pd::unbind_thread(Platform_thread *thread)
if (!thread)
return;
if (thread->_utcb)
free_sel(thread->_lock_sel);
free_sel(thread->_fault_handler_sel);
free_sel(thread->_ep_sel);
if (thread->_utcb)
_vm_space.unmap(thread->_utcb, 1);
else

View File

@ -80,7 +80,8 @@ 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, Cap_sel ep_sel)
static void prepopulate_ipc_buffer(addr_t ipc_buffer_phys, Cap_sel ep_sel,
Cap_sel lock_sel)
{
/* IPC buffer is one page */
size_t const page_rounded_size = get_page_size();
@ -99,6 +100,7 @@ static void prepopulate_ipc_buffer(addr_t ipc_buffer_phys, Cap_sel ep_sel)
/* populate IPC buffer with thread information */
Native_utcb &utcb = *(Native_utcb *)virt_addr;
utcb.ep_sel = ep_sel.value();
utcb.lock_sel = lock_sel.value();
/* unmap IPC buffer from core */
unmap_local((addr_t)virt_addr, 1);
@ -128,12 +130,16 @@ int Platform_thread::start(void *ip, void *sp, unsigned int cpu_no)
_pd->cspace_cnode(_ep_sel).copy(platform_specific()->core_cnode(),
_info.ep_sel, _ep_sel);
/* install the thread's notification object to the PD's CSpace */
_pd->cspace_cnode(_lock_sel).mint(platform_specific()->core_cnode(),
_info.lock_sel, _lock_sel);
/*
* Populate the thread's IPC buffer with initial information about the
* thread. Once started, the thread picks up this information in the
* 'Thread::_thread_bootstrap' method.
*/
prepopulate_ipc_buffer(_info.ipc_buffer_phys, _ep_sel);
prepopulate_ipc_buffer(_info.ipc_buffer_phys, _ep_sel, _lock_sel);
/* bind thread to PD and CSpace */
seL4_CapData_t const guard_cap_data =
@ -211,7 +217,7 @@ Thread_state Platform_thread::state()
void Platform_thread::cancel_blocking()
{
warning(__PRETTY_FUNCTION__, " not implemented");
seL4_Signal(_info.lock_sel.value());
}
@ -248,6 +254,16 @@ Platform_thread::~Platform_thread()
_pd->unbind_thread(this);
}
if (_pager) {
Cap_sel const pager_sel(Capability_space::ipc_cap_data(_pager->cap()).sel);
seL4_CNode_Revoke(seL4_CapInitThreadCNode, pager_sel.value(), 32);
}
seL4_CNode_Revoke(seL4_CapInitThreadCNode, _info.lock_sel.value(), 32);
seL4_CNode_Revoke(seL4_CapInitThreadCNode, _info.ep_sel.value(), 32);
_info.destruct();
platform_thread_registry().remove(*this);
platform_specific()->core_sel_alloc().free(_pager_obj_sel);
}

View File

@ -33,6 +33,7 @@ void Thread::_init_platform_thread(size_t, Type type)
if (type == MAIN) {
native_thread().tcb_sel = seL4_CapInitThreadTCB;
native_thread().lock_sel = INITIAL_SEL_LOCK;
return;
}
@ -44,8 +45,9 @@ void Thread::_init_platform_thread(size_t, Type type)
thread_info.ipc_buffer_phys, utcb_virt_addr);
}
native_thread().tcb_sel = thread_info.tcb_sel.value();
native_thread().ep_sel = thread_info.ep_sel.value();
native_thread().tcb_sel = thread_info.tcb_sel.value();
native_thread().ep_sel = thread_info.ep_sel.value();
native_thread().lock_sel = thread_info.lock_sel.value();
Platform &platform = *platform_specific();
@ -53,7 +55,15 @@ void Thread::_init_platform_thread(size_t, Type type)
int const ret = seL4_TCB_SetSpace(native_thread().tcb_sel, 0,
platform.top_cnode().sel().value(), no_cap_data,
seL4_CapInitThreadPD, no_cap_data);
ASSERT(ret == 0);
ASSERT(ret == seL4_NoError);
/* mint notification object with badge - used by Genode::Lock */
Cap_sel unbadged_sel = thread_info.lock_sel;
Cap_sel lock_sel = platform.core_sel_alloc().alloc();
platform.core_cnode().mint(platform.core_cnode(), unbadged_sel, lock_sel);
native_thread().lock_sel = lock_sel.value();
}

View File

@ -26,7 +26,7 @@
#define ASSERT(e) \
do { if (!(e)) { \
char line_buf[32]; \
snprintf(line_buf, sizeof(line_buf), "%d", __LINE__); \
Genode::snprintf(line_buf, sizeof(line_buf), "%d", __LINE__); \
kernel_debugger_outstring(ESC_ERR "Assertion failed: " #e ESC_END "\n"); \
kernel_debugger_outstring(__FILE__ ":"); \
kernel_debugger_outstring(line_buf); \

View File

@ -95,6 +95,7 @@ namespace Genode { namespace Capability_space {
namespace Genode
{
enum {
INITIAL_SEL_LOCK = 0,
INITIAL_SEL_PARENT = 1,
INITIAL_SEL_CNODE = 2,
INITIAL_SEL_END

View File

@ -2,12 +2,10 @@
* \brief seL4-specific helper functions for the Lock implementation
* \author Norman Feske
* \date 2015-05-07
*
* Based on the lock implementation of base-fiasco/src/base/lock/.
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
* Copyright (C) 2015-2016 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.
@ -16,10 +14,47 @@
#ifndef _INCLUDE__BASE__INTERNAL__LOCK_HELPER_H_
#define _INCLUDE__BASE__INTERNAL__LOCK_HELPER_H_
#include <base/log.h>
#include <base/thread.h>
/* seL4 includes */
#include <base/internal/capability_space_sel4.h>
#include <sel4/sel4.h>
static inline void thread_yield() { seL4_Yield(); }
static inline void thread_switch_to(Genode::Thread *thread)
{
Genode::warning(__FUNCTION__, " not implemented");
}
static inline bool thread_check_stopped_and_restart(Genode::Thread *thread)
{
unsigned lock_sel = Genode::INITIAL_SEL_LOCK; /* main thread */
if (thread)
lock_sel = thread->native_thread().lock_sel;
seL4_Signal(lock_sel);
return true;
}
static inline void thread_stop_myself()
{
Genode::Thread *myself = Genode::Thread::myself();
unsigned lock_sel = Genode::INITIAL_SEL_LOCK; /* main thread */
if (myself)
lock_sel = Genode::Thread::myself()->native_thread().lock_sel;
seL4_Word sender = ~0U;
seL4_Wait(lock_sel, &sender);
}
#endif /* _INCLUDE__BASE__INTERNAL__LOCK_HELPER_H_ */

View File

@ -23,6 +23,7 @@ struct Genode::Native_thread
unsigned tcb_sel = 0;
unsigned ep_sel = 0;
unsigned rcv_sel = 0;
unsigned lock_sel = 0;
};
#endif /* _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_ */

View File

@ -30,7 +30,7 @@ struct Genode::Native_utcb
addr_t raw[IPC_BUFFER_SIZE/sizeof(addr_t)];
struct { addr_t ep_sel; };
struct { addr_t ep_sel; addr_t lock_sel; };
};
};

View File

@ -1,44 +0,0 @@
/*
* \brief Lock implementation
* \author Norman Feske
* \date 2007-10-15
*/
/*
* Copyright (C) 2007-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.
*/
/* Genode includes */
#include <base/cancelable_lock.h>
#include <cpu/atomic.h>
#include <cpu/memory_barrier.h>
/* seL4 includes */
#include <sel4/sel4.h>
using namespace Genode;
Cancelable_lock::Cancelable_lock(Cancelable_lock::State initial)
: _state(UNLOCKED), _owner(nullptr)
{
if (initial == LOCKED)
lock();
}
void Cancelable_lock::lock()
{
while (!Genode::cmpxchg(&_state, UNLOCKED, LOCKED))
seL4_Yield();
}
void Cancelable_lock::unlock()
{
Genode::memory_barrier();
_state = UNLOCKED;
}

View File

@ -34,5 +34,6 @@ void Genode::Thread::_thread_bootstrap()
{
if (native_thread().ep_sel == 0) {
native_thread().ep_sel = _stack->utcb().ep_sel;
native_thread().lock_sel = _stack->utcb().lock_sel;
}
}

View File

@ -14,6 +14,7 @@
/* Genode includes */
#include <base/thread.h>
#include <base/internal/native_thread.h>
#include <base/internal/capability_space_sel4.h>
using namespace Genode;
@ -25,4 +26,9 @@ void Thread::_init_platform_thread(size_t, Type type)
* and associations the thread, like IPCbuffer in ipc.cc.
*/
native_thread() = Native_thread();
if (type == MAIN) {
native_thread().lock_sel = INITIAL_SEL_LOCK;
return;
}
}