From ffb26eb501ef19e0b9b065fbb70fa4e744dc0979 Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Wed, 16 Oct 2013 13:10:54 +0200 Subject: [PATCH] hw: make syscall backend private to Kernel::Thread ref #874 --- base-hw/src/core/kernel.cc | 679 ----------------------------- base-hw/src/core/kernel/thread.cc | 695 +++++++++++++++++++++++++++++- base-hw/src/core/kernel/thread.h | 132 ++++-- 3 files changed, 777 insertions(+), 729 deletions(-) diff --git a/base-hw/src/core/kernel.cc b/base-hw/src/core/kernel.cc index 702e153673..71540b71da 100644 --- a/base-hw/src/core/kernel.cc +++ b/base-hw/src/core/kernel.cc @@ -22,9 +22,6 @@ * under the terms of the GNU General Public License version 2. */ -/* Genode includes */ -#include - /* core includes */ #include #include @@ -46,7 +43,6 @@ extern "C" void CORE_MAIN(); namespace Kernel { /* import Genode types */ - typedef Genode::Thread_state Thread_state; typedef Genode::umword_t umword_t; typedef Genode::Core_tlb Core_tlb; } @@ -179,681 +175,6 @@ namespace Kernel /* disengage interrupt controller from IRQ */ pic()->finish_request(); } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_new_pd(Thread * const user) - { - /* check permissions */ - if (user->pd_id() != core_id()) { - PERR("not entitled to create protection domain"); - user->user_arg_0(0); - return; - } - /* create translation lookaside buffer and protection domain */ - void * p = (void *)user->user_arg_1(); - Tlb * const tlb = new (p) Tlb(); - p = (void *)((addr_t)p + sizeof(Tlb)); - Pd * const pd = new (p) Pd(tlb, (Platform_pd *)user->user_arg_2()); - user->user_arg_0(pd->id()); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_kill_pd(Thread * const user) - { - /* check permissions */ - if (user->pd_id() != core_id()) { - PERR("not entitled to destruct protection domain"); - user->user_arg_0(-1); - return; - } - /* lookup protection domain */ - unsigned id = user->user_arg_1(); - Pd * const pd = Pd::pool()->object(id); - if (!pd) { - PERR("unknown protection domain"); - user->user_arg_0(-1); - return; - } - /* destruct translation lookaside buffer and protection domain */ - Tlb * const tlb = pd->tlb(); - pd->~Pd(); - tlb->~Tlb(); - - /* clean up buffers of memory management */ - Cpu::flush_tlb_by_pid(pd->id()); - user->user_arg_0(0); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_new_thread(Thread * const user) - { - /* check permissions */ - assert(user->pd_id() == core_id()); - - /* dispatch arguments */ - Syscall_arg const arg1 = user->user_arg_1(); - Syscall_arg const arg2 = user->user_arg_2(); - - /* create thread */ - Thread * const t = new ((void *)arg1) - Thread((Platform_thread *)arg2); - - /* return thread ID */ - user->user_arg_0((Syscall_ret)t->id()); - } - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_delete_thread(Thread * const user) - { - /* check permissions */ - assert(user->pd_id() == core_id()); - - /* get targeted thread */ - unsigned thread_id = (unsigned)user->user_arg_1(); - Thread * const thread = Thread::pool()->object(thread_id); - assert(thread); - - /* destroy thread */ - thread->~Thread(); - } - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_start_thread(Thread * const user) - { - /* check permissions */ - assert(user->pd_id() == core_id()); - - /* dispatch arguments */ - Platform_thread * pt = (Platform_thread *)user->user_arg_1(); - void * const ip = (void *)user->user_arg_2(); - void * const sp = (void *)user->user_arg_3(); - unsigned const cpu_id = (unsigned)user->user_arg_4(); - - /* get targeted thread */ - Thread * const t = Thread::pool()->object(pt->id()); - assert(t); - - /* start thread */ - unsigned const pd_id = pt->pd_id(); - Native_utcb * const utcb_p = pt->phys_utcb(); - Native_utcb * const utcb_v = pt->virt_utcb(); - t->start(ip, sp, cpu_id, pd_id, utcb_p, utcb_v, pt->main_thread()); - - /* return software TLB that the thread is assigned to */ - Pd::Pool * const pp = Pd::pool(); - Pd * const pd = pp->object(t->pd_id()); - assert(pd); - user->user_arg_0((Syscall_ret)pd->tlb()); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_pause_thread(Thread * const user) - { - unsigned const tid = user->user_arg_1(); - - /* shortcut for a thread to pause itself */ - if (!tid) { - user->pause(); - user->user_arg_0(0); - return; - } - - /* get targeted thread and check permissions */ - Thread * const t = Thread::pool()->object(tid); - assert(t && (user->pd_id() == core_id() || user==t)); - - /* pause targeted thread */ - t->pause(); - user->user_arg_0(0); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_resume_thread(Thread * const user) - { - /* lookup thread */ - Thread * const t = Thread::pool()->object(user->user_arg_1()); - if (!t) { - PERR("unknown thread"); - user->user_arg_0(-1); - return; - } - /* check permissions */ - if (user->pd_id() != core_id() && user->pd_id() != t->pd_id()) { - PERR("not entitled to resume thread"); - user->user_arg_0(-1); - return; - } - /* resume targeted thread */ - user->user_arg_0(t->resume()); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_resume_faulter(Thread * const user) - { - /* lookup thread */ - Thread * const t = Thread::pool()->object(user->user_arg_1()); - if (!t) { - PERR("unknown thread"); - user->user_arg_0(-1); - return; - } - /* check permissions */ - if (user->pd_id() != core_id() && user->pd_id() != t->pd_id()) { - PERR("not entitled to resume thread"); - user->user_arg_0(-1); - return; - } - /* writeback translation table and resume faulter */ - Cpu::tlb_insertions(); - t->resume(); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_yield_thread(Thread * const user) - { - Thread * const t = Thread::pool()->object(user->user_arg_1()); - if (t) { t->receive_yielded_cpu(); } - cpu_scheduler()->yield(); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_current_thread_id(Thread * const user) - { user->user_arg_0((Syscall_ret)user->id()); } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_get_thread(Thread * const user) - { - /* check permissions */ - if (user->pd_id() != core_id()) { - PERR("not entitled to read address of platform thread"); - user->user_arg_0(0); - return; - } - /* lookup thread */ - unsigned const id = user->user_arg_1(); - Thread * t; - if (id) { - t = Thread::pool()->object(id); - if (!t) { - PERR("unknown thread"); - user->user_arg_0(0); - } - } else { t = user; } - user->user_arg_0((Syscall_ret)t->platform_thread()); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_wait_for_request(Thread * const user) - { - user->wait_for_request(); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_request_and_wait(Thread * const user) - { - /* get IPC receiver */ - Thread * const t = Thread::pool()->object(user->user_arg_1()); - assert(t); - - /* do IPC */ - user->request_and_wait(t, (size_t)user->user_arg_2()); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_reply(Thread * const user) { - user->reply((size_t)user->user_arg_1(), (bool)user->user_arg_2()); } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_set_pager(Thread * const user) - { - /* check permissions */ - if (user->pd_id() != core_id()) { - PERR("not entitled to set pager"); - return; - } - /* lookup faulter and pager thread */ - unsigned const pager_id = user->user_arg_1(); - Thread * const pager = Thread::pool()->object(pager_id); - Thread * const faulter = Thread::pool()->object(user->user_arg_2()); - if ((pager_id && !pager) || !faulter) { - PERR("failed to set pager"); - return; - } - /* assign pager */ - faulter->pager(pager); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_update_pd(Thread * const user) - { - assert(user->pd_id() == core_id()); - Cpu::flush_tlb_by_pid(user->user_arg_1()); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_update_region(Thread * const user) - { - assert(user->pd_id() == core_id()); - - /* FIXME we don't handle instruction caches by now */ - Cpu::flush_data_cache_by_virt_region((addr_t)user->user_arg_1(), - (size_t)user->user_arg_2()); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_allocate_irq(Thread * const user) - { - assert(user->pd_id() == core_id()); - unsigned irq = user->user_arg_1(); - user->user_arg_0(user->allocate_irq(irq)); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_free_irq(Thread * const user) - { - assert(user->pd_id() == core_id()); - unsigned irq = user->user_arg_1(); - user->user_arg_0(user->free_irq(irq)); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_await_irq(Thread * const user) - { - assert(user->pd_id() == core_id()); - user->await_irq(); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_print_char(Thread * const user) - { - Genode::printf("%c", (char)user->user_arg_1()); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_read_thread_state(Thread * const user) - { - assert(user->pd_id() == core_id()); - Thread * const t = Thread::pool()->object(user->user_arg_1()); - if (!t) PDBG("Targeted thread unknown"); - Thread_state * const ts = (Thread_state *)user->phys_utcb()->base(); - t->Cpu::Context::read_cpu_state(ts); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_write_thread_state(Thread * const user) - { - assert(user->pd_id() == core_id()); - Thread * const t = Thread::pool()->object(user->user_arg_1()); - if (!t) PDBG("Targeted thread unknown"); - Thread_state * const ts = (Thread_state *)user->phys_utcb()->base(); - t->Cpu::Context::write_cpu_state(ts); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_new_signal_receiver(Thread * const user) - { - /* check permissions */ - if (user->pd_id() != core_id()) { - PERR("not entitled to create signal receiver"); - user->user_arg_0(0); - return; - } - /* create receiver */ - void * p = (void *)user->user_arg_1(); - Signal_receiver * const r = new (p) Signal_receiver(); - user->user_arg_0(r->id()); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_new_signal_context(Thread * const user) - { - /* check permissions */ - if (user->pd_id() != core_id()) { - PERR("not entitled to create signal context"); - user->user_arg_0(0); - return; - } - /* lookup receiver */ - unsigned id = user->user_arg_2(); - Signal_receiver * const r = Signal_receiver::pool()->object(id); - if (!r) { - PERR("unknown signal receiver"); - user->user_arg_0(0); - return; - } - /* create and assign context*/ - void * p = (void *)user->user_arg_1(); - unsigned imprint = user->user_arg_3(); - if (r->new_context(p, imprint)) { - PERR("failed to create signal context"); - user->user_arg_0(0); - return; - } - /* return context name */ - Signal_context * const c = (Signal_context *)p; - user->user_arg_0(c->id()); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_await_signal(Thread * const user) - { - /* lookup receiver */ - unsigned id = user->user_arg_1(); - Signal_receiver * const r = Signal_receiver::pool()->object(id); - if (!r) { - PERR("unknown signal receiver"); - user->user_arg_0(-1); - return; - } - /* register handler at the receiver */ - if (r->add_handler(user)) { - PERR("failed to register handler at signal receiver"); - user->user_arg_0(-1); - return; - } - user->user_arg_0(0); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_signal_pending(Thread * const user) - { - /* lookup signal receiver */ - unsigned id = user->user_arg_1(); - Signal_receiver * const r = Signal_receiver::pool()->object(id); - if (!r) { - PERR("unknown signal receiver"); - user->user_arg_0(0); - return; - } - /* get pending state */ - user->user_arg_0(r->deliverable()); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_submit_signal(Thread * const user) - { - /* lookup signal context */ - unsigned const id = user->user_arg_1(); - Signal_context * const c = Signal_context::pool()->object(id); - if(!c) { - PERR("unknown signal context"); - user->user_arg_0(-1); - return; - } - /* trigger signal context */ - if (c->submit(user->user_arg_2())) { - PERR("failed to submit signal context"); - user->user_arg_0(-1); - return; - } - user->user_arg_0(0); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_ack_signal(Thread * const user) - { - /* lookup signal context */ - unsigned id = user->user_arg_1(); - Signal_context * const c = Signal_context::pool()->object(id); - if (!c) { - PERR("unknown signal context"); - return; - } - /* acknowledge */ - c->ack(); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_kill_signal_context(Thread * const user) - { - /* check permissions */ - if (user->pd_id() != core_id()) { - PERR("not entitled to kill signal context"); - user->user_arg_0(-1); - return; - } - /* lookup signal context */ - unsigned id = user->user_arg_1(); - Signal_context * const c = Signal_context::pool()->object(id); - if (!c) { - PERR("unknown signal context"); - user->user_arg_0(0); - return; - } - /* kill signal context */ - if (c->kill(user)) { - PERR("failed to kill signal context"); - user->user_arg_0(-1); - return; - } - user->user_arg_0(0); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_kill_signal_receiver(Thread * const user) - { - /* check permissions */ - if (user->pd_id() != core_id()) { - PERR("not entitled to kill signal receiver"); - user->user_arg_0(-1); - return; - } - /* lookup signal receiver */ - unsigned id = user->user_arg_1(); - Signal_receiver * const r = Signal_receiver::pool()->object(id); - if (!r) { - PERR("unknown signal receiver"); - user->user_arg_0(0); - return; - } - /* kill signal receiver */ - if (r->kill(user)) { - PERR("unknown signal receiver"); - user->user_arg_0(-1); - return; - } - user->user_arg_0(0); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_new_vm(Thread * const user) - { - /* check permissions */ - assert(user->pd_id() == core_id()); - - /* dispatch arguments */ - void * const allocator = (void * const)user->user_arg_1(); - Genode::Cpu_state_modes * const state = - (Genode::Cpu_state_modes * const)user->user_arg_2(); - Signal_context * const context = - Signal_context::pool()->object(user->user_arg_3()); - assert(context); - - /* create vm */ - Vm * const vm = new (allocator) Vm(state, context); - - /* return vm id */ - user->user_arg_0((Syscall_ret)vm->id()); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_run_vm(Thread * const user) - { - /* check permissions */ - assert(user->pd_id() == core_id()); - - /* get targeted vm via its id */ - Vm * const vm = Vm::pool()->object(user->user_arg_1()); - assert(vm); - - /* run targeted vm */ - vm->run(); - } - - - /** - * Do specific syscall for 'user', for details see 'syscall.h' - */ - void do_pause_vm(Thread * const user) - { - /* check permissions */ - assert(user->pd_id() == core_id()); - - /* get targeted vm via its id */ - Vm * const vm = Vm::pool()->object(user->user_arg_1()); - assert(vm); - - /* pause targeted vm */ - vm->pause(); - } - - - /** - * Handle a syscall request - * - * \param user thread that called the syscall - */ - void handle_syscall(Thread * const user) - { - switch (user->user_arg_0()) - { - case NEW_THREAD: do_new_thread(user); return; - case DELETE_THREAD: do_delete_thread(user); return; - case START_THREAD: do_start_thread(user); return; - case PAUSE_THREAD: do_pause_thread(user); return; - case RESUME_THREAD: do_resume_thread(user); return; - case RESUME_FAULTER: do_resume_faulter(user); return; - case GET_THREAD: do_get_thread(user); return; - case CURRENT_THREAD_ID: do_current_thread_id(user); return; - case YIELD_THREAD: do_yield_thread(user); return; - case READ_THREAD_STATE: do_read_thread_state(user); return; - case WRITE_THREAD_STATE: do_write_thread_state(user); return; - case REQUEST_AND_WAIT: do_request_and_wait(user); return; - case REPLY: do_reply(user); return; - case WAIT_FOR_REQUEST: do_wait_for_request(user); return; - case SET_PAGER: do_set_pager(user); return; - case UPDATE_PD: do_update_pd(user); return; - case UPDATE_REGION: do_update_region(user); return; - case NEW_PD: do_new_pd(user); return; - case ALLOCATE_IRQ: do_allocate_irq(user); return; - case AWAIT_IRQ: do_await_irq(user); return; - case FREE_IRQ: do_free_irq(user); return; - case PRINT_CHAR: do_print_char(user); return; - case NEW_SIGNAL_RECEIVER: do_new_signal_receiver(user); return; - case NEW_SIGNAL_CONTEXT: do_new_signal_context(user); return; - case KILL_SIGNAL_CONTEXT: do_kill_signal_context(user); return; - case KILL_SIGNAL_RECEIVER: do_kill_signal_receiver(user); return; - case AWAIT_SIGNAL: do_await_signal(user); return; - case SUBMIT_SIGNAL: do_submit_signal(user); return; - case SIGNAL_PENDING: do_signal_pending(user); return; - case ACK_SIGNAL: do_ack_signal(user); return; - case NEW_VM: do_new_vm(user); return; - case RUN_VM: do_run_vm(user); return; - case PAUSE_VM: do_pause_vm(user); return; - case KILL_PD: do_kill_pd(user); return; - default: - PERR("invalid syscall"); - user->stop(); - reset_lap_time(); - } - } } /** diff --git a/base-hw/src/core/kernel/thread.cc b/base-hw/src/core/kernel/thread.cc index ba8d60d663..ac03a52287 100644 --- a/base-hw/src/core/kernel/thread.cc +++ b/base-hw/src/core/kernel/thread.cc @@ -11,14 +11,23 @@ * under the terms of the GNU General Public License version 2. */ +/* Genode includes */ +#include + /* core includes */ +#include #include #include +#include #include #include using namespace Kernel; +namespace Kernel +{ + typedef Genode::Thread_state Thread_state; +} char const * Kernel::Thread::label() { @@ -47,7 +56,7 @@ Kernel::Thread::prepare_to_start(void * const ip, Native_utcb * const utcb_virt, bool const main) { - assert(_state == AWAIT_START) + assert(_state == AWAITS_START) /* FIXME: support SMP */ if (cpu_id) { PERR("multicore processing not supported"); } @@ -78,10 +87,684 @@ Kernel::Thread::prepare_to_start(void * const ip, Kernel::Thread::Thread(Platform_thread * const platform_thread) -: _platform_thread(platform_thread), _state(AWAIT_START), - _pager(0), _pd_id(0), _phys_utcb(0), _virt_utcb(0), - _signal_receiver(0) +: + _platform_thread(platform_thread), _state(AWAITS_START), + _pager(0), _pd_id(0), _phys_utcb(0), _virt_utcb(0), + _signal_receiver(0) { - priority = _platform_thread ? _platform_thread->priority() - : Kernel::Priority::MAX; + if (_platform_thread) { priority = _platform_thread->priority(); } + else { priority = Kernel::Priority::MAX; } +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_new_pd() +{ + /* check permissions */ + if (pd_id() != core_id()) { + PERR("not entitled to create protection domain"); + user_arg_0(0); + return; + } + /* create translation lookaside buffer and protection domain */ + void * p = (void *)user_arg_1(); + Tlb * const tlb = new (p) Tlb(); + p = (void *)((addr_t)p + sizeof(Tlb)); + Pd * const pd = new (p) Pd(tlb, (Platform_pd *)user_arg_2()); + user_arg_0(pd->id()); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_kill_pd() +{ + /* check permissions */ + if (pd_id() != core_id()) { + PERR("not entitled to destruct protection domain"); + user_arg_0(-1); + return; + } + /* lookup protection domain */ + unsigned id = user_arg_1(); + Pd * const pd = Pd::pool()->object(id); + if (!pd) { + PERR("unknown protection domain"); + user_arg_0(-1); + return; + } + /* destruct translation lookaside buffer and protection domain */ + Tlb * const tlb = pd->tlb(); + pd->~Pd(); + tlb->~Tlb(); + + /* clean up buffers of memory management */ + Cpu::flush_tlb_by_pid(pd->id()); + user_arg_0(0); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_new_thread() +{ + /* check permissions */ + assert(pd_id() == core_id()); + + /* dispatch arguments */ + Syscall_arg const arg1 = user_arg_1(); + Syscall_arg const arg2 = user_arg_2(); + + /* create thread */ + Thread * const t = new ((void *)arg1) + Thread((Platform_thread *)arg2); + + /* return thread ID */ + user_arg_0((Syscall_ret)t->id()); +} + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_delete_thread() +{ + /* check permissions */ + assert(pd_id() == core_id()); + + /* get targeted thread */ + unsigned thread_id = (unsigned)user_arg_1(); + Thread * const thread = Thread::pool()->object(thread_id); + assert(thread); + + /* destroy thread */ + thread->~Thread(); +} + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_start_thread() +{ + /* check permissions */ + assert(pd_id() == core_id()); + + /* dispatch arguments */ + Platform_thread * pt = (Platform_thread *)user_arg_1(); + void * const ip = (void *)user_arg_2(); + void * const sp = (void *)user_arg_3(); + unsigned const cpu_id = (unsigned)user_arg_4(); + + /* get targeted thread */ + Thread * const t = Thread::pool()->object(pt->id()); + assert(t); + + /* start thread */ + unsigned const pd_id = pt->pd_id(); + Native_utcb * const utcb_p = pt->phys_utcb(); + Native_utcb * const utcb_v = pt->virt_utcb(); + t->start(ip, sp, cpu_id, pd_id, utcb_p, utcb_v, pt->main_thread()); + + /* return software TLB that the thread is assigned to */ + Pd::Pool * const pp = Pd::pool(); + Pd * const pd = pp->object(t->pd_id()); + assert(pd); + user_arg_0((Syscall_ret)pd->tlb()); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_pause_thread() +{ + unsigned const tid = user_arg_1(); + + /* shortcut for a thread to pause itself */ + if (!tid) { + pause(); + user_arg_0(0); + return; + } + + /* get targeted thread and check permissions */ + Thread * const t = Thread::pool()->object(tid); + assert(t && (pd_id() == core_id() || this == t)); + + /* pause targeted thread */ + t->pause(); + user_arg_0(0); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_resume_thread() +{ + /* lookup thread */ + Thread * const t = Thread::pool()->object(user_arg_1()); + if (!t) { + PERR("unknown thread"); + user_arg_0(-1); + return; + } + /* check permissions */ + if (pd_id() != core_id() && pd_id() != t->pd_id()) { + PERR("not entitled to resume thread"); + user_arg_0(-1); + return; + } + /* resume targeted thread */ + user_arg_0(t->resume()); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_resume_faulter() +{ + /* lookup thread */ + Thread * const t = Thread::pool()->object(user_arg_1()); + if (!t) { + PERR("unknown thread"); + user_arg_0(-1); + return; + } + /* check permissions */ + if (pd_id() != core_id() && pd_id() != t->pd_id()) { + PERR("not entitled to resume thread"); + user_arg_0(-1); + return; + } + /* writeback translation table and resume faulter */ + Cpu::tlb_insertions(); + t->resume(); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_yield_thread() +{ + Thread * const t = Thread::pool()->object(user_arg_1()); + if (t) { t->receive_yielded_cpu(); } + cpu_scheduler()->yield(); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_current_thread_id() +{ user_arg_0((Syscall_ret)id()); } + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_get_thread() +{ + /* check permissions */ + if (pd_id() != core_id()) { + PERR("not entitled to read address of platform thread"); + user_arg_0(0); + return; + } + /* lookup thread */ + unsigned const id = user_arg_1(); + Thread * t; + if (id) { + t = Thread::pool()->object(id); + if (!t) { + PERR("unknown thread"); + user_arg_0(0); + } + } else { t = this; } + user_arg_0((Syscall_ret)t->platform_thread()); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_wait_for_request() +{ + wait_for_request(); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_request_and_wait() +{ + /* get IPC receiver */ + Thread * const t = Thread::pool()->object(user_arg_1()); + assert(t); + + /* do IPC */ + request_and_wait(t, (size_t)user_arg_2()); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_reply() { + reply((size_t)user_arg_1(), (bool)user_arg_2()); } + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_set_pager() +{ + /* check permissions */ + if (pd_id() != core_id()) { + PERR("not entitled to set pager"); + return; + } + /* lookup faulter and pager thread */ + unsigned const pager_id = user_arg_1(); + Thread * const pager = Thread::pool()->object(pager_id); + Thread * const faulter = Thread::pool()->object(user_arg_2()); + if ((pager_id && !pager) || !faulter) { + PERR("failed to set pager"); + return; + } + /* assign pager */ + faulter->pager(pager); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_update_pd() +{ + assert(pd_id() == core_id()); + Cpu::flush_tlb_by_pid(user_arg_1()); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_update_region() +{ + assert(pd_id() == core_id()); + + /* FIXME we don't handle instruction caches by now */ + Cpu::flush_data_cache_by_virt_region((addr_t)user_arg_1(), + (size_t)user_arg_2()); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_allocate_irq() +{ + assert(pd_id() == core_id()); + unsigned irq = user_arg_1(); + user_arg_0(allocate_irq(irq)); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_free_irq() +{ + assert(pd_id() == core_id()); + unsigned irq = user_arg_1(); + user_arg_0(free_irq(irq)); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_await_irq() +{ + assert(pd_id() == core_id()); + await_irq(); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_print_char() +{ + Genode::printf("%c", (char)user_arg_1()); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_read_thread_state() +{ + assert(pd_id() == core_id()); + Thread * const t = Thread::pool()->object(user_arg_1()); + if (!t) PDBG("Targeted thread unknown"); + Thread_state * const ts = (Thread_state *)phys_utcb()->base(); + t->Cpu::Context::read_cpu_state(ts); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_write_thread_state() +{ + assert(pd_id() == core_id()); + Thread * const t = Thread::pool()->object(user_arg_1()); + if (!t) PDBG("Targeted thread unknown"); + Thread_state * const ts = (Thread_state *)phys_utcb()->base(); + t->Cpu::Context::write_cpu_state(ts); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_new_signal_receiver() +{ + /* check permissions */ + if (pd_id() != core_id()) { + PERR("not entitled to create signal receiver"); + user_arg_0(0); + return; + } + /* create receiver */ + void * p = (void *)user_arg_1(); + Signal_receiver * const r = new (p) Signal_receiver(); + user_arg_0(r->id()); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_new_signal_context() +{ + /* check permissions */ + if (pd_id() != core_id()) { + PERR("not entitled to create signal context"); + user_arg_0(0); + return; + } + /* lookup receiver */ + unsigned id = user_arg_2(); + Signal_receiver * const r = Signal_receiver::pool()->object(id); + if (!r) { + PERR("unknown signal receiver"); + user_arg_0(0); + return; + } + /* create and assign context*/ + void * p = (void *)user_arg_1(); + unsigned imprint = user_arg_3(); + if (r->new_context(p, imprint)) { + PERR("failed to create signal context"); + user_arg_0(0); + return; + } + /* return context name */ + Signal_context * const c = (Signal_context *)p; + user_arg_0(c->id()); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_await_signal() +{ + /* lookup receiver */ + unsigned id = user_arg_1(); + Signal_receiver * const r = Signal_receiver::pool()->object(id); + if (!r) { + PERR("unknown signal receiver"); + user_arg_0(-1); + return; + } + /* register handler at the receiver */ + if (r->add_handler(this)) { + PERR("failed to register handler at signal receiver"); + user_arg_0(-1); + return; + } + user_arg_0(0); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_signal_pending() +{ + /* lookup signal receiver */ + unsigned id = user_arg_1(); + Signal_receiver * const r = Signal_receiver::pool()->object(id); + if (!r) { + PERR("unknown signal receiver"); + user_arg_0(0); + return; + } + /* get pending state */ + user_arg_0(r->deliverable()); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_submit_signal() +{ + /* lookup signal context */ + unsigned const id = user_arg_1(); + Signal_context * const c = Signal_context::pool()->object(id); + if(!c) { + PERR("unknown signal context"); + user_arg_0(-1); + return; + } + /* trigger signal context */ + if (c->submit(user_arg_2())) { + PERR("failed to submit signal context"); + user_arg_0(-1); + return; + } + user_arg_0(0); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_ack_signal() +{ + /* lookup signal context */ + unsigned id = user_arg_1(); + Signal_context * const c = Signal_context::pool()->object(id); + if (!c) { + PERR("unknown signal context"); + return; + } + /* acknowledge */ + c->ack(); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_kill_signal_context() +{ + /* check permissions */ + if (pd_id() != core_id()) { + PERR("not entitled to kill signal context"); + user_arg_0(-1); + return; + } + /* lookup signal context */ + unsigned id = user_arg_1(); + Signal_context * const c = Signal_context::pool()->object(id); + if (!c) { + PERR("unknown signal context"); + user_arg_0(0); + return; + } + /* kill signal context */ + if (c->kill(this)) { + PERR("failed to kill signal context"); + user_arg_0(-1); + return; + } + user_arg_0(0); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_kill_signal_receiver() +{ + /* check permissions */ + if (pd_id() != core_id()) { + PERR("not entitled to kill signal receiver"); + user_arg_0(-1); + return; + } + /* lookup signal receiver */ + unsigned id = user_arg_1(); + Signal_receiver * const r = Signal_receiver::pool()->object(id); + if (!r) { + PERR("unknown signal receiver"); + user_arg_0(0); + return; + } + /* kill signal receiver */ + if (r->kill(this)) { + PERR("unknown signal receiver"); + user_arg_0(-1); + return; + } + user_arg_0(0); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_new_vm() +{ + /* check permissions */ + assert(pd_id() == core_id()); + + /* dispatch arguments */ + void * const allocator = (void * const)user_arg_1(); + Genode::Cpu_state_modes * const state = + (Genode::Cpu_state_modes * const)user_arg_2(); + Signal_context * const context = + Signal_context::pool()->object(user_arg_3()); + assert(context); + + /* create vm */ + Vm * const vm = new (allocator) Vm(state, context); + + /* return vm id */ + user_arg_0((Syscall_ret)vm->id()); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_run_vm() +{ + /* check permissions */ + assert(pd_id() == core_id()); + + /* get targeted vm via its id */ + Vm * const vm = Vm::pool()->object(user_arg_1()); + assert(vm); + + /* run targeted vm */ + vm->run(); +} + + +/** + * Do specific syscall for this thread, for details see 'syscall.h' + */ +void Thread::_syscall_pause_vm() +{ + /* check permissions */ + assert(pd_id() == core_id()); + + /* get targeted vm via its id */ + Vm * const vm = Vm::pool()->object(user_arg_1()); + assert(vm); + + /* pause targeted vm */ + vm->pause(); +} + + +/** + * Handle a syscall request + */ +void Thread::_syscall() +{ + switch (user_arg_0()) + { + case NEW_THREAD : _syscall_new_thread(); return; + case DELETE_THREAD : _syscall_delete_thread(); return; + case START_THREAD : _syscall_start_thread(); return; + case PAUSE_THREAD : _syscall_pause_thread(); return; + case RESUME_THREAD : _syscall_resume_thread(); return; + case RESUME_FAULTER : _syscall_resume_faulter(); return; + case GET_THREAD : _syscall_get_thread(); return; + case CURRENT_THREAD_ID : _syscall_current_thread_id(); return; + case YIELD_THREAD : _syscall_yield_thread(); return; + case READ_THREAD_STATE : _syscall_read_thread_state(); return; + case WRITE_THREAD_STATE : _syscall_write_thread_state(); return; + case REQUEST_AND_WAIT : _syscall_request_and_wait(); return; + case REPLY : _syscall_reply(); return; + case WAIT_FOR_REQUEST : _syscall_wait_for_request(); return; + case SET_PAGER : _syscall_set_pager(); return; + case UPDATE_PD : _syscall_update_pd(); return; + case UPDATE_REGION : _syscall_update_region(); return; + case NEW_PD : _syscall_new_pd(); return; + case ALLOCATE_IRQ : _syscall_allocate_irq(); return; + case AWAIT_IRQ : _syscall_await_irq(); return; + case FREE_IRQ : _syscall_free_irq(); return; + case PRINT_CHAR : _syscall_print_char(); return; + case NEW_SIGNAL_RECEIVER : _syscall_new_signal_receiver(); return; + case NEW_SIGNAL_CONTEXT : _syscall_new_signal_context(); return; + case KILL_SIGNAL_CONTEXT : _syscall_kill_signal_context(); return; + case KILL_SIGNAL_RECEIVER : _syscall_kill_signal_receiver(); return; + case AWAIT_SIGNAL : _syscall_await_signal(); return; + case SUBMIT_SIGNAL : _syscall_submit_signal(); return; + case SIGNAL_PENDING : _syscall_signal_pending(); return; + case ACK_SIGNAL : _syscall_ack_signal(); return; + case NEW_VM : _syscall_new_vm(); return; + case RUN_VM : _syscall_run_vm(); return; + case PAUSE_VM : _syscall_pause_vm(); return; + case KILL_PD : _syscall_kill_pd(); return; + default: + PERR("invalid syscall"); + stop(); + reset_lap_time(); + } } diff --git a/base-hw/src/core/kernel/thread.h b/base-hw/src/core/kernel/thread.h index ed89fc9987..1e193f2d5d 100644 --- a/base-hw/src/core/kernel/thread.h +++ b/base-hw/src/core/kernel/thread.h @@ -37,7 +37,6 @@ namespace Kernel typedef Genode::Native_utcb Native_utcb; unsigned core_id(); - void handle_syscall(Thread * const); void handle_interrupt(void); void reset_lap_time(); @@ -70,17 +69,17 @@ class Kernel::Thread enum State { - SCHEDULED = 1, - AWAIT_START = 2, - AWAIT_IPC = 3, - AWAIT_RESUME = 4, - AWAIT_PAGER = 5, - AWAIT_PAGER_IPC = 6, - AWAIT_IRQ = 7, - AWAIT_SIGNAL = 8, - AWAIT_SIGNAL_CONTEXT_KILL = 9, - AWAIT_SIGNAL_RECEIVER_KILL = 10, - STOPPED = 11, + SCHEDULED = 1, + AWAITS_START = 2, + AWAITS_IPC = 3, + AWAITS_RESUME = 4, + AWAITS_PAGER = 5, + AWAITS_PAGER_IPC = 6, + AWAITS_IRQ = 7, + AWAITS_SIGNAL = 8, + AWAITS_SIGNAL_CONTEXT_KILL = 9, + AWAITS_SIGNAL_RECEIVER_KILL = 10, + STOPPED = 11, }; Platform_thread * const _platform_thread; @@ -109,13 +108,13 @@ class Kernel::Thread void _signal_context_kill_pending() { assert(_state == SCHEDULED); - _state = AWAIT_SIGNAL_CONTEXT_KILL; + _state = AWAITS_SIGNAL_CONTEXT_KILL; cpu_scheduler()->remove(this); } void _signal_context_kill_done() { - assert(_state == AWAIT_SIGNAL_CONTEXT_KILL); + assert(_state == AWAITS_SIGNAL_CONTEXT_KILL); user_arg_0(0); _schedule(); } @@ -128,13 +127,13 @@ class Kernel::Thread void _signal_receiver_kill_pending() { assert(_state == SCHEDULED); - _state = AWAIT_SIGNAL_RECEIVER_KILL; + _state = AWAITS_SIGNAL_RECEIVER_KILL; cpu_scheduler()->remove(this); } void _signal_receiver_kill_done() { - assert(_state == AWAIT_SIGNAL_RECEIVER_KILL); + assert(_state == AWAITS_SIGNAL_RECEIVER_KILL); user_arg_0(0); _schedule(); } @@ -147,13 +146,13 @@ class Kernel::Thread void _await_signal(Signal_receiver * const receiver) { cpu_scheduler()->remove(this); - _state = AWAIT_SIGNAL; + _state = AWAITS_SIGNAL; _signal_receiver = receiver; } void _receive_signal(void * const base, size_t const size) { - assert(_state == AWAIT_SIGNAL && size <= phys_utcb()->size()); + assert(_state == AWAITS_SIGNAL && size <= phys_utcb()->size()); Genode::memcpy(phys_utcb()->base(), base, size); _schedule(); } @@ -181,8 +180,8 @@ class Kernel::Thread switch (_state) { case SCHEDULED: cpu_scheduler()->remove(this); - _state = AWAIT_IPC; - case AWAIT_PAGER: + _state = AWAITS_IPC; + case AWAITS_PAGER: return; default: PERR("wrong thread state to await IPC"); @@ -194,7 +193,7 @@ class Kernel::Thread void _await_ipc_succeeded(bool const reply, size_t const s) { switch (_state) { - case AWAIT_IPC: + case AWAITS_IPC: /* FIXME: return error codes on all IPC transfers */ if (reply) { phys_utcb()->ipc_msg_size(s); @@ -205,11 +204,11 @@ class Kernel::Thread _schedule(); } return; - case AWAIT_PAGER_IPC: + case AWAITS_PAGER_IPC: _schedule(); return; - case AWAIT_PAGER: - _state = AWAIT_RESUME; + case AWAITS_PAGER: + _state = AWAITS_RESUME; return; default: PERR("wrong thread state to receive IPC"); @@ -221,7 +220,7 @@ class Kernel::Thread void _await_ipc_failed(bool const reply) { switch (_state) { - case AWAIT_IPC: + case AWAITS_IPC: /* FIXME: return error codes on all IPC transfers */ if (reply) { user_arg_0(-1); @@ -235,11 +234,11 @@ class Kernel::Thread PERR("failed to receive IPC"); stop(); return; - case AWAIT_PAGER_IPC: + case AWAITS_PAGER_IPC: PERR("failed to get pagefault resolved"); stop(); return; - case AWAIT_PAGER: + case AWAITS_PAGER: PERR("failed to get pagefault resolved"); stop(); return; @@ -257,16 +256,61 @@ class Kernel::Thread void _received_irq() { - assert(_state == AWAIT_IRQ); + assert(_state == AWAITS_IRQ); _schedule(); } void _awaits_irq() { cpu_scheduler()->remove(this); - _state = AWAIT_IRQ; + _state = AWAITS_IRQ; } + /** + * Handle syscall request of this thread + */ + void _syscall(); + + + /*************************************************** + ** Syscall backends, for details see 'syscall.h' ** + ***************************************************/ + + void _syscall_new_pd(); + void _syscall_kill_pd(); + void _syscall_new_thread(); + void _syscall_delete_thread(); + void _syscall_start_thread(); + void _syscall_pause_thread(); + void _syscall_resume_thread(); + void _syscall_resume_faulter(); + void _syscall_yield_thread(); + void _syscall_current_thread_id(); + void _syscall_get_thread(); + void _syscall_wait_for_request(); + void _syscall_request_and_wait(); + void _syscall_reply(); + void _syscall_set_pager(); + void _syscall_update_pd(); + void _syscall_update_region(); + void _syscall_allocate_irq(); + void _syscall_free_irq(); + void _syscall_await_irq(); + void _syscall_print_char(); + void _syscall_read_thread_state(); + void _syscall_write_thread_state(); + void _syscall_new_signal_receiver(); + void _syscall_new_signal_context(); + void _syscall_await_signal(); + void _syscall_signal_pending(); + void _syscall_submit_signal(); + void _syscall_ack_signal(); + void _syscall_kill_signal_context(); + void _syscall_kill_signal_receiver(); + void _syscall_new_vm(); + void _syscall_run_vm(); + void _syscall_pause_vm(); + public: /** @@ -352,9 +396,9 @@ class Kernel::Thread */ void pause() { - assert(_state == AWAIT_RESUME || _state == SCHEDULED); + assert(_state == AWAITS_RESUME || _state == SCHEDULED); cpu_scheduler()->remove(this); - _state = AWAIT_RESUME; + _state = AWAITS_RESUME; } /** @@ -363,33 +407,33 @@ class Kernel::Thread int resume() { switch (_state) { - case AWAIT_RESUME: + case AWAITS_RESUME: _schedule(); return 0; - case AWAIT_PAGER: - _state = AWAIT_PAGER_IPC; + case AWAITS_PAGER: + _state = AWAITS_PAGER_IPC; return 0; - case AWAIT_PAGER_IPC: + case AWAITS_PAGER_IPC: Ipc_node::cancel_waiting(); return 0; case SCHEDULED: return 1; - case AWAIT_IPC: + case AWAITS_IPC: Ipc_node::cancel_waiting(); return 0; - case AWAIT_IRQ: + case AWAITS_IRQ: Irq_receiver::cancel_waiting(); return 0; - case AWAIT_SIGNAL: + case AWAITS_SIGNAL: Signal_handler::cancel_waiting(); return 0; - case AWAIT_SIGNAL_CONTEXT_KILL: + case AWAITS_SIGNAL_CONTEXT_KILL: Signal_context_killer::cancel_waiting(); return 0; - case AWAIT_SIGNAL_RECEIVER_KILL: + case AWAITS_SIGNAL_RECEIVER_KILL: Signal_receiver_killer::cancel_waiting(); return 0; - case AWAIT_START: + case AWAITS_START: case STOPPED:; } PERR("failed to resume thread"); @@ -435,7 +479,7 @@ class Kernel::Thread { /* pause thread */ cpu_scheduler()->remove(this); - _state = AWAIT_PAGER; + _state = AWAITS_PAGER; /* check out cause and attributes */ addr_t va = 0; @@ -461,7 +505,7 @@ class Kernel::Thread */ void receive_yielded_cpu() { - if (_state == AWAIT_RESUME) { _schedule(); } + if (_state == AWAITS_RESUME) { _schedule(); } else { PERR("failed to receive yielded CPU"); } } @@ -474,7 +518,7 @@ class Kernel::Thread { switch(cpu_exception) { case SUPERVISOR_CALL: - handle_syscall(this); + _syscall(); return; case PREFETCH_ABORT: handle_mmu_exception();