genode/base-hw/src/core/kernel.cc

939 lines
24 KiB
C++
Raw Normal View History

/*
* \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
*
* 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 */
#include <base/thread_state.h>
/* core includes */
#include <kernel/pd.h>
#include <kernel/vm.h>
#include <platform_pd.h>
#include <trustzone.h>
#include <timer.h>
/* base-hw includes */
#include <singleton.h>
#include <kernel/perf_counter.h>
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 */
typedef Genode::Thread_state Thread_state;
typedef Genode::umword_t umword_t;
typedef Genode::Core_tlb Core_tlb;
}
namespace Kernel
{
/**
* Idle thread entry
*/
static void idle_main() { while (1) ; }
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>(); }
/**
* Access to static kernel timer
*/
static Timer * timer() { static Timer _object; return &_object; }
void reset_lap_time()
{
timer()->start_one_shot(timer()->ms_to_tics(USER_LAP_TIME_MS));
}
/**
* Static kernel PD that describes core
*/
static Pd * core()
{
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;
}
/**
* Get core attributes
*/
unsigned core_id() { return core()->id(); }
}
namespace Kernel
{
/**
* 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 */
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()'.
*/
idle.prepare_to_start(ip, sp, 0, core_id(), 0, 0, 0);
initial = 0;
}
/* create scheduler with a permanent idle thread */
static Cpu_scheduler cpu_sched(&idle);
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); }
size_t pd_size() { return sizeof(Tlb) + sizeof(Pd); }
size_t signal_context_size() { return sizeof(Signal_context); }
size_t signal_receiver_size() { return sizeof(Signal_receiver); }
unsigned pd_alignm_log2() { return Tlb::ALIGNM_LOG2; }
size_t vm_size() { return sizeof(Vm); }
/**
* Handle an interrupt request
*/
void handle_interrupt()
{
/* determine handling for specific interrupt */
unsigned irq;
if (pic()->take_request(irq))
{
switch (irq) {
case Timer::IRQ: {
cpu_scheduler()->yield();
timer()->clear_interrupt();
reset_lap_time();
break; }
default: {
Irq_receiver * const o = Irq_receiver::receiver(irq);
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 */
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());
}
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();
}
/**
* 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)
{
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());
}
/**
* 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;
}
/* 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();
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;
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);
}
/**
* 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 */
user->user_arg_0(r->deliverable());
}
/**
* 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);
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);
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);
}
/**
* 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 */
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();
}
/**
* Do specific syscall for 'user', for details see 'syscall.h'
*/
void do_kill_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 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);
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-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);
}
/**
* 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())
{
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;
case KILL_PD: do_kill_pd(user); return;
default:
PERR("invalid syscall");
2013-09-19 16:13:51 +02:00
user->stop();
reset_lap_time();
}
}
}
/**
* Prepare the system for the first run of 'kernel'
*/
extern "C" void init_phys_kernel() {
Cpu::init_phys_kernel(); }
/**
* 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 */
cpu_scheduler()->head()->handle_exception();
/* kernel initialization */
} else {
Genode::printf("Kernel started!\n");
/* enable kernel timer */
pic()->unmask(Timer::IRQ);
/* TrustZone initialization code */
trustzone_initialization(pic());
/* enable performance counter */
perf_counter()->enable();
/* switch to core address space */
Cpu::init_virt_kernel(core()->tlb()->base(), core_id());
/*
* 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'.
*/
/* 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 };
core_main.start((void *)CORE_MAIN,
(void *)&cm_stack[CM_STACK_SIZE - 1],
0, core_id(), &cm_utcb, &cm_utcb, 1);
/* kernel initialization finished */
reset_lap_time();
initial_call = false;
}
/* will jump to the context related mode-switch */
cpu_scheduler()->head()->proceed();
}
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);
}