diff options
author | Till Straumann <strauman@slac.stanford.edu> | 2007-12-08 23:43:24 +0000 |
---|---|---|
committer | Till Straumann <strauman@slac.stanford.edu> | 2007-12-08 23:43:24 +0000 |
commit | 94e1931c5b8ce7e34c4293efbb8dcc106a532ac9 (patch) | |
tree | 3723b8eeed0bb1cdf8905c4ba89a8b25720243da | |
parent | 2007-12-08 Till Straumann <strauman@slac.stanford.edu> (diff) | |
download | rtems-94e1931c5b8ce7e34c4293efbb8dcc106a532ac9.tar.bz2 |
2007-12-08 Till Straumann <strauman@slac.stanford.edu>
* new-exceptions/bspsupport/, new-exceptions/bspsupport/ppc_exc.S,
new-exceptions/bspsupport/ppc_exc_test.c,
new-exceptions/bspsupport/vectors.h,
new-exceptions/bspsupport/vectors_init.c,
new-exceptions/bspsupport/irq.c,
new-exceptions/bspsupport/ppc_exc_bspsupp.h,
new-exceptions/bspsupport/ppc_exc_hdl.c,
new-exceptions/bspsupport/ppc_exc_asm_macros.h,
new-exceptions/bspsupport/nested_irq_test.c:
New files. Added 'middleware' code for helping BSPs implement
exception and interrupt handling and implementing the 'new'
RTEMS IRQ API (which I personally dislike).
10 files changed, 2182 insertions, 0 deletions
diff --git a/c/src/lib/libcpu/powerpc/ChangeLog b/c/src/lib/libcpu/powerpc/ChangeLog index 6353711fa3..bb036d34d5 100644 --- a/c/src/lib/libcpu/powerpc/ChangeLog +++ b/c/src/lib/libcpu/powerpc/ChangeLog @@ -1,5 +1,20 @@ 2007-12-08 Till Straumann <strauman@slac.stanford.edu> + * new-exceptions/bspsupport/, new-exceptions/bspsupport/ppc_exc.S, + new-exceptions/bspsupport/ppc_exc_test.c, + new-exceptions/bspsupport/vectors.h, + new-exceptions/bspsupport/vectors_init.c, + new-exceptions/bspsupport/irq.c, + new-exceptions/bspsupport/ppc_exc_bspsupp.h, + new-exceptions/bspsupport/ppc_exc_hdl.c, + new-exceptions/bspsupport/ppc_exc_asm_macros.h, + new-exceptions/bspsupport/nested_irq_test.c: + New files. Added 'middleware' code for helping BSPs implement + exception and interrupt handling and implementing the 'new' + RTEMS IRQ API (which I personally dislike). + +2007-12-08 Till Straumann <strauman@slac.stanford.edu> + * new-exceptions/e500_raw_exc_init.c, new-exceptions/raw_exception.c, shared/include/cpuIdent.c, shared/include/cpuIdent.h: Added different kinds of 'bookE' to the ppc_cpu_is_bookE feature diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/irq.c b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/irq.c new file mode 100644 index 0000000000..01d96a2a3b --- /dev/null +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/irq.c @@ -0,0 +1,374 @@ +/* + * + * This file contains the PIC-independent implementation of the functions described in irq.h + * + * Copyright (C) 1998, 1999 valette@crf.canon.fr + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#include <stdlib.h> + +#include <rtems.h> +#include "irq_supp.h" +#include <rtems/score/apiext.h> /* for post ISR signal processing */ +#include <libcpu/raw_exception.h> +#include <libcpu/cpuIdent.h> +#include "vectors.h" +#include <stdlib.h> +#include <rtems/bspIo.h> /* for printk */ +#include <libcpu/spr.h> + +/* + * default handler connected on each irq after bsp initialization + */ +static rtems_irq_connect_data default_rtems_entry; + +/* + * location used to store initial tables used for interrupt + * management. + */ +static rtems_irq_global_settings* internal_config; +static rtems_irq_connect_data* rtems_hdl_tbl; + + +SPR_RW(BOOKE_TSR) + +/* legacy mode for bookE DEC exception; + * to avoid the double layer of function calls + * (dec_handler_bookE -> C_dispatch_irq_handler -> user handler) + * it is preferrable for the user to hook the DEC + * exception directly. + * However, the legacy mode works with less modifications + * of user code. + */ +void C_dispatch_dec_handler_bookE (BSP_Exception_frame *frame, unsigned int excNum) +{ + /* clear interrupt; we must do this + * before C_dispatch_irq_handler() + * re-enables MSR_EE. + */ + _write_BOOKE_TSR( BOOKE_TSR_DIS ); + C_dispatch_irq_handler(frame, ASM_DEC_VECTOR); +} + +/* + * ------------------------ RTEMS Irq helper functions ---------------- + */ + +/* + * This function check that the value given for the irq line + * is valid. + */ + +static int isValidInterrupt(int irq) +{ + if ( (irq < internal_config->irqBase) || (irq >= internal_config->irqBase + internal_config->irqNb)) + return 0; + return 1; +} + +/* + * ------------------------ RTEMS Shared Irq Handler Mngt Routines ---------------- + */ +int BSP_install_rtems_shared_irq_handler (const rtems_irq_connect_data* irq) +{ + rtems_interrupt_level level; + rtems_irq_connect_data* vchain; + + if (!isValidInterrupt(irq->name)) { + printk("Invalid interrupt vector %d\n",irq->name); + return 0; + } + + rtems_interrupt_disable(level); + + if ( (int)rtems_hdl_tbl[irq->name].next_handler == -1 ) { + rtems_interrupt_enable(level); + printk("IRQ vector %d already connected to an unshared handler\n",irq->name); + return 0; + } + + vchain = (rtems_irq_connect_data*)malloc(sizeof(rtems_irq_connect_data)); + + /* save off topmost handler */ + vchain[0]= rtems_hdl_tbl[irq->name]; + + /* + * store the data provided by user + */ + rtems_hdl_tbl[irq->name] = *irq; + + /* link chain to new topmost handler */ + rtems_hdl_tbl[irq->name].next_handler = (void *)vchain; + + /* + * enable_irq_at_pic is supposed to ignore + * requests to disable interrupts outside + * of the range handled by the PIC + */ + BSP_enable_irq_at_pic(irq->name); + + /* + * Enable interrupt on device + */ + if (irq->on) + irq->on(irq); + + rtems_interrupt_enable(level); + + return 1; +} + +/* + * ------------------------ RTEMS Single Irq Handler Mngt Routines ---------------- + */ + +int BSP_install_rtems_irq_handler (const rtems_irq_connect_data* irq) +{ + rtems_interrupt_level level; + + if (!isValidInterrupt(irq->name)) { + printk("Invalid interrupt vector %d\n",irq->name); + return 0; + } + /* + * Check if default handler is actually connected. If not issue an error. + * You must first get the current handler via i386_get_current_idt_entry + * and then disconnect it using i386_delete_idt_entry. + * RATIONALE : to always have the same transition by forcing the user + * to get the previous handler before accepting to disconnect. + */ + rtems_interrupt_disable(level); + if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) { + rtems_interrupt_enable(level); + printk("IRQ vector %d already connected\n",irq->name); + return 0; + } + + /* + * store the data provided by user + */ + rtems_hdl_tbl[irq->name] = *irq; + rtems_hdl_tbl[irq->name].next_handler = (void *)-1; + + /* + * enable_irq_at_pic is supposed to ignore + * requests to disable interrupts outside + * of the range handled by the PIC + */ + BSP_enable_irq_at_pic(irq->name); + + /* + * Enable interrupt on device + */ + if (irq->on) + irq->on(irq); + + rtems_interrupt_enable(level); + + return 1; +} + +int BSP_get_current_rtems_irq_handler (rtems_irq_connect_data* irq) +{ + rtems_interrupt_level level; + + if (!isValidInterrupt(irq->name)) { + return 0; + } + rtems_interrupt_disable(level); + *irq = rtems_hdl_tbl[irq->name]; + rtems_interrupt_enable(level); + return 1; +} + +int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq) +{ + rtems_irq_connect_data *pchain= NULL, *vchain = NULL; + rtems_interrupt_level level; + + if (!isValidInterrupt(irq->name)) { + return 0; + } + /* + * Check if default handler is actually connected. If not issue an error. + * You must first get the current handler via i386_get_current_idt_entry + * and then disconnect it using i386_delete_idt_entry. + * RATIONALE : to always have the same transition by forcing the user + * to get the previous handler before accepting to disconnect. + */ + rtems_interrupt_disable(level); + if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) { + rtems_interrupt_enable(level); + return 0; + } + + if( (int)rtems_hdl_tbl[irq->name].next_handler != -1 ) + { + int found = 0; + + for( (pchain= NULL, vchain = &rtems_hdl_tbl[irq->name]); + (vchain->hdl != default_rtems_entry.hdl); + (pchain= vchain, vchain = (rtems_irq_connect_data*)vchain->next_handler) ) + { + if( vchain->hdl == irq->hdl ) + { + found= -1; break; + } + } + + if( !found ) + { + rtems_interrupt_enable(level); + return 0; + } + } + else + { + if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) + { + rtems_interrupt_enable(level); + return 0; + } + } + + /* + * disable_irq_at_pic is supposed to ignore + * requests to disable interrupts outside + * of the range handled by the PIC + */ + BSP_disable_irq_at_pic(irq->name); + + /* + * Disable interrupt on device + */ + if (irq->off) + irq->off(irq); + + /* + * restore the default irq value + */ + if( !vchain ) + { + /* single handler vector... */ + rtems_hdl_tbl[irq->name] = default_rtems_entry; + } + else + { + if( pchain ) + { + /* non-first handler being removed */ + pchain->next_handler = vchain->next_handler; + } + else + { + /* first handler isn't malloc'ed, so just overwrite it. Since + the contents of vchain are being struct copied, vchain itself + goes away */ + vchain = vchain->next_handler; + rtems_hdl_tbl[irq->name]= *vchain; + } + free(vchain); + } + + rtems_interrupt_enable(level); + + return 1; +} + +/* + * Less cumbersome, alternate entry points; + * RETURNS: more traditional, 0 on success, nonzero on error + */ + +static int doit( + int (*p)(const rtems_irq_connect_data*), + rtems_irq_number n, + rtems_irq_hdl hdl, + rtems_irq_hdl_param prm) +{ +rtems_irq_connect_data xx; + xx.name = n; + xx.hdl = hdl; + xx.handle = prm; + xx.on = 0; + xx.off = 0; + xx.isOn = 0; + return ! p(&xx); +} + +int BSP_rtems_int_connect(rtems_irq_number n, rtems_irq_hdl hdl, rtems_irq_hdl_param p) +{ + return doit(BSP_install_rtems_shared_irq_handler, n, hdl, p); +} + +int BSP_rtems_int_disconnect(rtems_irq_number n, rtems_irq_hdl hdl, rtems_irq_hdl_param p) +{ + return doit(BSP_remove_rtems_irq_handler, n, hdl, p); +} + + +/* + * RTEMS Global Interrupt Handler Management Routines + */ + +int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config) +{ + int i; + rtems_interrupt_level level; + rtems_irq_connect_data* vchain; + + /* + * Store various code accelerators + */ + internal_config = config; + default_rtems_entry = config->defaultEntry; + rtems_hdl_tbl = config->irqHdlTbl; + + rtems_interrupt_disable(level); + + if ( !BSP_setup_the_pic(config) ) { + printk("PIC setup failed; leaving IRQs OFF\n"); + return 0; + } + + for ( i = config->irqBase; i < config->irqBase + config->irqNb; i++ ) { + for( vchain = &rtems_hdl_tbl[i]; + ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl); + vchain = (rtems_irq_connect_data*)vchain->next_handler ) + { + if (vchain->on) + vchain->on(vchain); + } + } + + rtems_interrupt_enable(level); + + { + ppc_exc_set_handler(ASM_EXT_VECTOR, C_dispatch_irq_handler); + + if ( ppc_cpu_is_bookE() ) { + /* bookE decrementer interrupt needs to be cleared BEFORE + * dispatching the user ISR (because the user ISR is called + * with EE enabled) + * We do this so that existing DEC handlers can be used + * with minor modifications. + */ + ppc_exc_set_handler(ASM_BOOKE_PIT_VECTOR, C_dispatch_dec_handler_bookE); + } else { + ppc_exc_set_handler(ASM_DEC_VECTOR, C_dispatch_irq_handler); + } + } + return 1; +} + +int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config) +{ + *config = internal_config; + return 0; +} diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/nested_irq_test.c b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/nested_irq_test.c new file mode 100644 index 0000000000..999563d12a --- /dev/null +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/nested_irq_test.c @@ -0,0 +1,107 @@ +/* + * Test nested interrupts. + * + * Author: Till Straumann <strauman@slac.stanford.edu>, 2007 + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + + +/* + * Needs board with 2 available openpic timers + * + * 'timer_instdis(timer, install, period)' + * + * installs 'timer_isr' to openpic timer # 'timer'. + * The interrupt priority is set to 8 + timer# + * + * The timer_isr prints a message then polls + * the variable 'timer_poll' while it has the value + * of the timer # then sets it to -1 and prints + * the 'leave' message. + * + * To test nested interrupts: + * + * timer_instdis(0, 1, period) + * wait_a_bit() + * timer_instdis(1, 1, period) + * timer_poll = 0; + * + * As soon as timer 0's IRQ fires the + * isr prints + * TIMER ISR (0) ... + * then starts polling (since timer_poll == 0 ) + * eventually, timer 1 goes off, interrupts (because + * it's priority is 9 (i.e., higher than timer 0's priority) + * and prints + * TIMER ISR (1) + * it skips polling since timer_poll is 0, not 1 but + * resets timer_poll -1 and prints + * Leaving ISR (1) + * timer 0 isr resumes polling and finds timer_poll == -1 + * so it also writes -1 to timer_poll and exits, printing + * Leaving ISR (0) + * + * The timer IRQs can be unhooked with + * timer_instdis( 0, 0, period ); + * timer_instdis( 1, 0, period ); + */ +#include <rtems.h> +#include <rtems/bspIo.h> +#include <bsp/openpic.h> +#include <bsp/irq.h> +#include <inttypes.h> +#include <stdio.h> + +volatile int timer_poll=-1; + +static void timer_isr(rtems_irq_hdl_param p) +{ +uint32_t top; +uint32_t r1; +uint32_t lat = (OpenPIC->Global.Timer[(int)p].Current_Count & 0x7fffffff); + + lat = OpenPIC->Global.Timer[(int)p].Base_Count - lat; + + asm volatile("mfspr %0, %2; mr %1, 1":"=r"(top),"=r"(r1):"i"(SPRG1)); + printk("Timer ISR (%i): LAT: 0x%08x, TOP 0x%08x, BOT 0x%08x, SP 0x%08x\n", + (int)p, lat, top, top-rtems_configuration_get_interrupt_stack_size(), r1); + printk("_ISR_Nest_level %i\n", _ISR_Nest_level); + while ( timer_poll == (int)p ) + ; + timer_poll = -1; + + printk("Leaving ISR (%i)\n",(int)p); +} + +int timer_instdis(int t, int inst, unsigned period) +{ +rtems_irq_connect_data xx; + xx.name = BSP_MISC_IRQ_LOWEST_OFFSET + t; + xx.hdl = timer_isr; + xx.handle = (rtems_irq_hdl_param)t; + xx.on = 0; + xx.off = 0; + xx.isOn = 0; + if ( !inst ) { + openpic_maptimer(t, 0); + openpic_inittimer(t, 0, 0); + } + if ( ! ( inst ? BSP_install_rtems_irq_handler(&xx) : BSP_remove_rtems_irq_handler(&xx) ) ) { + openpic_maptimer(t, 0); + openpic_inittimer(t, 0, 0); + fprintf(stderr,"unable to %s timer ISR #%i\n", inst ? "install" : "remove", t); + return -1; + } + if ( inst ) { + openpic_maptimer( t, 1 ); + openpic_inittimer( t, 8 + t, OPENPIC_VEC_SOURCE + xx.name ); + openpic_settimer( t, period, 1 ); + } + return 0; +} + diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc.S b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc.S new file mode 100644 index 0000000000..158f407e2b --- /dev/null +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc.S @@ -0,0 +1,368 @@ +/* + * (c) 1999, Eric Valette valette@crf.canon.fr + * + * Modified and partially rewritten by Till Straumann, 2007 + * + * Low-level assembly code for PPC exceptions. + * + * This file was written with the goal to eliminate + * ALL #ifdef <cpu_flavor> conditionals -- please do not + * reintroduce such statements. + */ + +/* Load macro definitions */ +#include "ppc_exc_asm_macros.h" + +/******************************************************/ +/* PROLOGUES */ +/******************************************************/ + + /* + * Expand prologue snippets for classic, ppc405-critical, bookE-critical + * and E500 machine-check, synchronous and asynchronous exceptions + */ + PPC_EXC_MIN_PROLOG_SYNC _NAME=tmpl_std _VEC=0 _PRI=std _FLVR=std + PPC_EXC_MIN_PROLOG_SYNC _NAME=tmpl_p405_crit _VEC=0 _PRI=crit _FLVR=p405_crit + PPC_EXC_MIN_PROLOG_SYNC _NAME=tmpl_bookE_crit _VEC=0 _PRI=crit _FLVR=bookE_crit + PPC_EXC_MIN_PROLOG_SYNC _NAME=tmpl_e500_mchk _VEC=0 _PRI=mchk _FLVR=e500_mchk + + PPC_EXC_MIN_PROLOG_ASYNC _NAME=tmpl_std _VEC=0 _PRI=std _FLVR=std + PPC_EXC_MIN_PROLOG_ASYNC _NAME=tmpl_p405_crit _VEC=0 _PRI=crit _FLVR=p405_crit + PPC_EXC_MIN_PROLOG_ASYNC _NAME=tmpl_bookE_crit _VEC=0 _PRI=crit _FLVR=bookE_crit + PPC_EXC_MIN_PROLOG_ASYNC _NAME=tmpl_e500_mchk _VEC=0 _PRI=mchk _FLVR=e500_mchk + + .global ppc_exc_min_prolog_size +ppc_exc_min_prolog_size = 4 * 4 + + /* Special prologue for 603e-style CPUs. + * + * 603e shadows GPR0..GPR3 for certain exceptions. We must switch + * that off before we can use the stack pointer. Note that this is + * ONLY safe if the shadowing is actually active -- otherwise, r1 + * is destroyed. We deliberately use r1 so problems become obvious + * if this is abused! + */ + .global ppc_exc_tgpr_clr_prolog +ppc_exc_tgpr_clr_prolog: + mfmsr r1 + rlwinm r1,r1,0,15,13 + mtmsr r1 + isync + /* FALL THRU TO 'auto' PROLOG */ + +/* Determine vector dynamically/automatically + * + * BUT: - only standard exceptions (no critical ones) + * - vector offset must be on 256 Byte boundary. + */ + .global ppc_exc_min_prolog_auto +ppc_exc_min_prolog_auto: + stwu r1, -EXCEPTION_FRAME_END(r1) + stw r3, GPR3_OFFSET(r1) + mflr r3 + bla wrap_auto + + .global ppc_exc_tgpr_clr_prolog_size +ppc_exc_tgpr_clr_prolog_size = . - ppc_exc_tgpr_clr_prolog + +/* + * Automatic vector, asynchronous exception; however, + * automatic vector calculation is less efficient than + * using an explicit vector in a minimal prolog snippet. + * The latter method is preferable since there usually + * are few asynchronous exceptions. + * + * For generic exceptions (which are the bulk) using + * the 'auto' prologue is OK since performance is not + * really an issue. + */ + .global ppc_exc_min_prolog_auto_async +ppc_exc_min_prolog_auto_async: + stw r1, ppc_exc_lock_std@sdarel(r13) + stw r3, ppc_exc_gpr3_std@sdarel(r13) + mflr r3 + bla wrap_auto_async + +/******************************************************/ +/* WRAPPERS */ +/******************************************************/ + + /* Tag start and end of the wrappers. + * If exceptions are installed farther removed + * from the text area than 32M then the wrappers + * must be moved to an area that is reachable + * from where the prologues reside. Branches into + * C-code are far. + */ + + .global __ppc_exc_wrappers_start +__ppc_exc_wrappers_start = . + + /* Expand wrappers for different exception flavors */ + + /* Standard/classic powerpc */ + WRAP _FLVR=std _PRI=std _SRR0=srr0 _SRR1=srr1 _RFI=rfi + + /* ppc405 has a critical exception using srr2/srr3 */ + WRAP _FLVR=p405_crit _PRI=crit _SRR0=srr2 _SRR1=srr3 _RFI=rfci + + /* bookE has critical exception using csrr0 cssr1 */ + WRAP _FLVR=bookE_crit _PRI=crit _SRR0=csrr0 _SRR1=csrr1 _RFI=rfci + + /* e500 has machine-check exception using mcsrr0 mcssr1 */ + WRAP _FLVR=e500_mchk _PRI=mchk _SRR0=mcsrr0 _SRR1=mcsrr1 _RFI=rfmci + + + /* LR holds vector, r3 holds orig. LR */ +wrap_auto: + stw r14, GPR14_OFFSET(r1) + /* find address where we jumped from */ + mflr r14 + /* restore LR */ + mtlr r3 + /* compute vector into R3 */ + rlwinm r3, r14, 24, 26, 31 + /* we're now in almost the same state as if called by + * min_prolog_std but we must skip saving r14 + * since that's done already + */ + b wrap_no_save_r14_std + +wrap_auto_async: + stwu r1, -EXCEPTION_FRAME_END(r1) + stw r14, GPR14_OFFSET(r1) + /* find address where we jumped from */ + mflr r14 + /* restore LR */ + mtlr r3 + /* set upper bits to indicate that non-volatile + * registers should not be saved/restored. + */ + li r3, 0xffff8000 + /* compute vector into R3 */ + rlwimi r3, r14, 24, 26, 31 + /* we're now in almost the same state as if called by + * min_prolog_std but we must skip saving r14 + * since that's done already + */ + b wrap_no_save_r14_std + +/* + * Common code for all flavors of exception and whether + * they are synchronous or asynchronous. + * + * Call with + * r3 : vector + * r4 : srr0 + * r5 : srr1 + * r14: exception frame + * cr4: OR of lower-priority locks + * cr2: exception type (asyn/isr [<0] or synchronous [>=0]) + * lr : is updated by 'bl' + * all others: original state + * + * If this is an asynchronous exception ( cr2 < 0 ): + * - save volatile registers only, + * - disable thread dispatching, + * - switch to interrupt stack (if necessary), + * - call the C-dispatcher, + * - switch back the stack, + * - decrement the dispatch-disable level + * - check if it is safe to dispatch (disable-level must be 0 + * AND no lower-priority asynchronous exception must be under + * way (as indicated by the lock variables). + * - If it would be OK to dispatch, call the C-wrapup code. + * - restore volatile registers + * + * Otherwise, i.e., if we are dealing with a synchronous exception + * then: + * - save all registers + * - call the C-dispatcher + * - restore registers + */ + +wrap_common: + stw r4, SRR0_FRAME_OFFSET(r14) + stw r5, SRR1_FRAME_OFFSET(r14) + + /* prepare for calling C code; */ + + /* use non-volatile r15 for remembering lr */ + stw r15, GPR15_OFFSET(r14) + + /* save vector; negative if only scratch regs. are valid */ + stw r3, EXCEPTION_NUMBER_OFFSET(r14) + + /* save scratch registers */ + + /* r2 should be unused or fixed anyways (eabi sdata2) */ + stw r0, GPR0_OFFSET(r14) + stw r2, GPR2_OFFSET(r14) + stw r6, GPR6_OFFSET(r14) + stw r7, GPR7_OFFSET(r14) + stw r8, GPR8_OFFSET(r14) + stw r9, GPR9_OFFSET(r14) + stw r10, GPR10_OFFSET(r14) + stw r11, GPR11_OFFSET(r14) + stw r12, GPR12_OFFSET(r14) + /* r13 must be fixed anyways (sysv sdata) */ + + /* save LR */ + mflr r15 + + mfctr r4 + mfxer r5 + stw r4, EXC_CTR_OFFSET(r14) + stw r5, EXC_XER_OFFSET(r14) + + /* + * Switch MMU / RI on if necessary; + * remember decision in cr3 + */ + lwz r4, ppc_exc_msr_bits@sdarel(r13) + cmpwi cr3, r4, 0 + beq cr3, 1f + mfmsr r5 + or r5, r5, r4 + mtmsr r5 + sync + isync +1: + + /* If this is a asynchronous exception we skip ahead */ + blt cr2, skip_save_nonvolatile_regs + + /* YES; they want everything ('normal exception') */ + + /* save original stack pointer */ + lwz r5, EXC_MIN_GPR1(r14) + stw r5, GPR1_OFFSET(r14) + + stw r13, GPR13_OFFSET(r14) + + /* store r16..r31 into the exception frame */ + stmw r16, GPR16_OFFSET(r14) + +skip_save_nonvolatile_regs: + /* store address of exception frame in r4; vector is in r3 */ + addi r4, r14, FRAME_LINK_SPACE + /* clear CR[6] to make sure no vararg callee assumes that + * there are any valid FP regs + */ + crxor 6,6,6 + + /* Far branch to ppc_C_wrapper */ + lis r5, ppc_exc_C_wrapper@h + addi r4, r14, FRAME_LINK_SPACE + ori r5, r5, ppc_exc_C_wrapper@l + mtlr r5 + blrl + + /* do not clobber r3 since we pass the return value + * of ppc_exc_C_wrapper on to ppc_exc_wrapup + */ + + /* skip decrementing the thread-dispatch disable level + * and calling ppc_exc_wrapup if this is a synchronous + * exception. + */ + bge cr2, restore_nonvolatile_regs + + /* decrement ISR nest level; + * disable all interrupts. + */ + lwz r4, ppc_exc_msr_irq_mask@sdarel(r13) + mfmsr r5 + andc r4, r5, r4 + mtmsr r4 + lwz r4, _ISR_Nest_level@sdarel(r13) + addi r4, r4, -1 + stw r4, _ISR_Nest_level@sdarel(r13) + + /* switch back to original stack */ + mr r1, r14 + + /* restore interrupt mask */ + mtmsr r5 + + /* decrement thread_dispatch level and check + * if we have to run the dispatcher. + */ + lwz r5, _Thread_Dispatch_disable_level@sdarel(r13) + addic. r5, r5, -1 + stw r5, _Thread_Dispatch_disable_level@sdarel(r13) + + /* test _Thread_Dispatch_disable nesting level AND + * lower priority locks (in cr4); ONLY if + * _Thread_Dispatch_disable_level == 0 AND no lock is set + * then call ppc_exc_wrapup which may do a context switch. + */ + crand EQ(cr0), EQ(cr0), EQ(cr4) + bne 2f + crxor 6,6,6 + /* Far branch to ppc_exc_wrapup */ + lis r5, ppc_exc_wrapup@h + addi r4, r14, FRAME_LINK_SPACE + ori r5, r5, ppc_exc_wrapup@l + mtlr r5 + blrl +2: + lwz r14, GPR14_OFFSET(r1) + + /* we can skip restoring r16..r31 */ + b skip_restore_nonvolatile_regs + +restore_nonvolatile_regs: + /* synchronous exc: restore everything from the exception frame */ + lwz r14, GPR14_OFFSET(r1) + + /* restore stack pointer */ + lwz r5, GPR1_OFFSET(r1) + stw r5, EXC_MIN_GPR1(r1) + + /* restore non-volatile regs */ + lwz r13, GPR13_OFFSET(r1) + lmw r16, GPR16_OFFSET(r1) + +skip_restore_nonvolatile_regs: + lwz r3, EXC_XER_OFFSET(r1) + lwz r4, EXC_CTR_OFFSET(r1) + mtxer r3 + mtctr r4 + + /* restore lr, r15 */ + mtlr r15 + lwz r15, GPR15_OFFSET(r1) + + /* restore scratch regs */ + lwz r12, GPR12_OFFSET(r1) + lwz r11, GPR11_OFFSET(r1) + lwz r10, GPR10_OFFSET(r1) + lwz r9, GPR9_OFFSET(r1) + lwz r8, GPR8_OFFSET(r1) + lwz r7, GPR7_OFFSET(r1) + lwz r6, GPR6_OFFSET(r1) + lwz r3, GPR3_OFFSET(r1) + lwz r2, GPR2_OFFSET(r1) + lwz r0, GPR0_OFFSET(r1) + + beq cr3, 2f + /* restore MSR settings */ + lwz r5, ppc_exc_msr_bits@sdarel(r13) + mfmsr r4 + andc r4, r4, r5 + mtmsr r4 + sync + isync +2: + + lwz r4, EXC_CR_OFFSET(r1) + mtcr r4 + + /* restore SRR and stack */ + lwz r4, SRR0_FRAME_OFFSET(r1) + lwz r5, SRR1_FRAME_OFFSET(r1) + blr + + .global __ppc_exc_wrappers_end +__ppc_exc_wrappers_end = . diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_asm_macros.h b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_asm_macros.h new file mode 100644 index 0000000000..04863203dd --- /dev/null +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_asm_macros.h @@ -0,0 +1,278 @@ +/* + * (c) 1999, Eric Valette valette@crf.canon.fr + * + * Modified and partially rewritten by Till Straumann, 2007 + * + * Low-level assembly code for PPC exceptions (macros). + * + * This file was written with the goal to eliminate + * ALL #ifdef <cpu_flavor> conditionals -- please do not + * reintroduce such statements. + */ + +#include <rtems/score/cpu.h> +#include <bsp/vectors.h> +#include <libcpu/raw_exception.h> + +#define EXC_MIN_GPR1 0 +#define FRAME_LINK_SPACE 8 + +#define r0 0 +#define r1 1 +#define r2 2 +#define r3 3 +#define r4 4 +#define r5 5 +#define r6 6 +#define r7 7 +#define r8 8 +#define r9 9 +#define r10 10 +#define r11 11 +#define r12 12 +#define r13 13 +#define r14 14 +#define r15 15 +#define r16 16 +#define r17 17 +#define r18 18 +#define r19 19 +#define r20 20 +#define r21 21 +#define r22 22 +#define r23 23 +#define r24 24 +#define r25 25 +#define r26 26 +#define r27 27 +#define r28 28 +#define r29 29 +#define r30 30 +#define r31 31 + +#define cr0 0 +#define cr1 1 +#define cr4 4 + +#define LT(cr) ((cr)*4+0) +#define GT(cr) ((cr)*4+1) +#define EQ(cr) ((cr)*4+2) + +#define NOFRAME 0xffff8000 + +/* Switch r1 to interrupt stack if not already there. + * + * USES: RA, RB + * ON EXIT: RA, RB available, r1 points into interrupt + * stack. + * + * NOTES: + * - NEVER store stuff in a frame before + * reserving it (stwu r1) - otherwise + * higher-priority exception may overwrite. + * - algorithm should allow nesting of higher + * priority exceptions (HPE) (by disabling + * them while the stack is switched). + */ +#if 0 + .macro SWITCH_STACK RA RB FLVR + mfspr \RB, SPRG1 + cmplw cr0, r1, \RB + bgt do_r1_reload_\FLVR + lwz \RA, ppc_exc_intr_stack_size@sdarel(r13) + subf \RB, \RB, \RA + cmplw cr0, r1, \RB + bge no_r1_reload_\FLVR +do_r1_reload_\FLVR: + mfspr r1, SPRG1 +no_r1_reload_\FLVR: + .endm +#else + .macro SWITCH_STACK RA RB FLVR + /* disable interrupts */ + lwz \RA, ppc_exc_msr_irq_mask@sdarel(r13) + mfmsr \RB + and \RA, \RB, \RA + mtmsr \RA + /* increment nest level */ + lwz \RA, _ISR_Nest_level@sdarel(r13) + cmplwi cr0, \RA, 0 + bne no_r1_reload_\FLVR + /* reload r1 */ + mfspr r1, SPRG1 +no_r1_reload_\FLVR: + addi \RA, \RA, 1 + stw \RA, _ISR_Nest_level@sdarel(r13) + /* restore IRQ mask */ + mtmsr \RB + .endm +#endif + + /* + * Minimal prologue snippets: + * + * Rationale: on some PPCs the vector offsets are spaced + * as closely as 16 bytes. + * + * If we deal with asynchronous exceptions ('interrupts') + * then we can use 4 instructions to + * 1. atomically write lock to indicate ISR is in progress + * (we cannot atomically increase the Thread_Dispatch_disable_level, + * see README) + * 2. save a register in special area + * 3. load register with vector info + * 4. branch + * + * If we deal with a synchronous exception (no stack switch + * nor dispatch-disabling necessary) then it's easier: + * 1. push stack frame + * 2. save register on stack + * 3. load register with vector info + * 4. branch + * + */ + .macro PPC_EXC_MIN_PROLOG_ASYNC _NAME _VEC _PRI _FLVR + .global ppc_exc_min_prolog_async_\_NAME +ppc_exc_min_prolog_async_\_NAME: + /* Atomically write lock variable in 1st instruction with non-zero value + * (r1 is always nonzero; r13 could also be used) + */ + stw r1, ppc_exc_lock_\_PRI@sdarel(r13) + /* We have no stack frame yet; store r3 in special area; + * a higher-priority (critical) interrupt uses a different area + * (hence the different prologue snippets) (\PRI) + */ + stw r3, ppc_exc_gpr3_\_PRI@sdarel(r13) + /* Load vector. + */ + li r3, ( \_VEC | 0xffff8000 ) + /* Branch (must be within 32MB) + */ + ba wrap_\_FLVR + .endm + + .macro PPC_EXC_MIN_PROLOG_SYNC _NAME _VEC _PRI _FLVR + .global ppc_exc_min_prolog_sync_\_NAME +ppc_exc_min_prolog_sync_\_NAME: + stwu r1, -EXCEPTION_FRAME_END(r1) + stw r3, GPR3_OFFSET(r1) + li r3, \_VEC + ba wrap_nopush_\_FLVR + .endm + + .macro TEST_LOCK_std + /* 'std' is lowest level, i.e., can not be locked -> EQ(cr4) = 1 */ + creqv EQ(cr4), EQ(cr4), EQ(cr4) + .endm + + /* critical-exception wrapper has to check 'std' lock: */ + .macro TEST_LOCK_crit + lwz r5, ppc_exc_lock_std@sdarel(r13) + cmpli cr4, r5, 0 + .endm + + /* machine-check wrapper has to check 'std' and 'crit' locks */ + .macro TEST_LOCK_mchk + lwz r5, ppc_exc_lock_std@sdarel(r13) + cmpli cr4, r5, 0 + lwz r5, ppc_exc_lock_crit@sdarel(r13) + cmpli cr0, r5, 0 + cror EQ(cr4), EQ(cr4), EQ(cr0) + .endm + + /* Minimal prologue snippets jump into WRAP + * which prepares calling code common to all + * flavors of exceptions. + * We must have this macro instantiated for + * each possible flavor of exception so that + * we use the proper lock variable, SRR register pair and + * RFI instruction. + */ + .macro WRAP _FLVR _PRI _SRR0 _SRR1 _RFI +wrap_\_FLVR: + stwu r1, -EXCEPTION_FRAME_END(r1) +wrap_nopush_\_FLVR: + stw r14, GPR14_OFFSET(r1) +wrap_no_save_r14_\_FLVR: + + /* Save r4 r5 and CR; we want CR soon */ + mfcr r14 + stw r4, GPR4_OFFSET(r1) + stw r5, GPR5_OFFSET(r1) + stw r14, EXC_CR_OFFSET(r1) + + /* Check if this is an 'interrupt-type' exception + * (MSB vector is set). + * 'interrupt-type' exceptions disable thread dispatching + * and switch to a private stack. + * The type of exception is kept in (non-volatile) cr2 + * < 0 -> interrupt-type + * > 0 -> 'normal' exception; always on task stack, + * may switch context at any time. + */ + cmpwi cr2, r3, 0 + + /* + * Save frame address in r14 + */ + mr r14, r1 + + bge cr2, no_thread_dispatch_disable_\_FLVR + + /* first thing we need to + * increment the thread-dispatch disable level + * in case a higher priority exception occurs + * we don't want it to run the scheduler. + */ + lwz r5, _Thread_Dispatch_disable_level@sdarel(r13) + addi r5, r5, 1 + stw r5, _Thread_Dispatch_disable_level@sdarel(r13) + + /* clear lock; no higher-priority interrupt occurring after + * this point can cause a context switch. + */ + li r5, 0 + stw r5, ppc_exc_lock_\_PRI@sdarel(r13) + + /* test lower-priority locks; result in (non-volatile) cr4 */ + TEST_LOCK_\_PRI + + /* Peform stack switch if necessary */ + SWITCH_STACK RA=r4 RB=r5 FLVR=\_FLVR + + /* save r3, in exception frame */ + lwz r5, ppc_exc_gpr3_\_PRI@sdarel(r13) + stw r5, GPR3_OFFSET(r14) + +no_thread_dispatch_disable_\_FLVR: + + /* save lr into exception frame */ + mflr r4 + stw r4, EXC_LR_OFFSET(r14) + + /* we now have r4,r5,lr,cr available; + * r3 still holds the vector, + * r14 a pointer to the exception frame (always on + * task stack) + * r1 is the stack pointer, either on the task stack + * or on the IRQ stack + */ + + /* retrieve SRR0/SRR1 */ + mf\_SRR0 r4 + mf\_SRR1 r5 + + /* branch to common routine */ + bl wrap_common + + /* restore SRR, r4, r5, r1 (stack pointer) and lr */ + mt\_SRR0 r4 + mt\_SRR1 r5 + /* restore lr */ + lwz r5, EXC_LR_OFFSET(r1) + lwz r4, GPR4_OFFSET(r1) + mtlr r5 + lwz r5, GPR5_OFFSET(r1) + lwz r1, EXC_MIN_GPR1(r1) + \_RFI + .endm diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_bspsupp.h b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_bspsupp.h new file mode 100644 index 0000000000..6a2b72d56f --- /dev/null +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_bspsupp.h @@ -0,0 +1,128 @@ +/* PowerPC exception handling middleware; consult README for more + * information. + * + * Author: Till Straumann <strauman@slac.stanford.edu>, 2007 + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifndef PPC_EXC_SHARED_H +#define PPC_EXC_SHARED_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********* C-Exception Handlers *********************/ + +/* API to be used by middleware, */ +/* BSP and application code (if necessary */ + +/****************************************************/ + +typedef int (*ppc_exc_handler_t)(BSP_Exception_frame *f, int vector); + +/* + * Bits in MSR that are enabled during execution of exception handlers / ISRs + * (on classic PPC these are DR/IR/RI [default], on bookE-style CPUs they should + * be set to 0 during initialization) + * + * By default, the setting of these bits that is in effect when exception + * handling is initialized is used. + */ +extern uint32_t ppc_exc_msr_bits; + +/* + * Set of MSR bits required to disable all + * asynchronous exceptions (depends on CPU type; + * must be set during initialization). + * Interrupt are disabled by writing the + * one's complement of this mask to msr: + * msr &= ~ppc_exc_msr_irq_mask; + */ +extern uint32_t ppc_exc_msr_irq_mask; + +/* + * Hook C exception handlers. + * - handlers for asynchronous exceptions run on the ISR stack + * with thread-dispatching disabled. + * - handlers for synchronous exceptions run on the task stack + * with thread-dispatching enabled. + * + * If a particular slot is NULL then the traditional 'globalExcHdl' is used. + * + * ppc_exc_set_handler() registers a handler (returning 0 on success, + * -1 if the vector argument is too big). + * + * It is legal to set a NULL handler. This leads to the globalExcHdl + * being called if an exception for 'vector' occurs. + */ +int +ppc_exc_set_handler(unsigned vector, ppc_exc_handler_t hdl); + +/* ppc_exc_get_handler() retrieves the currently active handler. + */ +ppc_exc_handler_t +ppc_exc_get_handler(unsigned vector); + +/********* Low-level Exception Handlers *************/ + +/* This API is used by middleware code */ + +/****************************************************/ + +typedef uint32_t ppc_exc_min_prolog_t[4]; + +/* Templates are ppc_raw_except_func BUT they must be exactly 16 bytes */ +typedef rtems_raw_except_func ppc_exc_min_prolog_template_t; + +/* + * Expand a prolog template into 'buf' using vector 'vec' + */ +void +ppc_exc_min_prolog_expand(ppc_exc_min_prolog_t buf, ppc_exc_min_prolog_template_t templ, uint16_t vec); + +extern unsigned ppc_exc_min_prolog_size[]; +/* Symbols are defined by the linker; declare as an array so + * that gcc doesn't attempt to emit a relocation looking for + * it in the SDA section + */ +extern unsigned ppc_exc_tgpr_clr_prolog_size[]; + +/* Templates for ppc_exc_min_prolog_expand() which fills-in the vector information */ +extern void ppc_exc_min_prolog_async_tmpl_std(); +extern void ppc_exc_min_prolog_sync_tmpl_std(); +extern void ppc_exc_min_prolog_async_tmpl_p405_crit(); +extern void ppc_exc_min_prolog_sync_tmpl_p405_crit(); +extern void ppc_exc_min_prolog_async_tmpl_bookE_crit(); +extern void ppc_exc_min_prolog_sync_tmpl_bookE_crit(); +extern void ppc_exc_min_prolog_sync_tmpl_e500_mchk(); +extern void ppc_exc_min_prolog_async_tmpl_e500_mchk(); + +/* Special prologue for handling register shadowing on 603-style CPUs */ +extern void ppc_exc_tgpr_clr_prolog(); +/* Classic prologue which determines the vector dynamically from + * the offset address. This must only be used for classic, synchronous + * exceptions with a vector offset aligned on a 256-byte boundary. + */ +extern void ppc_exc_min_prolog_auto(); + + +/* CPU support may store the address of a function here + * that can be used by the default exception handler to + * obtain fault-address info which is helpful. Unfortunately, + * the SPR holding this information is not uniform + * across PPC families so we need assistance from + * CPU support + */ +extern uint32_t (*ppc_exc_get_DAR)(); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_hdl.c b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_hdl.c new file mode 100644 index 0000000000..fbdcd9aa42 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_hdl.c @@ -0,0 +1,172 @@ +/* PowerPC exception handling middleware; consult README for more + * information. + * + * Author: Till Straumann <strauman@slac.stanford.edu>, 2007 + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#include <stdint.h> +#include <string.h> + +#include <rtems.h> +#include <rtems/score/cpu.h> +#include <libcpu/raw_exception.h> +#include <libcpu/spr.h> +#include <rtems/score/apiext.h> + +#include "vectors.h" +#include "ppc_exc_bspsupp.h" + +/* offset into min-prolog where vector # is hardcoded */ +#define PPC_EXC_PROLOG_VEC_OFFSET 2 + +/* Provide temp. storage space for a few registers. + * This is used by the assembly code prior to setting up + * the stack. + * One set is needed for each exception type with its + * own SRR0/SRR1 pair since such exceptions may nest. + * + * NOTE: The assembly code needs these variables to + * be in the .sdata section and accesses them + * via R13. + */ +uint32_t ppc_exc_lock_std = 0; +uint32_t ppc_exc_lock_crit = 0; +uint32_t ppc_exc_lock_mchk = 0; + +uint32_t ppc_exc_gpr3_std = 0; +uint32_t ppc_exc_gpr3_crit = 0; +uint32_t ppc_exc_gpr3_mchk = 0; + +uint32_t ppc_exc_msr_irq_mask = MSR_EE; + +/* MSR bits to enable once critical status info is saved and the stack + * is switched; must be set depending on CPU type + * + * Default is set here for classic PPC CPUs with a MMU + * but is overridden from vectors_init.c + */ +uint32_t ppc_exc_msr_bits = MSR_IR | MSR_DR | MSR_RI; + + +/* Table of C-handlers */ +static ppc_exc_handler_t ppc_exc_handlers[LAST_VALID_EXC + 1] = {0, }; + +ppc_exc_handler_t +ppc_exc_get_handler(unsigned vector) +{ + if ( vector > LAST_VALID_EXC ) + return 0; + return ppc_exc_handlers[vector]; +} + +int +ppc_exc_set_handler(unsigned vector, ppc_exc_handler_t hdl) +{ + if ( vector > LAST_VALID_EXC ) + return -1; + ppc_exc_handlers[vector] = hdl; + return 0; +} + +/* This routine executes on the interrupt stack (if vect < 0) */ +int +ppc_exc_C_wrapper(int vect, BSP_Exception_frame *f) +{ +int i = vect & 0x3f; +int rval = 1; + + if ( i <= LAST_VALID_EXC && ppc_exc_handlers[i] ) { + rval = ppc_exc_handlers[i](f, i); + } + + if ( rval ) { + /* not handled, so far ... */ + if ( globalExceptHdl ) { + /* + * global handler must be prepared to + * deal with asynchronous exceptions! + */ + globalExceptHdl(f); + } + rval = 0; + } + + return rval; +} + +void +ppc_exc_wrapup(int ll_rval, BSP_Exception_frame *f) +{ + /* Check if we need to run the global handler now */ + if ( ll_rval ) { + /* We get here if ppc_exc_C_wrapper() returned nonzero. + * This could be useful if we need to do something + * with thread-dispatching enabled (at this point it is) + * after handling an asynchronous exception. + */ + } + /* dispatch_disable level is decremented from assembly code. */ + if ( _Context_Switch_necessary ) + _Thread_Dispatch(); + else if ( _ISR_Signals_to_thread_executing ) { + _ISR_Signals_to_thread_executing = 0; + /* + * Process pending signals that have not already been + * processed by _Thread_Dispatch. This happens quite + * unfrequently : the ISR must have posted an action + * to the current running thread. + */ + if ( _Thread_Do_post_task_switch_extension || + _Thread_Executing->do_post_task_switch_extension ) { + _Thread_Executing->do_post_task_switch_extension = FALSE; + _API_extensions_Run_postswitch(); + } + } +} + +void +ppc_exc_min_prolog_expand(ppc_exc_min_prolog_t buf, ppc_exc_min_prolog_template_t templ, uint16_t vec) +{ + memcpy(&buf[0], templ, sizeof(ppc_exc_min_prolog_t)); + /* fixup the vector */ + buf[PPC_EXC_PROLOG_VEC_OFFSET] = (buf[PPC_EXC_PROLOG_VEC_OFFSET] & 0xffff8000) | (vec & 0x7fff); +} + +#undef TESTING +#ifdef TESTING + +static void noop(const struct __rtems_raw_except_connect_data__*x) {} + +rtems_raw_except_connect_data exc_conn = { + exceptIndex: ASM_SYS_VECTOR, + hdl : { + vector: ASM_SYS_VECTOR, + raw_hdl: 0, + raw_hdl_size: 0 + }, + on : noop, + off : noop, + isOn : 0 /* never used AFAIK */ +}; + +void +ppc_exc_raise() +{ + asm volatile("li 3, 0xffffdead; sc"); +} + + +int +exc_conn_do() +{ + exc_conn.hdl.raw_hdl = ppc_exc_min_prolog_auto; + exc_conn.hdl.raw_hdl_size = 16; + return ppc_set_exception(&exc_conn); +} +#endif diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_test.c b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_test.c new file mode 100644 index 0000000000..600b23b10a --- /dev/null +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_test.c @@ -0,0 +1,237 @@ +/* + * Test low-level exception handling code: + * + * - hook an exception handler + * - clobber (almost) all registers with a known value + * - raise exception + * - from exception handler, increment all saved register + * contents by one (to ensure registers are not only + * saved properly but also restored properly). + * - resume execution + * - verify registers are now 'clobber_value + 1' + * + * NOTE: cannot be used on PSIM because SYS exception is used + * internally by simulator (but we could use a trap or + * something else). + * + * Author: Till Straumann <strauman@slac.stanford.edu>, 2007 + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + + +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "vectors.h" +#include "ppc_exc_bspsupp.h" + + +typedef struct regs_ { + uint32_t cr, xer, lr, ctr; + uint32_t gpr0; + uint32_t gpr1; + uint32_t gpr2; + uint32_t gpr3; + uint32_t gpr4; + uint32_t gpr5; + uint32_t gpr6; + uint32_t gpr7; + uint32_t gpr8; + uint32_t gpr9; + uint32_t gpr10; + uint32_t gpr11; + uint32_t gpr12; + uint32_t gpr13; + uint32_t gpr14; + uint32_t gpr15; + uint32_t gpr16; + uint32_t gpr17; + uint32_t gpr18; + uint32_t gpr19; + uint32_t gpr20; + uint32_t gpr21; + uint32_t gpr22; + uint32_t gpr23; + uint32_t gpr24; + uint32_t gpr25; + uint32_t gpr26; + uint32_t gpr27; + uint32_t gpr28; + uint32_t gpr29; + uint32_t gpr30; + uint32_t gpr31; +} ppc_exc_int_regs; + +#define OFF(x) (uintptr_t)(&((ppc_exc_int_regs*)0)->x) + +void +storegs(ppc_exc_int_regs *p0, ppc_exc_int_regs *p1) +{ + asm volatile( + " stmw 0, %6(%0) ;" + " mfcr 0 ;" + " stw 0, %2(%0) ;" + " mflr 0 ;" + " stw 0, %3(%0) ;" + " mfxer 0 ;" + " stw 0, %4(%0) ;" + " mfctr 0 ;" + " stw 0, %5(%0) ;" + " lwz 0, %6(%0) ;" + " sc ;" + " stmw 0, %6(%1) ;" + " mfcr 0 ;" + " stw 0, %2(%1) ;" + " mflr 0 ;" + " stw 0, %3(%1) ;" + " mfxer 0 ;" + " stw 0, %4(%1) ;" + " mfctr 0 ;" + " stw 0, %5(%1) ;" + : + :"b"(p0),"b"(p1), + "i"(OFF(cr)), "i"(OFF(lr)), "i"(OFF(xer)), "i"(OFF(ctr)), + "i"(OFF(gpr0)) + :"r0"); +} + +/* Load up all registers from 'pre' issue system call and store + * registers in 'post' + */ + +ppc_exc_int_regs pre; +ppc_exc_int_regs pst; + +void +clobber() +{ + asm volatile( + " lis 2, pre@h ;" + " ori 2, 2, pre@l ;" + " lwz 3, %0(2) ;" + " mtcr 3 ;" + " lwz 3, %1(2) ;" + " mtlr 3 ;" + " lwz 3, %2(2) ;" + " mtxer 3 ;" + /* don't know which ones stick */ + " mfxer 3 ;" + " stw 3, %2(2) ;" + " lwz 3, %3(2) ;" + " mtctr 3 ;" + " lwz 0, %4(2) ;" + /* must not clobber R13, R1, R2 */ + " stw 13, %6(2) ;" + " lmw 3, %5(2) ;" + " sc ;" + " stmw 0, %4(2) ;" + " mfcr 0 ;" + " stw 0, %0(2) ;" + " mflr 0 ;" + " stw 0, %1(2) ;" + " mfxer 0 ;" + " stw 0, %2(2) ;" + " mfctr 0 ;" + " stw 0, %3(2) ;" + : + :"i"(OFF(cr)), "i"(OFF(lr)), "i"(OFF(xer)), "i"(OFF(ctr)), + "i"(OFF(gpr0)), "i"(OFF(gpr3)), "i"(OFF(gpr13)) + :"r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", + "r10", "r11", "r12", "r14", "r15", "r16", + "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + "xer","lr","ctr", + "cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7", + "memory"); +} + +typedef union { uint32_t u; uint8_t c[4]; } u32_a_t; + +/* exception handler; adds 1 to all register contents (except r1,r2,r13) */ +void +handle_clobber_exc(BSP_Exception_frame *f, int vector) +{ +int i; +u32_a_t *p = (u32_a_t*)&f->GPR0; + for ( i=0; i<32; i++ ) { + switch (i) { + case 1: case 2: case 13: break; + default: + p[i].u++; + break; + } + } + f->GPR2 = (uint32_t)&pst; + f->EXC_CR++; + f->EXC_CTR++; + f->EXC_XER++; + f->EXC_LR++; +} + + +/* This routine tests the raw exception code; + * - hook 'handle_clobber_exc' to SYS exception handler + * - clobber all registers with 0xaffe0000 + <index> + * (except: r1, r2, r13, non-sticky bits in xer) + * R2 is clobbered with the address of the pre area. + * - issue 'sc' -> SYS exception + * - exception handler increments all reg. contents by 1, + * stores address of 'pst' area in R2 and returns control + * to ppc_exc_clobber(). + * - save all register contents to *R2 (should be &pst). + * - test for mismatches (except R1, R2, R13 and parts of xer) + */ +void +ppc_exc_clobber() +{ +u32_a_t *a, *b; + int i; + a = (u32_a_t*)⪯ + b = (u32_a_t*)&pst; + for ( i=0; i< sizeof(pre)/sizeof(uint32_t); i++ ) { + a[i].u = 0xaffe0000 + i; + } + ppc_exc_set_handler(ASM_SYS_VECTOR, handle_clobber_exc); + clobber(); + ppc_exc_set_handler(ASM_SYS_VECTOR, 0); + for ( i=0; i< sizeof(pre)/sizeof(uint32_t); i++ ) { + switch (i) { + case OFF(gpr1)/sizeof(uint32_t): + case OFF(gpr2)/sizeof(uint32_t): + case OFF(gpr13)/sizeof(uint32_t): + break; + + default: + if ( a[i].u != b[i].u - 1 ) { + printf("MISMATCH at %i: 0x%08"PRIx32" -- 0x%08"PRIx32"\n", + i, a[i].u, b[i].u); + } + } + } +} + +#if 0 +void +ppc_exc_test() +{ +ppc_exc_int_regs a, b; +int i; + memset(&a, 0xaa, sizeof(a)); + memset(&b, 0x55, sizeof(b)); + storegs(&a, &b); + if ( memcmp(&a, &b, sizeof(a)) ) { + printf("FAILURE: context prior and after exception don't match!\n"); + } + for ( i=0; i< sizeof(a)/sizeof(uint32_t); i++ ) { + printf("0x%08"PRIx32" -- 0x%08"PRIx32"\n", + ((uint32_t __attribute__((may_alias)) *)&a)[i], + ((uint32_t __attribute__((may_alias)) *)&b)[i]); + } +} +#endif diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/vectors.h b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/vectors.h new file mode 100644 index 0000000000..19039bca38 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/vectors.h @@ -0,0 +1,145 @@ +/* + * vectors.h Exception frame related contant and API. + * + * This include file describe the data structure and the functions implemented + * by rtems to handle exceptions. + * + * CopyRight (C) 1999 valette@crf.canon.fr + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ +#ifndef LIBCPU_POWERPC_BSPSUPP_VECTORS_H +#define LIBCPU_POWERPC_BSPSUPP_VECTORS_H +#include <libcpu/raw_exception.h> + +/* + * The callee (high level exception code written in C) + * will store the Link Registers (return address) at entry r1 + 4 !!!. + * So let room for it!!!. + */ +#define LINK_REGISTER_CALLEE_UPDATE_ROOM 4 +#define SRR0_FRAME_OFFSET 8 +#define SRR1_FRAME_OFFSET 12 +#define EXCEPTION_NUMBER_OFFSET 16 +#define GPR0_OFFSET 20 +#define GPR1_OFFSET 24 +#define GPR2_OFFSET 28 +#define GPR3_OFFSET 32 +#define GPR4_OFFSET 36 +#define GPR5_OFFSET 40 +#define GPR6_OFFSET 44 +#define GPR7_OFFSET 48 +#define GPR8_OFFSET 52 +#define GPR9_OFFSET 56 +#define GPR10_OFFSET 60 +#define GPR11_OFFSET 64 +#define GPR12_OFFSET 68 +#define GPR13_OFFSET 72 +#define GPR14_OFFSET 76 +#define GPR15_OFFSET 80 +#define GPR16_OFFSET 84 +#define GPR17_OFFSET 88 +#define GPR18_OFFSET 92 +#define GPR19_OFFSET 96 +#define GPR20_OFFSET 100 +#define GPR21_OFFSET 104 +#define GPR22_OFFSET 108 +#define GPR23_OFFSET 112 +#define GPR24_OFFSET 116 +#define GPR25_OFFSET 120 +#define GPR26_OFFSET 124 +#define GPR27_OFFSET 128 +#define GPR28_OFFSET 132 +#define GPR29_OFFSET 136 +#define GPR30_OFFSET 140 +#define GPR31_OFFSET 144 +#define EXC_CR_OFFSET 148 +#define EXC_CTR_OFFSET 152 +#define EXC_XER_OFFSET 156 +#define EXC_LR_OFFSET 160 +/* + * maintain the EABI requested 8 bytes aligment + * As SVR4 ABI requires 16, make it 16 (as some + * exception may need more registers to be processed...) + */ +#define EXCEPTION_FRAME_END 176 + +#ifndef ASM + +/* codemove is like memmove, but it also gets the cache line size + * as 4th parameter to synchronize them. If this last parameter is + * zero, it performs more or less like memmove. No copy is performed if + * source and destination addresses are equal. However the caches + * are synchronized. Note that the size is always rounded up to the + * next mutiple of 4. + */ +extern void * codemove(void *, const void *, unsigned int, unsigned long); +extern void exception_nop_enable(const rtems_raw_except_connect_data* ptr); +extern int exception_always_enabled(const rtems_raw_except_connect_data* ptr); +extern void initialize_exceptions(); + +typedef struct _BSP_Exception_frame { + unsigned EXC_SRR0; + unsigned EXC_SRR1; + unsigned _EXC_number; + unsigned GPR0; + unsigned GPR1; + unsigned GPR2; + unsigned GPR3; + unsigned GPR4; + unsigned GPR5; + unsigned GPR6; + unsigned GPR7; + unsigned GPR8; + unsigned GPR9; + unsigned GPR10; + unsigned GPR11; + unsigned GPR12; + unsigned GPR13; + unsigned GPR14; + unsigned GPR15; + unsigned GPR16; + unsigned GPR17; + unsigned GPR18; + unsigned GPR19; + unsigned GPR20; + unsigned GPR21; + unsigned GPR22; + unsigned GPR23; + unsigned GPR24; + unsigned GPR25; + unsigned GPR26; + unsigned GPR27; + unsigned GPR28; + unsigned GPR29; + unsigned GPR30; + unsigned GPR31; + unsigned EXC_CR; + unsigned EXC_CTR; + unsigned EXC_XER; + unsigned EXC_LR; + unsigned EXC_MSR; + unsigned EXC_DAR; +} BSP_Exception_frame; + +typedef void (*exception_handler_t) (BSP_Exception_frame* excPtr); +extern exception_handler_t globalExceptHdl; +/* + * Compatibility with pc386 + */ +typedef BSP_Exception_frame CPU_Exception_frame; +typedef exception_handler_t cpuExcHandlerType; + +/* + * dummy functions for exception interface + */ +void exception_nop_enable(const rtems_raw_except_connect_data* ptr); +int exception_always_enabled(const rtems_raw_except_connect_data* ptr); + +#endif /* ASM */ + +#endif /* LIBCPU_POWERPC_BSPSUPP_VECTORS_H */ diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/vectors_init.c b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/vectors_init.c new file mode 100644 index 0000000000..ada2a3c8c9 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/vectors_init.c @@ -0,0 +1,358 @@ +/* + * vectors_init.c Exception hanlding initialisation (and generic handler). + * + * This include file describe the data structure and the functions implemented + * by rtems to handle exceptions. + * + * CopyRight (C) 1999 valette@crf.canon.fr + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ +#include <rtems.h> +#include <rtems/bspIo.h> +#include <rtems/error.h> + +#include <libcpu/raw_exception.h> +#include <libcpu/spr.h> +#include <libcpu/cpuIdent.h> + +#include "vectors.h" +#include "ppc_exc_bspsupp.h" + +static rtems_raw_except_global_settings exception_config; +static rtems_raw_except_connect_data exception_table[LAST_VALID_EXC + 1]; + +#if 0 +typedef struct ppc_exc_connect_data_ { + rtems_raw_except_connect_data raw; + ppc_exc_handler_t c_hdl; +} ppc_exc_connect_data; +#endif + +exception_handler_t globalExceptHdl; + +/* T. Straumann: provide a stack trace + * <strauman@slac.stanford.edu>, 6/26/2001 + */ +typedef struct LRFrameRec_ { + struct LRFrameRec_ *frameLink; + unsigned long *lr; +} LRFrameRec, *LRFrame; + +#define STACK_CLAMP 50 /* in case we have a corrupted bottom */ + +SPR_RO(LR) +SPR_RO(DAR) +#define DEAR_BOOKE 61 +#define DEAR_405 0x3d5 +SPR_RO(DEAR_BOOKE) +SPR_RO(DEAR_405) + +uint32_t ppc_exc_get_DAR_dflt() +{ + if ( ppc_cpu_is_60x() ) + return _read_DAR(); + else switch ( ppc_cpu_is_bookE() ) { + default: break; + case PPC_BOOKE_STD: + case PPC_BOOKE_E500: + return _read_DEAR_BOOKE(); + case PPC_BOOKE_405: + return _read_DEAR_405(); + } + return 0xdeadbeef; +} + +uint32_t (*ppc_exc_get_DAR)() = ppc_exc_get_DAR_dflt; + +void +BSP_printStackTrace(BSP_Exception_frame* excPtr) +{ +LRFrame f; +int i; +LRFrame sp; +void *lr; + + printk("Stack Trace: \n "); + if (excPtr) { + printk("IP: 0x%08x, ",excPtr->EXC_SRR0); + sp=(LRFrame)excPtr->GPR1; + lr=(void*)excPtr->EXC_LR; + } else { + /* there's no macro for this */ + __asm__ __volatile__("mr %0, 1":"=r"(sp)); + lr=(LRFrame)_read_LR(); + } + printk("LR: 0x%08x\n",lr); + { + uint32_t *x = (uint32_t*)sp; + uint32_t top; + asm volatile("mfspr %0, %1":"=r"(top):"i"(SPRG1)); + printk("TOS: 0x%08x\n",top); + while ( x < (uint32_t*)sp->frameLink ) { + printk(" 0x%08x\n",*x++); + } + } + for (f=(LRFrame)sp, i=0; f->frameLink && i<STACK_CLAMP; f=f->frameLink) { + printk("--^ 0x%08x", (long)(f->frameLink->lr)); + if (!(++i%5)) + printk("\n"); + } + if (i>=STACK_CLAMP) { + printk("Too many stack frames (stack possibly corrupted), giving up...\n"); + } else { + if (i%5) + printk("\n"); + } +} + +void C_exception_handler(BSP_Exception_frame* excPtr) +{ + int recoverable = 0; + int synch = (int)excPtr->_EXC_number >= 0 ; + + printk("Exception handler called for exception %d\n", excPtr->_EXC_number & 0x7fff); + printk("\t Next PC or Address of fault = %x\n", excPtr->EXC_SRR0); + printk("\t Saved MSR = %x\n", excPtr->EXC_SRR1); + printk("\t R0 = %08x", excPtr->GPR0); + if ( synch ) { + printk(" R1 = %08x", excPtr->GPR1); + printk(" R2 = %08x", excPtr->GPR2); + } else { + printk(" "); + printk(" "); + } + printk(" R3 = %08x\n", excPtr->GPR3); + printk("\t R4 = %08x", excPtr->GPR4); + printk(" R5 = %08x", excPtr->GPR5); + printk(" R6 = %08x", excPtr->GPR6); + printk(" R7 = %08x\n", excPtr->GPR7); + printk("\t R8 = %08x", excPtr->GPR8); + printk(" R9 = %08x", excPtr->GPR9); + printk(" R10 = %08x", excPtr->GPR10); + printk(" R11 = %08x\n", excPtr->GPR11); + printk("\t R12 = %08x", excPtr->GPR12); + if ( synch ) { + printk(" R13 = %08x", excPtr->GPR13); + printk(" R14 = %08x", excPtr->GPR14); + printk(" R15 = %08x\n", excPtr->GPR15); + printk("\t R16 = %08x", excPtr->GPR16); + printk(" R17 = %08x", excPtr->GPR17); + printk(" R18 = %08x", excPtr->GPR18); + printk(" R19 = %08x\n", excPtr->GPR19); + printk("\t R20 = %08x", excPtr->GPR20); + printk(" R21 = %08x", excPtr->GPR21); + printk(" R22 = %08x", excPtr->GPR22); + printk(" R23 = %08x\n", excPtr->GPR23); + printk("\t R24 = %08x", excPtr->GPR24); + printk(" R25 = %08x", excPtr->GPR25); + printk(" R26 = %08x", excPtr->GPR26); + printk(" R27 = %08x\n", excPtr->GPR27); + printk("\t R28 = %08x", excPtr->GPR28); + printk(" R29 = %08x", excPtr->GPR29); + printk(" R30 = %08x", excPtr->GPR30); + printk(" R31 = %08x\n", excPtr->GPR31); + } else { + printk("\n"); + } + printk("\t CR = %08x\n", excPtr->EXC_CR); + printk("\t CTR = %08x\n", excPtr->EXC_CTR); + printk("\t XER = %08x\n", excPtr->EXC_XER); + printk("\t LR = %08x\n", excPtr->EXC_LR); + + /* Would be great to print DAR but unfortunately, + * that is not portable across different CPUs. + * AFAIK on classic PPC DAR is SPR 19, on the + * 405 we have DEAR = SPR 0x3d5 and booE says + * DEAR = SPR 61 :-( + */ + if ( ppc_exc_get_DAR ) { + printk("\t DAR = %08x\n", ppc_exc_get_DAR()); + } + + BSP_printStackTrace(excPtr); + + if (excPtr->_EXC_number == ASM_DEC_VECTOR) + recoverable = 1; + if (excPtr->_EXC_number == ASM_SYS_VECTOR) +#ifdef TEST_RAW_EXCEPTION_CODE + recoverable = 1; +#else + recoverable = 0; +#endif + if (!recoverable) { + printk("unrecoverable exception!!! Push reset button\n"); + while(1); + } +} + +/*********************************************************** + * dummy functions for on/off/isOn calls + * these functions just do nothing fulfill the semantic + * requirements to enable/disable a certain exception + */ +void exception_nop_enable(const rtems_raw_except_connect_data* ptr) +{ +} + +int exception_always_enabled(const rtems_raw_except_connect_data* ptr) +{ + return 1; +} + +/* Raw exception framework wants to keep a pointer to + * the prologue so we must keep the ones we generate + * from templates around... + */ +#define NUM_PROLOG 8 /* just a reasonable limit */ +static int n_prolog = 0; +static ppc_exc_min_prolog_t prologues[NUM_PROLOG]; + +static ppc_exc_min_prolog_template_t prolog_templates[][2] = { + [ PPC_EXC_CLASSIC ] = + { + ppc_exc_min_prolog_sync_tmpl_std, + ppc_exc_min_prolog_async_tmpl_std, + }, + [ PPC_EXC_405_CRITICAL ] = + { + ppc_exc_min_prolog_sync_tmpl_p405_crit, + ppc_exc_min_prolog_async_tmpl_p405_crit, + }, + [ PPC_EXC_BOOKE_CRITICAL ] = + { + ppc_exc_min_prolog_sync_tmpl_bookE_crit, + ppc_exc_min_prolog_async_tmpl_bookE_crit, + }, + [ PPC_EXC_E500_MACHCHK ] = + { + ppc_exc_min_prolog_sync_tmpl_e500_mchk, + ppc_exc_min_prolog_async_tmpl_e500_mchk, + }, +}; + +static rtems_raw_except_func +make_prologue(int vector, ppc_raw_exception_category cat) +{ +int async = (cat & PPC_EXC_ASYNC) ? 1 : 0 ; +ppc_exc_min_prolog_template_t tmpl; + + cat &= ~PPC_EXC_ASYNC; + + if ( n_prolog >= NUM_PROLOG ) { + rtems_panic("Not enough exception prologue slots; increase NUM_PROLOG (%s)\n",__FILE__); + } + + if ( ! (tmpl = prolog_templates[cat][async]) ) { + rtems_panic("No exception prologue template for category 0x%02x found\n", cat); + } + + ppc_exc_min_prolog_expand(prologues[n_prolog], tmpl, vector); + + return (rtems_raw_except_func)prologues[n_prolog++]; +} + +void ppc_exc_init( + rtems_raw_except_connect_data *exception_table, + int nEntries) +{ +int i,v; +ppc_raw_exception_category cat; +uintptr_t vaddr; + + /* + * Initialize pointer used by low level execption handling + */ + globalExceptHdl = C_exception_handler; + /* + * Put default_exception_vector_code_prolog at relevant exception + * code entry addresses + */ + exception_config.exceptSize = nEntries; + exception_config.rawExceptHdlTbl = exception_table; + exception_config.defaultRawEntry.exceptIndex = 0; + exception_config.defaultRawEntry.hdl.vector = 0; + /* Note that the 'auto' handler cannot be used for everything; in particular, + * it assumes classic exceptions with a vector offset aligned on a 256-byte + * boundary. + */ + exception_config.defaultRawEntry.hdl.raw_hdl = ppc_exc_min_prolog_auto; + + /* + * Note that the cast of an array address to an unsigned + * is not a bug as it is defined by a .set directly in asm... + */ + exception_config.defaultRawEntry.hdl.raw_hdl_size = (unsigned)ppc_exc_min_prolog_size; + + for (i=0; i < exception_config.exceptSize; i++) { + + if ( PPC_EXC_INVALID == (cat = ppc_vector_is_valid ((v=exception_table[i].hdl.vector))) ) { + continue; + } + + exception_table[i].exceptIndex = i; + exception_table[v].hdl.raw_hdl_size = (unsigned)ppc_exc_min_prolog_size; + + /* special cases */ + if ( ppc_cpu_has_shadowed_gprs() + && ( ASM_60X_IMISS_VECTOR == v + || ASM_60X_DLMISS_VECTOR == v + || ASM_60X_DSMISS_VECTOR == v ) ) { + exception_table[i].hdl.raw_hdl = ppc_exc_tgpr_clr_prolog; + exception_table[i].hdl.raw_hdl_size = (unsigned)ppc_exc_tgpr_clr_prolog_size; + } else { + + vaddr = (uintptr_t)ppc_get_vector_addr( v ); + + /* + * default prolog can handle classic, synchronous exceptions + * with a vector offset aligned on a 256-byte boundary. + */ + if ( PPC_EXC_CLASSIC == cat && 0 == ( vaddr & 0xff ) ) { + exception_table[i].hdl.raw_hdl_size = exception_config.defaultRawEntry.hdl.raw_hdl_size; + exception_table[i].hdl.raw_hdl = exception_config.defaultRawEntry.hdl.raw_hdl; + } else { + exception_table[i].hdl.raw_hdl_size = (unsigned)ppc_exc_min_prolog_size; + exception_table[i].hdl.raw_hdl = make_prologue( v, cat ); + } + + } + exception_table[i].on = exception_nop_enable; + exception_table[i].off = exception_nop_enable; + exception_table[i].isOn = exception_always_enabled; + } + if (!ppc_init_exceptions(&exception_config)) { + BSP_panic("Exception handling initialization failed\n"); + } +#ifdef RTEMS_DEBUG + else { + printk("Exception handling initialization done\n"); + } +#endif +} + +void initialize_exceptions() +{ +int i; +int n = sizeof(exception_table)/sizeof(exception_table[0]); + + /* Use current MMU / RI settings when running C exception handlers */ + ppc_exc_msr_bits = _read_MSR() & ( MSR_DR | MSR_IR | MSR_RI ); + + /* Copy into a SDA variable that is easy to access from + * assembly code + */ + if ( ppc_cpu_is_bookE() ) { + ppc_exc_msr_irq_mask = MSR_EE | MSR_CE | MSR_DE ; + } else { + ppc_exc_msr_irq_mask = MSR_EE ; + } + + for ( i=0; i<n; i++ ) + exception_table[i].hdl.vector = i; + ppc_exc_init(exception_table, n); +} |