forked from Imagelibrary/rtems
add new files for exception handler
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup powerpc_shared
|
||||
*
|
||||
* @brief Code copy implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009
|
||||
* embedded brains GmbH
|
||||
* Obere Lagerstr. 30
|
||||
* D-82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.com/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <rtems.h>
|
||||
|
||||
#include <libcpu/powerpc-utility.h>
|
||||
|
||||
void ppc_code_copy(void *dest, const void *src, size_t n)
|
||||
{
|
||||
if (memcmp(dest, src, n) != 0) {
|
||||
memcpy(dest, src, n);
|
||||
|
||||
rtems_cache_flush_multiple_data_lines(dest, n);
|
||||
ppc_synchronize_data();
|
||||
|
||||
rtems_cache_invalidate_multiple_instruction_lines(dest, n);
|
||||
ppc_synchronize_instructions();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup ppc_exc
|
||||
*
|
||||
* @brief PowerPC Exceptions implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1999 Eric Valette (valette@crf.canon.fr)
|
||||
* Canon Centre Recherche France.
|
||||
*
|
||||
* Copyright (C) 2009 embedded brains GmbH.
|
||||
*
|
||||
* Enhanced by Jay Kulpinski <jskulpin@eng01.gdds.com>
|
||||
* to support 603, 603e, 604, 604e exceptions
|
||||
*
|
||||
* Moved to "libcpu/powerpc/new-exceptions" and consolidated
|
||||
* by Thomas Doerfler <Thomas.Doerfler@embedded-brains.de>
|
||||
* to be common for all PPCs with new exceptions.
|
||||
*
|
||||
* Derived from file "libcpu/powerpc/new-exceptions/raw_exception.c".
|
||||
*
|
||||
* 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 <bsp/vectors.h>
|
||||
|
||||
bool bsp_exceptions_in_RAM = true;
|
||||
|
||||
uint32_t ppc_exc_vector_base = 0;
|
||||
|
||||
void *ppc_exc_vector_address(unsigned vector)
|
||||
{
|
||||
uintptr_t vector_base = 0xfff00000;
|
||||
uintptr_t vector_offset = vector << 8;
|
||||
|
||||
if (ppc_cpu_has_altivec()) {
|
||||
if (vector == ASM_60X_VEC_VECTOR) {
|
||||
vector_offset = ASM_60X_VEC_VECTOR_OFFSET;
|
||||
}
|
||||
}
|
||||
|
||||
if (ppc_cpu_is(PPC_405)) {
|
||||
switch (vector) {
|
||||
case ASM_BOOKE_FIT_VECTOR:
|
||||
vector_offset = ASM_PPC405_FIT_VECTOR_OFFSET;
|
||||
break;
|
||||
case ASM_BOOKE_WDOG_VECTOR:
|
||||
vector_offset = ASM_PPC405_WDOG_VECTOR_OFFSET;
|
||||
break;
|
||||
case ASM_TRACE_VECTOR:
|
||||
vector_offset = ASM_PPC405_TRACE_VECTOR_OFFSET;
|
||||
break;
|
||||
case ASM_PPC405_APU_UNAVAIL_VECTOR:
|
||||
vector_offset = ASM_60X_VEC_VECTOR_OFFSET;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ppc_cpu_has_ivpr_and_ivor()) {
|
||||
vector_offset >>= 4;
|
||||
}
|
||||
|
||||
if (bsp_exceptions_in_RAM) {
|
||||
vector_base = ppc_exc_vector_base;
|
||||
}
|
||||
|
||||
return (void *) (vector_base + vector_offset);
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup ppc_exc
|
||||
*
|
||||
* @brief PowerPC Exceptions implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1999 Eric Valette (valette@crf.canon.fr)
|
||||
* Canon Centre Recherche France.
|
||||
*
|
||||
* Copyright (C) 2009 embedded brains GmbH.
|
||||
*
|
||||
* Enhanced by Jay Kulpinski <jskulpin@eng01.gdds.com>
|
||||
* to support 603, 603e, 604, 604e exceptions
|
||||
*
|
||||
* Moved to "libcpu/powerpc/new-exceptions" and consolidated
|
||||
* by Thomas Doerfler <Thomas.Doerfler@embedded-brains.de>
|
||||
* to be common for all PPCs with new exceptions.
|
||||
*
|
||||
* Derived from file "libcpu/powerpc/new-exceptions/raw_exception.c".
|
||||
*
|
||||
* 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 <bsp/vectors.h>
|
||||
|
||||
#define PPC_BASIC_VECS \
|
||||
[ASM_RESET_VECTOR] = PPC_EXC_CLASSIC, \
|
||||
[ASM_MACH_VECTOR] = PPC_EXC_CLASSIC, \
|
||||
[ASM_PROT_VECTOR] = PPC_EXC_CLASSIC, \
|
||||
[ASM_ISI_VECTOR] = PPC_EXC_CLASSIC, \
|
||||
[ASM_EXT_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC, \
|
||||
[ASM_ALIGN_VECTOR] = PPC_EXC_CLASSIC, \
|
||||
[ASM_PROG_VECTOR] = PPC_EXC_CLASSIC, \
|
||||
[ASM_FLOAT_VECTOR] = PPC_EXC_CLASSIC, \
|
||||
[ASM_DEC_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC, \
|
||||
[ASM_SYS_VECTOR] = PPC_EXC_CLASSIC, \
|
||||
[ASM_TRACE_VECTOR] = PPC_EXC_CLASSIC
|
||||
|
||||
static const ppc_exc_categories ppc_405_category_table = {
|
||||
[ASM_BOOKE_CRIT_VECTOR] = PPC_EXC_405_CRITICAL | PPC_EXC_ASYNC,
|
||||
[ASM_MACH_VECTOR] = PPC_EXC_405_CRITICAL,
|
||||
[ASM_PROT_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_ISI_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_EXT_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
[ASM_ALIGN_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_PROG_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_FLOAT_VECTOR] = PPC_EXC_CLASSIC,
|
||||
|
||||
[ASM_PPC405_APU_UNAVAIL_VECTOR] = PPC_EXC_CLASSIC,
|
||||
|
||||
[ASM_SYS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
|
||||
[ASM_BOOKE_DEC_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
[ASM_BOOKE_FIT_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
[ASM_BOOKE_WDOG_VECTOR] = PPC_EXC_405_CRITICAL | PPC_EXC_ASYNC,
|
||||
[ASM_BOOKE_DTLBMISS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_BOOKE_ITLBMISS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_TRACE_VECTOR] = PPC_EXC_405_CRITICAL,
|
||||
};
|
||||
|
||||
static const ppc_exc_categories mpc_5xx_category_table = {
|
||||
[ASM_RESET_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_MACH_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_EXT_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
[ASM_ALIGN_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_PROG_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_FLOAT_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_DEC_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
[ASM_SYS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_TRACE_VECTOR] = PPC_EXC_CLASSIC,
|
||||
|
||||
[ASM_5XX_FLOATASSIST_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_5XX_SOFTEMUL_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_5XX_IPROT_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_5XX_DPROT_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_5XX_DBREAK_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_5XX_IBREAK_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_5XX_MEBREAK_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_5XX_NMEBREAK_VECTOR] = PPC_EXC_CLASSIC,
|
||||
};
|
||||
|
||||
static const ppc_exc_categories mpc_603_category_table = {
|
||||
PPC_BASIC_VECS,
|
||||
|
||||
[ASM_60X_SYSMGMT_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
[ASM_60X_IMISS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_60X_DLMISS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_60X_DSMISS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_60X_ADDR_VECTOR] = PPC_EXC_CLASSIC,
|
||||
};
|
||||
|
||||
static const ppc_exc_categories mpc_604_category_table = {
|
||||
PPC_BASIC_VECS,
|
||||
|
||||
[ASM_60X_PERFMON_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_60X_SYSMGMT_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
[ASM_60X_ADDR_VECTOR] = PPC_EXC_CLASSIC,
|
||||
};
|
||||
|
||||
static const ppc_exc_categories mpc_604_altivec_category_table = {
|
||||
PPC_BASIC_VECS,
|
||||
|
||||
[ASM_60X_PERFMON_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_60X_SYSMGMT_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
[ASM_60X_ADDR_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_60X_VEC_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_60X_VEC_ASSIST_VECTOR] = PPC_EXC_CLASSIC,
|
||||
};
|
||||
|
||||
static const ppc_exc_categories mpc_750_category_table = {
|
||||
PPC_BASIC_VECS,
|
||||
|
||||
[ASM_60X_SYSMGMT_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
[ASM_60X_ADDR_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_60X_ITM_VECTOR] = PPC_EXC_CLASSIC,
|
||||
};
|
||||
|
||||
static const ppc_exc_categories mpc_750_altivec_category_table = {
|
||||
PPC_BASIC_VECS,
|
||||
|
||||
[ASM_60X_SYSMGMT_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
[ASM_60X_ADDR_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_60X_ITM_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_60X_VEC_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_60X_VEC_ASSIST_VECTOR] = PPC_EXC_CLASSIC,
|
||||
};
|
||||
|
||||
static const ppc_exc_categories mpc_860_category_table = {
|
||||
PPC_BASIC_VECS,
|
||||
|
||||
[ASM_8XX_FLOATASSIST_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_8XX_SOFTEMUL_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_8XX_ITLBMISS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_8XX_DTLBMISS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_8XX_ITLBERROR_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_8XX_DTLBERROR_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_8XX_DBREAK_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_8XX_IBREAK_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_8XX_PERIFBREAK_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_8XX_DEVPORT_VECTOR] = PPC_EXC_CLASSIC,
|
||||
};
|
||||
|
||||
static const ppc_exc_categories e200_category_table = {
|
||||
[ASM_MACH_VECTOR] = PPC_EXC_BOOKE_CRITICAL | PPC_EXC_ASYNC,
|
||||
[ASM_PROT_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_ISI_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_EXT_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
[ASM_ALIGN_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_PROG_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_FLOAT_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_SYS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_BOOKE_DEC_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
[ASM_BOOKE_FIT_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
[ASM_BOOKE_WDOG_VECTOR] = PPC_EXC_BOOKE_CRITICAL | PPC_EXC_ASYNC,
|
||||
[ASM_BOOKE_ITLBMISS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_BOOKE_DTLBMISS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
|
||||
/* FIXME: Depending on HDI0 [DAPUEN] this is a critical or debug exception */
|
||||
[ASM_TRACE_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_BOOKE_CRITICAL,
|
||||
|
||||
[ASM_E200_SPE_UNAVAILABLE_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_E200_SPE_DATA_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_E200_SPE_ROUND_VECTOR] = PPC_EXC_CLASSIC,
|
||||
};
|
||||
|
||||
static const ppc_exc_categories e300_category_table = {
|
||||
[ASM_RESET_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_MACH_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_PROT_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_ISI_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_EXT_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
[ASM_ALIGN_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_PROG_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_FLOAT_VECTOR] = PPC_EXC_NAKED,
|
||||
[ASM_DEC_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
[ASM_SYS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_TRACE_VECTOR] = PPC_EXC_CLASSIC,
|
||||
|
||||
[ASM_E300_CRIT_VECTOR] = PPC_EXC_BOOKE_CRITICAL | PPC_EXC_ASYNC,
|
||||
[ASM_E300_PERFMON_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_E300_IMISS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_E300_DLMISS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_E300_DSMISS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_E300_ADDR_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_E300_SYSMGMT_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
};
|
||||
|
||||
static const ppc_exc_categories e500_category_table = {
|
||||
[ASM_MACH_VECTOR] = PPC_EXC_E500_MACHCHK,
|
||||
|
||||
[ASM_BOOKE_CRIT_VECTOR] = PPC_EXC_BOOKE_CRITICAL | PPC_EXC_ASYNC,
|
||||
[ASM_BOOKE_WDOG_VECTOR] = PPC_EXC_BOOKE_CRITICAL | PPC_EXC_ASYNC,
|
||||
[ASM_TRACE_VECTOR] = PPC_EXC_BOOKE_CRITICAL,
|
||||
|
||||
[ASM_EXT_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
[ASM_BOOKE_DEC_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
[ASM_BOOKE_FIT_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
|
||||
[ASM_PROT_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_ISI_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_ALIGN_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_PROG_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_FLOAT_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_SYS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ /* APU unavailable */ 0x0b] = PPC_EXC_CLASSIC,
|
||||
|
||||
[ASM_60X_DLMISS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_60X_DSMISS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_60X_VEC_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_60X_PERFMON_VECTOR] = PPC_EXC_CLASSIC,
|
||||
|
||||
[ /* emb FP data */ 0x15] = PPC_EXC_CLASSIC,
|
||||
[ /* emb FP round */ 0x16] = PPC_EXC_CLASSIC,
|
||||
};
|
||||
|
||||
static const ppc_exc_categories psim_category_table = {
|
||||
PPC_BASIC_VECS,
|
||||
|
||||
[ASM_60X_SYSMGMT_VECTOR] = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
|
||||
[ASM_60X_IMISS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_60X_DLMISS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_60X_DSMISS_VECTOR] = PPC_EXC_CLASSIC,
|
||||
[ASM_60X_ADDR_VECTOR] = PPC_EXC_CLASSIC,
|
||||
};
|
||||
|
||||
const ppc_exc_categories *ppc_exc_categories_for_cpu(ppc_cpu_id_t cpu)
|
||||
{
|
||||
if (ppc_cpu_has_altivec()) {
|
||||
switch (cpu) {
|
||||
case PPC_7400:
|
||||
return &mpc_750_altivec_category_table;
|
||||
case PPC_7455:
|
||||
case PPC_7457:
|
||||
return &mpc_604_altivec_category_table;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (cpu) {
|
||||
case PPC_7400:
|
||||
case PPC_750:
|
||||
return &mpc_750_category_table;
|
||||
case PPC_7455:
|
||||
case PPC_7457:
|
||||
case PPC_604:
|
||||
case PPC_604e:
|
||||
case PPC_604r:
|
||||
return &mpc_604_category_table;
|
||||
case PPC_603:
|
||||
case PPC_603e:
|
||||
case PPC_603le:
|
||||
case PPC_603ev:
|
||||
/* case PPC_8240: same value as 8260 */
|
||||
case PPC_8260:
|
||||
case PPC_8245:
|
||||
return &mpc_603_category_table;
|
||||
case PPC_e300c1:
|
||||
case PPC_e300c2:
|
||||
case PPC_e300c3:
|
||||
return &e300_category_table;
|
||||
case PPC_PSIM:
|
||||
return &psim_category_table;
|
||||
case PPC_8540:
|
||||
return &e500_category_table;
|
||||
case PPC_e200z6:
|
||||
return &e200_category_table;
|
||||
case PPC_5XX:
|
||||
return &mpc_5xx_category_table;
|
||||
case PPC_860:
|
||||
return &mpc_860_category_table;
|
||||
case PPC_405:
|
||||
case PPC_405GP:
|
||||
case PPC_405EX:
|
||||
return &ppc_405_category_table;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ppc_exc_category ppc_exc_category_for_vector(const ppc_exc_categories *categories, unsigned vector)
|
||||
{
|
||||
if (vector <= LAST_VALID_EXC) {
|
||||
return (*categories) [vector];
|
||||
} else {
|
||||
return PPC_EXC_INVALID;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
/**
|
||||
* @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 found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.com/license/LICENSE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <bsp/vectors.h>
|
||||
|
||||
exception_handler_t globalExceptHdl = C_exception_handler;
|
||||
|
||||
/* 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(DAR);
|
||||
else
|
||||
switch (ppc_cpu_is_bookE()) {
|
||||
default:
|
||||
break;
|
||||
case PPC_BOOKE_STD:
|
||||
case PPC_BOOKE_E500:
|
||||
return PPC_SPECIAL_PURPOSE_REGISTER(DEAR_BOOKE);
|
||||
case PPC_BOOKE_405:
|
||||
return PPC_SPECIAL_PURPOSE_REGISTER(DEAR_405);
|
||||
}
|
||||
return 0xdeadbeef;
|
||||
}
|
||||
|
||||
uint32_t (*ppc_exc_get_DAR)(void) = 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) ppc_link_register();
|
||||
}
|
||||
printk("LR: 0x%08x\n", lr);
|
||||
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)
|
||||
{
|
||||
static int nest = 0;
|
||||
|
||||
int recoverable = 0;
|
||||
rtems_id id = 0;
|
||||
int synch;
|
||||
unsigned n;
|
||||
rtems_status_code sc;
|
||||
|
||||
/* Catch recursion */
|
||||
nest++;
|
||||
|
||||
if (nest > 2) {
|
||||
/* maybe printk() or dereferencing excPtr caused an exception;
|
||||
* die silently...
|
||||
*/
|
||||
while (1);
|
||||
}
|
||||
|
||||
synch = (int) excPtr->_EXC_number >= 0;
|
||||
n = excPtr->_EXC_number & 0x7fff;
|
||||
|
||||
printk("Exception handler called for exception %d (0x%x)\n", n, n);
|
||||
printk("\t Next PC or Address of fault = %08x\n", excPtr->EXC_SRR0);
|
||||
printk("\t Saved MSR = %08x\n", excPtr->EXC_SRR1);
|
||||
|
||||
if (nest > 1) {
|
||||
printk("Recursion in the exception handler detected; I'll spin now...\n");
|
||||
while (1);
|
||||
}
|
||||
|
||||
/* Try to find out more about the context where this happened */
|
||||
printk("\t Context: ");
|
||||
if (rtems_interrupt_is_in_progress()) {
|
||||
printk("ISR");
|
||||
} else if (!_Thread_Executing) {
|
||||
printk("Initialization (_Thread_Executing not available yet)");
|
||||
} else {
|
||||
if (RTEMS_SUCCESSFUL != (sc = rtems_task_ident(RTEMS_SELF, RTEMS_LOCAL, &id))) {
|
||||
printk("Unable to determine faulting task; rtems_task_ident() returned %u", sc);
|
||||
id = 0;
|
||||
} else {
|
||||
printk("Task ID 0x%08x", id);
|
||||
}
|
||||
}
|
||||
printk("\n");
|
||||
|
||||
/* Dump registers */
|
||||
|
||||
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) {
|
||||
if (id) {
|
||||
printk("Suspending faulting task (0x%08x)\n", id);
|
||||
/* Unnest here because rtems_task_suspend() never returns */
|
||||
nest--;
|
||||
rtems_task_suspend(id);
|
||||
} else {
|
||||
printk("unrecoverable exception!!! Push reset button\n");
|
||||
while (1);
|
||||
}
|
||||
} else {
|
||||
nest--;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup ppc_exc
|
||||
*
|
||||
* @brief PowerPC Exceptions implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1999 Eric Valette (valette@crf.canon.fr)
|
||||
* Canon Centre Recherche France.
|
||||
*
|
||||
* Copyright (C) 2007 Till Straumann <strauman@slac.stanford.edu>
|
||||
*
|
||||
* Copyright (C) 2009 embedded brains GmbH.
|
||||
*
|
||||
* Derived from file "libcpu/powerpc/new-exceptions/bspsupport/vectors_init.c".
|
||||
* Derived from file "libcpu/powerpc/new-exceptions/e500_raw_exc_init.c".
|
||||
*
|
||||
* 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 <bsp/vectors.h>
|
||||
|
||||
uint32_t ppc_exc_cache_wb_check = 1;
|
||||
|
||||
#define MTIVPR(prefix) asm volatile ("mtivpr %0" : : "r" (prefix))
|
||||
#define MTIVOR(x, vec) asm volatile ("mtivor"#x" %0" : : "r" (vec))
|
||||
|
||||
static void ppc_exc_initialize_e500(void)
|
||||
{
|
||||
/* Interupt vector prefix register */
|
||||
MTIVPR(ppc_exc_vector_base);
|
||||
|
||||
/* Interupt vector offset register */
|
||||
MTIVOR(0, ppc_exc_vector_address(ASM_BOOKE_CRIT_VECTOR)); /* Critical input not (yet) supported; use reset vector */
|
||||
MTIVOR(1, ppc_exc_vector_address(ASM_MACH_VECTOR));
|
||||
MTIVOR(2, ppc_exc_vector_address(ASM_PROT_VECTOR));
|
||||
MTIVOR(3, ppc_exc_vector_address(ASM_ISI_VECTOR));
|
||||
MTIVOR(4, ppc_exc_vector_address(ASM_EXT_VECTOR));
|
||||
MTIVOR(5, ppc_exc_vector_address(ASM_ALIGN_VECTOR));
|
||||
MTIVOR(6, ppc_exc_vector_address(ASM_PROG_VECTOR));
|
||||
MTIVOR(7, ppc_exc_vector_address(ASM_FLOAT_VECTOR));
|
||||
MTIVOR(8, ppc_exc_vector_address(ASM_SYS_VECTOR));
|
||||
MTIVOR(9, ppc_exc_vector_address(0x0b));
|
||||
MTIVOR(10, ppc_exc_vector_address(ASM_BOOKE_DEC_VECTOR));
|
||||
MTIVOR(11, ppc_exc_vector_address(ASM_BOOKE_FIT_VECTOR));
|
||||
MTIVOR(12, ppc_exc_vector_address(ASM_BOOKE_WDOG_VECTOR));
|
||||
MTIVOR(13, ppc_exc_vector_address(ASM_60X_DSMISS_VECTOR));
|
||||
MTIVOR(14, ppc_exc_vector_address(ASM_60X_DLMISS_VECTOR));
|
||||
MTIVOR(15, ppc_exc_vector_address(ASM_TRACE_VECTOR));
|
||||
MTIVOR(32, ppc_exc_vector_address(ASM_60X_VEC_VECTOR));
|
||||
MTIVOR(33, ppc_exc_vector_address(0x16));
|
||||
MTIVOR(34, ppc_exc_vector_address(0x15));
|
||||
MTIVOR(35, ppc_exc_vector_address(ASM_60X_PERFMON_VECTOR));
|
||||
}
|
||||
|
||||
static void ppc_exc_initialize_e200(void)
|
||||
{
|
||||
/* Interupt vector prefix register */
|
||||
MTIVPR(ppc_exc_vector_base);
|
||||
|
||||
/* Interupt vector offset register */
|
||||
MTIVOR(0, 0); /* Critical input */
|
||||
MTIVOR(1, ppc_exc_vector_address( ASM_MACH_VECTOR));
|
||||
MTIVOR(2, ppc_exc_vector_address( ASM_PROT_VECTOR));
|
||||
MTIVOR(3, ppc_exc_vector_address( ASM_ISI_VECTOR));
|
||||
MTIVOR(4, ppc_exc_vector_address( ASM_EXT_VECTOR));
|
||||
MTIVOR(5, ppc_exc_vector_address( ASM_ALIGN_VECTOR));
|
||||
MTIVOR(6, ppc_exc_vector_address( ASM_PROG_VECTOR));
|
||||
MTIVOR(7, ppc_exc_vector_address( ASM_FLOAT_VECTOR));
|
||||
MTIVOR(8, ppc_exc_vector_address( ASM_SYS_VECTOR));
|
||||
MTIVOR(9, 0); /* APU unavailable */
|
||||
MTIVOR(10, ppc_exc_vector_address( ASM_BOOKE_DEC_VECTOR));
|
||||
MTIVOR(11, ppc_exc_vector_address( ASM_BOOKE_FIT_VECTOR));
|
||||
MTIVOR(12, ppc_exc_vector_address( ASM_BOOKE_WDOG_VECTOR));
|
||||
MTIVOR(13, ppc_exc_vector_address( ASM_BOOKE_ITLBMISS_VECTOR));
|
||||
MTIVOR(14, ppc_exc_vector_address( ASM_BOOKE_DTLBMISS_VECTOR));
|
||||
MTIVOR(15, ppc_exc_vector_address( ASM_TRACE_VECTOR));
|
||||
MTIVOR(32, ppc_exc_vector_address( ASM_E200_SPE_UNAVAILABLE_VECTOR));
|
||||
MTIVOR(33, ppc_exc_vector_address( ASM_E200_SPE_DATA_VECTOR));
|
||||
MTIVOR(34, ppc_exc_vector_address( ASM_E200_SPE_ROUND_VECTOR));
|
||||
}
|
||||
|
||||
rtems_status_code ppc_exc_initialize(
|
||||
uint32_t interrupt_disable_mask,
|
||||
uintptr_t interrupt_stack_begin,
|
||||
uintptr_t interrupt_stack_size
|
||||
)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
const ppc_exc_categories *const categories = ppc_exc_current_categories();
|
||||
uintptr_t const interrupt_stack_end = interrupt_stack_begin + interrupt_stack_size;
|
||||
uintptr_t interrupt_stack_pointer = interrupt_stack_end - PPC_MINIMUM_STACK_FRAME_SIZE;
|
||||
unsigned vector = 0;
|
||||
uint32_t sda_base = 0;
|
||||
uint32_t r13 = 0;
|
||||
|
||||
if (categories == NULL) {
|
||||
return RTEMS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* Assembly code needs SDA_BASE in r13 (SVR4 or EABI). Make sure
|
||||
* early init code put it there.
|
||||
*/
|
||||
asm volatile (
|
||||
"lis %0, _SDA_BASE_@h\n"
|
||||
"ori %0, %0, _SDA_BASE_@l\n"
|
||||
"mr %1, 13\n"
|
||||
: "=r" (sda_base), "=r"(r13)
|
||||
);
|
||||
|
||||
if (sda_base != r13) {
|
||||
return RTEMS_NOT_CONFIGURED;
|
||||
}
|
||||
|
||||
/* Ensure proper interrupt stack alignment */
|
||||
interrupt_stack_pointer &= ~((uint32_t) CPU_STACK_ALIGNMENT - 1);
|
||||
|
||||
/* Tag interrupt stack bottom */
|
||||
*(uint32_t *) interrupt_stack_pointer = 0;
|
||||
|
||||
/* Move interrupt stack values to special purpose registers */
|
||||
PPC_SET_SPECIAL_PURPOSE_REGISTER(SPRG1, interrupt_stack_pointer);
|
||||
PPC_SET_SPECIAL_PURPOSE_REGISTER(SPRG2, interrupt_stack_begin);
|
||||
|
||||
ppc_interrupt_set_disable_mask(interrupt_disable_mask);
|
||||
|
||||
/* Use current MMU / RI settings when running C exception handlers */
|
||||
ppc_exc_msr_bits = ppc_machine_state_register() & (MSR_DR | MSR_IR | MSR_RI);
|
||||
|
||||
if (ppc_cpu_is(PPC_e200z6)) {
|
||||
ppc_exc_initialize_e200();
|
||||
} else if (ppc_cpu_is_bookE() == PPC_BOOKE_STD || ppc_cpu_is_bookE() == PPC_BOOKE_E500) {
|
||||
ppc_exc_initialize_e500();
|
||||
}
|
||||
|
||||
for (vector = 0; vector <= LAST_VALID_EXC; ++vector) {
|
||||
ppc_exc_category category = ppc_exc_category_for_vector(categories, vector);
|
||||
|
||||
if (category != PPC_EXC_INVALID) {
|
||||
void *const vector_address = ppc_exc_vector_address(vector);
|
||||
uint32_t prologue [16];
|
||||
size_t prologue_size = sizeof(prologue);
|
||||
|
||||
sc = ppc_exc_make_prologue(vector, category, prologue, &prologue_size);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
return RTEMS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
ppc_code_copy(vector_address, prologue, prologue_size);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we are on a classic PPC with MSR_DR enabled then
|
||||
* assert that the mapping for at least this task's
|
||||
* stack is write-back-caching enabled (see README/CAVEATS)
|
||||
* Do this only if the cache is physically enabled.
|
||||
* Since it is not easy to figure that out in a
|
||||
* generic way we need help from the BSP: BSPs
|
||||
* which run entirely w/o the cache may set
|
||||
* ppc_exc_cache_wb_check to zero prior to calling
|
||||
* this routine.
|
||||
*
|
||||
* We run this check only after exception handling is
|
||||
* initialized so that we have some chance to get
|
||||
* information printed if it fails.
|
||||
*
|
||||
* Note that it is unsafe to ignore this issue; if
|
||||
* the check fails, do NOT disable it unless caches
|
||||
* are always physically disabled.
|
||||
*/
|
||||
if (ppc_exc_cache_wb_check && (MSR_DR & ppc_exc_msr_bits)) {
|
||||
/* The size of 63 assumes cache lines are at most 32 bytes */
|
||||
uint8_t dummy[63];
|
||||
uintptr_t p = (uintptr_t) dummy;
|
||||
/* If the dcbz instruction raises an alignment exception
|
||||
* then the stack is mapped as write-thru or caching-disabled.
|
||||
* The low-level code is not capable of dealing with this
|
||||
* ATM.
|
||||
*/
|
||||
p = (p + 31U) & ~31U;
|
||||
asm volatile ("dcbz 0, %0"::"b" (p));
|
||||
/* If we make it thru here then things seem to be OK */
|
||||
}
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup ppc_exc
|
||||
*
|
||||
* @brief PowerPC Exceptions implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009
|
||||
* embedded brains GmbH
|
||||
* Obere Lagerstr. 30
|
||||
* D-82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.com/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include "ppc_exc_asm_macros.h"
|
||||
|
||||
.global ppc_exc_min_prolog_tmpl_naked
|
||||
|
||||
ppc_exc_min_prolog_tmpl_naked:
|
||||
|
||||
stwu r1, -EXCEPTION_FRAME_END(r1)
|
||||
stw VECTOR_REGISTER, VECTOR_OFFSET(r1)
|
||||
li VECTOR_REGISTER, 0
|
||||
ba wrap_naked
|
||||
|
||||
wrap_naked:
|
||||
|
||||
/* Save scratch registers */
|
||||
stw SCRATCH_REGISTER_0, SCRATCH_REGISTER_0_OFFSET(r1)
|
||||
stw SCRATCH_REGISTER_1, SCRATCH_REGISTER_1_OFFSET(r1)
|
||||
stw SCRATCH_REGISTER_2, SCRATCH_REGISTER_2_OFFSET(r1)
|
||||
|
||||
/* Save volatile registers */
|
||||
stw r0, GPR0_OFFSET(r1)
|
||||
stw r3, GPR3_OFFSET(r1)
|
||||
stw r8, GPR8_OFFSET(r1)
|
||||
stw r9, GPR9_OFFSET(r1)
|
||||
stw r10, GPR10_OFFSET(r1)
|
||||
stw r11, GPR11_OFFSET(r1)
|
||||
stw r12, GPR12_OFFSET(r1)
|
||||
|
||||
/* Save CR */
|
||||
mfcr SCRATCH_REGISTER_0
|
||||
stw SCRATCH_REGISTER_0, EXC_CR_OFFSET(r1)
|
||||
|
||||
/* Save SRR0 */
|
||||
mfspr SCRATCH_REGISTER_0, srr0
|
||||
stw SCRATCH_REGISTER_0, SRR0_FRAME_OFFSET(r1)
|
||||
|
||||
/* Save SRR1 */
|
||||
mfspr SCRATCH_REGISTER_0, srr1
|
||||
stw SCRATCH_REGISTER_0, SRR1_FRAME_OFFSET(r1)
|
||||
|
||||
/* Save CTR */
|
||||
mfctr SCRATCH_REGISTER_0
|
||||
stw SCRATCH_REGISTER_0, EXC_CTR_OFFSET(r1)
|
||||
|
||||
/* Save XER */
|
||||
mfxer SCRATCH_REGISTER_0
|
||||
stw SCRATCH_REGISTER_0, EXC_XER_OFFSET(r1)
|
||||
|
||||
/* Save LR */
|
||||
mflr SCRATCH_REGISTER_0
|
||||
stw SCRATCH_REGISTER_0, EXC_LR_OFFSET(r1)
|
||||
|
||||
/* Load MSR bit mask */
|
||||
lwz SCRATCH_REGISTER_0, ppc_exc_msr_bits@sdarel(r13)
|
||||
|
||||
/*
|
||||
* Change the MSR if necessary (MMU, RI), remember decision in
|
||||
* non-volatile CR_MSR.
|
||||
*/
|
||||
cmpwi CR_MSR, SCRATCH_REGISTER_0, 0
|
||||
bne CR_MSR, wrap_change_msr_naked
|
||||
|
||||
wrap_change_msr_done_naked:
|
||||
|
||||
/*
|
||||
* Call high level exception handler
|
||||
*/
|
||||
|
||||
/*
|
||||
* Get the handler table index from the vector number. We have to
|
||||
* discard the exception type. Take only the least significant five
|
||||
* bits (= LAST_VALID_EXC + 1) from the vector register. Multiply by
|
||||
* four (= size of function pointer).
|
||||
*/
|
||||
rlwinm SCRATCH_REGISTER_1, VECTOR_REGISTER, 2, 25, 29
|
||||
|
||||
/* Load handler table address */
|
||||
LA SCRATCH_REGISTER_0, ppc_exc_handler_table
|
||||
|
||||
/* Load handler address */
|
||||
lwzx SCRATCH_REGISTER_0, SCRATCH_REGISTER_0, SCRATCH_REGISTER_1
|
||||
|
||||
/*
|
||||
* First parameter = exception frame pointer + FRAME_LINK_SPACE
|
||||
*
|
||||
* We add FRAME_LINK_SPACE to the frame pointer because the high level
|
||||
* handler expects a BSP_Exception_frame structure.
|
||||
*/
|
||||
addi r3, r1, FRAME_LINK_SPACE
|
||||
|
||||
/*
|
||||
* Second parameter = vector number (r4 is the VECTOR_REGISTER)
|
||||
*
|
||||
* Discard the exception type and store the vector number
|
||||
* in the vector register. Take only the least significant
|
||||
* five bits (= LAST_VALID_EXC + 1).
|
||||
*/
|
||||
rlwinm VECTOR_REGISTER, VECTOR_REGISTER, 0, 27, 31
|
||||
|
||||
/* Call handler */
|
||||
mtctr SCRATCH_REGISTER_0
|
||||
bctrl
|
||||
|
||||
/* Restore MSR? */
|
||||
bne CR_MSR, wrap_restore_msr_naked
|
||||
|
||||
wrap_restore_msr_done_naked:
|
||||
|
||||
/* Restore XER and CTR */
|
||||
lwz SCRATCH_REGISTER_0, EXC_XER_OFFSET(r1)
|
||||
lwz SCRATCH_REGISTER_1, EXC_CTR_OFFSET(r1)
|
||||
mtxer SCRATCH_REGISTER_0
|
||||
mtctr SCRATCH_REGISTER_1
|
||||
|
||||
/* Restore CR and LR */
|
||||
lwz SCRATCH_REGISTER_0, EXC_CR_OFFSET(r1)
|
||||
lwz SCRATCH_REGISTER_1, EXC_LR_OFFSET(r1)
|
||||
mtcr SCRATCH_REGISTER_0
|
||||
mtlr SCRATCH_REGISTER_1
|
||||
|
||||
/* Restore volatile registers */
|
||||
lwz r0, GPR0_OFFSET(r1)
|
||||
lwz r3, GPR3_OFFSET(r1)
|
||||
lwz r8, GPR8_OFFSET(r1)
|
||||
lwz r9, GPR9_OFFSET(r1)
|
||||
lwz r10, GPR10_OFFSET(r1)
|
||||
lwz r11, GPR11_OFFSET(r1)
|
||||
lwz r12, GPR12_OFFSET(r1)
|
||||
|
||||
/* Restore vector register */
|
||||
lwz VECTOR_REGISTER, VECTOR_OFFSET(r1)
|
||||
|
||||
/* Restore scratch registers and SRRs */
|
||||
lwz SCRATCH_REGISTER_0, SRR0_FRAME_OFFSET(r1)
|
||||
lwz SCRATCH_REGISTER_1, SRR1_FRAME_OFFSET(r1)
|
||||
lwz SCRATCH_REGISTER_2, SCRATCH_REGISTER_2_OFFSET(r1)
|
||||
mtspr srr0, SCRATCH_REGISTER_0
|
||||
lwz SCRATCH_REGISTER_0, SCRATCH_REGISTER_0_OFFSET(r1)
|
||||
mtspr srr1, SCRATCH_REGISTER_1
|
||||
lwz SCRATCH_REGISTER_1, SCRATCH_REGISTER_1_OFFSET(r1)
|
||||
|
||||
/*
|
||||
* We restore r1 from the frame rather than just popping (adding to
|
||||
* current r1) since the exception handler might have done strange
|
||||
* things (e.g. a debugger moving and relocating the stack).
|
||||
*/
|
||||
lwz r1, 0(r1)
|
||||
|
||||
/* Return */
|
||||
rfi
|
||||
|
||||
wrap_change_msr_naked:
|
||||
|
||||
mfmsr SCRATCH_REGISTER_1
|
||||
or SCRATCH_REGISTER_1, SCRATCH_REGISTER_1, SCRATCH_REGISTER_0
|
||||
mtmsr SCRATCH_REGISTER_1
|
||||
sync
|
||||
isync
|
||||
b wrap_change_msr_done_naked
|
||||
|
||||
wrap_restore_msr_naked:
|
||||
|
||||
lwz SCRATCH_REGISTER_0, ppc_exc_msr_bits@sdarel(r13)
|
||||
mfmsr SCRATCH_REGISTER_1
|
||||
andc SCRATCH_REGISTER_1, SCRATCH_REGISTER_1, SCRATCH_REGISTER_0
|
||||
mtmsr SCRATCH_REGISTER_1
|
||||
sync
|
||||
isync
|
||||
b wrap_restore_msr_done_naked
|
||||
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup ppc_exc
|
||||
*
|
||||
* @brief PowerPC Exceptions implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2007 Till Straumann <strauman@slac.stanford.edu>
|
||||
*
|
||||
* Copyright (C) 2009 embedded brains GmbH.
|
||||
*
|
||||
* 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 <string.h>
|
||||
|
||||
#include <bsp/vectors.h>
|
||||
|
||||
/* Offset into minimal prolog where vector number is hardcoded */
|
||||
#define PPC_EXC_PROLOG_VEC_OFFSET 2
|
||||
|
||||
/* Symbols are defined by the linker */
|
||||
extern const char ppc_exc_min_prolog_size [];
|
||||
extern const char ppc_exc_tgpr_clr_prolog_size [];
|
||||
|
||||
/* Special prologue for handling register shadowing on 603-style CPUs */
|
||||
extern const uint32_t 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 const uint32_t ppc_exc_min_prolog_auto [];
|
||||
|
||||
extern const uint32_t ppc_exc_min_prolog_auto_packed [];
|
||||
|
||||
/* Minimal prologue templates */
|
||||
extern const uint32_t ppc_exc_min_prolog_async_tmpl_std [];
|
||||
extern const uint32_t ppc_exc_min_prolog_sync_tmpl_std [];
|
||||
extern const uint32_t ppc_exc_min_prolog_async_tmpl_p405_crit [];
|
||||
extern const uint32_t ppc_exc_min_prolog_sync_tmpl_p405_crit [];
|
||||
extern const uint32_t ppc_exc_min_prolog_async_tmpl_bookE_crit [];
|
||||
extern const uint32_t ppc_exc_min_prolog_sync_tmpl_bookE_crit [];
|
||||
extern const uint32_t ppc_exc_min_prolog_sync_tmpl_e500_mchk [];
|
||||
extern const uint32_t ppc_exc_min_prolog_async_tmpl_e500_mchk [];
|
||||
extern const uint32_t ppc_exc_min_prolog_tmpl_naked [];
|
||||
|
||||
static const uint32_t *const ppc_exc_prologue_templates [] = {
|
||||
[PPC_EXC_CLASSIC] = ppc_exc_min_prolog_sync_tmpl_std,
|
||||
[PPC_EXC_CLASSIC_ASYNC] = ppc_exc_min_prolog_async_tmpl_std,
|
||||
[PPC_EXC_405_CRITICAL] = ppc_exc_min_prolog_sync_tmpl_p405_crit,
|
||||
[PPC_EXC_405_CRITICAL_ASYNC] = ppc_exc_min_prolog_async_tmpl_p405_crit,
|
||||
[PPC_EXC_BOOKE_CRITICAL] = ppc_exc_min_prolog_sync_tmpl_bookE_crit,
|
||||
[PPC_EXC_BOOKE_CRITICAL_ASYNC] = ppc_exc_min_prolog_async_tmpl_bookE_crit,
|
||||
[PPC_EXC_E500_MACHCHK] = ppc_exc_min_prolog_sync_tmpl_e500_mchk,
|
||||
[PPC_EXC_E500_MACHCHK_ASYNC] = ppc_exc_min_prolog_async_tmpl_e500_mchk,
|
||||
[PPC_EXC_NAKED] = ppc_exc_min_prolog_tmpl_naked
|
||||
};
|
||||
|
||||
rtems_status_code ppc_exc_make_prologue(
|
||||
unsigned vector,
|
||||
ppc_exc_category category,
|
||||
uint32_t *prologue,
|
||||
size_t *prologue_size
|
||||
)
|
||||
{
|
||||
const uint32_t *prologue_template = NULL;
|
||||
size_t prologue_template_size = 0;
|
||||
uintptr_t vector_address = (uintptr_t) ppc_exc_vector_address(vector);
|
||||
bool fixup_vector = false;
|
||||
|
||||
if (!ppc_exc_is_valid_category(category)) {
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
}
|
||||
|
||||
if (
|
||||
ppc_cpu_has_shadowed_gprs()
|
||||
&& (vector == ASM_60X_IMISS_VECTOR
|
||||
|| vector == ASM_60X_DLMISS_VECTOR
|
||||
|| vector == ASM_60X_DSMISS_VECTOR)
|
||||
) {
|
||||
prologue_template = ppc_exc_tgpr_clr_prolog;
|
||||
prologue_template_size = (size_t) ppc_exc_tgpr_clr_prolog_size;
|
||||
} else if (
|
||||
category == PPC_EXC_CLASSIC
|
||||
&& ((vector_address & 0xffU) == 0
|
||||
|| (ppc_cpu_has_ivpr_and_ivor() && (vector_address & 0xfU) == 0))
|
||||
) {
|
||||
if (ppc_cpu_has_ivpr_and_ivor()) {
|
||||
prologue_template = ppc_exc_min_prolog_auto_packed;
|
||||
} else {
|
||||
prologue_template = ppc_exc_min_prolog_auto;
|
||||
}
|
||||
prologue_template_size = (size_t) ppc_exc_min_prolog_size;
|
||||
} else {
|
||||
prologue_template = ppc_exc_prologue_templates [category];
|
||||
prologue_template_size = (size_t) ppc_exc_min_prolog_size;
|
||||
fixup_vector = true;
|
||||
}
|
||||
|
||||
if (prologue_template_size <= *prologue_size) {
|
||||
*prologue_size = prologue_template_size;
|
||||
|
||||
memcpy(prologue, prologue_template, prologue_template_size);
|
||||
|
||||
if (fixup_vector) {
|
||||
if (vector <= 0x7fffU) {
|
||||
prologue [PPC_EXC_PROLOG_VEC_OFFSET] =
|
||||
(prologue [PPC_EXC_PROLOG_VEC_OFFSET] & 0xffff8000U)
|
||||
| (vector & 0x7fffU);
|
||||
} else {
|
||||
return RTEMS_INVALID_ID;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return RTEMS_INVALID_SIZE;
|
||||
}
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
Reference in New Issue
Block a user