From 7afc16f05918c55f8e6aae8c2b4bd15789d32116 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 13 Jan 2006 00:49:13 +0000 Subject: [PATCH] * Fixed a bug regarding storing/restoring FPSCR in the interrupt code. The stack pointer was not adjusted, hence we were overwriting the previous register value. But it looks like I missed to check in the arch_cpu.h with the iframe structure including the floating point registers anyway. * Backported the ELF PPC relocation code from the boot loader to the kernel. * Fixed the PPC version of arch_thread_switch_kstack_and_call(). Apparently the signature had changed, but the assembly implementation was not adjusted accordingly. * sc prints more registers now (LR, CR, CTR, XER,...). * Fixed several occurences of not-working fault handlers. Apparently the compiler realized, that the "error" label was never jumped to (by the code it knew), and optimized the respective code away. Now we use a trick to make it think the error label might actually be jumped to. I wonder whether the x86 version has the same problem when being compiled with GCC4. * Adopted the x86 page fault handling interrupt code. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15933 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/arch/ppc/arch_cpu.h | 36 ++ src/system/kernel/arch/ppc/arch_asm.S | 4 +- src/system/kernel/arch/ppc/arch_cpu.cpp | 42 ++- src/system/kernel/arch/ppc/arch_debug.cpp | 26 +- src/system/kernel/arch/ppc/arch_elf.cpp | 348 +++++++++++++++++-- src/system/kernel/arch/ppc/arch_exceptions.S | 4 +- src/system/kernel/arch/ppc/arch_int.cpp | 31 ++ src/system/kernel/arch/ppc/arch_thread.c | 15 +- 8 files changed, 448 insertions(+), 58 deletions(-) diff --git a/headers/private/kernel/arch/ppc/arch_cpu.h b/headers/private/kernel/arch/ppc/arch_cpu.h index 15bbe330f7..6ed695da24 100644 --- a/headers/private/kernel/arch/ppc/arch_cpu.h +++ b/headers/private/kernel/arch/ppc/arch_cpu.h @@ -22,6 +22,7 @@ struct iframe { uint32 cr; uint32 xer; uint32 ctr; + uint32 fpscr; uint32 r31; uint32 r30; uint32 r29; @@ -54,6 +55,38 @@ struct iframe { uint32 r2; uint32 r1; uint32 r0; + double f31; + double f30; + double f29; + double f28; + double f27; + double f26; + double f25; + double f24; + double f23; + double f22; + double f21; + double f20; + double f19; + double f18; + double f17; + double f16; + double f15; + double f14; + double f13; + double f12; + double f11; + double f10; + double f9; + double f8; + double f7; + double f6; + double f5; + double f4; + double f3; + double f2; + double f1; + double f0; }; enum machine_state { @@ -113,6 +146,9 @@ int64 __ppc_get_time_base(void); extern void ppc_context_switch(void **_oldStackPointer, void *newStackPointer); +extern bool ppc_set_fault_handler(addr_t *handlerLocation, addr_t handler) + __attribute__((noinline)); + #ifdef __cplusplus } #endif diff --git a/src/system/kernel/arch/ppc/arch_asm.S b/src/system/kernel/arch/ppc/arch_asm.S index de81e2c47b..1a558f8fc1 100644 --- a/src/system/kernel/arch/ppc/arch_asm.S +++ b/src/system/kernel/arch/ppc/arch_asm.S @@ -305,9 +305,9 @@ FUNCTION(ppc_context_switch): blr -// void arch_thread_switch_kstack_and_call(addr_t new_kstack, +// void ppc_switch_stack_and_call(addr_t newKstack, // void (*func)(void *), void *arg) -FUNCTION(arch_thread_switch_kstack_and_call): +FUNCTION(ppc_switch_stack_and_call): 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 diff --git a/src/system/kernel/arch/ppc/arch_cpu.cpp b/src/system/kernel/arch/ppc/arch_cpu.cpp index 7c69454a5f..c37209df05 100644 --- a/src/system/kernel/arch/ppc/arch_cpu.cpp +++ b/src/system/kernel/arch/ppc/arch_cpu.cpp @@ -146,21 +146,23 @@ arch_cpu_user_TLB_invalidate(void) status_t -arch_cpu_user_memcpy(void *to, const void *from, size_t size, addr_t *fault_handler) +arch_cpu_user_memcpy(void *to, const void *from, size_t size, + addr_t *faultHandler) { char *tmp = (char *)to; char *s = (char *)from; - *fault_handler = (addr_t)&&error; + if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) + goto error; while (size--) *tmp++ = *s++; - *fault_handler = 0; + *faultHandler = 0; return 0; error: - *fault_handler = 0; + *faultHandler = 0; return B_BAD_ADDRESS; } @@ -180,7 +182,8 @@ arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHand { int from_length = 0; - *faultHandler = (addr_t)&&error; + if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) + goto error; if (size > 0) { to[--size] = '\0'; @@ -204,20 +207,21 @@ error: status_t -arch_cpu_user_memset(void *s, char c, size_t count, addr_t *fault_handler) +arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler) { char *xs = (char *)s; - *fault_handler = (addr_t)&&error; + if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) + goto error; while (count--) *xs++ = c; - *fault_handler = 0; + *faultHandler = 0; return 0; error: - *fault_handler = 0; + *faultHandler = 0; return B_BAD_ADDRESS; } @@ -235,3 +239,23 @@ arch_cpu_idle(void) { } + +// The purpose of this function is to trick the compiler. When setting the +// page_handler to a label that is obviously (to the compiler) never used, +// it may reorganize the control flow, so that the labeled part is optimized +// away. +// By invoking the function like this +// +// if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) +// goto error; +// +// the compiler has to keep the labeled code, since it can't guess the return +// value of this (non-inlinable) function. At least in my tests it worked that +// way, and I hope it will continue to work like this in the future. +// +bool +ppc_set_fault_handler(addr_t *handlerLocation, addr_t handler) +{ + *handlerLocation = handler; + return false; +} diff --git a/src/system/kernel/arch/ppc/arch_debug.cpp b/src/system/kernel/arch/ppc/arch_debug.cpp index 02e50193d2..088562a619 100644 --- a/src/system/kernel/arch/ppc/arch_debug.cpp +++ b/src/system/kernel/arch/ppc/arch_debug.cpp @@ -1,10 +1,16 @@ /* - * Copyright 2003-2005, Axel D�fler, axeld@pinc-software.de. All rights reserved. + * Copyright 2003-2006, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler + * Ingo Weinhold */ #include + +#include #include #include #include @@ -61,8 +67,10 @@ get_next_frame(addr_t framePointer, addr_t *next, addr_t *ip) struct thread *thread = thread_get_current_thread(); // set fault handler, so that we can safely access user stacks - if (thread) - thread->fault_handler = (addr_t)&&error; + if (thread) { + if (ppc_set_fault_handler(&thread->fault_handler, (addr_t)&&error)) + goto error; + } *ip = ((struct stack_frame *)framePointer)->return_address; *next = (addr_t)((struct stack_frame *)framePointer)->previous; @@ -209,13 +217,11 @@ return 0; frame->r24, frame->r25, frame->r26, frame->r27); kprintf(" r28 0x%08lx r29 0x%08lx r30 0x%08lx r31 0x%08lx\n", frame->r28, frame->r29, frame->r30, frame->r31); - kprintf(" srr0 0x%08lx srr1 0x%08lx", frame->srr0, frame->srr1); -// TODO: Look up the bit in srr1! -// if ((frame->error_code & 0x4) != 0) { -// // from user space -// kprintf("user esp 0x%lx", frame->user_esp); -// } - kprintf("\n"); + kprintf(" lr 0x%08lx cr 0x%08lx xer 0x%08lx ctr 0x%08lx\n", + frame->lr, frame->cr, frame->xer, frame->ctr); + kprintf("fpscr 0x%08lx\n", frame->fpscr); + kprintf(" srr0 0x%08lx srr1 0x%08lx dar 0x%08lx dsisr 0x%08lx\n", + frame->srr0, frame->srr1, frame->dar, frame->dsisr); kprintf(" vector: 0x%lx\n", frame->vector); print_stack_frame(thread, frame->srr0, framePointer, frame->r1); diff --git a/src/system/kernel/arch/ppc/arch_elf.cpp b/src/system/kernel/arch/ppc/arch_elf.cpp index 2db564b34c..e45492de24 100644 --- a/src/system/kernel/arch/ppc/arch_elf.cpp +++ b/src/system/kernel/arch/ppc/arch_elf.cpp @@ -1,7 +1,11 @@ /* -** Copyright 2002, Travis Geiselbrecht. All rights reserved. -** Distributed under the terms of the NewOS License. -*/ + * Copyright 2005, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + * + * + * Copyright 2002, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. + */ #include @@ -22,6 +26,85 @@ arch_elf_relocate_rel(struct elf_image_info *image, const char *sym_prepend, } +static inline void +write_word32(addr_t P, Elf32_Word value) +{ + *(Elf32_Word*)P = value; +} + + +static inline void +write_word30(addr_t P, Elf32_Word value) +{ + // bits 0:29 + *(Elf32_Word*)P = (*(Elf32_Word*)P & 0x3) | (value << 2); +} + + +static inline bool +write_low24_check(addr_t P, Elf32_Word value) +{ + // bits 6:29 + if ((value & 0x3f000000) && (~value & 0x3f800000)) + return false; + *(Elf32_Word*)P = (*(Elf32_Word*)P & 0xfc000003) + | ((value & 0x00ffffff) << 2); + return true; +} + + +static inline bool +write_low14_check(addr_t P, Elf32_Word value) +{ + // bits 16:29 + if ((value & 0x3fffc000) && (~value & 0x3fffe000)) + return false; + *(Elf32_Word*)P = (*(Elf32_Word*)P & 0xffff0003) + | ((value & 0x00003fff) << 2); + return true; +} + + +static inline void +write_half16(addr_t P, Elf32_Word value) +{ + // bits 16:29 + *(Elf32_Half*)P = (Elf32_Half)value; +} + + +static inline bool +write_half16_check(addr_t P, Elf32_Word value) +{ + // bits 16:29 + if ((value & 0xffff0000) && (~value & 0xffff8000)) + return false; + *(Elf32_Half*)P = (Elf32_Half)value; + return true; +} + + +static inline Elf32_Word +lo(Elf32_Word value) +{ + return (value & 0xffff); +} + + +static inline Elf32_Word +hi(Elf32_Word value) +{ + return ((value >> 16) & 0xffff); +} + + +static inline Elf32_Word +ha(Elf32_Word value) +{ + return (((value >> 16) + (value & 0x8000 ? 1 : 0)) & 0xffff); +} + + int arch_elf_relocate_rela(struct elf_image_info *image, const char *sym_prepend, struct elf_image_info *resolve_image, struct Elf32_Rela *rel, int rel_len) @@ -29,77 +112,274 @@ arch_elf_relocate_rela(struct elf_image_info *image, const char *sym_prepend, int i; struct Elf32_Sym *sym; int vlErr; - addr_t S = 0; - addr_t final_val; + addr_t S = 0; // symbol address + addr_t R = 0; // section relative symbol address -#define P ((addr_t)(image->text_region.delta + rel[i].r_offset)) -#define A ((addr_t)rel[i].r_addend) -#define B (image->text_region.delta) + addr_t G = 0; // GOT address + addr_t L = 0; // PLT address + + #define P ((addr_t)(image->text_region.delta + rel[i].r_offset)) + #define A ((addr_t)rel[i].r_addend) + #define B (image->text_region.delta) + + // TODO: Get the GOT address! + #define REQUIRE_GOT \ + if (G == 0) { \ + dprintf("arch_elf_relocate_rela(): Failed to get GOT address!\n"); \ + return B_ERROR; \ + } + + // TODO: Get the PLT address! + #define REQUIRE_PLT \ + if (L == 0) { \ + dprintf("arch_elf_relocate_rela(): Failed to get PLT address!\n"); \ + return B_ERROR; \ + } for (i = 0; i * (int)sizeof(struct Elf32_Rela) < rel_len; i++) { #if CHATTY - dprintf("looking at rel type %d, offset 0x%x, sym 0x%x, addend 0x%x\n", + dprintf("looking at rel type %d, offset 0x%lx, sym 0x%lx, addend 0x%lx\n", ELF32_R_TYPE(rel[i].r_info), rel[i].r_offset, ELF32_R_SYM(rel[i].r_info), rel[i].r_addend); #endif switch (ELF32_R_TYPE(rel[i].r_info)) { + case R_PPC_SECTOFF: + case R_PPC_SECTOFF_LO: + case R_PPC_SECTOFF_HI: + case R_PPC_SECTOFF_HA: + dprintf("arch_elf_relocate_rela(): Getting section relative " + "symbol addresses not yet supported!\n"); + return B_ERROR; + case R_PPC_ADDR32: case R_PPC_ADDR24: case R_PPC_ADDR16: case R_PPC_ADDR16_LO: case R_PPC_ADDR16_HI: case R_PPC_ADDR16_HA: + case R_PPC_ADDR14: + case R_PPC_ADDR14_BRTAKEN: + case R_PPC_ADDR14_BRNTAKEN: case R_PPC_REL24: + case R_PPC_REL14: + case R_PPC_REL14_BRTAKEN: + case R_PPC_REL14_BRNTAKEN: + case R_PPC_GLOB_DAT: + case R_PPC_UADDR32: + case R_PPC_UADDR16: + case R_PPC_REL32: + case R_PPC_SDAREL16: + case R_PPC_ADDR30: + case R_PPC_JMP_SLOT: sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info)); - vlErr = elf_resolve_symbol(image, sym, resolve_image, sym_prepend, &S); - if (vlErr<0) + vlErr = elf_resolve_symbol(image, sym, resolve_image, + sym_prepend, &S); + if (vlErr < 0) { + dprintf("arch_elf_relocate_rela(): Failed to relocate " + "entry index %d, rel type %d, offset 0x%lx, sym 0x%lx, " + "addend 0x%lx\n", i, ELF32_R_TYPE(rel[i].r_info), + rel[i].r_offset, ELF32_R_SYM(rel[i].r_info), + rel[i].r_addend); return vlErr; + } break; } switch (ELF32_R_TYPE(rel[i].r_info)) { case R_PPC_NONE: - continue; + break; + + case R_PPC_COPY: + // TODO: Implement! + dprintf("arch_elf_relocate_rela(): R_PPC_COPY not yet " + "supported!\n"); + return B_ERROR; case R_PPC_ADDR32: - final_val = S + A; + case R_PPC_GLOB_DAT: + case R_PPC_UADDR32: + write_word32(P, S + A); break; + case R_PPC_ADDR24: + if (write_low24_check(P, (S + A) >> 2)) + break; +dprintf("R_PPC_ADDR24 overflow\n"); + return B_BAD_DATA; + case R_PPC_ADDR16: - *(Elf32_Half*)P = S; - continue; + case R_PPC_UADDR16: + if (write_half16_check(P, S + A)) + break; +dprintf("R_PPC_ADDR16 overflow\n"); + return B_BAD_DATA; case R_PPC_ADDR16_LO: - *(Elf32_Half*)P = S & 0xffff; - continue; - - case R_PPC_ADDR16_HI: - *(Elf32_Half*)P = (S >> 16) & 0xffff; - continue; - - case R_PPC_ADDR16_HA: - *(Elf32_Half*)P = ((S >> 16) + ((S & 0x8000) ? 1 : 0)) & 0xFFFF; - continue; - - case R_PPC_REL24: - final_val = (*(Elf32_Word *)P & 0xff000003) | ((S + A - P) & 0x3fffffc); + write_half16(P, lo(S + A)); break; + case R_PPC_ADDR16_HI: + write_half16(P, hi(S + A)); + break; + + case R_PPC_ADDR16_HA: + write_half16(P, ha(S + A)); + break; + + case R_PPC_ADDR14: + case R_PPC_ADDR14_BRTAKEN: + case R_PPC_ADDR14_BRNTAKEN: + if (write_low14_check(P, (S + A) >> 2)) + break; +dprintf("R_PPC_ADDR14 overflow\n"); + return B_BAD_DATA; + + case R_PPC_REL24: + if (write_low24_check(P, (S + A - P) >> 2)) + break; +dprintf("R_PPC_REL24 overflow: 0x%lx\n", (S + A - P) >> 2); + return B_BAD_DATA; + + case R_PPC_REL14: + case R_PPC_REL14_BRTAKEN: + case R_PPC_REL14_BRNTAKEN: + if (write_low14_check(P, (S + A - P) >> 2)) + break; +dprintf("R_PPC_REL14 overflow\n"); + return B_BAD_DATA; + + case R_PPC_GOT16: + REQUIRE_GOT; + if (write_half16_check(P, G + A)) + break; +dprintf("R_PPC_GOT16 overflow\n"); + return B_BAD_DATA; + + case R_PPC_GOT16_LO: + REQUIRE_GOT; + write_half16(P, lo(G + A)); + break; + + case R_PPC_GOT16_HI: + REQUIRE_GOT; + write_half16(P, hi(G + A)); + break; + + case R_PPC_GOT16_HA: + REQUIRE_GOT; + write_half16(P, ha(G + A)); + break; + + case R_PPC_JMP_SLOT: + { + // If the relative offset is small enough, we fabricate a + // relative branch instruction ("b "). + addr_t jumpOffset = S - P; + if ((jumpOffset & 0xfc000000) != 0 + && (~jumpOffset & 0xfe000000) != 0) { + // Offset > 24 bit. + // TODO: Implement! + // See System V PPC ABI supplement, p. 5-6! + dprintf("arch_elf_relocate_rela(): R_PPC_JMP_SLOT: " + "Offsets > 24 bit currently not supported!\n"); +dprintf("jumpOffset: %p\n", (void*)jumpOffset); + return B_ERROR; + } else { + // Offset <= 24 bit + // 0:5 opcode (= 18), 6:29 address, 30 AA, 31 LK + // "b" instruction: opcode = 18, AA = 0, LK = 0 + // address: 24 high-order bits of 26 bit offset + *(uint32*)P = 0x48000000 | ((jumpOffset) & 0x03fffffc); + } + break; + } + case R_PPC_RELATIVE: - final_val = B + A; + write_word32(P, B + A); + break; + + case R_PPC_LOCAL24PC: +// TODO: Implement! +// low24* +// if (write_low24_check(P, ?) +// break; +// return B_BAD_DATA; + dprintf("arch_elf_relocate_rela(): R_PPC_LOCAL24PC not yet " + "supported!\n"); + return B_ERROR; + + case R_PPC_REL32: + write_word32(P, S + A - P); + break; + + case R_PPC_PLTREL24: + REQUIRE_PLT; + if (write_low24_check(P, (L + A - P) >> 2)) + break; +dprintf("R_PPC_PLTREL24 overflow\n"); + return B_BAD_DATA; + + case R_PPC_PLT32: + REQUIRE_PLT; + write_word32(P, L + A); + break; + + case R_PPC_PLTREL32: + REQUIRE_PLT; + write_word32(P, L + A - P); + break; + + case R_PPC_PLT16_LO: + REQUIRE_PLT; + write_half16(P, lo(L + A)); + break; + + case R_PPC_PLT16_HI: + REQUIRE_PLT; + write_half16(P, hi(L + A)); + break; + + case R_PPC_PLT16_HA: + write_half16(P, ha(L + A)); + break; + + case R_PPC_SDAREL16: +// TODO: Implement! +// if (write_half16_check(P, S + A - _SDA_BASE_)) +// break; +// return B_BAD_DATA; + dprintf("arch_elf_relocate_rela(): R_PPC_SDAREL16 not yet " + "supported!\n"); + return B_ERROR; + + case R_PPC_SECTOFF: + if (write_half16_check(P, R + A)) + break; +dprintf("R_PPC_SECTOFF overflow\n"); + return B_BAD_DATA; + + case R_PPC_SECTOFF_LO: + write_half16(P, lo(R + A)); + break; + + case R_PPC_SECTOFF_HI: + write_half16(P, hi(R + A)); + break; + + case R_PPC_SECTOFF_HA: + write_half16(P, ha(R + A)); + break; + + case R_PPC_ADDR30: + write_word30(P, (S + A - P) >> 2); break; default: dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info)); return B_ERROR; } -#if CHATTY - dprintf("going to put 0x%x at 0x%x\n", final_val, P); -#endif - *(addr_t *)P = final_val; } return B_NO_ERROR; - } diff --git a/src/system/kernel/arch/ppc/arch_exceptions.S b/src/system/kernel/arch/ppc/arch_exceptions.S index 4e6436b469..b20198d257 100644 --- a/src/system/kernel/arch/ppc/arch_exceptions.S +++ b/src/system/kernel/arch/ppc/arch_exceptions.S @@ -316,7 +316,7 @@ __save_regs: /* save some of the other regs */ mffs %f0 - stfs %f0, -4(%r1) /* push FPSCR */ + stfsu %f0, -4(%r1) /* push FPSCR */ mfctr %r0 stwu %r0, -4(%r1) /* push CTR */ mfxer %r0 @@ -359,7 +359,7 @@ __restore_regs_and_rfi: mtxer %r0 lwzu %r0, 4(%r1) /* CTR */ mtctr %r0 - lfs %f0, 4(%r1) /* FPSCR */ + lfsu %f0, 4(%r1) /* FPSCR */ mtfsf 0xff, %f0 lwzu %r31, 4(%r1) diff --git a/src/system/kernel/arch/ppc/arch_int.cpp b/src/system/kernel/arch/ppc/arch_int.cpp index 54ab9b23c6..f5a3e5c6db 100644 --- a/src/system/kernel/arch/ppc/arch_int.cpp +++ b/src/system/kernel/arch/ppc/arch_int.cpp @@ -106,6 +106,37 @@ ppc_exception_entry(int vector, struct iframe *iframe) case 0x300: // DSI case 0x400: // ISI { + bool kernelDebugger = debug_debugger_running(); + + if (kernelDebugger) { + // if this thread has a fault handler, we're allowed to be here + struct thread *thread = thread_get_current_thread(); + if (thread && thread->fault_handler != NULL) { + iframe->srr0 = thread->fault_handler; + break; + } + + // otherwise, not really + panic("page fault in debugger without fault handler! Touching " + "address %p from ip %p\n", (void *)iframe->dar, + (void *)iframe->srr0); + break; + } else if ((iframe->srr1 & MSR_EXCEPTIONS_ENABLED) == 0) { + // if the interrupts were disabled, and we are not running the + // kernel startup the page fault was not allowed to happen and + // we must panic + panic("page fault, but interrupts were disabled. Touching " + "address %p from ip %p\n", (void *)iframe->dar, + (void *)iframe->srr0); + break; + } else if (thread != NULL && thread->page_faults_allowed < 1) { + panic("page fault not allowed at this place. Touching address " + "%p from ip %p\n", (void *)iframe->dar, + (void *)iframe->srr0); + } + + enable_interrupts(); + addr_t newip; ret = vm_page_fault(iframe->dar, iframe->srr0, diff --git a/src/system/kernel/arch/ppc/arch_thread.c b/src/system/kernel/arch/ppc/arch_thread.c index 8c82fe240b..05f844eaac 100644 --- a/src/system/kernel/arch/ppc/arch_thread.c +++ b/src/system/kernel/arch/ppc/arch_thread.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -25,9 +26,13 @@ // a new thread structure. static struct arch_thread sInitialState; -// Helper functions for thread creation, defined in arch_asm.S. +// Helper function for thread creation, defined in arch_asm.S. extern void ppc_kernel_thread_root(); +extern void ppc_switch_stack_and_call(addr_t newKstack, void (*func)(void *), + void *arg); + + void ppc_push_iframe(struct iframe_stack *stack, struct iframe *frame) { @@ -162,6 +167,14 @@ arch_thread_init_tls(struct thread *thread) } +void +arch_thread_switch_kstack_and_call(struct thread *t, addr_t newKstack, + void (*func)(void *), void *arg) +{ + ppc_switch_stack_and_call(newKstack, func, arg); +} + + void arch_thread_context_switch(struct thread *t_from, struct thread *t_to) {