mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-09 04:15:52 +00:00
parent
1843f10c62
commit
3070af9194
@ -28,9 +28,9 @@
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/pd.h>
|
||||
#include <platform_thread.h>
|
||||
#include <platform_pd.h>
|
||||
#include <trustzone.h>
|
||||
#include <timer.h>
|
||||
|
||||
/* base-hw includes */
|
||||
#include <singleton.h>
|
||||
@ -47,8 +47,7 @@ namespace Kernel
|
||||
/* import Genode types */
|
||||
typedef Genode::Thread_state Thread_state;
|
||||
typedef Genode::umword_t umword_t;
|
||||
|
||||
class Schedule_context;
|
||||
typedef Genode::Core_tlb Core_tlb;
|
||||
}
|
||||
|
||||
namespace Kernel
|
||||
@ -70,11 +69,6 @@ namespace Kernel
|
||||
timer()->start_one_shot(timer()->ms_to_tics(USER_LAP_TIME_MS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Access to the static CPU scheduler
|
||||
*/
|
||||
static Cpu_scheduler * cpu_scheduler();
|
||||
|
||||
|
||||
/**
|
||||
* Static kernel PD that describes core
|
||||
@ -92,119 +86,6 @@ namespace Kernel
|
||||
* Get core attributes
|
||||
*/
|
||||
unsigned core_id() { return core()->id(); }
|
||||
|
||||
|
||||
class Thread;
|
||||
|
||||
void handle_pagefault(Thread * const);
|
||||
void handle_syscall(Thread * const);
|
||||
void handle_interrupt(void);
|
||||
void handle_invalid_excpt(void);
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Thread::_schedule()
|
||||
{
|
||||
cpu_scheduler()->insert(this);
|
||||
_state = SCHEDULED;
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Thread::pause()
|
||||
{
|
||||
assert(_state == AWAIT_RESUMPTION || _state == SCHEDULED);
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAIT_RESUMPTION;
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Thread::stop()
|
||||
{
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAIT_START;
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Thread::request_and_wait(Thread * const dest, size_t const size) {
|
||||
Ipc_node::send_request_await_reply(dest, phys_utcb()->base(),
|
||||
size, phys_utcb()->base(),
|
||||
phys_utcb()->size()); }
|
||||
|
||||
|
||||
void Kernel::Thread::wait_for_request() {
|
||||
Ipc_node::await_request(phys_utcb()->base(),
|
||||
phys_utcb()->size()); }
|
||||
|
||||
|
||||
void Kernel::Thread::reply(size_t const size, bool const await_request)
|
||||
{
|
||||
Ipc_node::send_reply(phys_utcb()->base(), size);
|
||||
if (await_request)
|
||||
Ipc_node::await_request(phys_utcb()->base(),
|
||||
phys_utcb()->size());
|
||||
else user_arg_0(0);
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Thread::await_signal(Kernel::Signal_receiver * receiver)
|
||||
{
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAIT_SIGNAL;
|
||||
_signal_receiver = receiver;
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Thread::_received_irq()
|
||||
{
|
||||
assert(_state == AWAIT_IRQ);
|
||||
_schedule();
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Thread::handle_exception()
|
||||
{
|
||||
switch(cpu_exception) {
|
||||
case SUPERVISOR_CALL:
|
||||
handle_syscall(this);
|
||||
return;
|
||||
case PREFETCH_ABORT:
|
||||
case DATA_ABORT:
|
||||
handle_pagefault(this);
|
||||
return;
|
||||
case INTERRUPT_REQUEST:
|
||||
case FAST_INTERRUPT_REQUEST:
|
||||
handle_interrupt();
|
||||
return;
|
||||
default:
|
||||
handle_invalid_excpt();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Thread::proceed()
|
||||
{
|
||||
mtc()->continue_user(static_cast<Cpu::Context *>(this));
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Thread::_has_received(size_t const s)
|
||||
{
|
||||
user_arg_0(s);
|
||||
if (_state != SCHEDULED) _schedule();
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Thread::_awaits_receipt()
|
||||
{
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAIT_IPC;
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Thread::_awaits_irq()
|
||||
{
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAIT_IRQ;
|
||||
}
|
||||
|
||||
|
||||
@ -218,7 +99,7 @@ namespace Kernel
|
||||
}
|
||||
|
||||
class Vm : public Object<Vm, MAX_VMS>,
|
||||
public Schedule_context
|
||||
public Execution_context
|
||||
{
|
||||
private:
|
||||
|
||||
@ -245,9 +126,9 @@ namespace Kernel
|
||||
void pause() { cpu_scheduler()->remove(this); }
|
||||
|
||||
|
||||
/**********************
|
||||
** Schedule_context **
|
||||
**********************/
|
||||
/***********************
|
||||
** Execution_context **
|
||||
***********************/
|
||||
|
||||
void handle_exception()
|
||||
{
|
||||
@ -279,17 +160,18 @@ namespace Kernel
|
||||
if (initial)
|
||||
{
|
||||
/* initialize idle thread */
|
||||
void * sp;
|
||||
sp = (void *)&idle_stack[sizeof(idle_stack)/sizeof(idle_stack[0])];
|
||||
enum { STACK_SIZE = sizeof(idle_stack)/sizeof(idle_stack[0]) };
|
||||
void * const ip = (void *)&idle_main;
|
||||
void * const sp = (void *)&idle_stack[STACK_SIZE];
|
||||
|
||||
/*
|
||||
* Idle doesn't use its UTCB pointer, thus
|
||||
* utcb_phys = utcb_virt = 0 is save.
|
||||
* Base-hw doesn't support multiple cores, thus
|
||||
* cpu_no = 0 is ok. We don't use 'start' to avoid
|
||||
* recursive call of'cpu_scheduler'.
|
||||
* recursive call of'cpu_scheduler()'.
|
||||
*/
|
||||
idle.prepare_to_start((void *)&idle_main, sp, 0, core_id(), 0, 0);
|
||||
idle.prepare_to_start(ip, sp, 0, core_id(), 0, 0, 0);
|
||||
initial = 0;
|
||||
}
|
||||
/* create scheduler with a permanent idle thread */
|
||||
@ -444,14 +326,17 @@ namespace Kernel
|
||||
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 = (unsigned)user->user_arg_4();
|
||||
unsigned const cpu_id = (unsigned)user->user_arg_4();
|
||||
|
||||
/* get targeted thread */
|
||||
Thread * const t = Thread::pool()->object(pt->id());
|
||||
assert(t);
|
||||
|
||||
/* start thread */
|
||||
t->start(ip, sp, cpu, pt->pd_id(), pt->phys_utcb(), pt->virt_utcb());
|
||||
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();
|
||||
@ -979,7 +864,7 @@ extern "C" void kernel()
|
||||
enum { CM_STACK_SIZE = sizeof(cm_stack)/sizeof(cm_stack[0]) + 1 };
|
||||
core_main.start((void *)CORE_MAIN,
|
||||
(void *)&cm_stack[CM_STACK_SIZE - 1],
|
||||
0, core_id(), &cm_utcb, &cm_utcb);
|
||||
0, core_id(), &cm_utcb, &cm_utcb, 1);
|
||||
|
||||
/* kernel initialization finished */
|
||||
reset_lap_time();
|
||||
@ -989,128 +874,6 @@ extern "C" void kernel()
|
||||
cpu_scheduler()->head()->proceed();
|
||||
}
|
||||
|
||||
|
||||
/********************
|
||||
** Kernel::Thread **
|
||||
********************/
|
||||
|
||||
void Kernel::Thread::crash()
|
||||
{
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = CRASHED;
|
||||
}
|
||||
|
||||
int Kernel::Thread::resume()
|
||||
{
|
||||
switch (_state) {
|
||||
case AWAIT_RESUMPTION:
|
||||
_schedule();
|
||||
return 0;
|
||||
case SCHEDULED:
|
||||
return 1;
|
||||
case AWAIT_IPC:
|
||||
PDBG("cancel IPC receipt");
|
||||
Ipc_node::cancel_waiting();
|
||||
_schedule();
|
||||
return 0;
|
||||
case AWAIT_IRQ:
|
||||
PDBG("cancel IRQ receipt");
|
||||
Irq_receiver::cancel_waiting();
|
||||
_schedule();
|
||||
return 0;
|
||||
case AWAIT_SIGNAL:
|
||||
PDBG("cancel signal receipt");
|
||||
_signal_receiver->remove_handler(signal_handler());
|
||||
_schedule();
|
||||
return 0;
|
||||
case AWAIT_SIGNAL_CONTEXT_DESTRUCT:
|
||||
PDBG("cancel signal context destruction");
|
||||
_schedule();
|
||||
return 0;
|
||||
case AWAIT_START:
|
||||
default:
|
||||
PERR("unresumable state");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Thread::prepare_to_start(void * const ip,
|
||||
void * const sp,
|
||||
unsigned const cpu_id,
|
||||
unsigned const pd_id,
|
||||
Native_utcb * const utcb_phys,
|
||||
Native_utcb * const utcb_virt)
|
||||
{
|
||||
/* check state and arguments */
|
||||
assert(_state == AWAIT_START)
|
||||
assert(!cpu_id);
|
||||
|
||||
/* store thread parameters */
|
||||
_phys_utcb = utcb_phys;
|
||||
_virt_utcb = utcb_virt;
|
||||
_pd_id = pd_id;
|
||||
|
||||
/* join a protection domain */
|
||||
Pd * const pd = Pd::pool()->object(_pd_id);
|
||||
assert(pd)
|
||||
addr_t const tlb = pd->tlb()->base();
|
||||
|
||||
/* initialize CPU context */
|
||||
if (!_platform_thread)
|
||||
/* this is the main thread of core */
|
||||
User_context::init_core_main_thread(ip, sp, tlb, pd_id);
|
||||
else if (!_platform_thread->main_thread())
|
||||
/* this is not a main thread */
|
||||
User_context::init_thread(ip, sp, tlb, pd_id);
|
||||
else
|
||||
/* this is the main thread of a program other than core */
|
||||
User_context::init_main_thread(ip, _virt_utcb, tlb, pd_id);
|
||||
}
|
||||
|
||||
|
||||
void Thread::start(void * const ip,
|
||||
void * const sp,
|
||||
unsigned const cpu_id,
|
||||
unsigned const pd_id,
|
||||
Native_utcb * const utcb_phys,
|
||||
Native_utcb * const utcb_virt)
|
||||
{
|
||||
prepare_to_start(ip, sp, cpu_id, pd_id, utcb_phys, utcb_virt);
|
||||
_schedule();
|
||||
}
|
||||
|
||||
|
||||
void Thread::pagefault(addr_t const va, bool const w)
|
||||
{
|
||||
/* pause faulter */
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAIT_RESUMPTION;
|
||||
|
||||
/* inform pager through IPC */
|
||||
assert(_pager);
|
||||
_pagefault = Pagefault(id(), (Tlb *)tlb(), ip, va, w);
|
||||
Ipc_node::send_note(_pager, &_pagefault, sizeof(_pagefault));
|
||||
}
|
||||
|
||||
|
||||
void Thread::kill_signal_context_blocks()
|
||||
{
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAIT_SIGNAL_CONTEXT_DESTRUCT;
|
||||
}
|
||||
|
||||
|
||||
void Thread::kill_signal_context_done()
|
||||
{
|
||||
if (_state != AWAIT_SIGNAL_CONTEXT_DESTRUCT) {
|
||||
PDBG("ignore unexpected signal-context destruction");
|
||||
return;
|
||||
}
|
||||
user_arg_0(1);
|
||||
_schedule();
|
||||
}
|
||||
|
||||
static Kernel::Mode_transition_control * Kernel::mtc()
|
||||
{
|
||||
/* compose CPU context for kernel entry */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* \brief Kernel representation of a user thread
|
||||
* \brief Kernel backend for userland execution-contexts
|
||||
* \author Martin Stein
|
||||
* \date 2012-11-30
|
||||
*/
|
||||
@ -15,15 +15,13 @@
|
||||
#define _CORE__KERNEL__THREAD_H_
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/signal_receiver.h>
|
||||
#include <kernel/ipc_node.h>
|
||||
#include <kernel/configuration.h>
|
||||
#include <kernel/scheduler.h>
|
||||
#include <kernel/object.h>
|
||||
#include <kernel/signal_receiver.h>
|
||||
#include <kernel/ipc_node.h>
|
||||
#include <kernel/irq_receiver.h>
|
||||
#include <kernel/pd.h>
|
||||
#include <cpu.h>
|
||||
#include <tlb.h>
|
||||
#include <timer.h>
|
||||
|
||||
namespace Genode
|
||||
{
|
||||
@ -32,34 +30,61 @@ namespace Genode
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
typedef Genode::Cpu Cpu;
|
||||
typedef Genode::Core_tlb Core_tlb;
|
||||
typedef Genode::Pagefault Pagefault;
|
||||
typedef Genode::Native_utcb Native_utcb;
|
||||
class Thread;
|
||||
|
||||
class Schedule_context;
|
||||
typedef Scheduler<Schedule_context> Cpu_scheduler;
|
||||
typedef Genode::Cpu Cpu;
|
||||
typedef Genode::Pagefault Pagefault;
|
||||
typedef Genode::Native_utcb Native_utcb;
|
||||
|
||||
unsigned core_id();
|
||||
void handle_pagefault(Thread * const);
|
||||
void handle_syscall(Thread * const);
|
||||
void handle_interrupt(void);
|
||||
void handle_invalid_excpt(void);
|
||||
|
||||
/**
|
||||
* Kernel object that can be scheduled for the CPU
|
||||
*/
|
||||
class Schedule_context : public Cpu_scheduler::Item
|
||||
{
|
||||
public:
|
||||
class Execution_context;
|
||||
|
||||
virtual void handle_exception() = 0;
|
||||
virtual void proceed() = 0;
|
||||
};
|
||||
typedef Scheduler<Execution_context> Cpu_scheduler;
|
||||
|
||||
/**
|
||||
* Kernel representation of a user thread
|
||||
* Return the systems CPU scheduler
|
||||
*/
|
||||
class Thread : public Cpu::User_context,
|
||||
public Object<Thread, MAX_THREADS>,
|
||||
public Schedule_context,
|
||||
public Ipc_node,
|
||||
public Irq_receiver
|
||||
{
|
||||
static Cpu_scheduler * cpu_scheduler();
|
||||
|
||||
/**
|
||||
* Kernel backend for userland execution-contexts
|
||||
*/
|
||||
class Thread;
|
||||
}
|
||||
|
||||
class Kernel::Execution_context : public Cpu_scheduler::Item
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Handle an exception that occured during execution
|
||||
*/
|
||||
virtual void handle_exception() = 0;
|
||||
|
||||
/**
|
||||
* Continue execution
|
||||
*/
|
||||
virtual void proceed() = 0;
|
||||
};
|
||||
|
||||
class Kernel::Thread
|
||||
:
|
||||
public Cpu::User_context,
|
||||
public Object<Thread, MAX_THREADS>,
|
||||
public Execution_context,
|
||||
public Ipc_node,
|
||||
public Irq_receiver
|
||||
{
|
||||
private:
|
||||
|
||||
enum State
|
||||
{
|
||||
SCHEDULED,
|
||||
@ -72,179 +97,352 @@ namespace Kernel
|
||||
CRASHED,
|
||||
};
|
||||
|
||||
Platform_thread * const _platform_thread; /* userland object wich
|
||||
* addresses this thread */
|
||||
State _state; /* thread state, description given at the beginning */
|
||||
Pagefault _pagefault; /* last pagefault triggered by this thread */
|
||||
Thread * _pager; /* gets informed if thread throws a pagefault */
|
||||
unsigned _pd_id; /* ID of the PD this thread runs on */
|
||||
Native_utcb * _phys_utcb; /* physical UTCB base */
|
||||
Native_utcb * _virt_utcb; /* virtual UTCB base */
|
||||
Signal_receiver * _signal_receiver;
|
||||
Signal_handler _signal_handler;
|
||||
Platform_thread * const _platform_thread;
|
||||
State _state;
|
||||
Pagefault _pagefault;
|
||||
Thread * _pager;
|
||||
unsigned _pd_id;
|
||||
Native_utcb * _phys_utcb;
|
||||
Native_utcb * _virt_utcb;
|
||||
Signal_receiver * _signal_receiver;
|
||||
Signal_handler _signal_handler;
|
||||
|
||||
/**
|
||||
* Resume execution
|
||||
*/
|
||||
void _schedule();
|
||||
void _schedule()
|
||||
{
|
||||
cpu_scheduler()->insert(this);
|
||||
_state = SCHEDULED;
|
||||
}
|
||||
|
||||
|
||||
/**************
|
||||
** Ipc_node **
|
||||
**************/
|
||||
|
||||
void _has_received(size_t const s);
|
||||
void _has_received(size_t const s)
|
||||
{
|
||||
user_arg_0(s);
|
||||
if (_state != SCHEDULED) { _schedule(); }
|
||||
}
|
||||
|
||||
void _awaits_receipt();
|
||||
void _awaits_receipt()
|
||||
{
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAIT_IPC;
|
||||
}
|
||||
|
||||
|
||||
/***************
|
||||
** Irq_owner **
|
||||
***************/
|
||||
|
||||
void _received_irq();
|
||||
void _received_irq()
|
||||
{
|
||||
assert(_state == AWAIT_IRQ);
|
||||
_schedule();
|
||||
}
|
||||
|
||||
void _awaits_irq();
|
||||
void _awaits_irq()
|
||||
{
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAIT_IRQ;
|
||||
}
|
||||
|
||||
public:
|
||||
public:
|
||||
|
||||
void receive_signal(void * const base, size_t const size)
|
||||
{
|
||||
assert(_state == AWAIT_SIGNAL);
|
||||
assert(size <= phys_utcb()->size())
|
||||
Genode::memcpy(phys_utcb()->base(), base, size);
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param platform_thread userland backend of execution context
|
||||
*/
|
||||
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), _signal_handler((unsigned)this)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Suspend the thread due to unrecoverable misbehavior
|
||||
*/
|
||||
void crash()
|
||||
{
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = CRASHED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare thread to get scheduled the first time
|
||||
*
|
||||
* \param ip initial instruction pointer
|
||||
* \param sp initial stack pointer
|
||||
* \param cpu_id target cpu
|
||||
* \param pd_id target protection-domain
|
||||
* \param utcb_phys physical UTCB pointer
|
||||
* \param utcb_virt virtual UTCB pointer
|
||||
* \param main wether the thread is the first one in its PD
|
||||
*/
|
||||
void prepare_to_start(void * const ip,
|
||||
void * const sp,
|
||||
unsigned const cpu_id,
|
||||
unsigned const pd_id,
|
||||
Native_utcb * const utcb_phys,
|
||||
Native_utcb * const utcb_virt,
|
||||
bool const main)
|
||||
{
|
||||
assert(_state == AWAIT_START)
|
||||
|
||||
/* FIXME: support SMP */
|
||||
if (cpu_id) { PERR("multicore processing not supported"); }
|
||||
|
||||
/* store thread parameters */
|
||||
_phys_utcb = utcb_phys;
|
||||
_virt_utcb = utcb_virt;
|
||||
_pd_id = pd_id;
|
||||
|
||||
/* join a protection domain */
|
||||
Pd * const pd = Pd::pool()->object(_pd_id);
|
||||
assert(pd)
|
||||
addr_t const tlb = pd->tlb()->base();
|
||||
|
||||
/* initialize CPU context */
|
||||
User_context * const c = static_cast<User_context *>(this);
|
||||
bool const core = (_pd_id == core_id());
|
||||
if (!main) { c->init_thread(ip, sp, tlb, pd_id); }
|
||||
else if (!core) { c->init_main_thread(ip, utcb_virt, tlb, pd_id); }
|
||||
else { c->init_core_main_thread(ip, sp, tlb, pd_id); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Start this thread
|
||||
*
|
||||
* \param ip initial instruction pointer
|
||||
* \param sp initial stack pointer
|
||||
* \param cpu_id target cpu
|
||||
* \param pd_id target protection-domain
|
||||
* \param utcb_p physical UTCB pointer
|
||||
* \param utcb_v virtual UTCB pointer
|
||||
* \param main wether the thread is the first one in its PD
|
||||
*/
|
||||
void start(void * const ip,
|
||||
void * const sp,
|
||||
unsigned const cpu_id,
|
||||
unsigned const pd_id,
|
||||
Native_utcb * const utcb_p,
|
||||
Native_utcb * const utcb_v,
|
||||
bool const main)
|
||||
{
|
||||
prepare_to_start(ip, sp, cpu_id, pd_id, utcb_p, utcb_v, main);
|
||||
_schedule();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause this thread
|
||||
*/
|
||||
void pause()
|
||||
{
|
||||
assert(_state == AWAIT_RESUMPTION || _state == SCHEDULED);
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAIT_RESUMPTION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop this thread
|
||||
*/
|
||||
void stop()
|
||||
{
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAIT_START;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume this thread
|
||||
*/
|
||||
int resume()
|
||||
{
|
||||
switch (_state) {
|
||||
case AWAIT_RESUMPTION:
|
||||
_schedule();
|
||||
return 0;
|
||||
case SCHEDULED:
|
||||
return 1;
|
||||
case AWAIT_IPC:
|
||||
PDBG("cancel IPC receipt");
|
||||
Ipc_node::cancel_waiting();
|
||||
_schedule();
|
||||
return 0;
|
||||
case AWAIT_IRQ:
|
||||
PDBG("cancel IRQ receipt");
|
||||
Irq_receiver::cancel_waiting();
|
||||
_schedule();
|
||||
return 0;
|
||||
case AWAIT_SIGNAL:
|
||||
PDBG("cancel signal receipt");
|
||||
_signal_receiver->remove_handler(signal_handler());
|
||||
_schedule();
|
||||
return 0;
|
||||
case AWAIT_SIGNAL_CONTEXT_DESTRUCT:
|
||||
PDBG("cancel signal context destruction");
|
||||
_schedule();
|
||||
return 0;
|
||||
case AWAIT_START:
|
||||
default:
|
||||
PERR("unresumable state");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void * operator new (size_t, void * p) { return p; }
|
||||
/**
|
||||
* Send a request and await the reply
|
||||
*/
|
||||
void request_and_wait(Thread * const dest, size_t const size)
|
||||
{
|
||||
Ipc_node::send_request_await_reply(
|
||||
dest, phys_utcb()->base(), size, phys_utcb()->base(),
|
||||
phys_utcb()->size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
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), _signal_handler((unsigned)this)
|
||||
{ }
|
||||
/**
|
||||
* Wait for any request
|
||||
*/
|
||||
void wait_for_request()
|
||||
{
|
||||
Ipc_node::await_request(phys_utcb()->base(), phys_utcb()->size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Suspend the thread due to unrecoverable misbehavior
|
||||
*/
|
||||
void crash();
|
||||
/**
|
||||
* Reply to the last request
|
||||
*/
|
||||
void reply(size_t const size, bool const await_request)
|
||||
{
|
||||
Ipc_node::send_reply(phys_utcb()->base(), size);
|
||||
if (await_request) {
|
||||
Ipc_node * const ipc = static_cast<Ipc_node *>(this);
|
||||
ipc->await_request(phys_utcb()->base(), phys_utcb()->size());
|
||||
}
|
||||
else { user_arg_0(0); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare thread to get scheduled the first time
|
||||
*
|
||||
* \param ip initial instruction pointer
|
||||
* \param sp initial stack pointer
|
||||
* \param cpu_id target cpu
|
||||
* \param pd_id target protection-domain
|
||||
* \param utcb_phys physical UTCB pointer
|
||||
* \param utcb_virt virtual UTCB pointer
|
||||
*/
|
||||
void prepare_to_start(void * const ip,
|
||||
void * const sp,
|
||||
unsigned const cpu_id,
|
||||
unsigned const pd_id,
|
||||
Native_utcb * const utcb_phys,
|
||||
Native_utcb * const utcb_virt);
|
||||
/**
|
||||
* Handle a pagefault that originates from this thread
|
||||
*
|
||||
* \param va virtual fault address
|
||||
* \param w if fault was caused by a write access
|
||||
*/
|
||||
void pagefault(addr_t const va, bool const w)
|
||||
{
|
||||
assert(_state == SCHEDULED && _pager);
|
||||
|
||||
/**
|
||||
* Start this thread
|
||||
*
|
||||
* \param ip initial instruction pointer
|
||||
* \param sp initial stack pointer
|
||||
* \param cpu_id target cpu
|
||||
* \param pd_id target protection-domain
|
||||
* \param utcb_phys physical UTCB pointer
|
||||
* \param utcb_virt virtual UTCB pointer
|
||||
*/
|
||||
void start(void * const ip,
|
||||
void * const sp,
|
||||
unsigned const cpu_id,
|
||||
unsigned const pd_id,
|
||||
Native_utcb * const utcb_phys,
|
||||
Native_utcb * const utcb_virt);
|
||||
/* pause faulter */
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAIT_RESUMPTION;
|
||||
|
||||
/**
|
||||
* Pause this thread
|
||||
*/
|
||||
void pause();
|
||||
/* inform pager through IPC */
|
||||
_pagefault = Pagefault(id(), (Tlb *)tlb(), ip, va, w);
|
||||
Ipc_node::send_note(_pager, &_pagefault, sizeof(_pagefault));
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop this thread
|
||||
*/
|
||||
void stop();
|
||||
/**
|
||||
* Get unique thread ID, avoid method ambiguousness
|
||||
*/
|
||||
unsigned id() const { return Object::id(); }
|
||||
|
||||
/**
|
||||
* Resume this thread
|
||||
*/
|
||||
int resume();
|
||||
/**
|
||||
* Let the thread block for signal receipt
|
||||
*
|
||||
* \param receiver the signal pool that the thread blocks for
|
||||
*/
|
||||
void await_signal(Signal_receiver * receiver)
|
||||
{
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAIT_SIGNAL;
|
||||
_signal_receiver = receiver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a request and await the reply
|
||||
*/
|
||||
void request_and_wait(Thread * const dest, size_t const size);
|
||||
/**
|
||||
* Let the thread receive signal data
|
||||
*
|
||||
* \param base signal-data base
|
||||
* \param size signal-data size
|
||||
*/
|
||||
void receive_signal(void * const base, size_t const size)
|
||||
{
|
||||
assert(_state == AWAIT_SIGNAL && size <= phys_utcb()->size());
|
||||
Genode::memcpy(phys_utcb()->base(), base, size);
|
||||
_schedule();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for any request
|
||||
*/
|
||||
void wait_for_request();
|
||||
/**
|
||||
* Destructing a signal context blocks the thread for now
|
||||
*/
|
||||
void kill_signal_context_blocks()
|
||||
{
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAIT_SIGNAL_CONTEXT_DESTRUCT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reply to the last request
|
||||
*/
|
||||
void reply(size_t const size, bool const await_request);
|
||||
/**
|
||||
* A signal-context destruction that blocked the thread is done
|
||||
*/
|
||||
void kill_signal_context_done()
|
||||
{
|
||||
if (_state != AWAIT_SIGNAL_CONTEXT_DESTRUCT) {
|
||||
PDBG("ignore unexpected signal-context destruction");
|
||||
return;
|
||||
}
|
||||
user_arg_0(1);
|
||||
_schedule();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a pagefault that originates from this thread
|
||||
*
|
||||
* \param va virtual fault address
|
||||
* \param w if fault was caused by a write access
|
||||
*/
|
||||
void pagefault(addr_t const va, bool const w);
|
||||
|
||||
/**
|
||||
* Get unique thread ID, avoid method ambiguousness
|
||||
*/
|
||||
unsigned id() const { return Object::id(); }
|
||||
/***********************
|
||||
** Execution_context **
|
||||
***********************/
|
||||
|
||||
/**
|
||||
* Gets called when we await a signal at 'receiver'
|
||||
*/
|
||||
void await_signal(Kernel::Signal_receiver * receiver);
|
||||
void handle_exception()
|
||||
{
|
||||
switch(cpu_exception) {
|
||||
case SUPERVISOR_CALL:
|
||||
handle_syscall(this);
|
||||
return;
|
||||
case PREFETCH_ABORT:
|
||||
handle_pagefault(this);
|
||||
return;
|
||||
case DATA_ABORT:
|
||||
handle_pagefault(this);
|
||||
return;
|
||||
case INTERRUPT_REQUEST:
|
||||
handle_interrupt();
|
||||
return;
|
||||
case FAST_INTERRUPT_REQUEST:
|
||||
handle_interrupt();
|
||||
return;
|
||||
default:
|
||||
handle_invalid_excpt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the exception that currently blocks this thread
|
||||
*/
|
||||
void handle_exception();
|
||||
void proceed()
|
||||
{
|
||||
mtc()->continue_user(static_cast<Cpu::Context *>(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Continue executing this thread in userland
|
||||
*/
|
||||
void proceed();
|
||||
|
||||
void kill_signal_context_blocks();
|
||||
/***************
|
||||
** Accessors **
|
||||
***************/
|
||||
|
||||
void kill_signal_context_done();
|
||||
Platform_thread * platform_thread() const { return _platform_thread; }
|
||||
|
||||
/***************
|
||||
** Accessors **
|
||||
***************/
|
||||
void pager(Thread * const p) { _pager = p; }
|
||||
|
||||
Platform_thread * platform_thread() const {
|
||||
return _platform_thread; }
|
||||
unsigned pd_id() const { return _pd_id; }
|
||||
|
||||
void pager(Thread * const p) { _pager = p; }
|
||||
Native_utcb * phys_utcb() const { return _phys_utcb; }
|
||||
|
||||
unsigned pd_id() const { return _pd_id; }
|
||||
|
||||
Native_utcb * phys_utcb() const { return _phys_utcb; }
|
||||
|
||||
Signal_handler * signal_handler() { return &_signal_handler; }
|
||||
};
|
||||
}
|
||||
Signal_handler * signal_handler() { return &_signal_handler; }
|
||||
};
|
||||
|
||||
#endif /* _CORE__KERNEL__THREAD_H_ */
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user