summaryrefslogtreecommitdiffstats
path: root/cfe/cfe/arch/mips/common/src/exchandler.c
diff options
context:
space:
mode:
Diffstat (limited to 'cfe/cfe/arch/mips/common/src/exchandler.c')
-rw-r--r--cfe/cfe/arch/mips/common/src/exchandler.c580
1 files changed, 580 insertions, 0 deletions
diff --git a/cfe/cfe/arch/mips/common/src/exchandler.c b/cfe/cfe/arch/mips/common/src/exchandler.c
new file mode 100644
index 0000000..d69b980
--- /dev/null
+++ b/cfe/cfe/arch/mips/common/src/exchandler.c
@@ -0,0 +1,580 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Exception Handler File: exchandler.c
+ *
+ * This is the "C" part of the exception handler and the
+ * associated setup routines. We call these routines from
+ * the assembly-language exception handler.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include "sbmips.h"
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_printf.h"
+#include "lib_queue.h"
+#include "lib_malloc.h"
+#include "exception.h"
+#include "cfe.h"
+#include "cfe_error.h"
+#include "cfe_iocb.h"
+#include "exchandler.h"
+#include "cpu_config.h"
+#include "bsp_config.h"
+
+/* *********************************************************************
+ * Constants
+ ********************************************************************* */
+
+/*
+ * Temporary until all our CPU packages support a cache error handler
+ */
+
+#ifndef CPUCFG_CERRHANDLER
+#define CPUCFG_CERRHANDLER 0xBFC00000
+#else
+extern void CPUCFG_CERRHANDLER(void);
+#endif
+
+/* *********************************************************************
+ * Globals
+ ********************************************************************* */
+
+exc_handler_t exc_handler;
+extern void _exc_entry(void);
+extern void _exc_setup_locore(long);
+extern void CPUCFG_TLBHANDLER(void);
+extern void cfe_flushcache(uint32_t,long,long);
+extern uint32_t _getstatus(void);
+extern void _setstatus(uint32_t);
+
+static const char *regnames = "0 ATv0v1a0a1a2a3t0t1t2t3t4t5t6t7"
+ "s0s1s2s3s4s5s6s7t8t9k0k1gpspfpra";
+static const char *excnames =
+ "Interrupt" /* 0 */
+ "TLBMod " /* 1 */
+ "TLBMissRd" /* 2 */
+ "TLBMissWr" /* 3 */
+ "AddrErrRd" /* 4 */
+ "AddrErrWr" /* 5 */
+ "BusErrRd " /* 6 */
+ "BusErrWr " /* 7 */
+ "Syscall " /* 8 */
+ "Breakpt " /* 9 */
+ "InvOpcode" /* 10 */
+ "CoProcUnu" /* 11 */
+ "ArithOvfl" /* 12 */
+ "TrapExc " /* 13 */
+ "VCEI " /* 14 */
+ "FPUExc " /* 15 */
+ "CP2Exc " /* 16 */
+ "Exc17 " /* 17 */
+ "Exc18 " /* 18 */
+ "Exc19 " /* 19 */
+ "Exc20 " /* 20 */
+ "Exc21 " /* 21 */
+ "Exc22 " /* 22 */
+ "Watchpt " /* 23 */
+ "Exc24 " /* 24 */
+ "Exc25 " /* 25 */
+ "Exc26 " /* 26 */
+ "Exc27 " /* 27 */
+ "Exc28 " /* 28 */
+ "Exc29 " /* 29 */
+ "Exc30 " /* 30 */
+ "VCED "; /* 31 */
+
+
+
+/* *********************************************************************
+ * cfe_exception(code,info)
+ *
+ * Exception handler. This routine is called when any CPU
+ * exception that is handled by the assembly-language
+ * vectors is reached. The usual thing to do here is just to
+ * reboot.
+ *
+ * Input parameters:
+ * code - exception type
+ * info - exception stack frame
+ *
+ * Return value:
+ * usually reboots
+ ********************************************************************* */
+
+void cfe_exception(int code,uint64_t *info)
+{
+ int idx;
+
+ SETLEDS("EXC!");
+
+ if(exc_handler.catch_exc == 1) {
+ /*Deal with exception without restarting CFE.*/
+
+ /*Clear relevant SR bits*/
+ _exc_clear_sr_exl();
+ _exc_clear_sr_erl();
+
+ /*Reset flag*/
+ exc_handler.catch_exc = 0;
+
+ exc_longjmp_handler();
+ }
+
+
+#ifdef _MIPSREGS32_
+ xprintf("**Exception %d: EPC=%08X, Cause=%08X (%9s)\n",
+ code,(uint32_t)info[XCP0_EPC],
+ (uint32_t)info[XCP0_CAUSE],
+ excnames + G_CAUSE_EXC((uint32_t)info[XCP0_CAUSE])*9);
+ xprintf(" RA=%08X, VAddr=%08X\n",
+ (uint32_t)info[XGR_RA],(uint32_t)info[XCP0_VADDR]);
+ xprintf("\n");
+ for (idx = 0;idx < 32; idx+= 2) {
+ xprintf(" %2s ($%2d) = %08X %2s ($%2d) = %08X\n",
+ regnames+(idx*2),
+ idx,(uint32_t)info[XGR_ZERO+idx],
+ regnames+((idx+1)*2),
+ idx+1,(uint32_t)info[XGR_ZERO+idx+1]);
+ }
+#else
+ xprintf("**Exception %d: EPC=%016llX, Cause=%08X (%9s)\n",
+ code,info[XCP0_EPC],info[XCP0_CAUSE],
+ excnames + G_CAUSE_EXC((uint32_t)info[XCP0_CAUSE])*9);
+ xprintf(" RA=%016llX, VAddr=%016llX\n",
+ info[XGR_RA],info[XCP0_VADDR]);
+ xprintf("\n");
+ for (idx = 0;idx < 32; idx+= 2) {
+ xprintf(" %2s ($%2d) = %016llX %2s ($%2d) = %016llX\n",
+ regnames+(idx*2),
+ idx,info[XGR_ZERO+idx],
+ regnames+((idx+1)*2),
+ idx+1,info[XGR_ZERO+idx+1]);
+ }
+#endif
+
+ xprintf("\n");
+ _exc_restart();
+}
+
+#if (!CFG_BOOTRAM) && (CFG_RUNFROMKSEG0)
+/* *********************************************************************
+ * exc_setup_hw_vector(vecoffset,target,k0code)
+ *
+ * Install a patch of code at the specified offset in low
+ * KSEG0 memory that will jump to 'target' and load k0
+ * with the specified code value. This is used when we
+ * run with RAM vectors.
+ *
+ * Input parameters:
+ * vecoffset - offset into KSEG0
+ * target - location where we should branch when vector is called
+ * k0code - value to load into K0 before branching
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void exc_setup_hw_vector(uint32_t vecoffset,
+ void *target,
+ uint32_t k0code)
+{
+ uint32_t *vec;
+ uint32_t new;
+ uint32_t lower,upper;
+
+ new = (uint32_t) (intptr_t) target; /* warning: assumes compatibility addresses! */
+
+ lower = new & 0xffff;
+ upper = (new >> 16) & 0xffff;
+ if ((lower & 0x8000) != 0) {
+ upper++;
+ }
+
+ /*
+ * Get a KSEG0 version of the vector offset.
+ */
+ vec = (uint32_t *) PHYS_TO_K0(vecoffset);
+
+ /*
+ * Patch in the vector. Note that we have to flush
+ * the L1 Dcache and invalidate the L1 Icache before
+ * we can use this.
+ */
+
+ vec[0] = 0x3c1b0000 | upper; /* lui k1, HIGH(new) */
+ vec[1] = 0x277b0000 | lower; /* addiu k1, k1, LOW(new) */
+ vec[2] = 0x03600008; /* jr k1 */
+ vec[3] = 0x241a0000 | k0code; /* li k0, code */
+
+}
+
+
+/* *********************************************************************
+ * exc_install_ram_vectors()
+ *
+ * Install all of the hardware vectors into low memory,
+ * flush the cache, and clear the BEV bit so we can start
+ * using them.
+ *
+ * Input parameters:
+ * nothing
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void exc_install_ram_vectors(void)
+{
+ uint32_t *ptr;
+ int idx;
+
+ /* Debug: blow away the vector area so we can see what we did */
+ ptr = (uint32_t *) PHYS_TO_K0(0);
+ for (idx = 0; idx < 0x1000/sizeof(uint32_t); idx++) *ptr++ = 0;
+
+ /*
+ * Set up the vectors. The cache error handler is set up
+ * specially.
+ */
+
+ exc_setup_hw_vector(MIPS_RAM_VEC_TLBFILL, CPUCFG_TLBHANDLER,XTYPE_TLBFILL);
+ exc_setup_hw_vector(MIPS_RAM_VEC_XTLBFILL, _exc_entry,XTYPE_XTLBFILL);
+ exc_setup_hw_vector(MIPS_RAM_VEC_CACHEERR, _exc_entry,XTYPE_CACHEERR);
+ exc_setup_hw_vector(MIPS_RAM_VEC_EXCEPTION,_exc_entry,XTYPE_EXCEPTION);
+ exc_setup_hw_vector(MIPS_RAM_VEC_INTERRUPT,_exc_entry,XTYPE_INTERRUPT);
+
+ /*
+ * Flush the D-cache and invalidate the I-cache so we can start
+ * using these vectors.
+ */
+
+ cfe_flushcache(CFE_CACHE_FLUSH_D | CFE_CACHE_INVAL_I,0,0);
+
+ /*
+ * Write the handle into our low memory space. If we need to save
+ * other stuff down there, this is a good place to do it.
+ * This call uses uncached writes - we have not touched the
+ * memory in the handlers just yet, so they should not be
+ * in our caches.
+ */
+
+ _exc_setup_locore((intptr_t) CPUCFG_CERRHANDLER);
+
+ /*
+ * Finally, clear BEV so we'll use the vectors in RAM.
+ */
+
+ _setstatus(_getstatus() & ~M_SR_BEV);
+
+ /*
+ * XXX There's a hazard here, but we're not going to worry about
+ * XXX it. It is unlikely we'll use the vectors any time soon.
+ */
+}
+#endif
+
+/* *********************************************************************
+ * cfe_setup_exceptions()
+ *
+ * Set up the exception handlers.
+ *
+ * Input parameters:
+ * nothing
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+void cfe_setup_exceptions(void)
+{
+ _exc_setvector(XTYPE_TLBFILL, (void *) cfe_exception);
+ _exc_setvector(XTYPE_XTLBFILL, (void *) cfe_exception);
+ _exc_setvector(XTYPE_CACHEERR, (void *) _exc_cache_crash_sim);
+ _exc_setvector(XTYPE_EXCEPTION,(void *) cfe_exception);
+ _exc_setvector(XTYPE_INTERRUPT,(void *) cfe_exception);
+ _exc_setvector(XTYPE_EJTAG, (void *) cfe_exception);
+
+ exc_handler.catch_exc = 0;
+ q_init( &(exc_handler.jmpbuf_stack));
+
+#if (!CFG_BOOTRAM) && (CFG_RUNFROMKSEG0)
+ /*
+ * Install RAM vectors, and clear the BEV bit in the status
+ * register. Don't do this if we're running from PromICE RAM
+ */
+ exc_install_ram_vectors();
+#endif
+}
+
+
+
+/* *********************************************************************
+ * exc_initialize_block()
+ *
+ * Set up the exception handler. Allow exceptions to be caught.
+ * Allocate memory for jmpbuf and store it away.
+ *
+ * Returns NULL if error in memory allocation.
+ *
+ * Input parameters:
+ * nothing
+ *
+ * Return value:
+ * jmpbuf_t structure, or NULL if no memory
+ ********************************************************************* */
+jmpbuf_t *exc_initialize_block(void)
+{
+ jmpbuf_t *jmpbuf_local;
+
+ exc_handler.catch_exc = 1;
+
+ /* Create the jmpbuf_t object */
+ jmpbuf_local = (jmpbuf_t *) KMALLOC((sizeof(jmpbuf_t)),0);
+
+ if (jmpbuf_local == NULL) {
+ return NULL;
+ }
+
+ q_enqueue( &(exc_handler.jmpbuf_stack), &((*jmpbuf_local).stack));
+
+ return jmpbuf_local;
+}
+
+/* *********************************************************************
+ * exc_cleanup_block(dq_jmpbuf)
+ *
+ * Remove dq_jmpbuf from the exception handler stack and free
+ * the memory.
+ *
+ * Input parameters:
+ * dq_jmpbuf - block to deallocate
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void exc_cleanup_block(jmpbuf_t *dq_jmpbuf)
+{
+ int count;
+
+ if (dq_jmpbuf == NULL) {
+ return;
+ }
+
+ count = q_count( &(exc_handler.jmpbuf_stack));
+
+ if( count > 0 ) {
+ q_dequeue( &(*dq_jmpbuf).stack );
+ KFREE(dq_jmpbuf);
+ }
+}
+
+/* *********************************************************************
+ * exc_cleanup_handler(dq_jmpbuf,chain_exc)
+ *
+ * Clean a block, then chain to the next exception if required.
+ *
+ * Input parameters:
+ * dq_jmpbuf - current exception
+ * chain_exc - true if we should chain to the next handler
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void exc_cleanup_handler(jmpbuf_t *dq_jmpbuf, int chain_exc)
+{
+ exc_cleanup_block(dq_jmpbuf);
+
+ if( chain_exc == EXC_CHAIN_EXC ) {
+ /*Go to next exception on stack */
+ exc_longjmp_handler();
+ }
+}
+
+
+
+/* *********************************************************************
+ * exc_longjmp_handler()
+ *
+ * This routine long jumps to the exception handler on the top
+ * of the exception stack.
+ *
+ * Input parameters:
+ * nothing
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+void exc_longjmp_handler(void)
+{
+ int count;
+ jmpbuf_t *jmpbuf_local;
+
+ count = q_count( &(exc_handler.jmpbuf_stack));
+
+ if( count > 0 ) {
+ jmpbuf_local = (jmpbuf_t *) q_getlast(&(exc_handler.jmpbuf_stack));
+
+ SETLEDS("CFE ");
+
+ lib_longjmp( (*jmpbuf_local).jmpbuf, -1);
+ }
+}
+
+
+/* *********************************************************************
+ * mem_peek(d,addr,type)
+ *
+ * Read memory of the specified type at the specified address.
+ * Exceptions are caught in the case of a bad memory reference.
+ *
+ * Input parameters:
+ * d - pointer to where data should be placed
+ * addr - address to read
+ * type - type of read to do (MEM_BYTE, etc.)
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int mem_peek(void *d, long addr, int type)
+{
+
+ jmpbuf_t *jb;
+
+ jb = exc_initialize_block();
+ if( jb == NULL ) {
+ return CFE_ERR_NOMEM;
+ }
+
+ if (exc_try(jb) == 0) {
+
+ switch (type) {
+ case MEM_BYTE:
+ *(uint8_t *)d = *((volatile uint8_t *) addr);
+ break;
+ case MEM_HALFWORD:
+ *(uint16_t *)d = *((volatile uint16_t *) addr);
+ break;
+ case MEM_WORD:
+ *(uint32_t *)d = *((volatile uint32_t *) addr);
+ break;
+ case MEM_QUADWORD:
+ *(uint64_t *)d = *((volatile uint64_t *) addr);
+ break;
+ default:
+ return CFE_ERR_INV_PARAM;
+ }
+
+ exc_cleanup_block(jb);
+ }
+ else {
+ /*Exception handler*/
+
+ exc_cleanup_handler(jb, EXC_NORMAL_RETURN);
+ return CFE_ERR_GETMEM;
+ }
+
+ return 0;
+}
+
+/* *********************************************************************
+ * Write memory of type at address addr with value val.
+ * Exceptions are caught, handled (error message) and function
+ * returns with 0.
+ *
+ * 1 success
+ * 0 failure
+ ********************************************************************* */
+
+int mem_poke(long addr, uint64_t val, int type)
+{
+
+ jmpbuf_t *jb;
+
+ jb = exc_initialize_block();
+ if( jb == NULL ) {
+ return CFE_ERR_NOMEM;
+ }
+
+ if (exc_try(jb) == 0) {
+
+ switch (type) {
+ case MEM_BYTE:
+ *((volatile uint8_t *) addr) = (uint8_t) val;
+ break;
+ case MEM_HALFWORD:
+ *((volatile uint16_t *) addr) = (uint16_t) val;
+ break;
+ case MEM_WORD:
+ *((volatile uint32_t *) addr) = (uint32_t) val;
+ break;
+ case MEM_QUADWORD:
+ *((volatile uint64_t *) addr) = (uint64_t) val;
+ break;
+ default:
+ return CFE_ERR_INV_PARAM;
+ }
+
+ exc_cleanup_block(jb);
+ }
+ else {
+ /*Exception handler*/
+
+ exc_cleanup_handler(jb, EXC_NORMAL_RETURN);
+ return CFE_ERR_SETMEM;
+ }
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+