2012-11-30 14:08:42 +01:00
|
|
|
/*
|
2013-10-07 14:56:31 +02:00
|
|
|
* \brief Kernel backend for execution contexts in userland
|
2012-11-30 14:08:42 +01:00
|
|
|
* \author Martin Stein
|
|
|
|
* \date 2012-11-30
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2013-01-10 21:44:47 +01:00
|
|
|
* Copyright (C) 2012-2013 Genode Labs GmbH
|
2012-11-30 14:08:42 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _CORE__KERNEL__THREAD_H_
|
|
|
|
#define _CORE__KERNEL__THREAD_H_
|
|
|
|
|
|
|
|
/* core includes */
|
2013-09-02 13:37:55 +02:00
|
|
|
#include <kernel/configuration.h>
|
2013-09-03 14:20:43 +02:00
|
|
|
#include <kernel/scheduler.h>
|
2013-09-09 15:20:30 +02:00
|
|
|
#include <kernel/signal_receiver.h>
|
|
|
|
#include <kernel/ipc_node.h>
|
2013-09-05 12:47:19 +02:00
|
|
|
#include <kernel/irq_receiver.h>
|
2013-09-09 15:20:30 +02:00
|
|
|
#include <kernel/pd.h>
|
2013-09-05 13:40:54 +02:00
|
|
|
#include <cpu.h>
|
2013-05-14 22:40:30 +02:00
|
|
|
|
2012-11-30 14:08:42 +01:00
|
|
|
namespace Genode
|
|
|
|
{
|
|
|
|
class Platform_thread;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace Kernel
|
|
|
|
{
|
2013-09-09 15:20:30 +02:00
|
|
|
class Thread;
|
2012-11-30 14:08:42 +01:00
|
|
|
|
2013-09-09 15:20:30 +02:00
|
|
|
typedef Genode::Cpu Cpu;
|
|
|
|
typedef Genode::Pagefault Pagefault;
|
|
|
|
typedef Genode::Native_utcb Native_utcb;
|
|
|
|
|
|
|
|
unsigned core_id();
|
|
|
|
void handle_interrupt(void);
|
2013-10-15 17:15:30 +02:00
|
|
|
void reset_lap_time();
|
2012-11-30 14:08:42 +01:00
|
|
|
|
|
|
|
/**
|
2013-09-09 15:20:30 +02:00
|
|
|
* Kernel backend for userland execution-contexts
|
2012-11-30 14:08:42 +01:00
|
|
|
*/
|
2013-09-09 15:20:30 +02:00
|
|
|
class Thread;
|
2013-10-07 14:56:31 +02:00
|
|
|
|
2013-10-11 12:29:40 +02:00
|
|
|
class Thread_ids : public Id_allocator<MAX_THREADS> { };
|
|
|
|
typedef Object_pool<Thread> Thread_pool;
|
2013-10-07 14:56:31 +02:00
|
|
|
|
|
|
|
Thread_ids * thread_ids();
|
|
|
|
Thread_pool * thread_pool();
|
2013-09-09 15:20:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
class Kernel::Thread
|
|
|
|
:
|
|
|
|
public Cpu::User_context,
|
2013-10-11 12:29:40 +02:00
|
|
|
public Object<Thread, MAX_THREADS, Thread_ids, thread_ids, thread_pool>,
|
2013-09-09 15:20:30 +02:00
|
|
|
public Execution_context,
|
|
|
|
public Ipc_node,
|
2013-09-12 00:48:27 +02:00
|
|
|
public Irq_receiver,
|
|
|
|
public Signal_context_killer,
|
|
|
|
public Signal_receiver_killer,
|
|
|
|
public Signal_handler
|
2013-09-09 15:20:30 +02:00
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
2013-10-07 15:37:58 +02:00
|
|
|
enum { START_VERBOSE = 0 };
|
|
|
|
|
2013-05-22 14:41:47 +02:00
|
|
|
enum State
|
|
|
|
{
|
2013-10-16 13:10:54 +02:00
|
|
|
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,
|
2013-05-22 14:41:47 +02:00
|
|
|
};
|
2012-11-30 14:08:42 +01:00
|
|
|
|
2013-09-09 15:20:30 +02:00
|
|
|
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;
|
2012-11-30 14:08:42 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Resume execution
|
|
|
|
*/
|
2013-09-09 15:20:30 +02:00
|
|
|
void _schedule()
|
|
|
|
{
|
|
|
|
cpu_scheduler()->insert(this);
|
|
|
|
_state = SCHEDULED;
|
|
|
|
}
|
2012-11-30 14:08:42 +01:00
|
|
|
|
2013-09-19 16:13:51 +02:00
|
|
|
|
2013-09-12 00:48:27 +02:00
|
|
|
/***************************
|
|
|
|
** Signal_context_killer **
|
|
|
|
***************************/
|
|
|
|
|
|
|
|
void _signal_context_kill_pending()
|
|
|
|
{
|
2013-09-19 16:13:51 +02:00
|
|
|
assert(_state == SCHEDULED);
|
2013-10-16 13:10:54 +02:00
|
|
|
_state = AWAITS_SIGNAL_CONTEXT_KILL;
|
2013-09-19 16:13:51 +02:00
|
|
|
cpu_scheduler()->remove(this);
|
2013-09-12 00:48:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void _signal_context_kill_done()
|
|
|
|
{
|
2013-10-16 13:10:54 +02:00
|
|
|
assert(_state == AWAITS_SIGNAL_CONTEXT_KILL);
|
2013-09-19 16:13:51 +02:00
|
|
|
user_arg_0(0);
|
|
|
|
_schedule();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************
|
|
|
|
** Signal_receiver_killer **
|
|
|
|
****************************/
|
|
|
|
|
|
|
|
void _signal_receiver_kill_pending()
|
|
|
|
{
|
|
|
|
assert(_state == SCHEDULED);
|
2013-10-16 13:10:54 +02:00
|
|
|
_state = AWAITS_SIGNAL_RECEIVER_KILL;
|
2013-09-19 16:13:51 +02:00
|
|
|
cpu_scheduler()->remove(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void _signal_receiver_kill_done()
|
|
|
|
{
|
2013-10-16 13:10:54 +02:00
|
|
|
assert(_state == AWAITS_SIGNAL_RECEIVER_KILL);
|
2013-09-12 00:48:27 +02:00
|
|
|
user_arg_0(0);
|
|
|
|
_schedule();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/********************
|
|
|
|
** Signal_handler **
|
|
|
|
********************/
|
|
|
|
|
2013-09-12 21:13:22 +02:00
|
|
|
void _await_signal(Signal_receiver * const receiver)
|
|
|
|
{
|
|
|
|
cpu_scheduler()->remove(this);
|
2013-10-16 13:10:54 +02:00
|
|
|
_state = AWAITS_SIGNAL;
|
2013-09-12 21:13:22 +02:00
|
|
|
_signal_receiver = receiver;
|
|
|
|
}
|
|
|
|
|
|
|
|
void _receive_signal(void * const base, size_t const size)
|
2013-09-12 00:48:27 +02:00
|
|
|
{
|
2013-10-16 13:10:54 +02:00
|
|
|
assert(_state == AWAITS_SIGNAL && size <= phys_utcb()->size());
|
2013-09-12 00:48:27 +02:00
|
|
|
Genode::memcpy(phys_utcb()->base(), base, size);
|
|
|
|
_schedule();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-30 14:08:42 +01:00
|
|
|
/**************
|
|
|
|
** Ipc_node **
|
|
|
|
**************/
|
|
|
|
|
2013-09-16 17:01:52 +02:00
|
|
|
void _received_ipc_request(size_t const s)
|
|
|
|
{
|
|
|
|
switch (_state) {
|
|
|
|
case SCHEDULED:
|
|
|
|
user_arg_0(s);
|
|
|
|
return;
|
|
|
|
default:
|
|
|
|
PERR("wrong thread state to receive IPC");
|
2013-09-19 16:13:51 +02:00
|
|
|
stop();
|
2013-09-16 17:01:52 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void _await_ipc()
|
|
|
|
{
|
|
|
|
switch (_state) {
|
|
|
|
case SCHEDULED:
|
|
|
|
cpu_scheduler()->remove(this);
|
2013-10-16 13:10:54 +02:00
|
|
|
_state = AWAITS_IPC;
|
|
|
|
case AWAITS_PAGER:
|
2013-09-16 17:01:52 +02:00
|
|
|
return;
|
|
|
|
default:
|
|
|
|
PERR("wrong thread state to await IPC");
|
2013-09-19 16:13:51 +02:00
|
|
|
stop();
|
2013-09-16 17:01:52 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-07 16:01:03 +02:00
|
|
|
void _await_ipc_succeeded(bool const reply, size_t const s)
|
2013-09-09 15:20:30 +02:00
|
|
|
{
|
2013-09-13 01:05:38 +02:00
|
|
|
switch (_state) {
|
2013-10-16 13:10:54 +02:00
|
|
|
case AWAITS_IPC:
|
2013-10-07 16:01:03 +02:00
|
|
|
/* FIXME: return error codes on all IPC transfers */
|
|
|
|
if (reply) {
|
|
|
|
phys_utcb()->ipc_msg_size(s);
|
|
|
|
user_arg_0(0);
|
|
|
|
_schedule();
|
|
|
|
} else {
|
|
|
|
user_arg_0(s);
|
|
|
|
_schedule();
|
|
|
|
}
|
2013-09-13 01:05:38 +02:00
|
|
|
return;
|
2013-10-16 13:10:54 +02:00
|
|
|
case AWAITS_PAGER_IPC:
|
2013-09-13 01:05:38 +02:00
|
|
|
_schedule();
|
|
|
|
return;
|
2013-10-16 13:10:54 +02:00
|
|
|
case AWAITS_PAGER:
|
|
|
|
_state = AWAITS_RESUME;
|
2013-09-13 01:05:38 +02:00
|
|
|
return;
|
|
|
|
default:
|
|
|
|
PERR("wrong thread state to receive IPC");
|
2013-09-19 16:13:51 +02:00
|
|
|
stop();
|
2013-09-13 01:05:38 +02:00
|
|
|
return;
|
|
|
|
}
|
2013-09-09 15:20:30 +02:00
|
|
|
}
|
2012-11-30 14:08:42 +01:00
|
|
|
|
2013-10-07 16:01:03 +02:00
|
|
|
void _await_ipc_failed(bool const reply)
|
2013-09-09 15:20:30 +02:00
|
|
|
{
|
2013-09-13 01:05:38 +02:00
|
|
|
switch (_state) {
|
2013-10-16 13:10:54 +02:00
|
|
|
case AWAITS_IPC:
|
2013-10-07 16:01:03 +02:00
|
|
|
/* FIXME: return error codes on all IPC transfers */
|
|
|
|
if (reply) {
|
|
|
|
user_arg_0(-1);
|
|
|
|
_schedule();
|
|
|
|
} else {
|
|
|
|
PERR("failed to receive IPC");
|
|
|
|
stop();
|
|
|
|
}
|
2013-09-16 17:01:52 +02:00
|
|
|
return;
|
2013-09-13 01:05:38 +02:00
|
|
|
case SCHEDULED:
|
2013-09-16 17:01:52 +02:00
|
|
|
PERR("failed to receive IPC");
|
2013-09-19 16:13:51 +02:00
|
|
|
stop();
|
2013-09-16 17:01:52 +02:00
|
|
|
return;
|
2013-10-16 13:10:54 +02:00
|
|
|
case AWAITS_PAGER_IPC:
|
2013-09-16 17:01:52 +02:00
|
|
|
PERR("failed to get pagefault resolved");
|
2013-09-19 16:13:51 +02:00
|
|
|
stop();
|
2013-09-16 17:01:52 +02:00
|
|
|
return;
|
2013-10-16 13:10:54 +02:00
|
|
|
case AWAITS_PAGER:
|
2013-09-16 17:01:52 +02:00
|
|
|
PERR("failed to get pagefault resolved");
|
2013-09-19 16:13:51 +02:00
|
|
|
stop();
|
2013-09-13 01:05:38 +02:00
|
|
|
return;
|
|
|
|
default:
|
2013-09-16 17:01:52 +02:00
|
|
|
PERR("wrong thread state to cancel IPC");
|
2013-09-19 16:13:51 +02:00
|
|
|
stop();
|
2013-09-13 01:05:38 +02:00
|
|
|
return;
|
|
|
|
}
|
2013-09-09 15:20:30 +02:00
|
|
|
}
|
2012-11-30 14:08:42 +01:00
|
|
|
|
|
|
|
|
|
|
|
/***************
|
|
|
|
** Irq_owner **
|
|
|
|
***************/
|
|
|
|
|
2013-09-09 15:20:30 +02:00
|
|
|
void _received_irq()
|
|
|
|
{
|
2013-10-16 13:10:54 +02:00
|
|
|
assert(_state == AWAITS_IRQ);
|
2013-09-09 15:20:30 +02:00
|
|
|
_schedule();
|
|
|
|
}
|
2012-11-30 14:08:42 +01:00
|
|
|
|
2013-09-09 15:20:30 +02:00
|
|
|
void _awaits_irq()
|
|
|
|
{
|
|
|
|
cpu_scheduler()->remove(this);
|
2013-10-16 13:10:54 +02:00
|
|
|
_state = AWAITS_IRQ;
|
2013-09-09 15:20:30 +02:00
|
|
|
}
|
2012-11-30 14:08:42 +01:00
|
|
|
|
2013-10-16 13:10:54 +02:00
|
|
|
/**
|
|
|
|
* 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();
|
|
|
|
|
2013-09-09 15:20:30 +02:00
|
|
|
public:
|
2012-11-30 14:08:42 +01:00
|
|
|
|
2013-09-09 15:20:30 +02:00
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
|
|
|
* \param platform_thread userland backend of execution context
|
|
|
|
*/
|
2013-11-11 16:55:30 +01:00
|
|
|
Thread(Platform_thread * const platform_thread);
|
2013-09-09 15:20:30 +02:00
|
|
|
|
2013-10-07 15:37:58 +02:00
|
|
|
/**
|
|
|
|
* Return wether the thread is a core thread
|
|
|
|
*/
|
|
|
|
bool core() { return pd_id() == core_id(); }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return kernel backend of protection domain the thread is in
|
|
|
|
*/
|
|
|
|
Pd * pd() { return Pd::pool()->object(pd_id()); }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return user label of the thread
|
|
|
|
*/
|
|
|
|
char const * label();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* return user label of the protection domain the thread is in
|
|
|
|
*/
|
|
|
|
char const * pd_label();
|
|
|
|
|
2013-09-09 15:20:30 +02:00
|
|
|
/**
|
2013-09-19 16:13:51 +02:00
|
|
|
* Suspend the thread unrecoverably
|
2013-09-09 15:20:30 +02:00
|
|
|
*/
|
2013-09-19 16:13:51 +02:00
|
|
|
void stop()
|
2013-09-09 15:20:30 +02:00
|
|
|
{
|
2013-09-18 12:48:22 +02:00
|
|
|
if (_state == SCHEDULED) { cpu_scheduler()->remove(this); }
|
2013-09-19 16:13:51 +02:00
|
|
|
_state = STOPPED;
|
2013-09-09 15:20:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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,
|
2013-10-07 15:37:58 +02:00
|
|
|
bool const main);
|
2013-09-09 15:20:30 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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()
|
|
|
|
{
|
2013-10-16 13:10:54 +02:00
|
|
|
assert(_state == AWAITS_RESUME || _state == SCHEDULED);
|
2013-09-09 15:20:30 +02:00
|
|
|
cpu_scheduler()->remove(this);
|
2013-10-16 13:10:54 +02:00
|
|
|
_state = AWAITS_RESUME;
|
2013-09-09 15:20:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Resume this thread
|
|
|
|
*/
|
|
|
|
int resume()
|
|
|
|
{
|
|
|
|
switch (_state) {
|
2013-10-16 13:10:54 +02:00
|
|
|
case AWAITS_RESUME:
|
2013-09-09 15:20:30 +02:00
|
|
|
_schedule();
|
|
|
|
return 0;
|
2013-10-16 13:10:54 +02:00
|
|
|
case AWAITS_PAGER:
|
|
|
|
_state = AWAITS_PAGER_IPC;
|
2013-09-13 01:05:38 +02:00
|
|
|
return 0;
|
2013-10-16 13:10:54 +02:00
|
|
|
case AWAITS_PAGER_IPC:
|
2013-09-19 16:13:51 +02:00
|
|
|
Ipc_node::cancel_waiting();
|
|
|
|
return 0;
|
2013-09-09 15:20:30 +02:00
|
|
|
case SCHEDULED:
|
|
|
|
return 1;
|
2013-10-16 13:10:54 +02:00
|
|
|
case AWAITS_IPC:
|
2013-09-09 15:20:30 +02:00
|
|
|
Ipc_node::cancel_waiting();
|
|
|
|
return 0;
|
2013-10-16 13:10:54 +02:00
|
|
|
case AWAITS_IRQ:
|
2013-09-09 15:20:30 +02:00
|
|
|
Irq_receiver::cancel_waiting();
|
|
|
|
return 0;
|
2013-10-16 13:10:54 +02:00
|
|
|
case AWAITS_SIGNAL:
|
2013-09-19 16:13:51 +02:00
|
|
|
Signal_handler::cancel_waiting();
|
2013-09-09 15:20:30 +02:00
|
|
|
return 0;
|
2013-10-16 13:10:54 +02:00
|
|
|
case AWAITS_SIGNAL_CONTEXT_KILL:
|
2013-09-19 16:13:51 +02:00
|
|
|
Signal_context_killer::cancel_waiting();
|
|
|
|
return 0;
|
2013-10-16 13:10:54 +02:00
|
|
|
case AWAITS_SIGNAL_RECEIVER_KILL:
|
2013-09-19 16:13:51 +02:00
|
|
|
Signal_receiver_killer::cancel_waiting();
|
2013-09-09 15:20:30 +02:00
|
|
|
return 0;
|
2013-10-16 13:10:54 +02:00
|
|
|
case AWAITS_START:
|
2013-09-19 16:13:51 +02:00
|
|
|
case STOPPED:;
|
2013-09-06 01:36:03 +02:00
|
|
|
}
|
2013-09-19 16:13:51 +02:00
|
|
|
PERR("failed to resume thread");
|
|
|
|
return -1;
|
2013-09-09 15:20:30 +02:00
|
|
|
}
|
2013-09-06 01:36:03 +02:00
|
|
|
|
2013-09-09 15:20:30 +02:00
|
|
|
/**
|
|
|
|
* Send a request and await the reply
|
|
|
|
*/
|
|
|
|
void request_and_wait(Thread * const dest, size_t const size)
|
|
|
|
{
|
|
|
|
Ipc_node::send_request_await_reply(
|
2013-10-07 16:01:03 +02:00
|
|
|
dest, phys_utcb()->base(), size,
|
|
|
|
phys_utcb()->ipc_msg_base(),
|
|
|
|
phys_utcb()->max_ipc_msg_size());
|
2013-09-09 15:20:30 +02:00
|
|
|
}
|
2012-11-30 14:08:42 +01:00
|
|
|
|
2013-09-09 15:20:30 +02:00
|
|
|
/**
|
|
|
|
* Wait for any request
|
|
|
|
*/
|
|
|
|
void wait_for_request()
|
|
|
|
{
|
|
|
|
Ipc_node::await_request(phys_utcb()->base(), phys_utcb()->size());
|
|
|
|
}
|
2012-11-30 14:08:42 +01:00
|
|
|
|
2013-09-09 15:20:30 +02:00
|
|
|
/**
|
|
|
|
* 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); }
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-09-13 01:05:38 +02:00
|
|
|
* Handle an exception thrown by the MMU
|
2013-09-09 15:20:30 +02:00
|
|
|
*/
|
2013-09-13 01:05:38 +02:00
|
|
|
void handle_mmu_exception()
|
2013-09-09 15:20:30 +02:00
|
|
|
{
|
2013-09-13 01:05:38 +02:00
|
|
|
/* pause thread */
|
2013-09-09 15:20:30 +02:00
|
|
|
cpu_scheduler()->remove(this);
|
2013-10-16 13:10:54 +02:00
|
|
|
_state = AWAITS_PAGER;
|
2013-09-09 15:20:30 +02:00
|
|
|
|
2013-09-13 01:05:38 +02:00
|
|
|
/* check out cause and attributes */
|
|
|
|
addr_t va = 0;
|
|
|
|
bool w = 0;
|
|
|
|
if (!pagefault(va, w)) {
|
|
|
|
PERR("unknown MMU exception");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* inform pager */
|
2013-09-09 15:20:30 +02:00
|
|
|
_pagefault = Pagefault(id(), (Tlb *)tlb(), ip, va, w);
|
2013-09-13 01:05:38 +02:00
|
|
|
void * const base = &_pagefault;
|
|
|
|
size_t const size = sizeof(_pagefault);
|
|
|
|
Ipc_node::send_request_await_reply(_pager, base, size, base, size);
|
2013-09-09 15:20:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get unique thread ID, avoid method ambiguousness
|
|
|
|
*/
|
|
|
|
unsigned id() const { return Object::id(); }
|
|
|
|
|
2013-09-19 16:47:38 +02:00
|
|
|
/**
|
|
|
|
* Notice that another thread yielded the CPU to us
|
|
|
|
*/
|
|
|
|
void receive_yielded_cpu()
|
|
|
|
{
|
2013-10-16 13:10:54 +02:00
|
|
|
if (_state == AWAITS_RESUME) { _schedule(); }
|
2013-09-19 16:47:38 +02:00
|
|
|
else { PERR("failed to receive yielded CPU"); }
|
|
|
|
}
|
|
|
|
|
2013-09-09 15:20:30 +02:00
|
|
|
|
|
|
|
/***********************
|
|
|
|
** Execution_context **
|
|
|
|
***********************/
|
|
|
|
|
|
|
|
void handle_exception()
|
|
|
|
{
|
|
|
|
switch(cpu_exception) {
|
|
|
|
case SUPERVISOR_CALL:
|
2013-10-16 13:10:54 +02:00
|
|
|
_syscall();
|
2013-09-09 15:20:30 +02:00
|
|
|
return;
|
|
|
|
case PREFETCH_ABORT:
|
2013-09-13 01:05:38 +02:00
|
|
|
handle_mmu_exception();
|
2013-09-09 15:20:30 +02:00
|
|
|
return;
|
|
|
|
case DATA_ABORT:
|
2013-09-13 01:05:38 +02:00
|
|
|
handle_mmu_exception();
|
2013-09-09 15:20:30 +02:00
|
|
|
return;
|
|
|
|
case INTERRUPT_REQUEST:
|
|
|
|
handle_interrupt();
|
|
|
|
return;
|
|
|
|
case FAST_INTERRUPT_REQUEST:
|
|
|
|
handle_interrupt();
|
|
|
|
return;
|
|
|
|
default:
|
2013-10-15 17:15:30 +02:00
|
|
|
PERR("unknown exception");
|
|
|
|
stop();
|
|
|
|
reset_lap_time();
|
2013-09-09 15:20:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void proceed()
|
|
|
|
{
|
|
|
|
mtc()->continue_user(static_cast<Cpu::Context *>(this));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************
|
|
|
|
** Accessors **
|
|
|
|
***************/
|
|
|
|
|
|
|
|
Platform_thread * platform_thread() const { return _platform_thread; }
|
|
|
|
|
|
|
|
void pager(Thread * const p) { _pager = p; }
|
|
|
|
|
|
|
|
unsigned pd_id() const { return _pd_id; }
|
|
|
|
|
|
|
|
Native_utcb * phys_utcb() const { return _phys_utcb; }
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* _CORE__KERNEL__THREAD_H_ */
|