mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-05 23:23:13 +00:00
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).
This commit is contained in:
@@ -1,3 +1,18 @@
|
|||||||
|
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>
|
2007-12-08 Till Straumann <strauman@slac.stanford.edu>
|
||||||
|
|
||||||
* new-exceptions/e500_raw_exc_init.c, new-exceptions/raw_exception.c,
|
* new-exceptions/e500_raw_exc_init.c, new-exceptions/raw_exception.c,
|
||||||
|
|||||||
374
c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/irq.c
Normal file
374
c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/irq.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
368
c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc.S
Normal file
368
c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc.S
Normal file
@@ -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 = .
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
172
c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_hdl.c
Normal file
172
c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_hdl.c
Normal file
@@ -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
|
||||||
@@ -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
|
||||||
145
c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/vectors.h
Normal file
145
c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/vectors.h
Normal file
@@ -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 */
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user