mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-23 23:42:32 +00:00
parent
5cd2f6ee0b
commit
ffb26eb501
@ -22,9 +22,6 @@
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/thread_state.h>
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/pd.h>
|
||||
#include <kernel/vm.h>
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -11,14 +11,23 @@
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/thread_state.h>
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/kernel.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <kernel/pd.h>
|
||||
#include <kernel/vm.h>
|
||||
#include <platform_thread.h>
|
||||
#include <platform_pd.h>
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user