From 7176dd57e50431181ccd62bdd46fa78def8fdd62 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 9 Jan 2006 03:30:52 +0000 Subject: [PATCH] Reworked the exception handling code. The former one ran into the void after turning off BAT for the segment containing itself. The monster macro for the exception vector code was not really elegant besides being too long for the 32 byte performance monitor exception slot. Furthermore wasting three of the SPRG* registers as cheap scratch memory wasn't that nice either. We now have a three-step approach: The exception vectors themselves contain only five instructions which branch to common code at the beginning of the same physical page. That one sets up BAT for itself, turns address translation back on and jumps into the kernel. There we turn off BAT again, dump an iframe, and enter the actual exception handler (/dispatcher). Upon return the registers are restored from the iframe and we get back to the place where the exception occurred. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15881 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/arch/ppc/arch_int.h | 36 +- src/system/kernel/arch/ppc/arch_exceptions.S | 566 +++++++++---------- src/system/kernel/arch/ppc/arch_int.cpp | 68 ++- 3 files changed, 362 insertions(+), 308 deletions(-) diff --git a/headers/private/kernel/arch/ppc/arch_int.h b/headers/private/kernel/arch/ppc/arch_int.h index f98813cb07..af5d554ddf 100644 --- a/headers/private/kernel/arch/ppc/arch_int.h +++ b/headers/private/kernel/arch/ppc/arch_int.h @@ -1,12 +1,46 @@ /* - * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2005-2006, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler + * Ingo Weinhold */ #ifndef _KERNEL_ARCH_PPC_INT_H #define _KERNEL_ARCH_PPC_INT_H +#include #define NUM_IO_VECTORS 256 +/* The sprg0 register of each CPU points to the physical address of such + a structure. So it is at hand in the early exception handling code. +*/ +struct ppc_cpu_exception_context { + void *kernel_handle_exception; // exception handler routine in the + // kernel + void *exception_context; // the virtual address of this + // structure + void *kernel_stack; // kernel stack for the current thread + + uint32 scratch[8]; // scratch memory for free use in the + // early exception handling code +}; + +#ifdef __cplusplus +extern "C" { +#endif + + +struct ppc_cpu_exception_context *ppc_get_cpu_exception_context(int cpu); + +void ppc_set_current_cpu_exception_context( + struct ppc_cpu_exception_context *context); + // only called once per CPU + + +#ifdef __cplusplus +} +#endif #endif /* _KERNEL_ARCH_PPC_INT_H */ diff --git a/src/system/kernel/arch/ppc/arch_exceptions.S b/src/system/kernel/arch/ppc/arch_exceptions.S index eed4eff708..f4bf327469 100644 --- a/src/system/kernel/arch/ppc/arch_exceptions.S +++ b/src/system/kernel/arch/ppc/arch_exceptions.S @@ -1,134 +1,274 @@ /* -** 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 #define LOCAL_FUNCTION(x) .type x,@function; x -/* -** General exception handling pseudocode: -** save %r0 into sprg0 -** save %r2 into sprg1 -** save %r1 into sprg2 -** save cr into %r2 (will mess up cr in the conditional check below) -** load saved msr into %r0 -** see if was in kernel mode -** if not, -** load kernel stack from EAR into %r1 -** restore cr from %r2 -** set up in BAT 0 (instruction and data) a identity mapping of 0x0 -** load old msr -** merge old msr mmu bits with current msr -** load new msr (should turn the mmu on) -** save lr into sprg3 -** set up and branch to the next instruction (moving the program counter into kernel space) -** remove the BAT mapping -** set up stack frame and push everything -*/ +/* General exception handling concept: + The PPC architecture specifies entry point offsets for the various + exceptions in the first two physical pages. We put a short piece of code + (VEC_ENTRY()) into each exception vector. It calls exception_vector_common, + which is defined in the unused space at the beginning of the first physical + page. It re-enables address translation and calls ppc_exception_tail which + lies in the kernel. It dumps an iframe and invokes ppc_exception_entry() + (arch_int.cpp), which handles the exception and returns eventually. + The registers are restored from the iframe and we return from the + interrupt. + + algorithm overview: + + * VEC_ENTRY + * exception_vector_common + * ppc_exception_tail + - dump iframe + - ppc_exception_entry() + - restore registers and return from interrupt + + Here we use the following SPRG registers, which are at the disposal of the + operating system: + * SPRG0: Physical address pointer to a struct cpu_exception_context + for the current CPU. The structure contains helpful pointers + as well as some scratch memory for temporarily saving registers. + * SPRG1: Scratch. + + struct cpu_exception_context (defined in arch_int.h): + offset 0: virtual address of the exception handler routine in the kernel + offset 4: virtual address of the exception context + offset 8: kernel stack for the current thread + offset 12: start of scratch memory for saving registers etc. + + algorithm in detail: + + * VEC_ENTRY + - save r1 in SPRG1 and load cpu_exception_context into r1 + - save r0, save LR in r0 + * exception_vector_common + - params: + . r0: old LR + . r1: exception context (physical address) + . SPRG1: original r1 + - save r0-3 + - load virtual exception context address to r1 + - turn on BAT for exception vector code + - turn on address translation + - get exception vector offset from LR + * ppc_exception_tail + - params: + . r1: exception context (virtual address) + . r3: exception vector offset + . SPRG1: original r1 + - turn off BAT + - get kernel stack pointer + - dump iframe + - ppc_exception_entry() + - restore registers and return from interrupt + */ + + +/* exception vector definitions */ + +/* code in each exception vector */ #define VEC_ENTRY() \ - mtsprg0 %r0 ; /* save %r0 */ \ - mtsprg1 %r2 ; /* save %r2 */ \ - mtsprg2 %r1 ; /* save the old stack */ \ - mfcr %r2 ; /* save cr */ \ -\ - mfsrr1 %r0 ; /* load saved msr */ \ - andi. %r0, %r0, (1 << 14) ; /* see if it was in kernel mode */ \ - beq- 0f ; /* yep */ \ -\ - /* load the kernel stack */ \ - mfear %r1 ; /* load the kernel stack pointer from the EAR reg */ \ -0: \ - mtcrf 0xff, %r2 ; /* restore the CR, it was messed up in the previous compare */ \ -\ - /* we are going to turn on the mmu, lets have a BAT entry in place to keep us identity mapped */ \ - li %r0, 0x2 ; /* BATU_VS */ \ - mtibatu 0, %r0 ; /* load the upper word of the instruction BAT */ \ - mtdbatu 0, %r0 ; /* load the upper word of the data BAT */ \ - li %r0, 0x10|0x2 ; /* BATL_MC | BATL_PP_RW */ \ - mtibatl 0, %r0 ; /* load the lower word of the instruction BAT */ \ - mtdbatl 0, %r0 ; /* load the lower word of the data BAT */ \ - isync ; \ - sync ; \ -\ - /* turn the mmu back on */ \ - mfsrr1 %r0 ; /* load saved msr */ \ - rlwinm %r0, %r0, 28, 30, 31 ; /* extract mmu bits */ \ - mfmsr %r2 ; /* load the current msr */ \ - rlwimi %r2, %r0, 4, 26, 27 ; /* merge the mmu bits with the current msr */ \ - mtmsr %r2 ; /* load the new msr (turning the mmu back on */ \ - isync ; \ -\ - mflr %r0 ; /* load the lr */ \ - mtsprg 3, %r0 ; /* save it */ \ - lis %r0, 1f@h ; /* load the address of a label in a few instructions */ \ - ori %r0, %r0, 1f@l ; /* we will jump to it to get the program counter into the kernel region */ \ - mtlr %r0 ; /* get ready to jump to this label */ \ - blr ; /* branch to the next instruction (with the mmu on) */ \ -1: \ - /* turn the BAT back off */ \ - li %r2, 0 ; \ - mtibatu 0, %r2 ; \ - mtdbatu 0, %r2 ; \ - mtibatl 0, %r2 ; \ - mtdbatl 0, %r2 ; \ - isync ; \ - sync ; \ -\ - bl __save_regs ; /* dump an iframe on the stack */ + mtsprg1 %r1 ; /* temporarily save r1 in SPRG1 */ \ + mfsprg0 %r1 ; /* ppc_cpu_exception_context* -> r1 */ \ + stw %r0, 16(%r1) ; /* save r0 */ \ + mflr %r0 ; /* save LR in r0 */ \ + bl exception_vector_common ; /* continue with the common part */ + +/* defines an exception vector */ +#define DEFINE_VECTOR(offset, name) \ +.skip offset - (. - __irqvec_start); \ +FUNCTION(name): \ + VEC_ENTRY() + .global __irqvec_start __irqvec_start: .long 0 -/* called by the tail end of the VEC_ENTRY macro -** register expectations: -** %r1 - stack -** sprg0 - old %r0 -** sprg1 - old %r2 -** sprg2 - old stack (%r1) -** sprg3 - old lr -** all other regs should have been unmodified by the exception handler, -** and ready to be saved -*/ -FUNCTION(__save_regs): - mfsprg %r0, 0 - stwu %r0, -4(%r1) /* push %r0 */ - mfsprg %r0, 2 - stwu %r0, -4(%r1) /* push old %r1 (stack) */ - mfsprg %r0, 1 - stwu %r0, -4(%r1) /* push %r2 */ - stwu %r3, -4(%r1) /* push %r3-%r31 */ - stwu %r4, -4(%r1) /* push %r3-%r31 */ - stwu %r5, -4(%r1) /* push %r3-%r31 */ - stwu %r6, -4(%r1) /* push %r3-%r31 */ - stwu %r7, -4(%r1) /* push %r3-%r31 */ - stwu %r8, -4(%r1) /* push %r3-%r31 */ - stwu %r9, -4(%r1) /* push %r3-%r31 */ - stwu %r10, -4(%r1) /* push %r3-%r31 */ - stwu %r11, -4(%r1) /* push %r3-%r31 */ - stwu %r12, -4(%r1) /* push %r3-%r31 */ +/* Called by the exception vector code. + * LR: Points to the end of the exception vector code we're coming from. + * r0: original LR + * r1: ppc_cpu_exception_context* (physical address) + * SPRG1: original r1 + */ +exception_vector_common: + stw %r0, 20(%r1) /* save original LR */ + stw %r2, 24(%r1) /* save r2 */ + stw %r3, 28(%r1) /* save r3 */ - /* strictly speaking, we dont need to save %r13-%r31, but I will for now */ - stwu %r13, -4(%r1) /* push %r3-%r31 */ - stwu %r14, -4(%r1) /* push %r3-%r31 */ - stwu %r15, -4(%r1) /* push %r3-%r31 */ - stwu %r16, -4(%r1) /* push %r3-%r31 */ - stwu %r17, -4(%r1) /* push %r3-%r31 */ - stwu %r18, -4(%r1) /* push %r3-%r31 */ - stwu %r19, -4(%r1) /* push %r3-%r31 */ - stwu %r20, -4(%r1) /* push %r3-%r31 */ - stwu %r21, -4(%r1) /* push %r3-%r31 */ - stwu %r22, -4(%r1) /* push %r3-%r31 */ - stwu %r23, -4(%r1) /* push %r3-%r31 */ - stwu %r24, -4(%r1) /* push %r3-%r31 */ - stwu %r25, -4(%r1) /* push %r3-%r31 */ - stwu %r26, -4(%r1) /* push %r3-%r31 */ - stwu %r27, -4(%r1) /* push %r3-%r31 */ - stwu %r28, -4(%r1) /* push %r3-%r31 */ - stwu %r29, -4(%r1) /* push %r3-%r31 */ - stwu %r30, -4(%r1) /* push %r3-%r31 */ - stwu %r31, -4(%r1) /* push %r3-%r31 */ + /* load the virtual address of the ppc_cpu_exception_context for this CPU */ + lwz %r1, 4(%r1) + + /* Address translation is turned off. We map this code via BAT, turn on + address translation, and continue in the kernel proper. */ + li %r0, 0x10|0x2 /* BATL_MC | BATL_PP_RW */ + mtibatl 0, %r0 /* load lower word of the instruction BAT */ + li %r0, 0x2 /* BEPI = 0, BL = 0 (128 KB), BATU_VS */ + mtibatu 0, %r0 /* load upper word of the instruction BAT */ + isync + sync + + /* turn on address translation */ + mfsrr1 %r0 /* load saved msr */ + rlwinm %r0, %r0, 28, 30, 31 /* extract mmu bits */ + mfmsr %r3 /* load the current msr */ + rlwimi %r3, %r0, 4, 26, 27 /* merge the mmu bits with the current msr */ + mtmsr %r3 /* load new msr (turning the mmu back on) */ + isync + + /* Get LR -- it points to the end of the exception vector code. We adjust it + to point to the beginning and can use it to identify the vector later. */ + mflr %r3 + subi %r3, %r3, 20 /* 5 instructions */ + + /* jump to kernel code (ppc_exception_tail) */ + lwz %r2, 0(%r1) + mtlr %r2 + blr + + +DEFINE_VECTOR(0x100, system_reset_exception) +DEFINE_VECTOR(0x200, machine_check_exception) +DEFINE_VECTOR(0x300, DSI_exception) +DEFINE_VECTOR(0x400, ISI_exception) +DEFINE_VECTOR(0x500, external_interrupt_exception) +DEFINE_VECTOR(0x600, alignment_exception) +DEFINE_VECTOR(0x700, program_exception) +DEFINE_VECTOR(0x800, FP_unavailable_exception) +DEFINE_VECTOR(0x900, decrementer_exception) +DEFINE_VECTOR(0xc00, system_call_exception) +DEFINE_VECTOR(0xd00, trace_exception) +DEFINE_VECTOR(0xe00, FP_assist_exception) +DEFINE_VECTOR(0xf00, perf_monitor_exception) +DEFINE_VECTOR(0xf20, altivec_unavailable_exception) +DEFINE_VECTOR(0x1000, ITLB_miss_exception) +DEFINE_VECTOR(0x1100, DTLB_miss_on_load_exception) +DEFINE_VECTOR(0x1200, DTLB_miss_on_store_exception) +DEFINE_VECTOR(0x1300, instruction_address_breakpoint_exception) +DEFINE_VECTOR(0x1400, system_management_exception) +DEFINE_VECTOR(0x1600, altivec_assist_exception) +DEFINE_VECTOR(0x1700, thermal_management_exception) + +.global __irqvec_end +__irqvec_end: + + +/* This is where exception_vector_common continues. We're in the kernel here. + r1: ppc_cpu_exception_context* (virtual address) + r3: exception vector offset + SPRG1: original r1 + */ +FUNCTION(ppc_exception_tail): + /* turn off BAT */ + li %r2, 0 + mtibatu 0, %r2 + mtibatl 0, %r2 + isync + sync + + /* save CR */ + mfcr %r0 + + mfsrr1 %r2 /* load saved msr */ + andi. %r2, %r2, (1 << 14) /* see if it was in kernel mode */ + beq .kernel /* yep */ + + /* We come from userland. Load the kernel stack top address for the current + userland thread. */ + mr %r2, %r1 + lwz %r1, 8(%r1) + b .restore_stack_end + +.kernel: + mr %r2, %r1 + mfsprg1 %r1 + +.restore_stack_end: + /* now r2 points to the ppc_cpu_exception_context, r1 to the kernel stack */ + /* restore the CR, it was messed up in the previous compare */ + mtcrf 0xff, %r0 + + /* save the registers */ + bl __save_regs + + /* iframe pointer to r4 and a backup to r20 */ + mr %r4, %r1 + mr %r20, %r1 + + /* adjust the stack pointer for ABI compatibility */ + subi %r1, %r1, 8 /* make sure there's space for the previous + frame pointer and the return address */ + li %r2, 0xfffffff0 + and %r1, %r1, %r2 /* 16 byte align the stack pointer */ + li %r0, 0 + stw %r0, 0(%r1) /* previous frame pointer: NULL */ + /* 4(%r1) is room for the return address to be filled in by the + called function. */ + + /* r3: exception vector offset + r4: iframe pointer */ + bl ppc_exception_entry + + /* move the iframe to r1 */ + mr %r1, %r20 + + b __restore_regs_and_rfi + + +/* called by ppc_exception_tail + * register expectations: + * r1: stack + * r2: ppc_cpu_exception_context* + * SPRG1: original r1 + * r0,r3, LR: scrambled, but saved in scratch memory + * all other regs should have been unmodified by the exception handler, + * and ready to be saved + */ +__save_regs: + lwz %r0, 16(%r2) /* original r0 */ + stwu %r0, -4(%r1) /* push r0 */ + mfsprg1 %r0 /* original r1 */ + stwu %r0, -4(%r1) /* push r1 */ + lwz %r0, 24(%r2) /* original r2 */ + stwu %r0, -4(%r1) /* push r2 */ + lwz %r0, 28(%r2) /* original r3 */ + stwu %r0, -4(%r1) /* push r3 */ + + /* push r4-r31 */ + stwu %r4, -4(%r1) + stwu %r5, -4(%r1) + stwu %r6, -4(%r1) + stwu %r7, -4(%r1) + stwu %r8, -4(%r1) + stwu %r9, -4(%r1) + stwu %r10, -4(%r1) + stwu %r11, -4(%r1) + stwu %r12, -4(%r1) + stwu %r13, -4(%r1) + stwu %r14, -4(%r1) + stwu %r15, -4(%r1) + stwu %r16, -4(%r1) + stwu %r17, -4(%r1) + stwu %r18, -4(%r1) + stwu %r19, -4(%r1) + stwu %r20, -4(%r1) + stwu %r21, -4(%r1) + stwu %r22, -4(%r1) + stwu %r23, -4(%r1) + stwu %r24, -4(%r1) + stwu %r25, -4(%r1) + stwu %r26, -4(%r1) + stwu %r27, -4(%r1) + stwu %r28, -4(%r1) + stwu %r29, -4(%r1) + stwu %r30, -4(%r1) + stwu %r31, -4(%r1) /* save some of the other regs */ mfctr %r0 @@ -137,7 +277,7 @@ FUNCTION(__save_regs): stwu %r0, -4(%r1) /* push XER */ mfcr %r0 stwu %r0, -4(%r1) /* push CR */ - mfsprg %r0, 3 + lwz %r0, 20(%r2) /* original LR */ stwu %r0, -4(%r1) /* push LR */ mfspr %r0, %dsisr stwu %r0, -4(%r1) /* push DSISR */ @@ -148,92 +288,13 @@ FUNCTION(__save_regs): mfspr %r0, %srr0 stwu %r0, -4(%r1) /* push SRR0 */ - addi %r1, %r1, -8 /* adjust the stack pointer to leave some padding on it for C */ - - /* get outta here */ blr -/* not enough space for __restore_regs_and_rfi here, see below */ - -.skip 0x100 - (. - __irqvec_start) -FUNCTION(system_reset_exception): - VEC_ENTRY(); - li %r3, 0x100 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi - -.skip 0x200 - (. - __irqvec_start) -FUNCTION(machine_check_exception): - VEC_ENTRY(); - li %r3, 0x200 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi - -.skip 0x300 - (. - __irqvec_start) -FUNCTION(DSI_exception): - VEC_ENTRY(); - li %r3, 0x300 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi - -.skip 0x400 - (. - __irqvec_start) -FUNCTION(ISI_exception): - VEC_ENTRY(); - li %r3, 0x400 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi - -.skip 0x500 - (. - __irqvec_start) -FUNCTION(external_interrupt_exception): - VEC_ENTRY(); - li %r3, 0x500 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi - -.skip 0x600 - (. - __irqvec_start) -FUNCTION(alignment_exception): - VEC_ENTRY(); - li %r3, 0x600 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi - -.skip 0x700 - (. - __irqvec_start) -FUNCTION(program_exception): - VEC_ENTRY(); - li %r3, 0x700 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi - -.skip 0x800 - (. - __irqvec_start) -FUNCTION(FP_unavailable_exception): - VEC_ENTRY(); - li %r3, 0x800 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi - -.skip 0x900 - (. - __irqvec_start) -FUNCTION(decrementer_exception): - VEC_ENTRY(); - li %r3, 0x900 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi /* called at the tail end of each of the exceptions -** placed here because of the space between these two -** exception handlers. -*/ -FUNCTION(__restore_regs_and_rfi): - addi %r1, %r1, 8 /* adjust the stack pointer to get it back to the base of the iframe */ - + * r1: iframe pointer + */ +__restore_regs_and_rfi: lwz %r0, 0(%r1) /* SRR0 */ mtspr %srr0, %r0 lwzu %r0, 4(%r1) /* SRR1 */ @@ -251,7 +312,6 @@ FUNCTION(__restore_regs_and_rfi): lwzu %r0, 4(%r1) /* CTR */ mtctr %r0 - /* strictly speaking, we dont really need to have saved these regs */ lwzu %r31, 4(%r1) lwzu %r30, 4(%r1) lwzu %r29, 4(%r1) @@ -271,7 +331,6 @@ FUNCTION(__restore_regs_and_rfi): lwzu %r15, 4(%r1) lwzu %r14, 4(%r1) lwzu %r13, 4(%r1) - lwzu %r12, 4(%r1) lwzu %r11, 4(%r1) lwzu %r10, 4(%r1) @@ -286,102 +345,5 @@ FUNCTION(__restore_regs_and_rfi): lwz %r0, 8(%r1) lwz %r1, 4(%r1) - /* get out of here */ + /* return from interrupt */ rfi - -.skip 0xc00 - (. - __irqvec_start) -FUNCTION(system_call_exception): - VEC_ENTRY(); - li %r3, 0xc00 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi - -.skip 0xd00 - (. - __irqvec_start) -FUNCTION(trace_exception): - VEC_ENTRY(); - li %r3, 0xd00 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi - -.skip 0xe00 - (. - __irqvec_start) -FUNCTION(FP_assist_exception): - VEC_ENTRY(); - li %r3, 0xe00 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi - -.skip 0xf00 - (. - __irqvec_start) -FUNCTION(perf_monitor_exception): - /* XXX deal with this, normal VEC_ENTRY code is too big to fit here */ - rfi - -.skip 0xf20 - (. - __irqvec_start) -FUNCTION(altivec_unavailable_exception): - VEC_ENTRY(); - li %r3, 0xf20 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi - -.skip 0x1000 - (. - __irqvec_start) -FUNCTION(ITLB_miss_exception): - VEC_ENTRY(); - li %r3, 0x1000 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi - -.skip 0x1100 - (. - __irqvec_start) -FUNCTION(DTLB_miss_on_load_exception): - VEC_ENTRY(); - li %r3, 0x1100 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi - -.skip 0x1200 - (. - __irqvec_start) -FUNCTION(DTLB_miss_on_store_exception): - VEC_ENTRY(); - li %r3, 0x1200 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi - -.skip 0x1300 - (. - __irqvec_start) -FUNCTION(instruction_address_breakpoint_exception): - VEC_ENTRY(); - li %r3, 0x1300 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi - -.skip 0x1400 - (. - __irqvec_start) -FUNCTION(system_management_exception): - VEC_ENTRY(); - li %r3, 0x1400 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi - -.skip 0x1600 - (. - __irqvec_start) -FUNCTION(altivec_assist_exception): - VEC_ENTRY(); - li %r3, 0x1600 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi - -.skip 0x1700 - (. - __irqvec_start) -FUNCTION(thermal_management_exception): - VEC_ENTRY(); - li %r3, 0x1700 - addi %r4, %r1, 8 - bl ppc_exception_entry - bl __restore_regs_and_rfi - -.global __irqvec_end -__irqvec_end: - diff --git a/src/system/kernel/arch/ppc/arch_int.cpp b/src/system/kernel/arch/ppc/arch_int.cpp index 99e588f70e..ad14367fc9 100644 --- a/src/system/kernel/arch/ppc/arch_int.cpp +++ b/src/system/kernel/arch/ppc/arch_int.cpp @@ -1,7 +1,11 @@ /* - * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2003-2006, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * + * Authors: + * Axel Dörfler + * Ingo Weinhold + * * Copyright 2001, Travis Geiselbrecht. All rights reserved. * Distributed under the terms of the NewOS License. */ @@ -10,10 +14,13 @@ #include +#include #include +#include #include #include #include +#include #include #include @@ -22,6 +29,12 @@ extern int __irqvec_start; extern int __irqvec_end; +extern"C" void ppc_exception_tail(void); + + +// the exception contexts for all CPUs +static ppc_cpu_exception_context sCPUExceptionContexts[SMP_MAX_CPUS]; + void arch_int_enable_io_interrupt(int irq) @@ -59,7 +72,13 @@ print_iframe(struct iframe *frame) } -void ppc_exception_entry(int vector, struct iframe *iframe); +extern "C" void exception_tail_test(); +void +exception_tail_test() +{ +} + +extern "C" void ppc_exception_entry(int vector, struct iframe *iframe); void ppc_exception_entry(int vector, struct iframe *iframe) { @@ -164,7 +183,6 @@ arch_int_init(kernel_args *args) status_t arch_int_init_post_vm(kernel_args *args) { - area_id exceptionArea; void *handlers = (void *)args->arch_args.exception_handlers.start; // We may need to remap the exception handler area into the kernel address @@ -182,7 +200,7 @@ arch_int_init_post_vm(kernel_args *args) } // create a region to map the irq vector code into (physical address 0x0) - exceptionArea = create_area("exception_handlers", + area_id exceptionArea = create_area("exception_handlers", &handlers, B_EXACT_ADDRESS, args->arch_args.exception_handlers.size, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); if (exceptionArea < B_OK) @@ -192,8 +210,48 @@ arch_int_init_post_vm(kernel_args *args) // copy the handlers into this area memcpy(handlers, &__irqvec_start, args->arch_args.exception_handlers.size); - arch_cpu_sync_icache(handlers, 0x1000); + arch_cpu_sync_icache(handlers, args->arch_args.exception_handlers.size); + + // init the CPU exception contexts + int cpuCount = smp_get_num_cpus(); + for (int i = 0; i < cpuCount; i++) { + ppc_cpu_exception_context *context = ppc_get_cpu_exception_context(i); + context->kernel_handle_exception = (void*)&ppc_exception_tail; + context->exception_context = context; + // kernel_stack is set when the current thread changes. At this point + // we don't have threads yet. + } + + // set the exception context for this CPU + ppc_set_current_cpu_exception_context(ppc_get_cpu_exception_context(0)); return B_OK; } + +// #pragma mark - + +struct ppc_cpu_exception_context * +ppc_get_cpu_exception_context(int cpu) +{ + return sCPUExceptionContexts + cpu; +} + + +void +ppc_set_current_cpu_exception_context(struct ppc_cpu_exception_context *context) +{ + // translate to physical address + addr_t physicalPage; + addr_t inPageOffset = (addr_t)context & (B_PAGE_SIZE - 1); + status_t error = vm_get_page_mapping(vm_kernel_address_space_id(), + (addr_t)context - inPageOffset, &physicalPage); + if (error != B_OK) { + panic("ppc_set_current_cpu_exception_context(): Failed to get physical " + "address!"); + return; + } + + asm volatile("mtsprg0 %0" : : "r"(physicalPage + inPageOffset)); +} +