diff --git a/base-hw/src/core/cpu/arm.h b/base-hw/src/core/cpu/arm.h index ff032073c..00f34b93f 100644 --- a/base-hw/src/core/cpu/arm.h +++ b/base-hw/src/core/cpu/arm.h @@ -469,16 +469,6 @@ namespace Arm uint32_t cidr; /* context ID register backup */ uint32_t section_table; /* base address of applied section table */ - /*************** - ** Accessors ** - ***************/ - - void tlb(addr_t const st) { section_table = st; } - - addr_t tlb() const { return section_table; } - - void protection_domain(unsigned const id) { cidr = id; } - /** * Copy CPU state data to 'c' */ @@ -524,6 +514,21 @@ namespace Arm lr = s->lr; ip = s->ip; } + + /** + * Get base of assigned translation lookaside buffer + */ + addr_t tlb() const { return section_table; } + + /** + * Assign translation lookaside buffer + */ + void tlb(addr_t const st) { section_table = st; } + + /** + * Assign protection domain + */ + void protection_domain(unsigned const id) { cidr = id; } }; /** @@ -557,6 +562,62 @@ namespace Arm unsigned user_arg_6() const { return r6; } unsigned user_arg_7() const { return r7; } + /** + * Part of context init that is common for all types of threads + */ + void init_thread_common(void * const instr_p, + 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); + } + /** * Check if a pagefault has occured 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 bc99b0cd5..13fcd96a0 100644 --- a/base-hw/src/core/include/platform_thread.h +++ b/base-hw/src/core/include/platform_thread.h @@ -178,7 +178,7 @@ namespace Genode { Thread_base * thread_base() { - if (!_thread_base) assert(_main_thread); + if (!_thread_base) assert(main_thread()); return _thread_base; } @@ -188,6 +188,8 @@ namespace Genode { Ram_dataspace_capability utcb() const { return _utcb; } + bool main_thread() const { return _main_thread; } + Tlb * tlb() const { return _tlb; } }; } diff --git a/base-hw/src/core/kernel.cc b/base-hw/src/core/kernel.cc index fa55abcc9..af8f3b243 100644 --- a/base-hw/src/core/kernel.cc +++ b/base-hw/src/core/kernel.cc @@ -766,7 +766,15 @@ namespace Kernel /* initialize idle thread */ void * sp; sp = (void *)&idle_stack[sizeof(idle_stack)/sizeof(idle_stack[0])]; - idle.init_context((void *)&idle_main, sp, core_id()); + + /* + * 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((void *)&idle_main, sp, 0, core_id(), 0, 0); initial = 0; } /* create scheduler with a permanent idle thread */ @@ -929,8 +937,7 @@ namespace Kernel assert(t); /* start thread */ - assert(!t->start(ip, sp, cpu, pt->pd_id(), - pt->phys_utcb(), pt->virt_utcb())) + t->start(ip, sp, cpu, pt->pd_id(), pt->phys_utcb(), pt->virt_utcb()); /* return software TLB that the thread is assigned to */ Pd::Pool * const pp = Pd::pool(); @@ -1529,42 +1536,49 @@ int Kernel::Thread::resume() } -int Thread::start(void *ip, void *sp, unsigned cpu_no, - unsigned const pd_id, - Native_utcb * const phys_utcb, - Native_utcb * const virt_utcb) +void Thread::prepare_to_start(void * const ip, + void * const sp, + unsigned const cpu_id, + unsigned const pd_id, + Native_utcb * const utcb_phys, + Native_utcb * const utcb_virt) { /* check state and arguments */ assert(_state == AWAIT_START) - assert(!cpu_no); + assert(!cpu_id); - /* apply thread configuration */ - init_context(ip, sp, pd_id); - _phys_utcb = phys_utcb; - _virt_utcb = virt_utcb; + /* store thread parameters */ + _phys_utcb = utcb_phys; + _virt_utcb = utcb_virt; + _pd_id = pd_id; - /* offer thread-entry arguments */ - user_arg_0((unsigned)_virt_utcb); + /* join a protection domain */ + Pd * const pd = Pd::pool()->object(_pd_id); + assert(pd) + addr_t const tlb = pd->tlb()->base(); - /* start thread */ - _schedule(); - return 0; + /* initialize CPU context */ + if (!_platform_thread) + /* this is the main thread of core */ + User_context::init_core_main_thread(ip, sp, tlb, pd_id); + else if (!_platform_thread->main_thread()) + /* this is not a main thread */ + User_context::init_thread(ip, sp, tlb, pd_id); + else + /* this is the main thread of a program other than core */ + User_context::init_main_thread(ip, _virt_utcb, tlb, pd_id); } -void Thread::init_context(void * const instr_p, void * const stack_p, - unsigned const pd_id) +void Thread::start(void * const ip, + void * const sp, + unsigned const cpu_id, + unsigned const pd_id, + Native_utcb * const utcb_phys, + Native_utcb * const utcb_virt) { - /* basic thread state */ - sp = (addr_t)stack_p; - ip = (addr_t)instr_p; - - /* join a pd */ - _pd_id = pd_id; - Pd * const pd = Pd::pool()->object(_pd_id); - assert(pd) - protection_domain(pd_id); - tlb(pd->tlb()->base()); + prepare_to_start(ip, sp, cpu_id, pd_id, utcb_phys, utcb_virt); + _schedule(); } diff --git a/base-hw/src/core/kernel/thread.h b/base-hw/src/core/kernel/thread.h index 3ca1a6d01..838c6f5bb 100644 --- a/base-hw/src/core/kernel/thread.h +++ b/base-hw/src/core/kernel/thread.h @@ -847,19 +847,39 @@ namespace Kernel _phys_utcb(0), _virt_utcb(0), _signal_receiver(0) { } + /** + * Prepare thread to get scheduled the first time + * + * \param ip initial instruction pointer + * \param sp initial stack pointer + * \param cpu_id target cpu + * \param pd_id target protection-domain + * \param utcb_phys physical UTCB pointer + * \param utcb_virt virtual UTCB pointer + */ + void prepare_to_start(void * const ip, + void * const sp, + unsigned const cpu_id, + unsigned const pd_id, + Native_utcb * const utcb_phys, + Native_utcb * const utcb_virt); + /** * Start this thread * - * \param ip instruction pointer to start at - * \param sp stack pointer to use - * \param cpu_no target cpu - * - * \retval 0 successful - * \retval -1 thread could not be started + * \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 */ - int start(void *ip, void *sp, unsigned cpu_no, - unsigned const pd_id, Native_utcb * const phys_utcb, - Native_utcb * const virt_utcb); + void start(void * const ip, + void * const sp, + unsigned const cpu_id, + unsigned const pd_id, + Native_utcb * const utcb_phys, + Native_utcb * const utcb_virt); /** * Pause this thread @@ -891,16 +911,6 @@ namespace Kernel */ void reply(size_t const size, bool const await_request); - /** - * Initialize our execution context - * - * \param ip instruction pointer - * \param sp stack pointer - * \param pd_id identifies protection domain we're assigned to - */ - void init_context(void * const ip, void * const sp, - unsigned const pd_id); - /** * Handle a pagefault that originates from this thread * diff --git a/base-hw/src/core/platform_thread.cc b/base-hw/src/core/platform_thread.cc index c6b44dacd..3c12c34e1 100644 --- a/base-hw/src/core/platform_thread.cc +++ b/base-hw/src/core/platform_thread.cc @@ -28,7 +28,7 @@ bool Platform_thread::_attaches_utcb_by_itself() * virtual context area by itself, as it is done for other threads * through a sub RM-session. */ - return _pd_id == Kernel::core_id() || !_main_thread; + return _pd_id == Kernel::core_id() || !main_thread(); } diff --git a/base-hw/src/platform/arm/crt0.s b/base-hw/src/platform/arm/crt0.s index 093f9b0d6..dba4a8adc 100644 --- a/base-hw/src/platform/arm/crt0.s +++ b/base-hw/src/platform/arm/crt0.s @@ -19,8 +19,8 @@ _start: /* fetch thread-entry arguments to their destinations in BSS */ - ldr r1, =_main_utcb - str r0, [r1] + ldr r0, =_main_utcb + str sp, [r0] /* call _main routine */ ldr sp, =_stack_high