2013-10-07 15:37:58 +02:00
|
|
|
/*
|
2015-08-24 15:35:54 +02:00
|
|
|
* \brief Kernel back-end for execution contexts in userland
|
2013-10-07 15:37:58 +02:00
|
|
|
* \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>
|
2015-03-27 14:05:55 +01:00
|
|
|
#include <cpu_session/cpu_session.h>
|
2015-05-19 14:18:40 +02:00
|
|
|
#include <util/construct_at.h>
|
2013-11-14 12:07:07 +01:00
|
|
|
|
2016-01-20 18:27:18 +01:00
|
|
|
/* base-internal includes */
|
|
|
|
#include <base/internal/unmanaged_singleton.h>
|
2016-03-08 16:59:43 +01:00
|
|
|
#include <base/internal/native_utcb.h>
|
2016-01-20 18:27:18 +01:00
|
|
|
|
2013-10-07 15:37:58 +02:00
|
|
|
/* core includes */
|
2015-06-16 10:59:26 +02:00
|
|
|
#include <assert.h>
|
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-12-17 18:10:02 +01:00
|
|
|
#include <kernel/irq.h>
|
2015-05-19 14:18:40 +02:00
|
|
|
#include <map_local.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
|
|
|
|
2015-05-19 14:18:40 +02:00
|
|
|
extern "C" void _core_start(void);
|
|
|
|
|
2013-10-07 15:37:58 +02:00
|
|
|
using namespace Kernel;
|
|
|
|
|
2013-10-16 20:53:59 +02:00
|
|
|
|
2015-04-01 10:23:38 +02:00
|
|
|
bool Thread::_core() const { return pd() == core_pd(); }
|
2013-10-16 20:53:59 +02:00
|
|
|
|
|
|
|
void Thread::_signal_context_kill_pending()
|
|
|
|
{
|
2014-11-18 15:38:15 +01:00
|
|
|
assert(_state == ACTIVE);
|
|
|
|
_become_inactive(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);
|
2014-11-18 15:38:15 +01:00
|
|
|
_become_active();
|
2013-10-16 20:53:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-06 00:12:43 +01:00
|
|
|
void Thread::_signal_context_kill_failed()
|
|
|
|
{
|
|
|
|
assert(_state == AWAITS_SIGNAL_CONTEXT_KILL);
|
|
|
|
user_arg_0(-1);
|
2014-11-18 15:38:15 +01:00
|
|
|
_become_active();
|
2013-12-06 00:12:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-10-16 20:53:59 +02:00
|
|
|
void Thread::_await_signal(Signal_receiver * const receiver)
|
|
|
|
{
|
2014-11-18 15:38:15 +01:00
|
|
|
_become_inactive(AWAITS_SIGNAL);
|
2013-10-16 20:53:59 +02:00
|
|
|
_signal_receiver = receiver;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Thread::_receive_signal(void * const base, size_t const size)
|
|
|
|
{
|
2015-05-19 14:18:40 +02:00
|
|
|
assert(_state == AWAITS_SIGNAL);
|
|
|
|
Genode::memcpy((void*)utcb()->base(), base, size);
|
2014-11-18 15:38:15 +01:00
|
|
|
_become_active();
|
2013-10-16 20:53:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
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);
|
2014-12-01 15:10:33 +01:00
|
|
|
_state = ACTIVE;
|
|
|
|
if (!Cpu_job::own_share_active()) { _activate_used_shares(); }
|
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);
|
2014-12-01 15:10:33 +01:00
|
|
|
_state = ACTIVE;
|
|
|
|
if (!Cpu_job::own_share_active()) { _activate_used_shares(); }
|
2014-04-04 13:41:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Thread::_await_request_succeeded()
|
|
|
|
{
|
|
|
|
assert(_state == AWAITS_IPC);
|
|
|
|
user_arg_0(0);
|
2014-11-18 15:38:15 +01:00
|
|
|
_become_active();
|
2014-04-04 13:41:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Thread::_await_request_failed()
|
|
|
|
{
|
|
|
|
assert(_state == AWAITS_IPC);
|
|
|
|
user_arg_0(-1);
|
2014-11-18 15:38:15 +01:00
|
|
|
_become_active();
|
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:
|
2014-11-18 15:38:15 +01:00
|
|
|
_become_active();
|
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();
|
2015-03-18 17:42:02 +01:00
|
|
|
user_arg_0(-1);
|
|
|
|
_become_active();
|
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
|
|
|
{
|
2014-11-18 15:38:15 +01:00
|
|
|
assert(_state == AWAITS_RESUME || _state == ACTIVE);
|
|
|
|
_become_inactive(AWAITS_RESUME);
|
2013-10-16 20:53:59 +02:00
|
|
|
}
|
|
|
|
|
2014-12-01 15:10:33 +01:00
|
|
|
void Thread::_deactivate_used_shares()
|
|
|
|
{
|
|
|
|
Cpu_job::_deactivate_own_share();
|
|
|
|
Ipc_node::for_each_helper([&] (Ipc_node * const h) {
|
|
|
|
static_cast<Thread *>(h)->_deactivate_used_shares(); });
|
|
|
|
}
|
|
|
|
|
|
|
|
void Thread::_activate_used_shares()
|
|
|
|
{
|
|
|
|
Cpu_job::_activate_own_share();
|
|
|
|
Ipc_node::for_each_helper([&] (Ipc_node * const h) {
|
|
|
|
static_cast<Thread *>(h)->_activate_used_shares(); });
|
|
|
|
}
|
2013-10-16 20:53:59 +02:00
|
|
|
|
2014-11-18 15:38:15 +01:00
|
|
|
void Thread::_become_active()
|
2013-10-16 20:53:59 +02:00
|
|
|
{
|
2014-12-01 15:10:33 +01:00
|
|
|
if (_state != ACTIVE) { _activate_used_shares(); }
|
2014-11-18 15:38:15 +01:00
|
|
|
_state = ACTIVE;
|
2013-10-16 20:53:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-18 15:38:15 +01:00
|
|
|
void Thread::_become_inactive(State const s)
|
2013-12-17 18:10:02 +01:00
|
|
|
{
|
2014-12-01 15:10:33 +01:00
|
|
|
if (_state == ACTIVE) { _deactivate_used_shares(); }
|
2013-12-17 18:10:02 +01:00
|
|
|
_state = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-18 15:38:15 +01:00
|
|
|
void Thread::_stop() { _become_inactive(STOPPED); }
|
2013-10-16 20:53:59 +02:00
|
|
|
|
|
|
|
|
2014-12-01 15:10:33 +01:00
|
|
|
Cpu_job * Thread::helping_sink() {
|
|
|
|
return static_cast<Thread *>(Ipc_node::helping_sink()); }
|
|
|
|
|
|
|
|
|
2013-10-16 20:53:59 +02:00
|
|
|
void Thread::_receive_yielded_cpu()
|
|
|
|
{
|
2014-11-18 15:38:15 +01:00
|
|
|
if (_state == AWAITS_RESUME) { _become_active(); }
|
2014-03-12 16:23:01 +01:00
|
|
|
else { PWRN("failed to receive yielded CPU"); }
|
2013-10-16 20:53:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-19 14:50:27 +01:00
|
|
|
void Thread::proceed(unsigned const cpu) { mtc()->switch_to_user(this, cpu); }
|
2013-10-16 20:53:59 +02:00
|
|
|
|
|
|
|
|
2015-03-27 14:05:55 +01:00
|
|
|
size_t Thread::_core_to_kernel_quota(size_t const quota) const
|
|
|
|
{
|
|
|
|
using Genode::Cpu_session;
|
|
|
|
using Genode::sizet_arithm_t;
|
|
|
|
size_t const tics = cpu_pool()->timer()->ms_to_tics(Kernel::cpu_quota_ms);
|
|
|
|
return Cpu_session::quota_lim_downscale<sizet_arithm_t>(quota, tics);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_new_thread()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
2015-05-19 14:18:40 +02:00
|
|
|
void * const p = (void *)user_arg_1();
|
|
|
|
unsigned const priority = user_arg_2();
|
|
|
|
unsigned const quota = _core_to_kernel_quota(user_arg_3());
|
|
|
|
char const * const label = (char *)user_arg_4();
|
|
|
|
Core_object<Thread> * co =
|
|
|
|
Genode::construct_at<Core_object<Thread> >(p, priority, quota, label);
|
|
|
|
user_arg_0(co->core_capid());
|
2013-10-16 13:10:54 +02:00
|
|
|
}
|
|
|
|
|
2013-11-14 17:29:34 +01:00
|
|
|
|
2015-03-20 09:22:02 +01:00
|
|
|
void Thread::_call_thread_quota()
|
|
|
|
{
|
|
|
|
Thread * const thread = (Thread *)user_arg_1();
|
2015-03-27 14:05:55 +01:00
|
|
|
thread->Cpu_job::quota(_core_to_kernel_quota(user_arg_2()));
|
2015-03-20 09:22:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 15:14:41 +01:00
|
|
|
void Thread::_call_start_thread()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
2014-10-10 16:13:52 +02:00
|
|
|
/* lookup CPU */
|
|
|
|
Cpu * const cpu = cpu_pool()->cpu(user_arg_2());
|
|
|
|
if (!cpu) {
|
|
|
|
PWRN("failed to lookup CPU");
|
2014-12-11 16:09:00 +01:00
|
|
|
user_arg_0(-2);
|
2014-03-06 13:24:36 +01:00
|
|
|
return;
|
|
|
|
}
|
2015-05-19 14:18:40 +02:00
|
|
|
user_arg_0(0);
|
2015-04-01 10:23:38 +02:00
|
|
|
Thread * const thread = (Thread*) user_arg_1();
|
|
|
|
|
2015-05-19 14:18:40 +02:00
|
|
|
assert(thread->_state == AWAITS_START)
|
|
|
|
|
|
|
|
thread->affinity(cpu);
|
|
|
|
|
|
|
|
/* join protection domain */
|
|
|
|
thread->_pd = (Pd *) user_arg_3();
|
|
|
|
thread->_pd->admit(thread);
|
|
|
|
|
|
|
|
/* print log message */
|
|
|
|
if (START_VERBOSE) {
|
|
|
|
Genode::printf("start thread '%s' in program '%s' ",
|
|
|
|
thread->label(), thread->pd_label());
|
|
|
|
if (NR_OF_CPUS) {
|
|
|
|
Genode::printf("on CPU %u/%u ", cpu->id(), NR_OF_CPUS); }
|
|
|
|
Genode::printf("\n");
|
|
|
|
}
|
2015-08-24 15:35:54 +02:00
|
|
|
thread->Ipc_node::_init((Native_utcb *)user_arg_4(), this);
|
2015-05-19 14:18:40 +02:00
|
|
|
thread->_become_active();
|
2013-10-16 13:10:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-16 16:00:55 +01:00
|
|
|
void Thread::_call_pause_current_thread() { _pause(); }
|
|
|
|
|
|
|
|
|
2015-04-01 10:23:38 +02:00
|
|
|
void Thread::_call_pause_thread() {
|
|
|
|
reinterpret_cast<Thread*>(user_arg_1())->_pause(); }
|
2013-10-16 13:10:54 +02:00
|
|
|
|
|
|
|
|
2015-04-01 10:23:38 +02:00
|
|
|
void Thread::_call_resume_thread() {
|
|
|
|
user_arg_0(reinterpret_cast<Thread*>(user_arg_1())->_resume()); }
|
2014-03-25 16:34:20 +01:00
|
|
|
|
|
|
|
|
|
|
|
void Thread::_call_resume_local_thread()
|
|
|
|
{
|
2015-05-19 14:18:40 +02:00
|
|
|
if (!pd()) return;
|
|
|
|
|
2014-03-25 16:34:20 +01:00
|
|
|
/* lookup thread */
|
2015-05-19 14:18:40 +02:00
|
|
|
Thread * const thread = pd()->cap_tree().find<Thread>(user_arg_1());
|
2015-04-01 10:23:38 +02:00
|
|
|
if (!thread || pd() != thread->pd()) {
|
2015-05-19 14:18:40 +02:00
|
|
|
PWRN("%s -> %s: failed to lookup thread %u to resume it",
|
|
|
|
pd_label(), label(), (capid_t)user_arg_1());
|
|
|
|
_stop();
|
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
|
|
|
Thread_event::Thread_event(Thread * const t)
|
2015-04-01 10:23:38 +02:00
|
|
|
: _thread(t), _signal_context(0) { }
|
2013-11-14 15:14:41 +01:00
|
|
|
|
|
|
|
|
2015-05-19 14:18:40 +02:00
|
|
|
void Thread_event::submit() { if (_signal_context) _signal_context->submit(1); }
|
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
|
|
|
{
|
2015-05-19 14:18:40 +02:00
|
|
|
Thread * const t = pd()->cap_tree().find<Thread>(user_arg_1());
|
2013-10-16 20:53:59 +02:00
|
|
|
if (t) { t->_receive_yielded_cpu(); }
|
2014-10-09 14:24:27 +02:00
|
|
|
Cpu_job::_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
|
|
|
{
|
2015-05-19 14:18:40 +02:00
|
|
|
if (Ipc_node::await_request(user_arg_1())) {
|
2014-03-27 12:28:53 +01:00
|
|
|
user_arg_0(0);
|
|
|
|
return;
|
|
|
|
}
|
2014-11-18 15:38:15 +01:00
|
|
|
_become_inactive(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
|
|
|
{
|
2015-05-19 14:18:40 +02:00
|
|
|
Object_identity_reference * oir = pd()->cap_tree().find(user_arg_1());
|
|
|
|
Thread * const dst = (oir) ? oir->object<Thread>() : nullptr;
|
2013-10-17 00:41:14 +02:00
|
|
|
if (!dst) {
|
2015-03-19 18:10:03 +01:00
|
|
|
PWRN("%s -> %s: cannot send to unknown recipient %llu",
|
|
|
|
pd_label(), label(), (unsigned long long)user_arg_1());
|
2014-11-18 15:38:15 +01:00
|
|
|
_become_inactive(AWAITS_IPC);
|
2013-10-17 00:41:14 +02:00
|
|
|
return;
|
|
|
|
}
|
2014-12-01 15:10:33 +01:00
|
|
|
bool const help = Cpu_job::_helping_possible(dst);
|
2015-05-19 14:18:40 +02:00
|
|
|
oir = oir->find(dst->pd());
|
|
|
|
|
|
|
|
Ipc_node::send_request(dst, oir ? oir->capid() : cap_id_invalid(),
|
|
|
|
help, user_arg_2());
|
2014-12-01 15:10:33 +01:00
|
|
|
_state = AWAITS_IPC;
|
|
|
|
if (!help || !dst->own_share_active()) { _deactivate_used_shares(); }
|
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
|
|
|
{
|
2015-05-19 14:18:40 +02:00
|
|
|
Ipc_node::send_reply();
|
|
|
|
bool const await_request_msg = user_arg_2();
|
2013-11-21 11:35:33 +01:00
|
|
|
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()
|
|
|
|
{
|
|
|
|
/* override event route */
|
2015-04-01 10:23:38 +02:00
|
|
|
Thread * const t = (Thread*) user_arg_1();
|
2013-11-14 15:14:41 +01:00
|
|
|
unsigned const event_id = user_arg_2();
|
2015-05-19 14:18:40 +02:00
|
|
|
Signal_context * c = pd()->cap_tree().find<Signal_context>(user_arg_3());
|
|
|
|
user_arg_0(t->_route_event(event_id, c));
|
2013-11-14 15:14:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int Thread::_route_event(unsigned const event_id,
|
2015-05-19 14:18:40 +02:00
|
|
|
Signal_context * c)
|
2013-11-14 15:14:41 +01:00
|
|
|
{
|
|
|
|
/* 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); }
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-19 14:18:40 +02:00
|
|
|
Signal_context * const Thread_event::signal_context() const {
|
|
|
|
return _signal_context; }
|
2013-10-16 13:10:54 +02:00
|
|
|
|
|
|
|
|
2013-12-09 16:41:23 +01:00
|
|
|
void Thread::_print_activity(bool const printing_thread)
|
2013-11-28 00:45:48 +01:00
|
|
|
{
|
2015-03-10 12:06:55 +01:00
|
|
|
Genode::printf("\033[33m%s -> %s:\033[0m", pd_label(), label());
|
2013-11-28 00:45:48 +01:00
|
|
|
switch (_state) {
|
|
|
|
case AWAITS_START: {
|
|
|
|
Genode::printf("\033[32m init\033[0m");
|
|
|
|
break; }
|
2014-11-18 15:38:15 +01:00
|
|
|
case ACTIVE: {
|
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: {
|
2015-05-19 14:18:40 +02:00
|
|
|
Genode::printf("\033[32m await SIG\033[0m");
|
2013-11-28 00:45:48 +01:00
|
|
|
break; }
|
|
|
|
case AWAITS_SIGNAL_CONTEXT_KILL: {
|
2015-05-19 14:18:40 +02:00
|
|
|
Genode::printf("\033[32m await SCK\033[0m");
|
2013-11-28 00:45:48 +01:00
|
|
|
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: {
|
2015-05-19 14:18:40 +02:00
|
|
|
Thread * const server = dynamic_cast<Thread *>(Ipc_node::callee());
|
|
|
|
Genode::printf("\033[32m await RPL %s -> %s\033[0m",
|
|
|
|
server->pd_label(), server->label());
|
2013-11-28 00:45:48 +01:00
|
|
|
break; }
|
|
|
|
case AWAIT_REQUEST: {
|
|
|
|
Genode::printf("\033[32m await REQ\033[0m");
|
|
|
|
break; }
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-19 14:18:40 +02:00
|
|
|
void Thread::_call_print_char() { Genode::printf("%c", (char)user_arg_1()); }
|
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
|
|
|
{
|
|
|
|
/* lookup receiver */
|
2015-05-19 14:18:40 +02:00
|
|
|
Signal_receiver * const r = pd()->cap_tree().find<Signal_receiver>(user_arg_1());
|
2013-10-16 13:10:54 +02:00
|
|
|
if (!r) {
|
2015-03-10 12:06:55 +01:00
|
|
|
PWRN("%s -> %s: cannot await, unknown signal receiver %u",
|
2015-05-19 14:18:40 +02:00
|
|
|
pd_label(), label(), (capid_t)user_arg_1());
|
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_submit_signal()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
|
|
|
/* lookup signal context */
|
2015-05-19 14:18:40 +02:00
|
|
|
Signal_context * const c = pd()->cap_tree().find<Signal_context>(user_arg_1());
|
2013-10-16 13:10:54 +02:00
|
|
|
if(!c) {
|
2015-05-19 14:18:40 +02:00
|
|
|
PWRN("%s -> %s: cannot submit unknown signal context",
|
|
|
|
pd_label(), label());
|
2013-10-16 13:10:54 +02:00
|
|
|
user_arg_0(-1);
|
|
|
|
return;
|
|
|
|
}
|
2015-05-19 14:18:40 +02:00
|
|
|
|
2013-10-16 13:10:54 +02:00
|
|
|
/* 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 */
|
2015-05-19 14:18:40 +02:00
|
|
|
Signal_context * const c = pd()->cap_tree().find<Signal_context>(user_arg_1());
|
2013-10-16 13:10:54 +02:00
|
|
|
if (!c) {
|
2015-05-19 14:18:40 +02:00
|
|
|
PWRN("%s -> %s: cannot ack unknown signal context",
|
|
|
|
pd_label(), label());
|
2013-10-16 13:10:54 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-05-19 14:18:40 +02:00
|
|
|
|
2013-10-16 13:10:54 +02:00
|
|
|
/* acknowledge */
|
|
|
|
c->ack();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-06 00:12:43 +01:00
|
|
|
void Thread::_call_kill_signal_context()
|
|
|
|
{
|
|
|
|
/* lookup signal context */
|
2015-05-19 14:18:40 +02:00
|
|
|
Signal_context * const c = pd()->cap_tree().find<Signal_context>(user_arg_1());
|
2013-12-06 00:12:43 +01:00
|
|
|
if (!c) {
|
2015-05-19 14:18:40 +02:00
|
|
|
PWRN("%s -> %s: cannot kill unknown signal context",
|
|
|
|
pd_label(), label());
|
2013-12-06 00:12:43 +01:00
|
|
|
user_arg_0(-1);
|
|
|
|
return;
|
|
|
|
}
|
2015-05-19 14:18:40 +02:00
|
|
|
|
2013-12-06 00:12:43 +01:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-17 15:41:47 +01:00
|
|
|
void Thread::_call_new_irq()
|
|
|
|
{
|
2015-05-19 14:18:40 +02:00
|
|
|
Signal_context * const c = pd()->cap_tree().find<Signal_context>(user_arg_3());
|
2015-03-17 15:41:47 +01:00
|
|
|
if (!c) {
|
|
|
|
PWRN("%s -> %s: invalid signal context for interrupt",
|
|
|
|
pd_label(), label());
|
|
|
|
user_arg_0(-1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
new ((void *)user_arg_1()) User_irq(user_arg_2(), *c);
|
|
|
|
user_arg_0(0);
|
|
|
|
}
|
2015-04-03 17:22:16 +02:00
|
|
|
|
|
|
|
|
2015-04-28 12:56:59 +02:00
|
|
|
void Thread::_call_ack_irq() {
|
|
|
|
reinterpret_cast<User_irq*>(user_arg_1())->enable(); }
|
|
|
|
|
|
|
|
|
2015-05-19 14:18:40 +02:00
|
|
|
void Thread::_call_new_obj()
|
|
|
|
{
|
|
|
|
/* lookup thread */
|
|
|
|
Object_identity_reference * ref = pd()->cap_tree().find(user_arg_2());
|
|
|
|
Thread * thread = ref ? ref->object<Thread>() : nullptr;
|
|
|
|
if (!thread ||
|
|
|
|
(static_cast<Core_object<Thread>*>(thread)->capid() != ref->capid())) {
|
|
|
|
if (thread)
|
|
|
|
PWRN("faked thread %s -> %s", thread->pd_label(), thread->label());
|
|
|
|
user_arg_0(cap_id_invalid());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
using Thread_identity = Core_object_identity<Thread>;
|
|
|
|
Thread_identity * coi =
|
|
|
|
Genode::construct_at<Thread_identity>((void *)user_arg_1(), *thread);
|
|
|
|
user_arg_0(coi->core_capid());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Thread::_call_delete_obj()
|
|
|
|
{
|
|
|
|
using Object = Core_object_identity<Thread>;
|
|
|
|
reinterpret_cast<Object*>(user_arg_1())->~Object();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-12-01 14:50:14 +01:00
|
|
|
void Thread::_call_ack_cap()
|
|
|
|
{
|
|
|
|
Object_identity_reference * oir = pd()->cap_tree().find(user_arg_1());
|
|
|
|
if (oir) oir->remove_from_utcb();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-19 14:18:40 +02:00
|
|
|
void Thread::_call_delete_cap()
|
|
|
|
{
|
|
|
|
Object_identity_reference * oir = pd()->cap_tree().find(user_arg_1());
|
2015-12-01 14:50:14 +01:00
|
|
|
if (!oir) return;
|
|
|
|
|
|
|
|
if (oir->in_utcb()) return;
|
|
|
|
|
|
|
|
destroy(pd()->platform_pd()->capability_slab(), oir);
|
2015-05-19 14:18:40 +02:00
|
|
|
}
|
2015-04-03 17:22:16 +02:00
|
|
|
|
|
|
|
|
2014-03-26 11:00:01 +01:00
|
|
|
void Thread::_call()
|
2013-10-16 13:10:54 +02:00
|
|
|
{
|
2015-05-19 14:18:40 +02:00
|
|
|
try {
|
|
|
|
|
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_ack_signal(): _call_ack_signal(); return;
|
2014-03-25 17:23:33 +01:00
|
|
|
case call_id_print_char(): _call_print_char(); return;
|
2015-12-01 14:50:14 +01:00
|
|
|
case call_id_ack_cap(): _call_ack_cap(); return;
|
2015-05-19 14:18:40 +02:00
|
|
|
case call_id_delete_cap(): _call_delete_cap(); return;
|
2014-03-25 17:23:33 +01:00
|
|
|
default:
|
|
|
|
/* check wether this is a core thread */
|
|
|
|
if (!_core()) {
|
2015-03-10 12:06:55 +01:00
|
|
|
PWRN("%s -> %s: not entitled to do kernel call",
|
|
|
|
pd_label(), label());
|
2014-03-25 17:23:33 +01:00
|
|
|
_stop();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* switch over kernel calls that are restricted to core */
|
|
|
|
switch (call_id) {
|
2015-03-19 14:53:48 +01:00
|
|
|
case call_id_new_thread(): _call_new_thread(); return;
|
2015-03-20 09:22:02 +01:00
|
|
|
case call_id_thread_quota(): _call_thread_quota(); return;
|
2015-05-19 14:18:40 +02:00
|
|
|
case call_id_delete_thread(): _call_delete<Thread>(); return;
|
2015-03-19 14:53:48 +01:00
|
|
|
case call_id_start_thread(): _call_start_thread(); return;
|
|
|
|
case call_id_resume_thread(): _call_resume_thread(); return;
|
|
|
|
case call_id_route_thread_event(): _call_route_thread_event(); return;
|
|
|
|
case call_id_update_pd(): _call_update_pd(); return;
|
2015-05-19 14:18:40 +02:00
|
|
|
case call_id_new_pd():
|
|
|
|
_call_new<Pd>((Genode::Translation_table *) user_arg_2(),
|
|
|
|
(Genode::Platform_pd *) user_arg_3());
|
|
|
|
return;
|
|
|
|
case call_id_delete_pd(): _call_delete<Pd>(); return;
|
|
|
|
case call_id_new_signal_receiver(): _call_new<Signal_receiver>(); return;
|
|
|
|
case call_id_new_signal_context():
|
|
|
|
_call_new<Signal_context>((Signal_receiver*) user_arg_2(),
|
|
|
|
(unsigned) user_arg_3());
|
|
|
|
return;
|
|
|
|
case call_id_delete_signal_context(): _call_delete<Signal_context>(); return;
|
|
|
|
case call_id_delete_signal_receiver(): _call_delete<Signal_receiver>(); return;
|
2015-03-19 14:53:48 +01:00
|
|
|
case call_id_new_vm(): _call_new_vm(); return;
|
|
|
|
case call_id_delete_vm(): _call_delete_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;
|
2015-04-03 17:22:16 +02:00
|
|
|
case call_id_new_irq(): _call_new_irq(); return;
|
2015-05-19 14:18:40 +02:00
|
|
|
case call_id_delete_irq(): _call_delete<Irq>(); return;
|
2015-04-28 12:56:59 +02:00
|
|
|
case call_id_ack_irq(): _call_ack_irq(); return;
|
2015-05-19 14:18:40 +02:00
|
|
|
case call_id_new_obj(): _call_new_obj(); return;
|
|
|
|
case call_id_delete_obj(): _call_delete_obj(); return;
|
2013-10-16 13:10:54 +02:00
|
|
|
default:
|
2015-03-10 12:06:55 +01:00
|
|
|
PWRN("%s -> %s: unknown kernel call", pd_label(), label());
|
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
|
|
|
}
|
2015-05-19 14:18:40 +02:00
|
|
|
} catch (Genode::Allocator::Out_of_memory &e) { user_arg_0(-2); }
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-24 15:35:54 +02:00
|
|
|
Thread::Thread(unsigned const priority, unsigned const quota,
|
|
|
|
char const * const label)
|
|
|
|
:
|
|
|
|
Cpu_job(priority, quota), _fault(this), _fault_pd(0), _fault_addr(0),
|
|
|
|
_fault_writes(0), _fault_signal(0), _state(AWAITS_START),
|
|
|
|
_signal_receiver(0), _label(label)
|
|
|
|
{
|
|
|
|
_init();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Thread_event Thread::* Thread::_event(unsigned const id) const
|
|
|
|
{
|
|
|
|
static Thread_event Thread::* _events[] = { &Thread::_fault };
|
|
|
|
return id < sizeof(_events)/sizeof(_events[0]) ? _events[id] : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-19 14:18:40 +02:00
|
|
|
/*****************
|
|
|
|
** Core_thread **
|
|
|
|
*****************/
|
|
|
|
|
|
|
|
Core_thread::Core_thread()
|
2015-06-29 13:30:35 +02:00
|
|
|
: Core_object<Thread>(Cpu_priority::MAX, 0, "core")
|
2015-05-19 14:18:40 +02:00
|
|
|
{
|
|
|
|
using Genode::Native_utcb;
|
|
|
|
|
|
|
|
static Genode::uint8_t stack[DEFAULT_STACK_SIZE];
|
|
|
|
static Native_utcb * const utcb =
|
|
|
|
unmanaged_singleton<Native_utcb, Genode::get_page_size()>();
|
|
|
|
|
|
|
|
/* map UTCB */
|
|
|
|
Genode::map_local((addr_t)utcb, (addr_t)Genode::utcb_main_thread(),
|
|
|
|
sizeof(Native_utcb) / Genode::get_page_size());
|
|
|
|
|
2015-06-08 15:24:43 +02:00
|
|
|
utcb->cap_add(core_capid());
|
2015-05-19 14:18:40 +02:00
|
|
|
utcb->cap_add(cap_id_invalid());
|
|
|
|
utcb->cap_add(cap_id_invalid());
|
|
|
|
|
|
|
|
/* start thread with stack pointer at the top of stack */
|
|
|
|
sp = (addr_t)&stack + DEFAULT_STACK_SIZE;
|
|
|
|
ip = (addr_t)&_core_start;
|
|
|
|
|
|
|
|
affinity(cpu_pool()->primary_cpu());
|
|
|
|
_utcb = utcb;
|
|
|
|
Thread::_pd = core_pd();
|
|
|
|
Thread::_pd->admit(this);
|
|
|
|
_become_active();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Thread & Core_thread::singleton()
|
|
|
|
{
|
|
|
|
static Core_thread ct;
|
|
|
|
return ct;
|
2013-11-11 16:55:30 +01:00
|
|
|
}
|