diff --git a/base-hw/include/kernel/interface.h b/base-hw/include/kernel/interface.h index 90ba15bdb0..6bd2a41b25 100644 --- a/base-hw/include/kernel/interface.h +++ b/base-hw/include/kernel/interface.h @@ -19,6 +19,7 @@ namespace Genode { + class Native_utcb; class Platform_thread; class Platform_pd; class Tlb; @@ -31,6 +32,7 @@ namespace Kernel typedef Genode::size_t size_t; typedef Genode::Platform_thread Platform_thread; typedef Genode::Platform_pd Platform_pd; + typedef Genode::Native_utcb Native_utcb; /** * Kernel names of all kernel calls @@ -232,23 +234,20 @@ namespace Kernel /** - * Start thread with a given context and let it participate in CPU scheduling + * Start executing a thread * - * \param id ID of targeted thread - * \param ip initial instruction pointer - * \param sp initial stack pointer - * - * \retval >0 success, return value is the TLB of the thread - * \retval 0 the targeted thread wasn't started or was already started - * when this gets called (in both cases it remains untouched) + * \param thread_id kernel name of targeted thread + * \param cpu_id kernel name of targeted processor + * \param pd_id kernel name of targeted protection domain + * \param utcb core local pointer to userland thread-context * * Restricted to core threads. */ - inline Tlb * start_thread(Platform_thread * const phys_pt, void * const ip, - void * const sp, unsigned const cpu_no) + inline Tlb * start_thread(unsigned const thread_id, unsigned const cpu_id, + unsigned const pd_id, Native_utcb * const utcb) { - return (Tlb *)call(Call_id::START_THREAD, (Call_arg)phys_pt, - (Call_arg)ip, (Call_arg)sp, cpu_no); + return (Tlb *)call(Call_id::START_THREAD, thread_id, cpu_id, pd_id, + (Call_arg)utcb); } diff --git a/base-hw/src/core/cpu/arm.h b/base-hw/src/core/cpu/arm.h index e3f1bf204a..ff7fbde708 100644 --- a/base-hw/src/core/cpu/arm.h +++ b/base-hw/src/core/cpu/arm.h @@ -517,61 +517,17 @@ namespace Arm unsigned user_arg_7() const { return r7; } /** - * Part of context init that is common for all types of threads + * Initialize thread context + * + * \param tlb physical base of appropriate page table + * \param pd_id kernel name of appropriate protection domain */ - void init_thread_common(void * const instr_p, - addr_t const tlb, - unsigned const pd_id) + void init_thread(addr_t const tlb, unsigned const pd_id) { - ip = (addr_t)instr_p; cidr = pd_id; section_table = tlb; } - /** - * Init context of the first thread of core - */ - void init_core_main_thread(void * const instr_p, - void * const stack_p, - addr_t const tlb, - unsigned const pd_id) - { - sp = (addr_t)stack_p; - init_thread_common(instr_p, tlb, pd_id); - } - - /** - * Init context of a thread that isn't first thread of a program - */ - void init_thread(void * const instr_p, - void * const stack_p, - addr_t const tlb, - unsigned const pd_id) - { - sp = (addr_t)stack_p; - init_thread_common(instr_p, tlb, pd_id); - } - - /** - * Init context of the first thread of a program other than core - */ - void init_main_thread(void * const instr_p, - void * const utcb_virt, - addr_t const tlb, - unsigned const pd_id) - { - /* - * Normally threads receive their UTCB pointer through their - * 'Thread_base' but the first thread of a program doesn't - * have such object. Thus the kernel hands out the UTCB pointer - * through the main threads initial CPU context. 'crt0.s' then - * can save the received pointer to local mem before polluting - * the CPU context. - */ - sp = (addr_t)utcb_virt; - init_thread_common(instr_p, tlb, pd_id); - } - /** * Return if the context is in a page fault due to a translation miss * diff --git a/base-hw/src/core/include/platform_thread.h b/base-hw/src/core/include/platform_thread.h index 1daeb685ee..dacae70a96 100644 --- a/base-hw/src/core/include/platform_thread.h +++ b/base-hw/src/core/include/platform_thread.h @@ -48,8 +48,8 @@ namespace Genode { Weak_ptr _address_space; unsigned _id; Rm_client * _rm_client; - Native_utcb * _phys_utcb; - Native_utcb * _virt_utcb; + Native_utcb * _utcb_phys; + Native_utcb * _utcb_virt; Tlb * _tlb; Ram_dataspace_capability _utcb; char _name[NAME_MAX_LEN]; @@ -109,8 +109,12 @@ namespace Genode { /** * Run this thread + * + * \param ip initial instruction pointer + * \param sp initial stack pointer + * \param cpu_id kernel name of targeted CPU */ - int start(void * ip, void * sp, unsigned int cpu_no = 0); + int start(void * const ip, void * const sp, unsigned const cpu_id = 0); /** * Pause this thread @@ -182,9 +186,9 @@ namespace Genode { return _thread_base; } - Native_utcb * phys_utcb() const { return _phys_utcb; } + Native_utcb * utcb_phys() const { return _utcb_phys; } - Native_utcb * virt_utcb() const { return _virt_utcb; } + Native_utcb * utcb_virt() const { return _utcb_virt; } Ram_dataspace_capability utcb() const { return _utcb; } diff --git a/base-hw/src/core/kernel/kernel.cc b/base-hw/src/core/kernel/kernel.cc index 67fc25b8e0..f0e94753b0 100644 --- a/base-hw/src/core/kernel/kernel.cc +++ b/base-hw/src/core/kernel/kernel.cc @@ -119,9 +119,9 @@ namespace Kernel static bool init = 0; if (!init) { 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.init(ip, sp, 0, core_id(), 0, 0, 0, 0); + idle.ip = (addr_t)&idle_main;; + idle.sp = (addr_t)&idle_stack[STACK_SIZE];; + idle.init(0, core_id(), 0, 0); init = 1; } /* create CPU scheduler with a permanent idle thread */ @@ -231,12 +231,12 @@ extern "C" void kernel() *(Core_thread_id *)s = 0; /* start thread with stack pointer at the top of stack */ - void * const sp = (void *)((addr_t)s + STACK_SIZE); - void * const ip = (void *)CORE_MAIN; static Native_utcb utcb; _main_utcb = &utcb; static Thread t((Platform_thread *)0); - t.init(ip, sp, 0, core_id(), &utcb, &utcb, 1, 1); + t.ip = (addr_t)CORE_MAIN;; + t.sp = (addr_t)s + STACK_SIZE; + t.init(0, core_id(), &utcb, 1); } /* kernel initialization finished */ init_platform(); diff --git a/base-hw/src/core/kernel/thread.cc b/base-hw/src/core/kernel/thread.cc index 068cf45c15..60396918e2 100644 --- a/base-hw/src/core/kernel/thread.cc +++ b/base-hw/src/core/kernel/thread.cc @@ -75,8 +75,8 @@ void Thread::_await_signal(Signal_receiver * const receiver) void Thread::_receive_signal(void * const base, size_t const size) { - assert(_state == AWAITS_SIGNAL && size <= _phys_utcb->size()); - Genode::memcpy(_phys_utcb->base(), base, size); + assert(_state == AWAITS_SIGNAL && size <= _utcb_phys->size()); + Genode::memcpy(_utcb_phys->base(), base, size); _schedule(); } @@ -191,17 +191,14 @@ Thread::Thread(Platform_thread * const pt) _platform_thread(pt), _state(AWAITS_START), _pd(0), - _phys_utcb(0), - _virt_utcb(0), + _utcb_phys(0), _signal_receiver(0) { } void -Thread::init(void * const ip, void * const sp, unsigned const cpu_id, - unsigned const pd_id_arg, Native_utcb * const utcb_phys, - Native_utcb * const utcb_virt, bool const main, - bool const start) +Thread::init(unsigned const cpu_id, unsigned const pd_id_arg, + Native_utcb * const utcb_phys, bool const start) { assert(_state == AWAITS_START) @@ -209,19 +206,13 @@ Thread::init(void * const ip, void * const sp, unsigned const cpu_id, if (cpu_id) { PERR("multicore processing not supported"); } /* store thread parameters */ - _phys_utcb = utcb_phys; - _virt_utcb = utcb_virt; + _utcb_phys = utcb_phys; /* join protection domain */ _pd = Pd::pool()->object(pd_id_arg); assert(_pd); addr_t const tlb = _pd->tlb()->base(); - - /* initialize CPU context */ - User_context * const c = static_cast(this); - 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()); } + User_context::init_thread(tlb, pd_id()); /* print log message */ if (START_VERBOSE) { @@ -282,7 +273,7 @@ void Thread::proceed() char const * Kernel::Thread::label() const { if (!platform_thread()) { - if (!_phys_utcb) { return "idle"; } + if (!_utcb_phys) { return "idle"; } return "core"; } return platform_thread()->name(); @@ -377,24 +368,26 @@ void Thread::_call_delete_thread() void Thread::_call_start_thread() { /* check permissions */ - assert(_core()); - + if (!_core()) { + PERR("not entitled to start thread"); + user_arg_0(0); + return; + } /* dispatch arguments */ - Platform_thread * pt = (Platform_thread *)user_arg_1(); - void * const ip = (void *)user_arg_2(); - void * const sp = (void *)user_arg_3(); - unsigned const cpu_id = (unsigned)user_arg_4(); - - /* get targeted thread */ - Thread * const t = Thread::pool()->object(pt->id()); - assert(t); + unsigned const thread_id = user_arg_1(); + unsigned const cpu_id = user_arg_2(); + unsigned const pd_id = user_arg_3(); + Native_utcb * const utcb = (Native_utcb *)user_arg_4(); + /* lookup targeted thread */ + Thread * const t = Thread::pool()->object(thread_id); + if (!t) { + PERR("unknown thread"); + user_arg_0(0); + return; + } /* 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(); - bool const main = pt->main_thread(); - t->init(ip, sp, cpu_id, pd_id, utcb_p, utcb_v, main, 1); + t->init(cpu_id, pd_id, utcb, 1); user_arg_0((Call_ret)t->_pd->tlb()); } @@ -475,7 +468,7 @@ void Thread::_call_wait_for_request() { void * buf_base; size_t buf_size; - _phys_utcb->call_wait_for_request(buf_base, buf_size); + _utcb_phys->call_wait_for_request(buf_base, buf_size); Ipc_node::await_request(buf_base, buf_size); } @@ -492,7 +485,7 @@ void Thread::_call_request_and_wait() size_t msg_size; void * buf_base; size_t buf_size; - _phys_utcb->call_request_and_wait(msg_base, msg_size, + _utcb_phys->call_request_and_wait(msg_base, msg_size, buf_base, buf_size); Ipc_node::send_request_await_reply(dst, msg_base, msg_size, buf_base, buf_size); @@ -503,7 +496,7 @@ void Thread::_call_reply() { void * msg_base; size_t msg_size; - _phys_utcb->call_reply(msg_base, msg_size); + _utcb_phys->call_reply(msg_base, msg_size); Ipc_node::send_reply(msg_base, msg_size); bool const await_request = user_arg_1(); if (await_request) { _call_wait_for_request(); } @@ -590,7 +583,7 @@ void Thread::_call_access_thread_regs() /* execute read operations */ unsigned const reads = user_arg_2(); unsigned const writes = user_arg_3(); - addr_t * const utcb = (addr_t *)_phys_utcb->base(); + addr_t * const utcb = (addr_t *)_utcb_phys->base(); addr_t * const read_ids = &utcb[0]; addr_t * const read_values = (addr_t *)user_arg_4(); for (unsigned i = 0; i < reads; i++) { diff --git a/base-hw/src/core/kernel/thread.h b/base-hw/src/core/kernel/thread.h index 50bab30fa8..cba33bbf95 100644 --- a/base-hw/src/core/kernel/thread.h +++ b/base-hw/src/core/kernel/thread.h @@ -81,8 +81,7 @@ class Kernel::Thread Platform_thread * const _platform_thread; State _state; Pd * _pd; - Native_utcb * _phys_utcb; - Native_utcb * _virt_utcb; + Native_utcb * _utcb_phys; Signal_receiver * _signal_receiver; /** @@ -263,19 +262,13 @@ class Kernel::Thread /** * 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 - * \param start wether to start execution + * \param cpu_id kernel name of targeted processor + * \param pd_id kernel name of target protection domain + * \param utcb core local pointer to userland thread-context + * \param start wether to start executing the thread */ - void init(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, - bool const start); + void init(unsigned const cpu_id, unsigned const pd_id, + Native_utcb * const utcb, bool const start); /*********************** diff --git a/base-hw/src/core/platform_thread.cc b/base-hw/src/core/platform_thread.cc index 123988fb62..0e7747d493 100644 --- a/base-hw/src/core/platform_thread.cc +++ b/base-hw/src/core/platform_thread.cc @@ -46,13 +46,13 @@ Platform_thread::~Platform_thread() /* the RM client may be destructed before platform thread */ if (_rm_client) { Rm_session_component * const rm = _rm_client->member_rm_session(); - rm->detach(_virt_utcb); + rm->detach(utcb_virt()); } } /* free UTCB */ if (_pd_id == Kernel::core_id()) { Range_allocator * const ram = platform()->ram_alloc(); - ram->free((void *)_phys_utcb, sizeof(Native_utcb)); + ram->free(utcb_phys(), sizeof(Native_utcb)); } else { Ram_session_component * const ram = dynamic_cast(core_env()->ram_session()); @@ -77,7 +77,7 @@ Platform_thread::Platform_thread(const char * name, size_t const stack_size, unsigned const pd_id) : _thread_base(thread_base), _stack_size(stack_size), - _pd_id(pd_id), _rm_client(0), _virt_utcb(0), + _pd_id(pd_id), _rm_client(0), _utcb_virt(0), _priority(Kernel::Priority::MAX), _main_thread(0) { @@ -85,13 +85,13 @@ Platform_thread::Platform_thread(const char * name, /* create UTCB for a core thread */ Range_allocator * const ram = platform()->ram_alloc(); - if (!ram->alloc_aligned(sizeof(Native_utcb), (void **)&_phys_utcb, + if (!ram->alloc_aligned(sizeof(Native_utcb), (void **)&_utcb_phys, MIN_MAPPING_SIZE_LOG2).is_ok()) { PERR("failed to allocate UTCB"); throw Cpu_session::Out_of_metadata(); } - _virt_utcb = _phys_utcb; + _utcb_virt = _utcb_phys; /* common constructor parts */ _init(); @@ -102,7 +102,7 @@ Platform_thread::Platform_thread(const char * name, unsigned int priority, addr_t utcb) : _thread_base(0), _stack_size(0), _pd_id(0), _rm_client(0), - _virt_utcb((Native_utcb *)utcb), + _utcb_virt((Native_utcb *)utcb), _priority(Cpu_session::scale_priority(Kernel::Priority::MAX, priority)), _main_thread(0) { @@ -121,7 +121,7 @@ Platform_thread::Platform_thread(const char * name, unsigned int priority, PERR("failed to allocate UTCB"); throw Cpu_session::Out_of_metadata(); } - _phys_utcb = (Native_utcb *)ram->phys_addr(_utcb); + _utcb_phys = (Native_utcb *)ram->phys_addr(_utcb); /* common constructor parts */ _init(); @@ -155,21 +155,14 @@ void Platform_thread::_init() } -int Platform_thread::start(void * ip, void * sp, unsigned int cpu_no) +int Platform_thread::start(void * const ip, void * const sp, + unsigned int const cpu_id) { - /* must be in a PD to get started */ - if (!_pd_id) { - PERR("invalid PD"); - return -1; - } /* attach UTCB if the thread can't do this by itself */ if (!_attaches_utcb_by_itself()) { - /* - * Declare page aligned virtual UTCB outside the context area. - * Kernel afterwards offers this as bootstrap argument to the thread. - */ - _virt_utcb = (Native_utcb *)((platform()->vm_start() + /* declare page aligned virtual UTCB outside the context area */ + _utcb_virt = (Native_utcb *)((platform()->vm_start() + platform()->vm_size() - sizeof(Native_utcb)) & ~((1<member_rm_session(); - try { rm->attach(_utcb, 0, 0, true, _virt_utcb, 0); } + try { rm->attach(_utcb, 0, 0, true, _utcb_virt, 0); } catch (...) { PERR("failed to attach UTCB"); return -1; } } + /* initialize thread regisers */ + typedef Kernel::Thread_reg_id Reg_id; + enum { WRITES = 2 }; + addr_t * write_regs = (addr_t *)Thread_base::myself()->utcb()->base(); + write_regs[0] = Reg_id::IP; + write_regs[1] = Reg_id::SP; + addr_t write_values[] = { + (addr_t)ip, + main_thread() ? (addr_t)_utcb_virt : (addr_t)sp + }; + if (Kernel::access_thread_regs(id(), 0, WRITES, 0, write_values)) { + PERR("failed to initialize thread registers"); + return -1; + } /* let thread participate in CPU scheduling */ - _tlb = Kernel::start_thread(this, ip, sp, cpu_no); + _tlb = Kernel::start_thread(id(), cpu_id, _pd_id, utcb_phys()); if (!_tlb) { PERR("failed to start thread"); return -1; diff --git a/base-hw/src/core/thread.cc b/base-hw/src/core/thread.cc index d2b6ff4bc8..b380952066 100644 --- a/base-hw/src/core/thread.cc +++ b/base-hw/src/core/thread.cc @@ -33,7 +33,7 @@ Native_utcb * Thread_base::utcb() if (!this) { return _main_utcb; } /* this isn't the main thread */ - return _tid.pt->phys_utcb(); + return _tid.pt->utcb_phys(); }