diff options
author | Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> | 2009-10-23 09:51:03 +0000 |
---|---|---|
committer | Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> | 2009-10-23 09:51:03 +0000 |
commit | 856cce506825d1257efafdb89ce632530c182d8b (patch) | |
tree | 591d090786d561a2237c929a23b315985232d34c | |
parent | 402ac7b7c81bd257d1a384866b144ecc5d586599 (diff) |
add new files for exception handler
9 files changed, 1232 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/powerpc/mbx8xx/include/irq-config.h b/c/src/lib/libbsp/powerpc/mbx8xx/include/irq-config.h new file mode 100644 index 0000000000..da5bbbec5d --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mbx8xx/include/irq-config.h @@ -0,0 +1,47 @@ +/** + * @file + * + * @ingroup bsp_interrupt + * + * @brief BSP interrupt support configuration. + */ + +/* + * 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. + */ + +#ifndef LIBBSP_POWERPC_MBX8XX_IRQ_CONFIG_H +#define LIBBSP_POWERPC_MBX8XX_IRQ_CONFIG_H + +#include <stdint.h> + +#include <bsp/irq.h> + +/** + * @addtogroup bsp_interrupt + * + * @{ + */ + +/** + * @brief Minimum vector number. + */ +#define BSP_INTERRUPT_VECTOR_MIN BSP_LOWEST_OFFSET + +/** + * @brief Maximum vector number. + */ +#define BSP_INTERRUPT_VECTOR_MAX BSP_MAX_OFFSET + +/** @} */ + +#endif /* LIBBSP_POWERPC_MBX8XX_IRQ_CONFIG_H */ diff --git a/c/src/lib/libbsp/powerpc/mpc8260ads/include/irq-config.h b/c/src/lib/libbsp/powerpc/mpc8260ads/include/irq-config.h new file mode 100644 index 0000000000..da5bbbec5d --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mpc8260ads/include/irq-config.h @@ -0,0 +1,47 @@ +/** + * @file + * + * @ingroup bsp_interrupt + * + * @brief BSP interrupt support configuration. + */ + +/* + * 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. + */ + +#ifndef LIBBSP_POWERPC_MBX8XX_IRQ_CONFIG_H +#define LIBBSP_POWERPC_MBX8XX_IRQ_CONFIG_H + +#include <stdint.h> + +#include <bsp/irq.h> + +/** + * @addtogroup bsp_interrupt + * + * @{ + */ + +/** + * @brief Minimum vector number. + */ +#define BSP_INTERRUPT_VECTOR_MIN BSP_LOWEST_OFFSET + +/** + * @brief Maximum vector number. + */ +#define BSP_INTERRUPT_VECTOR_MAX BSP_MAX_OFFSET + +/** @} */ + +#endif /* LIBBSP_POWERPC_MBX8XX_IRQ_CONFIG_H */ diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc-code-copy.c b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc-code-copy.c new file mode 100644 index 0000000000..9e327e5141 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc-code-copy.c @@ -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(); + } +} diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_address.c b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_address.c new file mode 100644 index 0000000000..1121afc9f4 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_address.c @@ -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); +} diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_categories.c b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_categories.c new file mode 100644 index 0000000000..2856957639 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_categories.c @@ -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; + } +} diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_global_handler.c b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_global_handler.c new file mode 100644 index 0000000000..116199332c --- /dev/null +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_global_handler.c @@ -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--; + } +} diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_initialize.c b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_initialize.c new file mode 100644 index 0000000000..5d2de9dc3e --- /dev/null +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_initialize.c @@ -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; +} diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_naked.S b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_naked.S new file mode 100644 index 0000000000..1c4a3b8462 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_naked.S @@ -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 diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_prologue.c b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_prologue.c new file mode 100644 index 0000000000..b259589aa6 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_prologue.c @@ -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; +} |