forked from Imagelibrary/rtems
237 lines
7.0 KiB
C
237 lines
7.0 KiB
C
/**
|
|
* @file
|
|
*
|
|
* @ingroup ppc_exc
|
|
*
|
|
* @brief PowerPC Exceptions implementation.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 1999 Eric Valette (valette@crf.canon.fr)
|
|
* Canon Centre Recherche France.
|
|
*
|
|
* Derived from file "libcpu/powerpc/new-exceptions/bspsupport/vectors_init.c".
|
|
*
|
|
* The license and distribution terms for this file may be
|
|
* found in the file LICENSE in this distribution or at
|
|
* http://www.rtems.org/license/LICENSE.
|
|
*/
|
|
|
|
#include <bsp/vectors.h>
|
|
|
|
#include <rtems/score/threaddispatch.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#ifndef __SPE__
|
|
#define GET_GPR(gpr) (gpr)
|
|
#else
|
|
#define GET_GPR(gpr) ((uintptr_t) ((gpr) >> 32))
|
|
#endif
|
|
|
|
/* 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 */
|
|
|
|
static uint32_t ppc_exc_get_DAR_dflt(void)
|
|
{
|
|
if (ppc_cpu_is_60x())
|
|
return PPC_SPECIAL_PURPOSE_REGISTER(PPC_DAR);
|
|
else
|
|
switch (ppc_cpu_is_bookE()) {
|
|
default:
|
|
break;
|
|
case PPC_BOOKE_STD:
|
|
case PPC_BOOKE_E500:
|
|
return PPC_SPECIAL_PURPOSE_REGISTER(BOOKE_DEAR);
|
|
case PPC_BOOKE_405:
|
|
return PPC_SPECIAL_PURPOSE_REGISTER(PPC405_DEAR);
|
|
}
|
|
return 0xdeadbeef;
|
|
}
|
|
|
|
uint32_t (*ppc_exc_get_DAR)(void) = ppc_exc_get_DAR_dflt;
|
|
|
|
void BSP_printStackTrace(const BSP_Exception_frame *excPtr)
|
|
{
|
|
LRFrame f;
|
|
int i;
|
|
LRFrame sp;
|
|
void *lr;
|
|
|
|
printk("Stack Trace: \n ");
|
|
if (excPtr) {
|
|
printk("IP: 0x%08" PRIxPTR ", ", excPtr->EXC_SRR0);
|
|
sp = (LRFrame) GET_GPR(excPtr->GPR1);
|
|
lr = (void *) excPtr->EXC_LR;
|
|
} else {
|
|
/* there's no macro for this */
|
|
__asm__ __volatile__("mr %0, 1":"=r"(sp));
|
|
lr = (LRFrame) ppc_link_register();
|
|
}
|
|
printk("LR: 0x%08" PRIxPTR "\n", (uintptr_t) lr);
|
|
for (f = (LRFrame) sp, i = 0; f->frameLink && i < STACK_CLAMP; f = f->frameLink) {
|
|
printk("--^ 0x%08" PRIxPTR "", (uintptr_t) (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 _CPU_Exception_frame_print(const CPU_Exception_frame *excPtr)
|
|
{
|
|
const Thread_Control *executing = _Thread_Executing;
|
|
bool synch = (int) excPtr->_EXC_number >= 0;
|
|
unsigned n = excPtr->_EXC_number & 0x7fff;
|
|
|
|
printk("exception vector %d (0x%x)\n", n, n);
|
|
printk(" next PC or address of fault = 0x%08" PRIxPTR "\n", excPtr->EXC_SRR0);
|
|
printk(" saved MSR = 0x%08" PRIxPTR "\n", excPtr->EXC_SRR1);
|
|
|
|
/* Try to find out more about the context where this happened */
|
|
printk(
|
|
" context = %s, ISR nest level = %" PRIu32 "\n",
|
|
_ISR_Nest_level == 0 ? "task" : "interrupt",
|
|
_ISR_Nest_level
|
|
);
|
|
printk(
|
|
" thread dispatch disable level = %" PRIu32 "\n",
|
|
_Thread_Dispatch_disable_level
|
|
);
|
|
|
|
/* Dump registers */
|
|
|
|
printk(" R0 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR0));
|
|
if (synch) {
|
|
printk(" R1 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR1));
|
|
printk(" R2 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR2));
|
|
} else {
|
|
printk(" ");
|
|
printk(" ");
|
|
}
|
|
printk(" R3 = 0x%08" PRIxPTR "\n", GET_GPR(excPtr->GPR3));
|
|
printk(" R4 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR4));
|
|
printk(" R5 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR5));
|
|
printk(" R6 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR6));
|
|
printk(" R7 = 0x%08" PRIxPTR "\n", GET_GPR(excPtr->GPR7));
|
|
printk(" R8 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR8));
|
|
printk(" R9 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR9));
|
|
printk(" R10 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR10));
|
|
printk(" R11 = 0x%08" PRIxPTR "\n", GET_GPR(excPtr->GPR11));
|
|
printk(" R12 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR12));
|
|
if (synch) {
|
|
printk(" R13 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR13));
|
|
printk(" R14 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR14));
|
|
printk(" R15 = 0x%08" PRIxPTR "\n", GET_GPR(excPtr->GPR15));
|
|
printk(" R16 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR16));
|
|
printk(" R17 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR17));
|
|
printk(" R18 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR18));
|
|
printk(" R19 = 0x%08" PRIxPTR "\n", GET_GPR(excPtr->GPR19));
|
|
printk(" R20 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR20));
|
|
printk(" R21 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR21));
|
|
printk(" R22 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR22));
|
|
printk(" R23 = 0x%08" PRIxPTR "\n", GET_GPR(excPtr->GPR23));
|
|
printk(" R24 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR24));
|
|
printk(" R25 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR25));
|
|
printk(" R26 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR26));
|
|
printk(" R27 = 0x%08" PRIxPTR "\n", GET_GPR(excPtr->GPR27));
|
|
printk(" R28 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR28));
|
|
printk(" R29 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR29));
|
|
printk(" R30 = 0x%08" PRIxPTR "", GET_GPR(excPtr->GPR30));
|
|
printk(" R31 = 0x%08" PRIxPTR "\n", GET_GPR(excPtr->GPR31));
|
|
} else {
|
|
printk("\n");
|
|
}
|
|
printk(" CR = 0x%08" PRIx32 "\n", excPtr->EXC_CR);
|
|
printk(" CTR = 0x%08" PRIxPTR "\n", excPtr->EXC_CTR);
|
|
printk(" XER = 0x%08" PRIx32 "\n", excPtr->EXC_XER);
|
|
printk(" LR = 0x%08" PRIxPTR "\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 bookE says
|
|
* DEAR = SPR 61 :-(
|
|
*/
|
|
if (ppc_exc_get_DAR != NULL) {
|
|
char* reg = ppc_cpu_is_60x() ? " DAR" : "DEAR";
|
|
printk(" %s = 0x%08" PRIx32 "\n", reg, ppc_exc_get_DAR());
|
|
}
|
|
if (ppc_cpu_is_bookE()) {
|
|
unsigned esr, mcsr;
|
|
if (ppc_cpu_is_bookE() == PPC_BOOKE_405) {
|
|
esr = PPC_SPECIAL_PURPOSE_REGISTER(PPC405_ESR);
|
|
mcsr = PPC_SPECIAL_PURPOSE_REGISTER(PPC405_MCSR);
|
|
} else {
|
|
esr = PPC_SPECIAL_PURPOSE_REGISTER(BOOKE_ESR);
|
|
mcsr = PPC_SPECIAL_PURPOSE_REGISTER(BOOKE_MCSR);
|
|
}
|
|
printk(" ESR = 0x%08x\n", esr);
|
|
printk(" MCSR = 0x%08x\n", mcsr);
|
|
}
|
|
|
|
#ifdef PPC_MULTILIB_ALTIVEC
|
|
{
|
|
unsigned char *v = (unsigned char *) &excPtr->V0;
|
|
int i;
|
|
int j;
|
|
|
|
printk(" VSCR = 0x%08" PRIx32 "\n", excPtr->VSCR);
|
|
printk("VRSAVE = 0x%08" PRIx32 "\n", excPtr->VRSAVE);
|
|
|
|
for (i = 0; i < 32; ++i) {
|
|
printk(" V%02i = 0x", i);
|
|
|
|
for (j = 0; j < 16; ++j) {
|
|
printk("%02x", v[j]);
|
|
}
|
|
|
|
printk("\n");
|
|
|
|
v += 16;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef PPC_MULTILIB_FPU
|
|
{
|
|
uint64_t *f = (uint64_t *) &excPtr->F0;
|
|
int i;
|
|
|
|
printk("FPSCR = 0x%08" PRIu64 "\n", excPtr->FPSCR);
|
|
|
|
for (i = 0; i < 32; ++i) {
|
|
printk(" F%02i = 0x%016" PRIu64 "\n", i, f[i]);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (executing != NULL) {
|
|
const char *name = (const char *) &executing->Object.name;
|
|
|
|
printk(
|
|
" executing thread ID = 0x%08" PRIx32 ", name = %c%c%c%c\n",
|
|
executing->Object.id,
|
|
name [0],
|
|
name [1],
|
|
name [2],
|
|
name [3]
|
|
);
|
|
} else {
|
|
printk(" executing thread pointer is NULL");
|
|
}
|
|
|
|
BSP_printStackTrace(excPtr);
|
|
}
|