From 9b6eaae23480b3742f85ce706944c1268baa9290 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Wed, 11 Jan 2006 02:17:29 +0000 Subject: [PATCH] * Fixed thread support. The entry and exist functions are now called, too -- introduced a function ppc_kernel_thread_root() which calls the three functions (entry, start, exit) in sequence. This brings us well into the second part of the kernel initialization. * Replaced stmw/lmw in ppc_context_switch() by individual stwu/lwzu sequences. The former ones are documented to perform suboptimal on some architecture implementations. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15904 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/kernel/arch/ppc/arch_asm.S | 101 +++++++++++++++++++---- src/system/kernel/arch/ppc/arch_thread.c | 80 +++++++++++++++--- 2 files changed, 151 insertions(+), 30 deletions(-) diff --git a/src/system/kernel/arch/ppc/arch_asm.S b/src/system/kernel/arch/ppc/arch_asm.S index 692997ce49..c254faaefb 100644 --- a/src/system/kernel/arch/ppc/arch_asm.S +++ b/src/system/kernel/arch/ppc/arch_asm.S @@ -1,7 +1,10 @@ /* -** Copyright 2003, Travis Geiselbrecht. All rights reserved. -** Distributed under the terms of the NewOS License. -*/ + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + * + * Copyright 2003, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. + */ #define FUNCTION(x) .global x; .type x,@function; x @@ -185,42 +188,104 @@ FUNCTION(setl2cr): mtspr 1017, %r3 blr + // void ppc_context_switch(addr_t *old_sp, addr_t new_sp); FUNCTION(ppc_context_switch): // regs to push on the stack: r13-r31, cr, r2, lr -#define SAVE_FRAME_SIZE (((31 - 13 + 1) + 1 + 1 + 1) * 4) // push the old regs we need to save on the stack - addi %sp, %sp, -SAVE_FRAME_SIZE - stmw %r13, 12(%sp) - stw %r2, 8(%sp) + // r31-13, r2 + stwu %r31, -4(%r1) + stwu %r30, -4(%r1) + stwu %r29, -4(%r1) + stwu %r28, -4(%r1) + stwu %r27, -4(%r1) + stwu %r26, -4(%r1) + stwu %r25, -4(%r1) + stwu %r24, -4(%r1) + stwu %r23, -4(%r1) + stwu %r22, -4(%r1) + stwu %r21, -4(%r1) + stwu %r20, -4(%r1) + stwu %r19, -4(%r1) + stwu %r18, -4(%r1) + stwu %r17, -4(%r1) + stwu %r16, -4(%r1) + stwu %r15, -4(%r1) + stwu %r14, -4(%r1) + stwu %r13, -4(%r1) + stwu %r2, -4(%r1) + + // CR and LR mfcr %r0 - stw %r0, 4(%sp) + stwu %r0, -4(%r1) mflr %r0 - stw %r0, 0(%sp) + stwu %r0, -4(%r1) // save the old stack pointer - stw %sp, 0(%r3) + stwu %r1, 0(%r3) // restore the new stack pointer - mr %sp, %r4 + mr %r1, %r4 // restore the new regs - lwz %r0, 0(%sp) + // LR and CR + lwz %r0, 0(%r1) mtlr %r0 - lwz %r0, 4(%sp) + lwzu %r0, 4(%r1) mtcr %r0 - lwz %r2, 8(%sp) - lmw %r13, 12(%sp) - addi %sp, %sp, SAVE_FRAME_SIZE + + // r2, r13-31 + lwzu %r2, 4(%r1) + lwzu %r13, 4(%r1) + lwzu %r14, 4(%r1) + lwzu %r15, 4(%r1) + lwzu %r16, 4(%r1) + lwzu %r17, 4(%r1) + lwzu %r18, 4(%r1) + lwzu %r19, 4(%r1) + lwzu %r20, 4(%r1) + lwzu %r21, 4(%r1) + lwzu %r22, 4(%r1) + lwzu %r23, 4(%r1) + lwzu %r24, 4(%r1) + lwzu %r25, 4(%r1) + lwzu %r26, 4(%r1) + lwzu %r27, 4(%r1) + lwzu %r28, 4(%r1) + lwzu %r29, 4(%r1) + lwzu %r30, 4(%r1) + lwzu %r31, 4(%r1) + + addi %r1, %r1, 4 blr -// void arch_thread_switch_kstack_and_call(addr_t new_kstack, void (*func)(void *), void *arg) + +// void arch_thread_switch_kstack_and_call(addr_t new_kstack, +// void (*func)(void *), void *arg) FUNCTION(arch_thread_switch_kstack_and_call): - mr %sp, %r3 // set the new stack pointer + mr %r1, %r3 // set the new stack pointer mtctr %r4 // move the target function into CTR mr %r3, %r5 // move the arg to this func to the new arg bctr + +// ppc_kernel_thread_root(): parameters in r13-r15, the functions to call +// (in that order). The function is used when spawing threads. It usually calls +// an initialization function, the actual thread function, and a function that +// destroys the thread. +FUNCTION(ppc_kernel_thread_root): + mtlr %r13 + blrl + mtlr %r14 + blrl + mtlr %r15 + blrl + + // We should never get here. If we do, it's time to enter the kernel + // debugger (without a message at the moment). + li %r3, 0 + b kernel_debugger + diff --git a/src/system/kernel/arch/ppc/arch_thread.c b/src/system/kernel/arch/ppc/arch_thread.c index 8354cf10bf..d84aab3cc5 100644 --- a/src/system/kernel/arch/ppc/arch_thread.c +++ b/src/system/kernel/arch/ppc/arch_thread.c @@ -12,14 +12,21 @@ #include +#include +#include #include #include -#include #include //#include #include +// Valid initial arch_thread state. We just memcpy() it when initializing +// a new thread structure. +static struct arch_thread sInitialState; + +// Helper functions for thread creation, defined in arch_asm.S. +extern void ppc_kernel_thread_root(); void ppc_push_iframe(struct iframe_stack *stack, struct iframe *frame) @@ -52,12 +59,37 @@ ppc_get_current_iframe(void) } +/** \brief Returns the current thread's topmost (i.e. most recent) + * userland->kernel transition iframe (usually the first one, save for + * interrupts in signal handlers). + * \return The iframe, or \c NULL, if there is no such iframe (e.g. when + * the thread is a kernel thread). + */ +struct iframe * +ppc_get_user_iframe(void) +{ + struct thread *thread = thread_get_current_thread(); + int i; + + for (i = thread->arch_info.iframes.index - 1; i >= 0; i--) { + struct iframe *frame = thread->arch_info.iframes.frames[i]; + if (frame->srr1 & MSR_PRIVILEGE_LEVEL) + return frame; + } + + return NULL; +} + + // #pragma mark - status_t arch_thread_init(struct kernel_args *args) { + // Initialize the static initial arch_thread state (sInitialState). + // Currently nothing to do, i.e. zero initialized is just fine. + return B_OK; } @@ -65,36 +97,59 @@ arch_thread_init(struct kernel_args *args) status_t arch_team_init_team_struct(struct team *team, bool kernel) { + // Nothing to do. The structure is empty. return B_OK; } status_t -arch_thread_init_thread_struct(struct thread *t) +arch_thread_init_thread_struct(struct thread *thread) { // set up an initial state (stack & fpu) - memset(&t->arch_info, 0, sizeof(t->arch_info)); + memcpy(&thread->arch_info, &sInitialState, sizeof(struct arch_thread)); return B_OK; } status_t -arch_thread_init_kthread_stack(struct thread *t, int (*start_func)(void), void (*entry_func)(void), void (*exit_func)(void)) +arch_thread_init_kthread_stack(struct thread *t, int (*start_func)(void), + void (*entry_func)(void), void (*exit_func)(void)) { addr_t *kstack = (addr_t *)t->kernel_stack_base; - size_t kstack_size = KERNEL_STACK_SIZE; - addr_t *kstack_top = kstack + kstack_size / sizeof(addr_t) - 2 * 4; + addr_t *kstackTop = kstack + KERNEL_STACK_SIZE / sizeof(addr_t); - // r13-r31, cr, r2 - kstack_top -= (31 - 13 + 1) + 1 + 1; + // clear the kernel stack +#ifdef DEBUG_KERNEL_STACKS +# ifdef STACK_GROWS_DOWNWARDS + memset((void *)((addr_t)kstack + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE), 0, + KERNEL_STACK_SIZE - KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE); +# else + memset(kstack, 0, KERNEL_STACK_SIZE - KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE); +# endif +#else + memset(kstack, 0, KERNEL_STACK_SIZE); +#endif - // set the saved lr address to be the start_func - kstack_top--; - *kstack_top = (addr_t)start_func; + // space for frame pointer and return address, and stack frames must be + // 16 byte aligned + kstackTop -= 2; + kstackTop = (addr_t*)((addr_t)kstackTop & ~0xf); + + // LR, CR, r2, r13-r31, as pushed by ppc_context_switch() + kstackTop -= 22; + + // let LR point to ppc_kernel_thread_root() + kstackTop[0] = (addr_t)&ppc_kernel_thread_root; + + // the arguments of ppc_kernel_thread_root() are the functions to call, + // provided in registers r13-r15 + kstackTop[3] = (addr_t)entry_func; + kstackTop[4] = (addr_t)start_func; + kstackTop[5] = (addr_t)exit_func; // save this stack position - t->arch_info.sp = (void *)kstack_top; + t->arch_info.sp = (void *)kstackTop; return B_OK; } @@ -103,6 +158,7 @@ arch_thread_init_kthread_stack(struct thread *t, int (*start_func)(void), void ( void arch_thread_init_tls(struct thread *thread) { +// TODO: Implement! }