2013-10-07 15:37:58 +02:00
|
|
|
/*
|
|
|
|
* \brief Kernel backend for execution contexts in userland
|
|
|
|
* \author Martin Stein
|
hw: restrict processor broadcast to TLB flushing
Removes the generic processor broadcast function call. By now, that call
was used for cross processor TLB maintance operations only. When core/kernel
gets its memory mapped on demand, and unmapped again, the previous cross
processor flush routine doesn't work anymore, because of a hen-egg problem.
The previous cross processor broadcast is realized using a thread constructed
by core running on top of each processor core. When constructing threads in
core, a dataspace for its thread context is constructed. Each constructed
RAM dataspace gets attached, zeroed out, and detached again. The detach
routine requires a TLB flush operation executed on each processor core.
Instead of executing a thread on each processor core, now a thread waiting
for a global TLB flush is removed from the scheduler queue, and gets attached
to a TLB flush queue of each processor. The processor local queue gets checked
whenever the kernel is entered. The last processor, which executed the TLB
flush, re-attaches the blocked thread to its scheduler queue again.
To ease uo the above described mechanism, a platform thread is now directly
associated with a platform pd object, instead of just associate it with the
kernel pd's id.
Ref #723
2014-04-28 20:36:00 +02:00
|
|
|
* \author Stefan Kalkowski
|
2013-10-07 15:37:58 +02:00
|
|
|
* \date 2013-09-15
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (C) 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.
|
|
|
|
*/
|
|
|
|
|
2013-10-16 13:10:54 +02:00
|
|
|
/* Genode includes */
|
|
|
|
#include <base/thread_state.h>
|
|
|
|
|
2013-11-14 12:07:07 +01:00
|
|
|
/* base-hw includes */
|
|
|
|
#include <placement_new.h>
|
|
|
|
|
2013-10-07 15:37:58 +02:00
|
|
|
/* core includes */
|
2013-10-16 13:10:54 +02:00
|
|
|
#include <kernel/kernel.h>
|
2013-10-07 15:37:58 +02:00
|
|
|
#include <kernel/thread.h>
|
2013-10-16 13:10:54 +02:00
|
|
|
#include <kernel/vm.h>
|
2013-12-17 18:10:02 +01:00
|
|
|
#include <kernel/irq.h>
|
2013-10-07 15:37:58 +02:00
|
|
|
#include <platform_pd.h>
|
2013-12-17 18:10:02 +01:00
|
|
|
#include <pic.h>
|
2013-10-07 15:37:58 +02:00
|
|
|
|
|
|
|
using namespace Kernel;
|
|
|
|
|
2013-10-16 20:53:59 +02:00
|
|
|
typedef Genode::Thread_state Thread_state;
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
unsigned Thread::pd_id() const { return _pd ? _pd->id() : 0; }
|
2013-10-16 20:53:59 +02:00
|
|
|
|
hw: restrict processor broadcast to TLB flushing
Removes the generic processor broadcast function call. By now, that call
was used for cross processor TLB maintance operations only. When core/kernel
gets its memory mapped on demand, and unmapped again, the previous cross
processor flush routine doesn't work anymore, because of a hen-egg problem.
The previous cross processor broadcast is realized using a thread constructed
by core running on top of each processor core. When constructing threads in
core, a dataspace for its thread context is constructed. Each constructed
RAM dataspace gets attached, zeroed out, and detached again. The detach
routine requires a TLB flush operation executed on each processor core.
Instead of executing a thread on each processor core, now a thread waiting
for a global TLB flush is removed from the scheduler queue, and gets attached
to a TLB flush queue of each processor. The processor local queue gets checked
whenever the kernel is entered. The last processor, which executed the TLB
flush, re-attaches the blocked thread to its scheduler queue again.
To ease uo the above described mechanism, a platform thread is now directly
associated with a platform pd object, instead of just associate it with the
kernel pd's id.
Ref #723
2014-04-28 20:36:00 +02:00
|
|
|
bool Thread::_core() const { return pd_id() == core_pd()->id(); }
|
2013-10-16 20:53:59 +02:00
|
|
|
|
|
|
|
void Thread::_signal_context_kill_pending()
|
|
|
|
{
|
|
|
|
assert(_state == SCHEDULED);
|
2013-12-17 18:10:02 +01:00
|
|
|
_unschedule(AWAITS_SIGNAL_CONTEXT_KILL);
|
2013-10-16 20:53:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Thread::_signal_context_kill_done()
|
|
|
|
{
|
|
|
|
assert(_state == AWAITS_SIGNAL_CONTEXT_KILL);
|
|
|
|
user_arg_0(0);
|
|
|
|
_schedule();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-06 00:12:43 +01:00
|
|
|
void Thread::_signal_context_kill_failed()
|
|
|
|
{
|
|
|
|
assert(_state == AWAITS_SIGNAL_CONTEXT_KILL);
|
|
|
|
user_arg_0(-1);
|
|
|
|
_schedule();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-10-16 20:53:59 +02:00
|
|
|
void Thread::_await_signal(Signal_receiver * const receiver)
|
|
|
|
{
|
2013-12-17 18:10:02 +01:00
|
|
|
_unschedule(AWAITS_SIGNAL);
|
2013-10-16 20:53:59 +02:00
|
|
|
_signal_receiver = receiver;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Thread::_receive_signal(void * const base, size_t const size)
|
|
|
|
{
|
2013-11-18 12:47:14 +01:00
|
|
|
assert(_state == AWAITS_SIGNAL && size <= _utcb_phys->size());
|
|
|
|
Genode::memcpy(_utcb_phys->base(), base, size);
|
2013-10-16 20:53:59 +02:00
|
|
|
_schedule();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-04 13:41:04 +02:00
|
|
|
void Thread::_send_request_succeeded()
|
2013-10-16 20:53:59 +02:00
|
|
|
{
|
2014-04-04 13:41:04 +02:00
|
|
|
assert(_state == AWAITS_IPC);
|
|
|
|
user_arg_0(0);
|
|
|
|
_schedule();
|
2013-10-16 20:53:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-04 13:41:04 +02:00
|
|
|
void Thread::_send_request_failed()
|
2013-10-16 20:53:59 +02:00
|
|
|
{
|
2014-04-04 13:41:04 +02:00
|
|
|
assert(_state == AWAITS_IPC);
|
|
|
|
user_arg_0(-1);
|
|
|
|
_schedule();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Thread::_await_request_succeeded()
|
|
|
|
{
|
|
|
|
assert(_state == AWAITS_IPC);
|
|
|
|
user_arg_0(0);
|
|
|
|
_schedule();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Thread::_await_request_failed()
|
|
|
|
{
|
|
|
|
assert(_state == AWAITS_IPC);
|
|
|
|
user_arg_0(-1);
|
|
|
|
_schedule();
|
2013-10-16 20:53:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-17 12:12:04 +01:00
|
|
|
bool Thread::_resume()
|
2013-10-16 20:53:59 +02:00
|
|
|
{
|
|
|
|
switch (_state) {
|
|
|
|
case AWAITS_RESUME:
|
|
|
|
_schedule();
|
2014-03-17 12:12:04 +01:00
|
|
|
return true;
|
2013-10-16 20:53:59 +02:00
|
|
|
case AWAITS_IPC:
|
|
|
|
Ipc_node::cancel_waiting();
|
2014-03-17 12:12:04 +01:00
|
|
|
return true;
|
2013-10-16 20:53:59 +02:00
|
|
|
case AWAITS_SIGNAL:
|
|
|
|
Signal_handler::cancel_waiting();
|
2014-03-17 12:12:04 +01:00
|
|
|
return true;
|
2013-10-16 20:53:59 +02:00
|
|
|
case AWAITS_SIGNAL_CONTEXT_KILL:
|
|
|
|
Signal_context_killer::cancel_waiting();
|
2014-03-17 12:12:04 +01:00
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
2013-10-16 20:53:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Thread::_pause()
|
2013-10-07 15:37:58 +02:00
|
|
|
{
|
2013-10-16 20:53:59 +02:00
|
|
|
assert(_state == AWAITS_RESUME || _state == SCHEDULED);
|
2013-12-17 18:10:02 +01:00
|
|
|
_unschedule(AWAITS_RESUME);
|
2013-10-16 20:53:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Thread::_schedule()
|
|
|
|
{
|
2013-12-17 18:10:02 +01:00
|
|
|
if (_state == SCHEDULED) { return; }
|
2014-03-10 22:22:50 +01:00
|
|
|
Processor_client::_schedule();
|
2013-10-16 20:53:59 +02:00
|
|
|
_state = SCHEDULED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-17 18:10:02 +01:00
|
|
|
void Thread::_unschedule(State const s)
|
|
|
|
{
|
2014-03-10 22:22:50 +01:00
|
|
|
if (_state == SCHEDULED) { Processor_client::_unschedule(); }
|
2013-12-17 18:10:02 +01:00
|
|
|
_state = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-18 15:31:54 +01:00
|
|
|
Thread::Thread(unsigned const priority, char const * const label)
|
2013-10-16 20:53:59 +02:00
|
|
|
:
|
2014-03-10 22:22:50 +01:00
|
|
|
Processor_client(0, priority),
|
2013-11-14 15:14:41 +01:00
|
|
|
Thread_cpu_support(this),
|
|
|
|
_state(AWAITS_START),
|
|
|
|
_pd(0),
|
2013-11-18 12:47:14 +01:00
|
|
|
_utcb_phys(0),
|
2013-11-18 15:31:54 +01:00
|
|
|
_signal_receiver(0),
|
|
|
|
_label(label)
|
2013-12-18 16:18:16 +01:00
|
|
|
{
|
|
|
|
cpu_exception = RESET;
|
|
|
|
}
|
2013-10-07 15:37:58 +02:00
|
|
|
|
|
|
|
|
2014-03-16 18:25:37 +01:00
|
|
|
void Thread::init(Processor * const processor, Pd * const pd,
|
2013-11-18 12:47:14 +01:00
|
|
|
Native_utcb * const utcb_phys, bool const start)
|
2013-10-07 15:37:58 +02:00
|
|
|
{
|
2013-10-16 13:10:54 +02:00
|
|
|
assert(_state == AWAITS_START)
|
2013-10-07 15:37:58 +02:00
|
|
|
|
|
|
|
/* store thread parameters */
|
2014-04-09 12:14:38 +02:00
|
|
|
Processor_client::_processor = processor;
|
2013-11-18 12:47:14 +01:00
|
|
|
_utcb_phys = utcb_phys;
|
2013-10-07 15:37:58 +02:00
|
|
|
|
2013-10-16 20:53:59 +02:00
|
|
|
/* join protection domain */
|
2014-03-16 18:25:37 +01:00
|
|
|
_pd = pd;
|
2014-04-28 21:31:57 +02:00
|
|
|
User_context::init_thread((addr_t)_pd->translation_table(), pd_id());
|
2013-10-07 15:37:58 +02:00
|
|
|
|
|
|
|
/* print log message */
|
|
|
|
if (START_VERBOSE) {
|
2014-03-06 13:28:35 +01:00
|
|
|
Genode::printf("start thread %u '%s' in program %u '%s' ",
|
|
|
|
id(), label(), pd_id(), pd_label());
|
|
|
|
if (PROCESSORS) {
|
|
|
|
Genode::printf("on processor %u/%u ",
|
|
|
|
processor->id(), PROCESSORS);
|
|
|
|
}
|
|
|
|
Genode::printf("\n");
|
2013-10-07 15:37:58 +02:00
|
|
|
}
|
2013-10-16 20:53:59 +02:00
|
|
|
/* start execution */
|
|
|
|
if (start) { _schedule(); }
|
2013-10-07 15:37:58 +02:00
|
|
|
}
|
2013-11-11 16:55:30 +01:00
|
|
|
|
|
|
|
|
2013-12-17 18:10:02 +01:00
|
|
|
void Thread::_stop() { _unschedule(STOPPED); }
|
2013-10-16 20:53:59 +02:00
|
|
|
|
|
|
|
|
2014-02-28 15:49:24 +01:00
|
|
|
void Thread::exception(unsigned const processor_id)
|
2013-10-16 20:53:59 +02:00
|
|
|
{
|
|
|
|
switch (cpu_exception) {
|
|
|
|
case SUPERVISOR_CALL:
|
2014-03-26 11:00:01 +01:00
|
|
|
_call();
|
2013-10-16 20:53:59 +02:00
|
|
|
return;
|
|
|
|
case PREFETCH_ABORT:
|
|
|
|
_mmu_exception();
|
|
|
|
return;
|
|
|
|
case DATA_ABORT:
|
|
|
|
_mmu_exception();
|
|
|
|
return;
|
|
|
|
case INTERRUPT_REQUEST:
|
2014-02-28 14:46:21 +01:00
|
|
|
_interrupt(processor_id);
|
2013-10-16 20:53:59 +02:00
|
|
|
return;
|
|
|
|
case FAST_INTERRUPT_REQUEST:
|
2014-02-28 14:46:21 +01:00
|
|
|
_interrupt(processor_id);
|
2013-10-16 20:53:59 +02:00
|
|
|
return;
|
2014-04-09 12:14:38 +02:00
|
|
|
case UNDEFINED_INSTRUCTION:
|
|
|
|
if (_processor->retry_undefined_instr(&_lazy_state)) { return; }
|
|
|
|
PWRN("undefined instruction");
|
|
|
|
_stop();
|
|
|
|
return;
|
2013-12-18 16:18:16 +01:00
|
|
|
case RESET:
|
|
|
|
return;
|
2013-10-16 20:53:59 +02:00
|
|
|
default:
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("unknown exception");
|
2013-10-16 20:53:59 +02:00
|
|
|
_stop();
|
2014-04-09 12:14:38 +02:00
|
|
|
return;
|
2013-10-16 20:53:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Thread::_receive_yielded_cpu()
|
|
|
|
{
|
|
|
|
if (_state == AWAITS_RESUME) { _schedule(); }
|
2014-03-12 16:23:01 +01:00
|
|
|
else { PWRN("failed to receive yielded CPU"); }
|
2013-10-16 20:53:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-17 18:10:02 +01:00
|
|
|
void Thread::proceed(unsigned const processor_id)
|
2013-10-16 20:53:59 +02:00
|
|
|
{
|
2013-12-17 18:10:02 +01:00
|
|
|
mtc()->continue_user(this, processor_id);
|
2013-10-16 20:53:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char const * Kernel::Thread::pd_label() const
|
|
|
|
{
|
|
|
|
if (_core()) { return "core"; }
|
2013-11-14 15:14:41 +01:00
|
|
|
if (!_pd) { return "?"; }
|
|
|
|
return _pd->platform_pd()->label();
|
2013-10-16 13:10:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_new_pd()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
2014-04-28 21:31:57 +02:00
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
/* create protection domain */
|
|
|
|
void * p = (void *) user_arg_1();
|
|
|
|
Platform_pd * ppd = (Platform_pd *) user_arg_2();
|
|
|
|
Translation_table * tt = ppd->translation_table_phys();
|
|
|
|
Pd * const pd = new (p) Pd(tt, ppd);
|
2013-10-16 13:10:54 +02:00
|
|
|
user_arg_0(pd->id());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-05 16:12:48 +01:00
|
|
|
void Thread::_call_bin_pd()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
|
|
|
/* lookup protection domain */
|
|
|
|
unsigned id = user_arg_1();
|
|
|
|
Pd * const pd = Pd::pool()->object(id);
|
|
|
|
if (!pd) {
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("unknown protection domain");
|
2013-10-16 13:10:54 +02:00
|
|
|
user_arg_0(-1);
|
|
|
|
return;
|
|
|
|
}
|
2014-04-28 21:31:57 +02:00
|
|
|
/* destruct protection domain */
|
2013-10-16 13:10:54 +02:00
|
|
|
pd->~Pd();
|
|
|
|
|
|
|
|
/* clean up buffers of memory management */
|
2014-03-03 00:12:53 +01:00
|
|
|
Processor::flush_tlb_by_pid(pd->id());
|
2013-10-16 13:10:54 +02:00
|
|
|
user_arg_0(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_new_thread()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
2013-11-18 15:31:54 +01:00
|
|
|
/* create new thread */
|
|
|
|
void * const p = (void *)user_arg_1();
|
|
|
|
unsigned const priority = user_arg_2();
|
|
|
|
char const * const label = (char *)user_arg_3();
|
|
|
|
Thread * const t = new (p) Thread(priority, label);
|
|
|
|
user_arg_0(t->id());
|
2013-10-16 13:10:54 +02:00
|
|
|
}
|
|
|
|
|
2013-11-14 17:29:34 +01:00
|
|
|
|
2013-12-05 16:12:48 +01:00
|
|
|
void Thread::_call_bin_thread()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
2014-03-17 00:54:00 +01:00
|
|
|
/* lookup thread */
|
|
|
|
Thread * const thread = Thread::pool()->object(user_arg_1());
|
|
|
|
if (!thread) {
|
|
|
|
PWRN("failed to lookup thread");
|
|
|
|
return;
|
|
|
|
}
|
2013-10-16 13:10:54 +02:00
|
|
|
/* destroy thread */
|
|
|
|
thread->~Thread();
|
|
|
|
}
|
|
|
|
|
2013-11-14 17:29:34 +01:00
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_start_thread()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
2014-03-16 18:25:37 +01:00
|
|
|
/* lookup thread */
|
2014-03-06 13:24:36 +01:00
|
|
|
unsigned const thread_id = user_arg_1();
|
|
|
|
Thread * const thread = Thread::pool()->object(thread_id);
|
|
|
|
if (!thread) {
|
2014-03-16 18:25:37 +01:00
|
|
|
PWRN("failed to lookup thread");
|
2013-11-18 12:47:14 +01:00
|
|
|
user_arg_0(0);
|
|
|
|
return;
|
|
|
|
}
|
2014-03-16 18:25:37 +01:00
|
|
|
/* lookup processor */
|
2014-03-06 13:24:36 +01:00
|
|
|
unsigned const processor_id = user_arg_2();
|
2014-03-11 01:21:56 +01:00
|
|
|
Processor * const processor = processor_pool()->processor(processor_id);
|
2014-03-06 13:24:36 +01:00
|
|
|
if (!processor) {
|
2014-03-16 18:25:37 +01:00
|
|
|
PWRN("failed to lookup processor");
|
2014-03-06 13:24:36 +01:00
|
|
|
user_arg_0(0);
|
|
|
|
return;
|
|
|
|
}
|
2014-03-16 18:25:37 +01:00
|
|
|
/* lookup domain */
|
2014-03-06 13:24:36 +01:00
|
|
|
unsigned const pd_id = user_arg_3();
|
2014-03-16 18:25:37 +01:00
|
|
|
Pd * const pd = Pd::pool()->object(pd_id);
|
|
|
|
if (!pd) {
|
|
|
|
PWRN("failed to lookup domain");
|
|
|
|
user_arg_0(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* start thread */
|
2014-03-06 13:24:36 +01:00
|
|
|
Native_utcb * const utcb = (Native_utcb *)user_arg_4();
|
2014-03-16 18:25:37 +01:00
|
|
|
thread->init(processor, pd, utcb, 1);
|
2014-04-28 21:31:57 +02:00
|
|
|
user_arg_0((Call_ret)thread->_pd->translation_table());
|
2013-10-16 13:10:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-16 16:00:55 +01:00
|
|
|
void Thread::_call_pause_current_thread() { _pause(); }
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_pause_thread()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
2014-03-16 15:33:45 +01:00
|
|
|
/* lookup thread */
|
2014-03-16 16:00:55 +01:00
|
|
|
Thread * const thread = Thread::pool()->object(user_arg_1());
|
2014-03-16 15:33:45 +01:00
|
|
|
if (!thread) {
|
|
|
|
PWRN("failed to lookup thread");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* pause thread */
|
|
|
|
thread->_pause();
|
2013-10-16 13:10:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_resume_thread()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
|
|
|
/* lookup thread */
|
2014-03-17 12:12:04 +01:00
|
|
|
Thread * const thread = Thread::pool()->object(user_arg_1());
|
|
|
|
if (!thread) {
|
|
|
|
PWRN("failed to lookup thread");
|
|
|
|
user_arg_0(false);
|
2013-10-16 13:10:54 +02:00
|
|
|
return;
|
|
|
|
}
|
2014-03-25 16:34:20 +01:00
|
|
|
/* resume thread */
|
|
|
|
user_arg_0(thread->_resume());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Thread::_call_resume_local_thread()
|
|
|
|
{
|
|
|
|
/* lookup thread */
|
|
|
|
Thread * const thread = Thread::pool()->object(user_arg_1());
|
|
|
|
if (!thread || pd_id() != thread->pd_id()) {
|
|
|
|
PWRN("failed to lookup thread");
|
|
|
|
user_arg_0(0);
|
2013-10-16 13:10:54 +02:00
|
|
|
return;
|
|
|
|
}
|
2014-03-17 12:12:04 +01:00
|
|
|
/* resume thread */
|
|
|
|
user_arg_0(thread->_resume());
|
2013-10-16 13:10:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread_event::_signal_acknowledged()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
2014-03-03 00:12:53 +01:00
|
|
|
Processor::tlb_insertions();
|
2013-11-14 15:14:41 +01:00
|
|
|
_thread->_resume();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Thread_event::Thread_event(Thread * const t)
|
|
|
|
:
|
|
|
|
_thread(t), _signal_context(0)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
void Thread_event::submit()
|
|
|
|
{
|
|
|
|
if (_signal_context && !_signal_context->submit(1)) { return; }
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("failed to communicate thread event");
|
2013-10-16 13:10:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_yield_thread()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
|
|
|
Thread * const t = Thread::pool()->object(user_arg_1());
|
2013-10-16 20:53:59 +02:00
|
|
|
if (t) { t->_receive_yielded_cpu(); }
|
2014-03-10 22:22:50 +01:00
|
|
|
Processor_client::_yield();
|
2013-10-16 13:10:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-21 11:35:33 +01:00
|
|
|
void Thread::_call_await_request_msg()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
2013-10-18 17:01:51 +02:00
|
|
|
void * buf_base;
|
|
|
|
size_t buf_size;
|
2014-03-27 14:07:48 +01:00
|
|
|
_utcb_phys->message()->buffer_info(buf_base, buf_size);
|
2014-03-27 12:28:53 +01:00
|
|
|
if (Ipc_node::await_request(buf_base, buf_size)) {
|
|
|
|
user_arg_0(0);
|
|
|
|
return;
|
|
|
|
}
|
2014-03-27 12:20:55 +01:00
|
|
|
_unschedule(AWAITS_IPC);
|
2013-10-16 13:10:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-21 11:35:33 +01:00
|
|
|
void Thread::_call_send_request_msg()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
2013-10-17 00:41:14 +02:00
|
|
|
Thread * const dst = Thread::pool()->object(user_arg_1());
|
|
|
|
if (!dst) {
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("unknown recipient");
|
2014-03-27 12:20:55 +01:00
|
|
|
_unschedule(AWAITS_IPC);
|
2013-10-17 00:41:14 +02:00
|
|
|
return;
|
|
|
|
}
|
2013-10-18 17:01:51 +02:00
|
|
|
void * buf_base;
|
2014-03-27 14:23:49 +01:00
|
|
|
size_t buf_size, msg_size;
|
|
|
|
_utcb_phys->message()->request_info(buf_base, buf_size, msg_size);
|
|
|
|
Ipc_node::send_request(dst, buf_base, buf_size, msg_size);
|
2014-03-27 12:20:55 +01:00
|
|
|
_unschedule(AWAITS_IPC);
|
2013-10-16 13:10:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-21 11:35:33 +01:00
|
|
|
void Thread::_call_send_reply_msg()
|
2013-10-16 20:53:59 +02:00
|
|
|
{
|
2013-10-18 17:01:51 +02:00
|
|
|
void * msg_base;
|
|
|
|
size_t msg_size;
|
2014-03-27 14:07:48 +01:00
|
|
|
_utcb_phys->message()->reply_info(msg_base, msg_size);
|
2013-10-17 13:51:17 +02:00
|
|
|
Ipc_node::send_reply(msg_base, msg_size);
|
2013-11-21 11:35:33 +01:00
|
|
|
bool const await_request_msg = user_arg_1();
|
|
|
|
if (await_request_msg) { _call_await_request_msg(); }
|
2013-11-21 12:04:21 +01:00
|
|
|
else { user_arg_0(0); }
|
2013-11-14 15:14:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Thread::_call_route_thread_event()
|
|
|
|
{
|
|
|
|
/* get targeted thread */
|
|
|
|
unsigned const thread_id = user_arg_1();
|
|
|
|
Thread * const t = Thread::pool()->object(thread_id);
|
|
|
|
if (!t) {
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("unknown thread");
|
2013-11-14 15:14:41 +01:00
|
|
|
user_arg_0(-1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* override event route */
|
|
|
|
unsigned const event_id = user_arg_2();
|
|
|
|
unsigned const signal_context_id = user_arg_3();
|
|
|
|
if (t->_route_event(event_id, signal_context_id)) { user_arg_0(-1); }
|
|
|
|
else { user_arg_0(0); }
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int Thread::_route_event(unsigned const event_id,
|
|
|
|
unsigned const signal_context_id)
|
|
|
|
{
|
|
|
|
/* lookup signal context */
|
|
|
|
Signal_context * c;
|
|
|
|
if (signal_context_id) {
|
|
|
|
c = Signal_context::pool()->object(signal_context_id);
|
|
|
|
if (!c) {
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("unknown signal context");
|
2013-11-14 15:14:41 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else { c = 0; }
|
|
|
|
|
|
|
|
/* lookup event and assign signal context */
|
|
|
|
Thread_event Thread::* e = _event(event_id);
|
|
|
|
if (!e) { return -1; }
|
|
|
|
(this->*e).signal_context(c);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Thread_event::signal_context(Signal_context * const c)
|
|
|
|
{
|
|
|
|
_signal_context = c;
|
|
|
|
if (_signal_context) { _signal_context->ack_handler(this); }
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
unsigned Thread_event::signal_context_id() const
|
|
|
|
{
|
|
|
|
if (_signal_context) { return _signal_context->id(); }
|
|
|
|
return 0;
|
2013-10-16 20:53:59 +02:00
|
|
|
}
|
2013-10-16 13:10:54 +02:00
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_access_thread_regs()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
2013-11-14 15:14:41 +01:00
|
|
|
/* get targeted thread */
|
|
|
|
unsigned const thread_id = user_arg_1();
|
2014-03-25 17:23:33 +01:00
|
|
|
unsigned const reads = user_arg_2();
|
|
|
|
unsigned const writes = user_arg_3();
|
2013-11-14 15:14:41 +01:00
|
|
|
Thread * const t = Thread::pool()->object(thread_id);
|
|
|
|
if (!t) {
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("unknown thread");
|
2014-03-16 11:41:51 +01:00
|
|
|
user_arg_0(reads + writes);
|
2013-10-16 13:10:54 +02:00
|
|
|
return;
|
|
|
|
}
|
2013-11-14 15:14:41 +01:00
|
|
|
/* execute read operations */
|
2013-11-18 12:47:14 +01:00
|
|
|
addr_t * const utcb = (addr_t *)_utcb_phys->base();
|
2013-11-14 15:14:41 +01:00
|
|
|
addr_t * const read_ids = &utcb[0];
|
2014-03-16 11:57:01 +01:00
|
|
|
addr_t * values = (addr_t *)user_arg_4();
|
2013-11-14 15:14:41 +01:00
|
|
|
for (unsigned i = 0; i < reads; i++) {
|
2014-03-16 11:57:01 +01:00
|
|
|
if (t->_read_reg(read_ids[i], *values)) {
|
2013-11-14 15:14:41 +01:00
|
|
|
user_arg_0(reads + writes - i);
|
|
|
|
return;
|
|
|
|
}
|
2014-03-16 11:57:01 +01:00
|
|
|
values++;
|
2013-11-14 15:14:41 +01:00
|
|
|
}
|
|
|
|
/* execute write operations */
|
|
|
|
addr_t * const write_ids = &utcb[reads];
|
|
|
|
for (unsigned i = 0; i < writes; i++) {
|
2014-03-16 11:57:01 +01:00
|
|
|
if (t->_write_reg(write_ids[i], *values)) {
|
2013-11-14 15:14:41 +01:00
|
|
|
user_arg_0(writes - i);
|
|
|
|
return;
|
|
|
|
}
|
2014-03-16 11:57:01 +01:00
|
|
|
values++;
|
2013-11-14 15:14:41 +01:00
|
|
|
}
|
|
|
|
user_arg_0(0);
|
|
|
|
return;
|
2013-10-16 13:10:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_update_pd()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
2014-05-02 18:14:51 +02:00
|
|
|
if (Processor_domain_update::_perform(user_arg_1())) { _pause(); }
|
2013-10-16 13:10:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-07 15:45:44 +02:00
|
|
|
void Thread::_call_update_data_region()
|
2013-11-11 16:55:30 +01:00
|
|
|
{
|
2014-04-17 12:42:39 +02:00
|
|
|
/*
|
|
|
|
* FIXME: If the caller is not a core thread, the kernel operates in a
|
|
|
|
* different address space than the caller. Combined with the fact
|
|
|
|
* that at least ARMv7 doesn't provide cache operations by physical
|
|
|
|
* address, this prevents us from selectively maintaining caches.
|
|
|
|
* The future solution will be a kernel that is mapped to every
|
|
|
|
* address space so we can use virtual addresses of the caller. Up
|
|
|
|
* until then we apply operations to caches as a whole instead.
|
|
|
|
*/
|
|
|
|
if (!_core()) {
|
|
|
|
Processor::flush_data_caches();
|
|
|
|
return;
|
|
|
|
}
|
2014-04-07 15:52:21 +02:00
|
|
|
auto base = (addr_t)user_arg_1();
|
|
|
|
auto const size = (size_t)user_arg_2();
|
|
|
|
Processor::flush_data_caches_by_virt_region(base, size);
|
2013-10-16 13:10:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-07 16:18:43 +02:00
|
|
|
void Thread::_call_update_instr_region()
|
|
|
|
{
|
2014-04-17 12:42:39 +02:00
|
|
|
/*
|
|
|
|
* FIXME: If the caller is not a core thread, the kernel operates in a
|
|
|
|
* different address space than the caller. Combined with the fact
|
|
|
|
* that at least ARMv7 doesn't provide cache operations by physical
|
|
|
|
* address, this prevents us from selectively maintaining caches.
|
|
|
|
* The future solution will be a kernel that is mapped to every
|
|
|
|
* address space so we can use virtual addresses of the caller. Up
|
|
|
|
* until then we apply operations to caches as a whole instead.
|
|
|
|
*/
|
|
|
|
if (!_core()) {
|
|
|
|
Processor::flush_data_caches();
|
|
|
|
Processor::invalidate_instr_caches();
|
|
|
|
return;
|
|
|
|
}
|
2014-04-07 16:18:43 +02:00
|
|
|
auto base = (addr_t)user_arg_1();
|
|
|
|
auto const size = (size_t)user_arg_2();
|
|
|
|
Processor::flush_data_caches_by_virt_region(base, size);
|
|
|
|
Processor::invalidate_instr_caches_by_virt_region(base, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-28 00:45:48 +01:00
|
|
|
void Thread::_print_activity_table()
|
|
|
|
{
|
|
|
|
for (unsigned id = 0; id < MAX_THREADS; id++) {
|
|
|
|
Thread * const t = Thread::pool()->object(id);
|
|
|
|
if (!t) { continue; }
|
2013-12-09 16:41:23 +01:00
|
|
|
t->_print_activity(t == this);
|
2013-11-28 00:45:48 +01:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-09 16:41:23 +01:00
|
|
|
void Thread::_print_activity(bool const printing_thread)
|
2013-11-28 00:45:48 +01:00
|
|
|
{
|
|
|
|
Genode::printf("\033[33m[%u] %s", pd_id(), pd_label());
|
2013-12-06 19:12:06 +01:00
|
|
|
Genode::printf(" (%u) %s:\033[0m", id(), label());
|
2013-11-28 00:45:48 +01:00
|
|
|
switch (_state) {
|
|
|
|
case AWAITS_START: {
|
|
|
|
Genode::printf("\033[32m init\033[0m");
|
|
|
|
break; }
|
|
|
|
case SCHEDULED: {
|
2013-12-09 16:41:23 +01:00
|
|
|
if (!printing_thread) { Genode::printf("\033[32m run\033[0m"); }
|
|
|
|
else { Genode::printf("\033[32m debug\033[0m"); }
|
2013-11-28 00:45:48 +01:00
|
|
|
break; }
|
|
|
|
case AWAITS_IPC: {
|
|
|
|
_print_activity_when_awaits_ipc();
|
|
|
|
break; }
|
|
|
|
case AWAITS_RESUME: {
|
2013-12-06 19:12:06 +01:00
|
|
|
Genode::printf("\033[32m await RES\033[0m");
|
2013-11-28 00:45:48 +01:00
|
|
|
break; }
|
|
|
|
case AWAITS_SIGNAL: {
|
|
|
|
unsigned const receiver_id = Signal_handler::receiver()->id();
|
|
|
|
Genode::printf("\033[32m await SIG %u\033[0m", receiver_id);
|
|
|
|
break; }
|
|
|
|
case AWAITS_SIGNAL_CONTEXT_KILL: {
|
2013-12-06 12:04:48 +01:00
|
|
|
unsigned const context_id = Signal_context_killer::context()->id();
|
2013-11-28 00:45:48 +01:00
|
|
|
Genode::printf("\033[32m await SCK %u\033[0m", context_id);
|
|
|
|
break; }
|
|
|
|
case STOPPED: {
|
|
|
|
Genode::printf("\033[32m stop\033[0m");
|
|
|
|
break; }
|
|
|
|
}
|
|
|
|
_print_common_activity();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Thread::_print_common_activity()
|
|
|
|
{
|
|
|
|
Genode::printf(" ip %lx sp %lx\n", ip, sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Thread::_print_activity_when_awaits_ipc()
|
|
|
|
{
|
|
|
|
switch (Ipc_node::state()) {
|
|
|
|
case AWAIT_REPLY: {
|
|
|
|
Thread * const server = dynamic_cast<Thread *>(Ipc_node::outbuf_dst());
|
|
|
|
Genode::printf("\033[32m await RPL %u\033[0m", server->id());
|
|
|
|
break; }
|
|
|
|
case AWAIT_REQUEST: {
|
|
|
|
Genode::printf("\033[32m await REQ\033[0m");
|
|
|
|
break; }
|
|
|
|
case PREPARE_AND_AWAIT_REPLY: {
|
|
|
|
Thread * const server = dynamic_cast<Thread *>(Ipc_node::outbuf_dst());
|
|
|
|
Genode::printf("\033[32m prep RPL await RPL %u\033[0m", server->id());
|
|
|
|
break; }
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_print_char()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
2013-11-28 00:45:48 +01:00
|
|
|
char const c = user_arg_1();
|
|
|
|
if (!c) { _print_activity_table(); }
|
2013-10-16 13:10:54 +02:00
|
|
|
Genode::printf("%c", (char)user_arg_1());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_new_signal_receiver()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
|
|
|
/* create receiver */
|
2013-10-30 13:56:57 +01:00
|
|
|
void * const p = (void *)user_arg_1();
|
2013-10-16 13:10:54 +02:00
|
|
|
Signal_receiver * const r = new (p) Signal_receiver();
|
|
|
|
user_arg_0(r->id());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_new_signal_context()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
|
|
|
/* lookup receiver */
|
2013-10-30 13:56:57 +01:00
|
|
|
unsigned const id = user_arg_2();
|
2013-10-16 13:10:54 +02:00
|
|
|
Signal_receiver * const r = Signal_receiver::pool()->object(id);
|
|
|
|
if (!r) {
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("unknown signal receiver");
|
2013-10-16 13:10:54 +02:00
|
|
|
user_arg_0(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* create and assign context*/
|
2013-10-30 13:56:57 +01:00
|
|
|
void * const p = (void *)user_arg_1();
|
|
|
|
unsigned const imprint = user_arg_3();
|
2013-12-06 11:53:08 +01:00
|
|
|
Signal_context * const c = new (p) Signal_context(r, imprint);
|
|
|
|
user_arg_0(c->id());
|
2013-10-16 13:10:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_await_signal()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
2013-10-30 13:56:57 +01:00
|
|
|
/* check wether to acknowledge a context */
|
|
|
|
unsigned const context_id = user_arg_2();
|
|
|
|
if (context_id) {
|
|
|
|
Signal_context * const c = Signal_context::pool()->object(context_id);
|
|
|
|
if (c) { c->ack(); }
|
2014-03-12 16:23:01 +01:00
|
|
|
else { PWRN("failed to acknowledge signal context"); }
|
2013-10-30 13:56:57 +01:00
|
|
|
}
|
2013-10-16 13:10:54 +02:00
|
|
|
/* lookup receiver */
|
2013-10-30 13:56:57 +01:00
|
|
|
unsigned const receiver_id = user_arg_1();
|
|
|
|
Signal_receiver * const r = Signal_receiver::pool()->object(receiver_id);
|
2013-10-16 13:10:54 +02:00
|
|
|
if (!r) {
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("unknown signal receiver");
|
2013-10-16 13:10:54 +02:00
|
|
|
user_arg_0(-1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* register handler at the receiver */
|
|
|
|
if (r->add_handler(this)) {
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("failed to register handler at signal receiver");
|
2013-10-16 13:10:54 +02:00
|
|
|
user_arg_0(-1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
user_arg_0(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_signal_pending()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
|
|
|
/* lookup signal receiver */
|
2013-10-30 13:56:57 +01:00
|
|
|
unsigned const id = user_arg_1();
|
2013-10-16 13:10:54 +02:00
|
|
|
Signal_receiver * const r = Signal_receiver::pool()->object(id);
|
|
|
|
if (!r) {
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("unknown signal receiver");
|
2013-10-16 13:10:54 +02:00
|
|
|
user_arg_0(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* get pending state */
|
|
|
|
user_arg_0(r->deliverable());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_submit_signal()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
|
|
|
/* lookup signal context */
|
|
|
|
unsigned const id = user_arg_1();
|
|
|
|
Signal_context * const c = Signal_context::pool()->object(id);
|
|
|
|
if(!c) {
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("unknown signal context");
|
2013-10-16 13:10:54 +02:00
|
|
|
user_arg_0(-1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* trigger signal context */
|
|
|
|
if (c->submit(user_arg_2())) {
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("failed to submit signal context");
|
2013-10-16 13:10:54 +02:00
|
|
|
user_arg_0(-1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
user_arg_0(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_ack_signal()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
|
|
|
/* lookup signal context */
|
2013-10-30 13:56:57 +01:00
|
|
|
unsigned const id = user_arg_1();
|
2013-10-16 13:10:54 +02:00
|
|
|
Signal_context * const c = Signal_context::pool()->object(id);
|
|
|
|
if (!c) {
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("unknown signal context");
|
2013-10-16 13:10:54 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* acknowledge */
|
|
|
|
c->ack();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-06 00:12:43 +01:00
|
|
|
void Thread::_call_kill_signal_context()
|
|
|
|
{
|
|
|
|
/* lookup signal context */
|
|
|
|
unsigned const id = user_arg_1();
|
|
|
|
Signal_context * const c = Signal_context::pool()->object(id);
|
|
|
|
if (!c) {
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("unknown signal context");
|
2013-12-06 00:12:43 +01:00
|
|
|
user_arg_0(-1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* kill signal context */
|
|
|
|
if (c->kill(this)) {
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("failed to kill signal context");
|
2013-12-06 00:12:43 +01:00
|
|
|
user_arg_0(-1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-05 16:12:48 +01:00
|
|
|
void Thread::_call_bin_signal_context()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
|
|
|
/* lookup signal context */
|
2013-10-30 13:56:57 +01:00
|
|
|
unsigned const id = user_arg_1();
|
2013-10-16 13:10:54 +02:00
|
|
|
Signal_context * const c = Signal_context::pool()->object(id);
|
|
|
|
if (!c) {
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("unknown signal context");
|
2013-10-16 13:10:54 +02:00
|
|
|
user_arg_0(0);
|
|
|
|
return;
|
|
|
|
}
|
2013-12-06 00:12:43 +01:00
|
|
|
/* destruct signal context */
|
|
|
|
c->~Signal_context();
|
2013-10-16 13:10:54 +02:00
|
|
|
user_arg_0(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-05 16:12:48 +01:00
|
|
|
void Thread::_call_bin_signal_receiver()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
|
|
|
/* lookup signal receiver */
|
2013-10-30 13:56:57 +01:00
|
|
|
unsigned const id = user_arg_1();
|
2013-10-16 13:10:54 +02:00
|
|
|
Signal_receiver * const r = Signal_receiver::pool()->object(id);
|
|
|
|
if (!r) {
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("unknown signal receiver");
|
2013-10-16 13:10:54 +02:00
|
|
|
user_arg_0(0);
|
|
|
|
return;
|
|
|
|
}
|
2013-12-06 11:53:08 +01:00
|
|
|
r->~Signal_receiver();
|
2013-10-16 13:10:54 +02:00
|
|
|
user_arg_0(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_new_vm()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
2014-03-17 01:42:34 +01:00
|
|
|
/* lookup signal context */
|
|
|
|
auto const context = Signal_context::pool()->object(user_arg_3());
|
|
|
|
if (!context) {
|
|
|
|
PWRN("failed to lookup signal context");
|
|
|
|
user_arg_0(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* create virtual machine */
|
|
|
|
typedef Genode::Cpu_state_modes Cpu_state_modes;
|
|
|
|
auto const allocator = reinterpret_cast<void *>(user_arg_1());
|
|
|
|
auto const state = reinterpret_cast<Cpu_state_modes *>(user_arg_2());
|
2013-10-16 13:10:54 +02:00
|
|
|
Vm * const vm = new (allocator) Vm(state, context);
|
|
|
|
|
2014-03-17 01:42:34 +01:00
|
|
|
/* return kernel name of virtual machine */
|
|
|
|
user_arg_0(vm->id());
|
2013-10-16 13:10:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_run_vm()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
2014-03-17 01:48:24 +01:00
|
|
|
/* lookup virtual machine */
|
2013-10-16 13:10:54 +02:00
|
|
|
Vm * const vm = Vm::pool()->object(user_arg_1());
|
2014-03-17 01:48:24 +01:00
|
|
|
if (!vm) {
|
|
|
|
PWRN("failed to lookup virtual machine");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* run virtual machine */
|
2013-10-16 13:10:54 +02:00
|
|
|
vm->run();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_pause_vm()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
2014-03-17 01:55:19 +01:00
|
|
|
/* lookup virtual machine */
|
2013-10-16 13:10:54 +02:00
|
|
|
Vm * const vm = Vm::pool()->object(user_arg_1());
|
2014-03-17 01:55:19 +01:00
|
|
|
if (!vm) {
|
|
|
|
PWRN("failed to lookup virtual machine");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* pause virtual machine */
|
2013-10-16 13:10:54 +02:00
|
|
|
vm->pause();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
int Thread::_read_reg(addr_t const id, addr_t & value) const
|
|
|
|
{
|
|
|
|
addr_t Thread::* const reg = _reg(id);
|
|
|
|
if (reg) {
|
|
|
|
value = this->*reg;
|
|
|
|
return 0;
|
|
|
|
}
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("unknown thread register");
|
2013-11-14 15:14:41 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int Thread::_write_reg(addr_t const id, addr_t const value)
|
|
|
|
{
|
|
|
|
addr_t Thread::* const reg = _reg(id);
|
|
|
|
if (reg) {
|
|
|
|
this->*reg = value;
|
|
|
|
return 0;
|
|
|
|
}
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("unknown thread register");
|
2013-11-14 15:14:41 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-26 11:00:01 +01:00
|
|
|
void Thread::_call()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
2014-03-25 17:23:33 +01:00
|
|
|
/* switch over unrestricted kernel calls */
|
|
|
|
unsigned const call_id = user_arg_0();
|
|
|
|
switch (call_id) {
|
2014-04-07 15:52:21 +02:00
|
|
|
case call_id_update_data_region(): _call_update_data_region(); return;
|
2014-04-07 16:18:43 +02:00
|
|
|
case call_id_update_instr_region(): _call_update_instr_region(); return;
|
2014-03-16 16:00:55 +01:00
|
|
|
case call_id_pause_current_thread(): _call_pause_current_thread(); return;
|
2014-03-25 16:34:20 +01:00
|
|
|
case call_id_resume_local_thread(): _call_resume_local_thread(); return;
|
2014-03-15 01:26:53 +01:00
|
|
|
case call_id_yield_thread(): _call_yield_thread(); return;
|
|
|
|
case call_id_send_request_msg(): _call_send_request_msg(); return;
|
|
|
|
case call_id_send_reply_msg(): _call_send_reply_msg(); return;
|
|
|
|
case call_id_await_request_msg(): _call_await_request_msg(); return;
|
|
|
|
case call_id_kill_signal_context(): _call_kill_signal_context(); return;
|
|
|
|
case call_id_submit_signal(): _call_submit_signal(); return;
|
2014-03-25 17:23:33 +01:00
|
|
|
case call_id_await_signal(): _call_await_signal(); return;
|
2014-03-15 01:26:53 +01:00
|
|
|
case call_id_signal_pending(): _call_signal_pending(); return;
|
|
|
|
case call_id_ack_signal(): _call_ack_signal(); return;
|
2014-03-25 17:23:33 +01:00
|
|
|
case call_id_print_char(): _call_print_char(); return;
|
|
|
|
default:
|
|
|
|
/* check wether this is a core thread */
|
|
|
|
if (!_core()) {
|
|
|
|
PWRN("not entitled to do kernel call");
|
|
|
|
_stop();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* switch over kernel calls that are restricted to core */
|
|
|
|
switch (call_id) {
|
|
|
|
case call_id_new_thread(): _call_new_thread(); return;
|
|
|
|
case call_id_bin_thread(): _call_bin_thread(); return;
|
|
|
|
case call_id_start_thread(): _call_start_thread(); return;
|
|
|
|
case call_id_resume_thread(): _call_resume_thread(); return;
|
|
|
|
case call_id_access_thread_regs(): _call_access_thread_regs(); return;
|
|
|
|
case call_id_route_thread_event(): _call_route_thread_event(); return;
|
|
|
|
case call_id_update_pd(): _call_update_pd(); return;
|
|
|
|
case call_id_new_pd(): _call_new_pd(); return;
|
|
|
|
case call_id_bin_pd(): _call_bin_pd(); return;
|
|
|
|
case call_id_new_signal_receiver(): _call_new_signal_receiver(); return;
|
|
|
|
case call_id_new_signal_context(): _call_new_signal_context(); return;
|
|
|
|
case call_id_bin_signal_context(): _call_bin_signal_context(); return;
|
|
|
|
case call_id_bin_signal_receiver(): _call_bin_signal_receiver(); return;
|
|
|
|
case call_id_new_vm(): _call_new_vm(); return;
|
|
|
|
case call_id_run_vm(): _call_run_vm(); return;
|
|
|
|
case call_id_pause_vm(): _call_pause_vm(); return;
|
|
|
|
case call_id_pause_thread(): _call_pause_thread(); return;
|
2013-10-16 13:10:54 +02:00
|
|
|
default:
|
2014-03-12 16:23:01 +01:00
|
|
|
PWRN("unknown kernel call");
|
2013-10-16 20:53:59 +02:00
|
|
|
_stop();
|
2014-03-25 17:23:33 +01:00
|
|
|
return;
|
2013-10-16 13:10:54 +02:00
|
|
|
}
|
2013-11-11 16:55:30 +01:00
|
|
|
}
|