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;
};
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

View File

@ -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)

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));
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()) {

View File

@ -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;
}
}

View File

@ -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");
}

View File

@ -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_ */

View File

@ -41,19 +41,32 @@ class Genode::Platform_thread : public List<Platform_thread>::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:
/**

View File

@ -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);

View File

@ -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)
:

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 **
*******************************/
@ -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);
}