sel4: initialization of non-main threads

This commit is contained in:
Norman Feske 2015-05-13 11:15:58 +02:00 committed by Christian Helmuth
parent 06d143d51f
commit 84c5437437
10 changed files with 116 additions and 41 deletions

View File

@ -108,17 +108,22 @@ namespace Genode {
bool valid() const; 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 };
/** union {
* On seL4, the UTCB is called IPC buffer. We use one page
* for each IPC buffer.
*/
enum { IPC_BUFFER_SIZE = 4096 };
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 struct Native_config

View File

@ -215,10 +215,8 @@ class Genode::Capability_space_sel4
{ {
Lock::Guard guard(_lock); Lock::Guard guard(_lock);
if (!_is_core_managed(data) && !data.dec_ref()) { if (!_is_core_managed(data) && !data.dec_ref())
PDBG("remove cap");
_remove(data); _remove(data);
}
} }
void inc_ref(Data &data) void inc_ref(Data &data)

View File

@ -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)); 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()); dst_msg.append_cap(Native_capability());
continue; continue;
} }
@ -193,8 +208,6 @@ static void decode_seL4_message(umword_t badge,
ASSERT(delegated); ASSERT(delegated);
ASSERT(delegated);
Native_capability arg_cap = Capability_space::lookup(rpc_obj_key); Native_capability arg_cap = Capability_space::lookup(rpc_obj_key);
if (arg_cap.valid()) { if (arg_cap.valid()) {

View File

@ -29,4 +29,9 @@ void prepare_reinit_main_thread() { prepare_init_main_thread(); }
** Thread_base ** ** 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;
}
}

View File

@ -21,10 +21,4 @@ using namespace Genode;
void Thread_base::_init_platform_thread(size_t, Type type) 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");
} }

View File

@ -63,12 +63,8 @@ class Genode::Platform_pd : public Address_space
Sel_alloc _sel_alloc; Sel_alloc _sel_alloc;
Lock _sel_alloc_lock; Lock _sel_alloc_lock;
bool _initial_ipc_buffer_mapped = false;
public: public:
enum { INITIAL_IPC_BUFFER_VIRT = 0x1000 };
/** /**
* Constructors * Constructors
*/ */
@ -123,8 +119,6 @@ class Genode::Platform_pd : public Address_space
size_t cspace_size_log2() { return CSPACE_SIZE_LOG2; } size_t cspace_size_log2() { return CSPACE_SIZE_LOG2; }
void install_mapping(Mapping const &mapping); void install_mapping(Mapping const &mapping);
void map_ipc_buffer_of_initial_thread(addr_t ipc_buffer_phys);
}; };
#endif /* _CORE__INCLUDE__PLATFORM_PD_H_ */ #endif /* _CORE__INCLUDE__PLATFORM_PD_H_ */

View File

@ -41,19 +41,32 @@ class Genode::Platform_thread : public List<Platform_thread>::Element
String<128> _name; 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; Thread_info _info;
unsigned const _pager_obj_sel; 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 _fault_handler_sel = 0;
unsigned _ep_sel = 0;
friend class Platform_pd; friend class Platform_pd;
Platform_pd *_pd = nullptr; Platform_pd *_pd = nullptr;
enum { INITIAL_IPC_BUFFER_VIRT = 0x1000 };
public: public:
/** /**

View File

@ -36,6 +36,8 @@ namespace Genode {
addr_t ipc_buffer_phys = 0; addr_t ipc_buffer_phys = 0;
inline void write_thread_info_to_ipc_buffer(unsigned pd_ep_sel);
Thread_info() { } Thread_info() { }
inline void init(addr_t const utcb_virt_addr); inline void init(addr_t const utcb_virt_addr);

View File

@ -57,6 +57,23 @@ int Platform_pd::bind_thread(Platform_thread *thread)
ASSERT(thread); ASSERT(thread);
thread->_pd = this; 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; 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, Platform_pd::Platform_pd(Allocator * md_alloc, size_t ram_quota,
char const *, signed pd_id, bool create) char const *, signed pd_id, bool create)
: :

View File

@ -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 ** ** 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, _pd->cspace_cnode().copy(platform_specific()->core_cnode(), pager_sel,
_fault_handler_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 */ /* bind thread to PD and CSpace */
seL4_CapData_t const guard_cap_data = 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) addr_t utcb)
: :
_name(name), _name(name),
_utcb(utcb),
_pager_obj_sel(platform_specific()->alloc_core_sel()) _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); platform_thread_registry().insert(*this);
} }