2011-12-22 16:19:25 +01:00
|
|
|
/*
|
|
|
|
* \brief Fiasco thread facility
|
|
|
|
* \author Stefan Kalkowski
|
|
|
|
* \date 2011-01-04
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2012-01-03 15:35:05 +01:00
|
|
|
* Copyright (C) 2011-2012 Genode Labs GmbH
|
2011-12-22 16:19:25 +01:00
|
|
|
*
|
|
|
|
* 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/ipc.h>
|
|
|
|
#include <base/printf.h>
|
|
|
|
#include <util/string.h>
|
|
|
|
|
|
|
|
/* core includes */
|
|
|
|
#include <cap_session_component.h>
|
|
|
|
#include <platform_thread.h>
|
|
|
|
#include <platform.h>
|
|
|
|
#include <core_env.h>
|
|
|
|
|
|
|
|
/* Fiasco includes */
|
|
|
|
namespace Fiasco {
|
|
|
|
#include <l4/sys/debugger.h>
|
|
|
|
#include <l4/sys/factory.h>
|
|
|
|
#include <l4/sys/irq.h>
|
|
|
|
#include <l4/sys/scheduler.h>
|
|
|
|
#include <l4/sys/thread.h>
|
|
|
|
#include <l4/sys/types.h>
|
|
|
|
}
|
|
|
|
|
|
|
|
using namespace Genode;
|
|
|
|
using namespace Fiasco;
|
|
|
|
|
|
|
|
|
|
|
|
int Platform_thread::start(void *ip, void *sp)
|
|
|
|
{
|
|
|
|
if (_pager && _platform_pd) {
|
|
|
|
/* map pager cap */
|
|
|
|
l4_msgtag_t tag = l4_task_map(_platform_pd->native_task(), L4_BASE_TASK_CAP,
|
2012-03-09 12:25:11 +01:00
|
|
|
l4_obj_fpage(_pager->cap().dst(), 0, L4_FPAGE_RWX),
|
2011-12-22 16:19:25 +01:00
|
|
|
_remote_pager_cap | L4_ITEM_MAP);
|
|
|
|
if (l4_msgtag_has_error(tag))
|
|
|
|
PWRN("mapping pager cap failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reserve utcb area and associate thread with this task */
|
|
|
|
l4_thread_control_start();
|
|
|
|
l4_thread_control_pager(_remote_pager_cap);
|
|
|
|
l4_thread_control_exc_handler(_remote_pager_cap);
|
|
|
|
l4_thread_control_bind(_utcb, _platform_pd->native_task());
|
|
|
|
|
2012-03-09 12:25:11 +01:00
|
|
|
l4_msgtag_t tag = l4_thread_control_commit(_thread_cap.dst());
|
2011-12-22 16:19:25 +01:00
|
|
|
if (l4_msgtag_has_error(tag)) {
|
|
|
|
PWRN("l4_thread_control_commit for %lx failed!",
|
2012-03-09 12:25:11 +01:00
|
|
|
(unsigned long) _thread_cap.dst());
|
2011-12-22 16:19:25 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set ip and sp and run the thread */
|
2012-03-09 12:25:11 +01:00
|
|
|
tag = l4_thread_ex_regs(_thread_cap.dst(), (l4_addr_t) ip, (l4_addr_t) sp, 0);
|
2011-12-22 16:19:25 +01:00
|
|
|
if (l4_msgtag_has_error(tag)) {
|
|
|
|
PWRN("l4_thread_ex_regs failed!");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Platform_thread::pause()
|
|
|
|
{
|
|
|
|
if (!_pager)
|
|
|
|
return;
|
|
|
|
|
|
|
|
_pager->state.lock.lock();
|
|
|
|
|
|
|
|
if (_pager->state.paused == true) {
|
|
|
|
_pager->state.lock.unlock();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned exc = _pager->state.exceptions;
|
|
|
|
_pager->state.ip = ~0UL;
|
|
|
|
_pager->state.sp = ~0UL;
|
|
|
|
l4_umword_t flags = L4_THREAD_EX_REGS_TRIGGER_EXCEPTION;
|
|
|
|
|
|
|
|
/* Mark thread to be stopped */
|
|
|
|
_pager->state.paused = true;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Force the thread to be paused to trigger an exception.
|
|
|
|
* The pager thread, which also acts as exception handler, will
|
|
|
|
* leave the thread in exception state until, it gets woken again
|
|
|
|
*/
|
2012-03-09 12:25:11 +01:00
|
|
|
l4_thread_ex_regs_ret(_thread_cap.dst(), &_pager->state.ip,
|
2011-12-22 16:19:25 +01:00
|
|
|
&_pager->state.sp, &flags);
|
2011-12-23 14:04:29 +01:00
|
|
|
bool in_syscall = flags == 0;
|
2011-12-22 16:19:25 +01:00
|
|
|
_pager->state.lock.unlock();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check whether the thread was in ongoing ipc, if so it won't raise
|
|
|
|
* an exception before ipc is completed.
|
|
|
|
*/
|
|
|
|
if (!in_syscall) {
|
|
|
|
/*
|
|
|
|
* Wait until the pager thread got an exception from
|
|
|
|
* the requested thread, and stored its thread state
|
|
|
|
*/
|
|
|
|
while (exc == _pager->state.exceptions && !_pager->state.in_exception)
|
2012-03-09 12:25:11 +01:00
|
|
|
l4_thread_switch(_thread_cap.dst());
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Platform_thread::resume()
|
|
|
|
{
|
|
|
|
if (!_pager)
|
|
|
|
return;
|
|
|
|
|
|
|
|
_pager->state.lock.lock();
|
|
|
|
|
|
|
|
/* Mark thread to be runable again */
|
|
|
|
_pager->state.paused = false;
|
|
|
|
_pager->state.lock.unlock();
|
|
|
|
|
|
|
|
/* Send a message to the exception handler, to unblock the client */
|
|
|
|
Msgbuf<16> snd, rcv;
|
|
|
|
Ipc_client ipc_client(_pager->cap(), &snd, &rcv);
|
|
|
|
ipc_client << _pager << IPC_CALL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Platform_thread::bind(Platform_pd *pd)
|
|
|
|
{
|
|
|
|
l4_msgtag_t tag;
|
|
|
|
Native_task task = pd->native_task();
|
|
|
|
|
|
|
|
_platform_pd = pd;
|
|
|
|
|
|
|
|
if (!_core_thread) {
|
|
|
|
/* map parent and task cap if it doesn't happen already */
|
|
|
|
_platform_pd->map_task_cap();
|
|
|
|
_platform_pd->map_parent_cap();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_gate_cap.valid()) {
|
|
|
|
/* map thread's gate cap */
|
|
|
|
tag = l4_task_map(task, L4_BASE_TASK_CAP,
|
2012-03-09 12:25:11 +01:00
|
|
|
l4_obj_fpage(_gate_cap.dst(), 0, L4_FPAGE_RWX),
|
|
|
|
_remote_gate_cap.dst() | L4_ITEM_MAP);
|
2011-12-22 16:19:25 +01:00
|
|
|
if (l4_msgtag_has_error(tag))
|
|
|
|
PWRN("mapping thread's gate cap failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* map thread's irq cap */
|
|
|
|
tag = l4_task_map(task, L4_BASE_TASK_CAP,
|
|
|
|
l4_obj_fpage(_irq_cap, 0, L4_FPAGE_RWX),
|
|
|
|
_remote_irq_cap | L4_ITEM_MAP);
|
|
|
|
if (l4_msgtag_has_error(tag))
|
|
|
|
PWRN("mapping thread's irq cap failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Platform_thread::unbind()
|
|
|
|
{
|
2012-03-09 12:25:11 +01:00
|
|
|
l4_thread_ex_regs(_thread_cap.dst(), 0, 0, 0);
|
2011-12-22 16:19:25 +01:00
|
|
|
l4_task_unmap(L4_BASE_TASK_CAP,
|
2012-03-09 12:25:11 +01:00
|
|
|
l4_obj_fpage(_gate_cap.dst(), 0, L4_FPAGE_RWX),
|
2011-12-22 16:19:25 +01:00
|
|
|
L4_FP_ALL_SPACES | L4_FP_DELETE_OBJ);
|
|
|
|
l4_task_unmap(L4_BASE_TASK_CAP,
|
2012-03-09 12:25:11 +01:00
|
|
|
l4_obj_fpage(_thread_cap.dst(), 0, L4_FPAGE_RWX),
|
2011-12-22 16:19:25 +01:00
|
|
|
L4_FP_ALL_SPACES | L4_FP_DELETE_OBJ);
|
|
|
|
_platform_pd = (Platform_pd*) 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Platform_thread::pager(Pager_object *pager)
|
|
|
|
{
|
|
|
|
_pager = pager;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int Platform_thread::state(Thread_state *state_dst)
|
|
|
|
{
|
|
|
|
if (_pager)
|
|
|
|
*state_dst = _pager->state;
|
|
|
|
|
|
|
|
state_dst->cap = _remote_gate_cap;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Platform_thread::cancel_blocking()
|
|
|
|
{
|
|
|
|
l4_irq_trigger(_irq_cap);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Platform_thread::_create_thread()
|
|
|
|
{
|
|
|
|
l4_msgtag_t tag = l4_factory_create_thread(L4_BASE_FACTORY_CAP,
|
2012-03-09 12:25:11 +01:00
|
|
|
_thread_cap.dst());
|
2011-12-22 16:19:25 +01:00
|
|
|
if (l4_msgtag_has_error(tag))
|
|
|
|
PERR("cannot create more thread kernel-objects!");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Platform_thread::_finalize_construction(const char *name, unsigned prio)
|
|
|
|
{
|
|
|
|
/* create irq for new thread */
|
2012-02-27 17:22:42 +01:00
|
|
|
_irq_cap = cap_alloc()->alloc();
|
2011-12-22 16:19:25 +01:00
|
|
|
l4_msgtag_t tag = l4_factory_create_irq(L4_BASE_FACTORY_CAP, _irq_cap);
|
|
|
|
if (l4_msgtag_has_error(tag))
|
|
|
|
PWRN("creating thread's irq failed");
|
|
|
|
|
|
|
|
/* attach thread to irq */
|
2012-03-09 12:25:11 +01:00
|
|
|
tag = l4_irq_attach(_irq_cap, 0, _thread_cap.dst());
|
2011-12-22 16:19:25 +01:00
|
|
|
if (l4_msgtag_has_error(tag))
|
|
|
|
PWRN("attaching thread's irq failed");
|
|
|
|
|
|
|
|
/* set human readable name in kernel debugger */
|
|
|
|
strncpy(_name, name, sizeof(_name));
|
2012-03-09 12:25:11 +01:00
|
|
|
Fiasco::l4_debugger_set_object_name(_thread_cap.dst(), name);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/* set priority of thread */
|
|
|
|
prio = Cpu_session::scale_priority(DEFAULT_PRIORITY, prio);
|
|
|
|
l4_sched_param_t params = l4_sched_param(prio);
|
2012-03-09 12:25:11 +01:00
|
|
|
l4_scheduler_run_thread(L4_BASE_SCHEDULER_CAP, _thread_cap.dst(), ¶ms);
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Platform_thread::Platform_thread(const char *name,
|
|
|
|
unsigned prio)
|
|
|
|
: _core_thread(false),
|
2012-02-27 17:22:42 +01:00
|
|
|
_badge(Badge_allocator::allocator()->alloc()),
|
|
|
|
_thread_cap(cap_alloc()->alloc_id(_badge),
|
|
|
|
_badge),
|
2012-03-09 12:25:11 +01:00
|
|
|
_node(_thread_cap.local_name(), 0, this, _thread_cap.dst()),
|
2011-12-22 16:19:25 +01:00
|
|
|
_utcb(0),
|
|
|
|
_platform_pd(0),
|
|
|
|
_pager(0)
|
|
|
|
{
|
|
|
|
/* register the thread capability */
|
|
|
|
Capability_tree::tree()->insert(&_node);
|
|
|
|
|
|
|
|
_create_thread();
|
|
|
|
|
|
|
|
/* create gate for new thread */
|
|
|
|
_gate_cap = core_env()->cap_session()->alloc(_thread_cap);
|
|
|
|
|
|
|
|
_finalize_construction(name, prio);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Platform_thread::Platform_thread(Native_thread cap, const char *name)
|
|
|
|
: _core_thread(true),
|
|
|
|
_thread_cap(cap, -1),
|
2012-03-09 12:25:11 +01:00
|
|
|
_node(_thread_cap.local_name(), 0, this, _thread_cap.dst()),
|
2011-12-22 16:19:25 +01:00
|
|
|
_utcb(0),
|
|
|
|
_platform_pd(0),
|
|
|
|
_pager(0)
|
|
|
|
{
|
|
|
|
/* register the thread capability */
|
|
|
|
Capability_tree::tree()->insert(&_node);
|
|
|
|
|
|
|
|
_finalize_construction(name, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Platform_thread::Platform_thread(const char *name)
|
|
|
|
: _core_thread(true),
|
2012-02-27 17:22:42 +01:00
|
|
|
_badge(Badge_allocator::allocator()->alloc()),
|
|
|
|
_thread_cap(cap_alloc()->alloc_id(_badge),
|
|
|
|
_badge),
|
2012-03-09 12:25:11 +01:00
|
|
|
_node(_thread_cap.local_name(), 0, this, _thread_cap.dst()),
|
2011-12-22 16:19:25 +01:00
|
|
|
_utcb(0),
|
|
|
|
_platform_pd(0),
|
|
|
|
_pager(0)
|
|
|
|
{
|
|
|
|
/* register the thread capability */
|
|
|
|
Capability_tree::tree()->insert(&_node);
|
|
|
|
|
|
|
|
_create_thread();
|
|
|
|
|
|
|
|
/* create gate for new thread */
|
|
|
|
_gate_cap = Cap_session_component::alloc(0, _thread_cap);
|
|
|
|
|
|
|
|
_finalize_construction(name, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Platform_thread::~Platform_thread()
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We inform our protection domain about thread destruction, which will end up in
|
|
|
|
* Thread::unbind()
|
|
|
|
*/
|
|
|
|
if (_platform_pd)
|
|
|
|
_platform_pd->unbind_thread(this);
|
|
|
|
|
|
|
|
/* remove the thread capability */
|
|
|
|
Capability_tree::tree()->remove(&_node);
|
2012-03-09 12:25:11 +01:00
|
|
|
cap_alloc()->free(_thread_cap.dst());
|
2012-02-27 17:22:42 +01:00
|
|
|
Badge_allocator::allocator()->free(_badge);
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|