* 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:
parent
31ac264b1e
commit
9b6eaae234
@ -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
|
||||
|
||||
|
@ -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!
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user