* 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
This commit is contained in:
Ingo Weinhold 2006-01-11 02:17:29 +00:00
parent 31ac264b1e
commit 9b6eaae234
2 changed files with 151 additions and 30 deletions

View File

@ -1,7 +1,10 @@
/*
** Copyright 2003, Travis Geiselbrecht. All rights reserved.
** Distributed under the terms of the NewOS License.
*/
* Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* 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

View File

@ -12,14 +12,21 @@
#include <arch_thread.h>
#include <arch_cpu.h>
#include <boot/stage2.h>
#include <kernel.h>
#include <thread.h>
#include <boot/stage2.h>
#include <vm_types.h>
//#include <arch/vm_translation_map.h>
#include <string.h>
// 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!
}