2012-05-30 20:13:09 +02:00
|
|
|
/*
|
|
|
|
* \brief Singlethreaded minimalistic kernel
|
|
|
|
* \author Martin Stein
|
|
|
|
* \date 2011-10-20
|
|
|
|
*
|
|
|
|
* This kernel is the only code except the mode transition PIC, that runs in
|
|
|
|
* privileged CPU mode. It has two tasks. First it initializes the process
|
|
|
|
* 'core', enriches it with the whole identically mapped address range,
|
|
|
|
* joins and applies it, assigns one thread to it with a userdefined
|
|
|
|
* entrypoint (the core main thread) and starts this thread in userland.
|
|
|
|
* Afterwards it is called each time an exception occurs in userland to do
|
|
|
|
* a minimum of appropriate exception handling. Thus it holds a CPU context
|
|
|
|
* for itself as for any other thread. But due to the fact that it never
|
|
|
|
* relies on prior kernel runs this context only holds some constant pointers
|
|
|
|
* such as SP and IP.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2013-01-10 21:44:47 +01:00
|
|
|
* Copyright (C) 2011-2013 Genode Labs GmbH
|
2012-05-30 20:13:09 +02:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Genode includes */
|
2012-11-12 16:52:12 +01:00
|
|
|
#include <base/thread_state.h>
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
/* core includes */
|
2013-09-06 17:37:09 +02:00
|
|
|
#include <kernel/pd.h>
|
2013-10-16 11:47:19 +02:00
|
|
|
#include <kernel/vm.h>
|
2013-02-22 10:30:48 +01:00
|
|
|
#include <platform_pd.h>
|
2012-10-02 14:27:32 +02:00
|
|
|
#include <trustzone.h>
|
2013-09-09 15:20:30 +02:00
|
|
|
#include <timer.h>
|
2012-05-30 20:13:09 +02:00
|
|
|
|
2013-05-14 22:40:30 +02:00
|
|
|
/* base-hw includes */
|
|
|
|
#include <singleton.h>
|
2013-09-26 17:03:33 +02:00
|
|
|
#include <kernel/perf_counter.h>
|
2013-05-14 22:40:30 +02:00
|
|
|
|
2012-05-30 20:13:09 +02:00
|
|
|
using namespace Kernel;
|
|
|
|
|
|
|
|
/* get core configuration */
|
|
|
|
extern Genode::Native_utcb * _main_utcb;
|
|
|
|
extern int _kernel_stack_high;
|
|
|
|
extern "C" void CORE_MAIN();
|
|
|
|
|
|
|
|
namespace Kernel
|
|
|
|
{
|
|
|
|
/* import Genode types */
|
2012-11-12 16:52:12 +01:00
|
|
|
typedef Genode::Thread_state Thread_state;
|
2013-09-06 01:36:03 +02:00
|
|
|
typedef Genode::umword_t umword_t;
|
2013-09-09 15:20:30 +02:00
|
|
|
typedef Genode::Core_tlb Core_tlb;
|
2012-11-30 14:08:42 +01:00
|
|
|
}
|
2012-05-30 20:13:09 +02:00
|
|
|
|
2012-11-30 14:08:42 +01:00
|
|
|
namespace Kernel
|
|
|
|
{
|
2012-05-30 20:13:09 +02:00
|
|
|
/**
|
|
|
|
* Idle thread entry
|
|
|
|
*/
|
|
|
|
static void idle_main() { while (1) ; }
|
|
|
|
|
2013-10-07 14:56:31 +02:00
|
|
|
Pd_ids * pd_ids() { return unsynchronized_singleton<Pd_ids>(); }
|
|
|
|
Thread_ids * thread_ids() { return unsynchronized_singleton<Thread_ids>(); }
|
|
|
|
Signal_context_ids * signal_context_ids() { return unsynchronized_singleton<Signal_context_ids>(); }
|
|
|
|
Signal_receiver_ids * signal_receiver_ids() { return unsynchronized_singleton<Signal_receiver_ids>(); }
|
|
|
|
|
|
|
|
Pd_pool * pd_pool() { return unsynchronized_singleton<Pd_pool>(); }
|
|
|
|
Thread_pool * thread_pool() { return unsynchronized_singleton<Thread_pool>(); }
|
|
|
|
Signal_context_pool * signal_context_pool() { return unsynchronized_singleton<Signal_context_pool>(); }
|
|
|
|
Signal_receiver_pool * signal_receiver_pool() { return unsynchronized_singleton<Signal_receiver_pool>(); }
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Access to static kernel timer
|
|
|
|
*/
|
|
|
|
static Timer * timer() { static Timer _object; return &_object; }
|
|
|
|
|
|
|
|
|
2013-10-15 17:15:30 +02:00
|
|
|
void reset_lap_time()
|
2013-09-02 09:39:31 +02:00
|
|
|
{
|
|
|
|
timer()->start_one_shot(timer()->ms_to_tics(USER_LAP_TIME_MS));
|
|
|
|
}
|
|
|
|
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Static kernel PD that describes core
|
|
|
|
*/
|
2012-11-07 15:12:56 +01:00
|
|
|
static Pd * core()
|
|
|
|
{
|
2013-05-14 22:40:30 +02:00
|
|
|
constexpr int tlb_align = 1 << Core_tlb::ALIGNM_LOG2;
|
|
|
|
|
|
|
|
Core_tlb *core_tlb = unsynchronized_singleton<Core_tlb, tlb_align>();
|
|
|
|
Pd *pd = unsynchronized_singleton<Pd>(core_tlb, nullptr);
|
|
|
|
return pd;
|
2012-11-07 15:12:56 +01:00
|
|
|
}
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get core attributes
|
|
|
|
*/
|
|
|
|
unsigned core_id() { return core()->id(); }
|
2012-11-30 14:08:42 +01:00
|
|
|
}
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
|
2012-11-30 14:08:42 +01:00
|
|
|
namespace Kernel
|
|
|
|
{
|
2012-05-30 20:13:09 +02:00
|
|
|
/**
|
|
|
|
* Access to static CPU scheduler
|
|
|
|
*/
|
|
|
|
Cpu_scheduler * cpu_scheduler()
|
|
|
|
{
|
|
|
|
/* create idle thread */
|
|
|
|
static char idle_stack[DEFAULT_STACK_SIZE]
|
|
|
|
__attribute__((aligned(Cpu::DATA_ACCESS_ALIGNM)));
|
|
|
|
static Thread idle((Platform_thread *)0);
|
|
|
|
static bool initial = 1;
|
|
|
|
if (initial)
|
|
|
|
{
|
|
|
|
/* initialize idle thread */
|
2013-09-09 15:20:30 +02:00
|
|
|
enum { STACK_SIZE = sizeof(idle_stack)/sizeof(idle_stack[0]) };
|
|
|
|
void * const ip = (void *)&idle_main;
|
|
|
|
void * const sp = (void *)&idle_stack[STACK_SIZE];
|
2013-06-06 14:18:36 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
2013-09-09 15:20:30 +02:00
|
|
|
* recursive call of'cpu_scheduler()'.
|
2013-06-06 14:18:36 +02:00
|
|
|
*/
|
2013-09-09 15:20:30 +02:00
|
|
|
idle.prepare_to_start(ip, sp, 0, core_id(), 0, 0, 0);
|
2012-05-30 20:13:09 +02:00
|
|
|
initial = 0;
|
|
|
|
}
|
|
|
|
/* create scheduler with a permanent idle thread */
|
2013-08-23 00:18:58 +02:00
|
|
|
static Cpu_scheduler cpu_sched(&idle);
|
2012-05-30 20:13:09 +02:00
|
|
|
return &cpu_sched;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get attributes of the mode transition region in every PD
|
|
|
|
*/
|
|
|
|
addr_t mode_transition_virt_base() { return mtc()->VIRT_BASE; }
|
|
|
|
size_t mode_transition_size() { return mtc()->SIZE; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get attributes of the kernel objects
|
|
|
|
*/
|
|
|
|
size_t thread_size() { return sizeof(Thread); }
|
2012-11-07 15:12:56 +01:00
|
|
|
size_t pd_size() { return sizeof(Tlb) + sizeof(Pd); }
|
2012-05-30 20:13:09 +02:00
|
|
|
size_t signal_context_size() { return sizeof(Signal_context); }
|
|
|
|
size_t signal_receiver_size() { return sizeof(Signal_receiver); }
|
2012-11-07 15:12:56 +01:00
|
|
|
unsigned pd_alignm_log2() { return Tlb::ALIGNM_LOG2; }
|
2012-10-02 14:27:32 +02:00
|
|
|
size_t vm_size() { return sizeof(Vm); }
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle an interrupt request
|
|
|
|
*/
|
2012-10-02 14:27:32 +02:00
|
|
|
void handle_interrupt()
|
2012-05-30 20:13:09 +02:00
|
|
|
{
|
|
|
|
/* determine handling for specific interrupt */
|
|
|
|
unsigned irq;
|
|
|
|
if (pic()->take_request(irq))
|
|
|
|
{
|
|
|
|
switch (irq) {
|
|
|
|
|
|
|
|
case Timer::IRQ: {
|
|
|
|
|
2013-08-23 00:18:58 +02:00
|
|
|
cpu_scheduler()->yield();
|
2012-05-30 20:13:09 +02:00
|
|
|
timer()->clear_interrupt();
|
2013-09-02 09:39:31 +02:00
|
|
|
reset_lap_time();
|
2012-05-30 20:13:09 +02:00
|
|
|
break; }
|
|
|
|
|
|
|
|
default: {
|
|
|
|
|
2013-09-05 12:47:19 +02:00
|
|
|
Irq_receiver * const o = Irq_receiver::receiver(irq);
|
2012-05-30 20:13:09 +02:00
|
|
|
assert(o);
|
|
|
|
o->receive_irq(irq);
|
|
|
|
break; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* 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 */
|
2013-09-18 13:12:32 +02:00
|
|
|
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());
|
|
|
|
}
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
|
2013-09-18 13:12:32 +02:00
|
|
|
/**
|
|
|
|
* 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);
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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());
|
|
|
|
}
|
|
|
|
|
2012-10-09 15:41:40 +02:00
|
|
|
/**
|
|
|
|
* 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();
|
|
|
|
}
|
|
|
|
|
2012-05-30 20:13:09 +02:00
|
|
|
/**
|
|
|
|
* 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();
|
2013-09-09 15:20:30 +02:00
|
|
|
unsigned const cpu_id = (unsigned)user->user_arg_4();
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
/* get targeted thread */
|
|
|
|
Thread * const t = Thread::pool()->object(pt->id());
|
|
|
|
assert(t);
|
|
|
|
|
|
|
|
/* start thread */
|
2013-09-09 15:20:30 +02:00
|
|
|
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());
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
/* 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);
|
2012-11-06 15:03:08 +01:00
|
|
|
user->user_arg_0((Syscall_ret)pd->tlb());
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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)
|
|
|
|
{
|
2013-09-19 16:47:38 +02:00
|
|
|
/* lookup thread */
|
2012-05-30 20:13:09 +02:00
|
|
|
Thread * const t = Thread::pool()->object(user->user_arg_1());
|
2013-09-19 16:47:38 +02:00
|
|
|
if (!t) {
|
|
|
|
PERR("unknown thread");
|
|
|
|
user->user_arg_0(-1);
|
|
|
|
return;
|
|
|
|
}
|
2012-05-30 20:13:09 +02:00
|
|
|
/* check permissions */
|
2013-09-19 16:47:38 +02:00
|
|
|
if (user->pd_id() != core_id() && user->pd_id() != t->pd_id()) {
|
|
|
|
PERR("not entitled to resume thread");
|
|
|
|
user->user_arg_0(-1);
|
|
|
|
return;
|
|
|
|
}
|
2012-05-30 20:13:09 +02:00
|
|
|
/* resume targeted thread */
|
|
|
|
user->user_arg_0(t->resume());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-09 17:10:38 +01:00
|
|
|
/**
|
|
|
|
* Do specific syscall for 'user', for details see 'syscall.h'
|
|
|
|
*/
|
|
|
|
void do_resume_faulter(Thread * const user)
|
|
|
|
{
|
2013-09-19 16:47:38 +02:00
|
|
|
/* lookup thread */
|
2012-11-09 17:10:38 +01:00
|
|
|
Thread * const t = Thread::pool()->object(user->user_arg_1());
|
2013-09-19 16:47:38 +02:00
|
|
|
if (!t) {
|
|
|
|
PERR("unknown thread");
|
|
|
|
user->user_arg_0(-1);
|
|
|
|
return;
|
|
|
|
}
|
2012-11-09 17:10:38 +01:00
|
|
|
/* check permissions */
|
2013-09-19 16:47:38 +02:00
|
|
|
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 */
|
2012-12-18 11:32:48 +01:00
|
|
|
Cpu::tlb_insertions();
|
2012-11-09 17:10:38 +01:00
|
|
|
t->resume();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-30 20:13:09 +02:00
|
|
|
/**
|
|
|
|
* 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());
|
2013-09-19 16:47:38 +02:00
|
|
|
if (t) { t->receive_yielded_cpu(); }
|
2012-05-30 20:13:09 +02:00
|
|
|
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 */
|
2013-09-18 22:33:56 +02:00
|
|
|
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();
|
2012-05-30 20:13:09 +02:00
|
|
|
Thread * t;
|
2013-09-18 22:33:56 +02:00
|
|
|
if (id) {
|
|
|
|
t = Thread::pool()->object(id);
|
|
|
|
if (!t) {
|
|
|
|
PERR("unknown thread");
|
|
|
|
user->user_arg_0(0);
|
|
|
|
}
|
|
|
|
} else { t = user; }
|
2012-05-30 20:13:09 +02:00
|
|
|
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'
|
|
|
|
*/
|
2012-11-30 10:33:57 +01:00
|
|
|
void do_reply(Thread * const user) {
|
|
|
|
user->reply((size_t)user->user_arg_1(), (bool)user->user_arg_2()); }
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Do specific syscall for 'user', for details see 'syscall.h'
|
|
|
|
*/
|
|
|
|
void do_set_pager(Thread * const user)
|
|
|
|
{
|
2013-09-18 12:57:01 +02:00
|
|
|
/* 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;
|
|
|
|
}
|
2012-05-30 20:13:09 +02:00
|
|
|
/* assign pager */
|
2013-09-18 12:57:01 +02:00
|
|
|
faulter->pager(pager);
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-29 18:58:11 +02:00
|
|
|
/**
|
|
|
|
* 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());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-30 20:13:09 +02:00
|
|
|
/**
|
|
|
|
* 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'
|
|
|
|
*/
|
2012-11-12 16:52:12 +01:00
|
|
|
void do_read_thread_state(Thread * const user)
|
2012-05-30 20:13:09 +02:00
|
|
|
{
|
|
|
|
assert(user->pd_id() == core_id());
|
|
|
|
Thread * const t = Thread::pool()->object(user->user_arg_1());
|
2012-11-12 16:52:12 +01:00
|
|
|
if (!t) PDBG("Targeted thread unknown");
|
|
|
|
Thread_state * const ts = (Thread_state *)user->phys_utcb()->base();
|
|
|
|
t->Cpu::Context::read_cpu_state(ts);
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Do specific syscall for 'user', for details see 'syscall.h'
|
|
|
|
*/
|
2012-11-12 16:52:12 +01:00
|
|
|
void do_write_thread_state(Thread * const user)
|
2012-05-30 20:13:09 +02:00
|
|
|
{
|
|
|
|
assert(user->pd_id() == core_id());
|
|
|
|
Thread * const t = Thread::pool()->object(user->user_arg_1());
|
2012-11-12 16:52:12 +01:00
|
|
|
if (!t) PDBG("Targeted thread unknown");
|
|
|
|
Thread_state * const ts = (Thread_state *)user->phys_utcb()->base();
|
|
|
|
t->Cpu::Context::write_cpu_state(ts);
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Do specific syscall for 'user', for details see 'syscall.h'
|
|
|
|
*/
|
|
|
|
void do_new_signal_receiver(Thread * const user)
|
|
|
|
{
|
2013-09-12 00:48:27 +02:00
|
|
|
/* check permissions */
|
|
|
|
if (user->pd_id() != core_id()) {
|
2013-09-12 21:13:22 +02:00
|
|
|
PERR("not entitled to create signal receiver");
|
2013-09-12 00:48:27 +02:00
|
|
|
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());
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Do specific syscall for 'user', for details see 'syscall.h'
|
|
|
|
*/
|
|
|
|
void do_new_signal_context(Thread * const user)
|
|
|
|
{
|
|
|
|
/* check permissions */
|
2013-09-12 00:48:27 +02:00
|
|
|
if (user->pd_id() != core_id()) {
|
|
|
|
PERR("not entitled to create signal context");
|
|
|
|
user->user_arg_0(0);
|
|
|
|
return;
|
|
|
|
}
|
2012-05-30 20:13:09 +02:00
|
|
|
/* lookup receiver */
|
2013-09-12 00:48:27 +02:00
|
|
|
unsigned id = user->user_arg_2();
|
|
|
|
Signal_receiver * const r = Signal_receiver::pool()->object(id);
|
|
|
|
if (!r) {
|
2013-09-12 21:13:22 +02:00
|
|
|
PERR("unknown signal receiver");
|
2013-09-12 00:48:27 +02:00
|
|
|
user->user_arg_0(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* create and assign context*/
|
|
|
|
void * p = (void *)user->user_arg_1();
|
2012-05-30 20:13:09 +02:00
|
|
|
unsigned imprint = user->user_arg_3();
|
2013-09-12 00:48:27 +02:00
|
|
|
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;
|
2012-05-30 20:13:09 +02:00
|
|
|
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 */
|
2013-09-12 00:48:27 +02:00
|
|
|
unsigned id = user->user_arg_1();
|
|
|
|
Signal_receiver * const r = Signal_receiver::pool()->object(id);
|
|
|
|
if (!r) {
|
2013-09-12 21:13:22 +02:00
|
|
|
PERR("unknown signal receiver");
|
2013-09-12 00:48:27 +02:00
|
|
|
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);
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-24 16:03:31 +02:00
|
|
|
/**
|
|
|
|
* Do specific syscall for 'user', for details see 'syscall.h'
|
|
|
|
*/
|
|
|
|
void do_signal_pending(Thread * const user)
|
|
|
|
{
|
2013-09-12 00:48:27 +02:00
|
|
|
/* lookup signal receiver */
|
|
|
|
unsigned id = user->user_arg_1();
|
|
|
|
Signal_receiver * const r = Signal_receiver::pool()->object(id);
|
|
|
|
if (!r) {
|
2013-09-12 21:13:22 +02:00
|
|
|
PERR("unknown signal receiver");
|
2013-09-12 00:48:27 +02:00
|
|
|
user->user_arg_0(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* get pending state */
|
2013-09-06 01:36:03 +02:00
|
|
|
user->user_arg_0(r->deliverable());
|
2012-10-24 16:03:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-30 20:13:09 +02:00
|
|
|
/**
|
|
|
|
* Do specific syscall for 'user', for details see 'syscall.h'
|
|
|
|
*/
|
|
|
|
void do_submit_signal(Thread * const user)
|
|
|
|
{
|
2013-09-12 00:48:27 +02:00
|
|
|
/* lookup signal context */
|
|
|
|
unsigned const id = user->user_arg_1();
|
|
|
|
Signal_context * const c = Signal_context::pool()->object(id);
|
2013-02-18 13:58:09 +01:00
|
|
|
if(!c) {
|
2013-09-12 21:13:22 +02:00
|
|
|
PERR("unknown signal context");
|
2013-09-12 00:48:27 +02:00
|
|
|
user->user_arg_0(-1);
|
2013-02-18 13:58:09 +01:00
|
|
|
return;
|
|
|
|
}
|
2013-09-12 00:48:27 +02:00
|
|
|
/* trigger signal context */
|
|
|
|
if (c->submit(user->user_arg_2())) {
|
2013-09-12 21:13:22 +02:00
|
|
|
PERR("failed to submit signal context");
|
2013-09-12 00:48:27 +02:00
|
|
|
user->user_arg_0(-1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
user->user_arg_0(0);
|
2013-02-18 13:58:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Do specific syscall for 'user', for details see 'syscall.h'
|
|
|
|
*/
|
|
|
|
void do_ack_signal(Thread * const user)
|
|
|
|
{
|
2013-09-12 00:48:27 +02:00
|
|
|
/* lookup signal context */
|
2013-09-06 01:36:03 +02:00
|
|
|
unsigned id = user->user_arg_1();
|
|
|
|
Signal_context * const c = Signal_context::pool()->object(id);
|
2013-09-12 00:48:27 +02:00
|
|
|
if (!c) {
|
2013-09-12 21:13:22 +02:00
|
|
|
PERR("unknown signal context");
|
2013-09-12 00:48:27 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* acknowledge */
|
|
|
|
c->ack();
|
2012-10-02 14:27:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-02-18 13:58:09 +01:00
|
|
|
/**
|
|
|
|
* Do specific syscall for 'user', for details see 'syscall.h'
|
|
|
|
*/
|
|
|
|
void do_kill_signal_context(Thread * const user)
|
|
|
|
{
|
2013-09-11 23:30:57 +02:00
|
|
|
/* check permissions */
|
2013-09-12 00:48:27 +02:00
|
|
|
if (user->pd_id() != core_id()) {
|
|
|
|
PERR("not entitled to kill signal context");
|
|
|
|
user->user_arg_0(-1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* lookup signal context */
|
2013-09-06 01:36:03 +02:00
|
|
|
unsigned id = user->user_arg_1();
|
|
|
|
Signal_context * const c = Signal_context::pool()->object(id);
|
2013-09-12 00:48:27 +02:00
|
|
|
if (!c) {
|
2013-09-12 21:13:22 +02:00
|
|
|
PERR("unknown signal context");
|
2013-09-12 00:48:27 +02:00
|
|
|
user->user_arg_0(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* kill signal context */
|
|
|
|
if (c->kill(user)) {
|
2013-09-12 21:13:22 +02:00
|
|
|
PERR("failed to kill signal context");
|
2013-09-12 00:48:27 +02:00
|
|
|
user->user_arg_0(-1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
user->user_arg_0(0);
|
2013-02-18 13:58:09 +01:00
|
|
|
}
|
|
|
|
|
2013-09-12 00:48:27 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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) {
|
2013-09-12 21:13:22 +02:00
|
|
|
PERR("unknown signal receiver");
|
2013-09-12 00:48:27 +02:00
|
|
|
user->user_arg_0(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* kill signal receiver */
|
|
|
|
if (r->kill(user)) {
|
2013-09-12 21:13:22 +02:00
|
|
|
PERR("unknown signal receiver");
|
2013-09-12 00:48:27 +02:00
|
|
|
user->user_arg_0(-1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
user->user_arg_0(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-02 14:27:32 +02:00
|
|
|
/**
|
|
|
|
* 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();
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-08 15:22:28 +02:00
|
|
|
/**
|
|
|
|
* 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();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-30 20:13:09 +02:00
|
|
|
/**
|
|
|
|
* Handle a syscall request
|
|
|
|
*
|
|
|
|
* \param user thread that called the syscall
|
|
|
|
*/
|
|
|
|
void handle_syscall(Thread * const user)
|
|
|
|
{
|
2013-09-02 09:39:31 +02:00
|
|
|
switch (user->user_arg_0())
|
2012-05-30 20:13:09 +02:00
|
|
|
{
|
2013-09-12 00:48:27 +02:00
|
|
|
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;
|
2013-09-18 13:12:32 +02:00
|
|
|
case KILL_PD: do_kill_pd(user); return;
|
2013-09-02 09:39:31 +02:00
|
|
|
default:
|
|
|
|
PERR("invalid syscall");
|
2013-09-19 16:13:51 +02:00
|
|
|
user->stop();
|
2013-09-02 09:39:31 +02:00
|
|
|
reset_lap_time();
|
|
|
|
}
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-23 17:12:09 +02:00
|
|
|
/**
|
|
|
|
* Prepare the system for the first run of 'kernel'
|
|
|
|
*/
|
|
|
|
extern "C" void init_phys_kernel() {
|
|
|
|
Cpu::init_phys_kernel(); }
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Kernel main routine
|
|
|
|
*/
|
|
|
|
extern "C" void kernel()
|
|
|
|
{
|
|
|
|
static bool initial_call = true;
|
|
|
|
|
|
|
|
/* an exception occured */
|
|
|
|
if (!initial_call)
|
|
|
|
{
|
|
|
|
/* handle exception that interrupted the last user */
|
2013-08-23 00:18:58 +02:00
|
|
|
cpu_scheduler()->head()->handle_exception();
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
/* kernel initialization */
|
|
|
|
} else {
|
|
|
|
|
2013-07-15 13:06:08 +02:00
|
|
|
Genode::printf("Kernel started!\n");
|
|
|
|
|
2013-08-22 20:51:19 +02:00
|
|
|
/* enable kernel timer */
|
|
|
|
pic()->unmask(Timer::IRQ);
|
|
|
|
|
2012-10-02 14:27:32 +02:00
|
|
|
/* TrustZone initialization code */
|
|
|
|
trustzone_initialization(pic());
|
|
|
|
|
2013-09-26 17:03:33 +02:00
|
|
|
/* enable performance counter */
|
|
|
|
perf_counter()->enable();
|
|
|
|
|
2012-05-30 20:13:09 +02:00
|
|
|
/* switch to core address space */
|
2012-11-06 15:03:08 +01:00
|
|
|
Cpu::init_virt_kernel(core()->tlb()->base(), core_id());
|
2012-05-30 20:13:09 +02:00
|
|
|
|
2013-05-14 22:40:30 +02:00
|
|
|
/*
|
|
|
|
* From this point on, it is safe to use 'cmpxchg', i.e., to create
|
|
|
|
* singleton objects via the static-local object pattern. See
|
|
|
|
* the comment in 'src/base/singleton.h'.
|
|
|
|
*/
|
|
|
|
|
2012-05-30 20:13:09 +02:00
|
|
|
/* create the core main thread */
|
|
|
|
static Native_utcb cm_utcb;
|
|
|
|
static char cm_stack[DEFAULT_STACK_SIZE]
|
|
|
|
__attribute__((aligned(Cpu::DATA_ACCESS_ALIGNM)));
|
|
|
|
static Thread core_main((Platform_thread *)0);
|
|
|
|
_main_utcb = &cm_utcb;
|
|
|
|
enum { CM_STACK_SIZE = sizeof(cm_stack)/sizeof(cm_stack[0]) + 1 };
|
2012-10-23 17:12:09 +02:00
|
|
|
core_main.start((void *)CORE_MAIN,
|
2012-05-30 20:13:09 +02:00
|
|
|
(void *)&cm_stack[CM_STACK_SIZE - 1],
|
2013-09-09 15:20:30 +02:00
|
|
|
0, core_id(), &cm_utcb, &cm_utcb, 1);
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
/* kernel initialization finished */
|
2013-09-02 09:39:31 +02:00
|
|
|
reset_lap_time();
|
2012-05-30 20:13:09 +02:00
|
|
|
initial_call = false;
|
|
|
|
}
|
2012-10-02 14:27:32 +02:00
|
|
|
/* will jump to the context related mode-switch */
|
2013-08-23 00:18:58 +02:00
|
|
|
cpu_scheduler()->head()->proceed();
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
|
|
|
|
2013-09-06 17:37:09 +02:00
|
|
|
static Kernel::Mode_transition_control * Kernel::mtc()
|
|
|
|
{
|
|
|
|
/* compose CPU context for kernel entry */
|
|
|
|
struct Kernel_context : Cpu::Context
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*/
|
|
|
|
Kernel_context()
|
|
|
|
{
|
|
|
|
ip = (addr_t)kernel;
|
|
|
|
sp = (addr_t)&_kernel_stack_high;
|
|
|
|
core()->admit(this);
|
|
|
|
}
|
|
|
|
} * const k = unsynchronized_singleton<Kernel_context>();
|
|
|
|
|
|
|
|
/* initialize mode transition page */
|
|
|
|
return unsynchronized_singleton<Mode_transition_control>(k);
|
|
|
|
}
|