summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTill Straumann <strauman@slac.stanford.edu>2007-12-08 23:43:24 +0000
committerTill Straumann <strauman@slac.stanford.edu>2007-12-08 23:43:24 +0000
commit94e1931c5b8ce7e34c4293efbb8dcc106a532ac9 (patch)
tree3723b8eeed0bb1cdf8905c4ba89a8b25720243da
parent2007-12-08 Till Straumann <strauman@slac.stanford.edu> (diff)
downloadrtems-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).
-rw-r--r--c/src/lib/libcpu/powerpc/ChangeLog15
-rw-r--r--c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/irq.c374
-rw-r--r--c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/nested_irq_test.c107
-rw-r--r--c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc.S368
-rw-r--r--c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_asm_macros.h278
-rw-r--r--c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_bspsupp.h128
-rw-r--r--c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_hdl.c172
-rw-r--r--c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_test.c237
-rw-r--r--c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/vectors.h145
-rw-r--r--c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/vectors_init.c358
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*)&pre;
+ 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);
+}