diff options
Diffstat (limited to 'libgloss/mips/hal/mips_excpt_handler.c')
-rw-r--r-- | libgloss/mips/hal/mips_excpt_handler.c | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/libgloss/mips/hal/mips_excpt_handler.c b/libgloss/mips/hal/mips_excpt_handler.c new file mode 100644 index 0000000..c763d7f --- /dev/null +++ b/libgloss/mips/hal/mips_excpt_handler.c @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2014-2018 MIPS Tech, LLC + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY 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) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <mips/cpu.h> +#include <mips/fpa.h> +#include <mips/hal.h> +#include <mips/uhi_syscalls.h> + +/* Defined in .ld file */ +extern char __use_excpt_boot[]; +extern char __attribute__((weak)) __flush_to_zero[]; + +#ifdef VERBOSE_EXCEPTIONS +/* + * Write a string, a formatted number, then a string. + */ +static void +putsnds (const char *pre, reg_t value, int digits, const char *post) +{ + char buf[digits]; + int shift; + int idx = 0; + + if (pre != NULL) + write (1, pre, strlen (pre)); + + for (shift = ((digits - 1) * 4) ; shift >= 0 ; shift -= 4) + buf[idx++] = "0123456789ABCDEF"[(value >> shift) & 0xf]; + write (1, buf, digits); + + if (post != NULL) + write (1, post, strlen (post)); +} + +static void +putsns (const char *pre, reg_t value, const char *post) +{ + putsnds (pre, value, sizeof (reg_t) * 2, post); +} + +# define WRITE(MSG) write (1, (MSG), strlen (MSG)) +# define PUTSNDS(PRE, VALUE, DIGITS, POST) \ + putsnds ((PRE), (VALUE), (DIGITS), (POST)) +# define PUTSNS(PRE, VALUE, POST) \ + putsns ((PRE), (VALUE), (POST)) + +#else + +# define WRITE(MSG) +# define PUTSNDS(PRE, VALUE, DIGITS, POST) +# define PUTSNS(PRE, VALUE, POST) + +#endif // !VERBOSE_EXCEPTIONS + +/* Handle an exception */ +#ifdef VERBOSE_EXCEPTIONS +void _MIPS_HAL_NOMIPS16 +__exception_handle_verbose (struct gpctx *ctx, int exception) +#else +void _MIPS_HAL_NOMIPS16 +__exception_handle_quiet (struct gpctx *ctx, int exception) +#endif +{ + switch (exception) + { + case EXC_MOD: + WRITE ("TLB modification exception\n"); + break; + case EXC_TLBL: + PUTSNS ("TLB error on load from 0x", ctx->badvaddr, NULL); + PUTSNS (" @0x", ctx->epc, "\n"); + break; + case EXC_TLBS: + PUTSNS ("TLB error on store to 0x", ctx->badvaddr, NULL); + PUTSNS (" @0x", ctx->epc, "\n"); + break; + case EXC_ADEL: + PUTSNS ("Address error on load from 0x", ctx->badvaddr, NULL); + PUTSNS (" @0x", ctx->epc, "\n"); + break; + case EXC_ADES: + PUTSNS ("Address error on store to 0x", ctx->badvaddr, NULL); + PUTSNS (" @0x", ctx->epc, "\n"); + break; + case EXC_IBE: + WRITE ("Instruction bus error\n"); + break; + case EXC_DBE: + WRITE ("Data bus error\n"); + break; + case EXC_SYS: + /* Process a UHI SYSCALL, all other SYSCALLs should have been processed + by our caller. __use_excpt_boot has following values: + 0 = Do not use exception handler present in boot. + 1 = Use exception handler present in boot if BEV + is 0 at startup. + 2 = Always use exception handler present in boot. */ + + /* Special handling for boot/low level failures. */ + if (ctx->t2[1] == __MIPS_UHI_BOOTFAIL) + { + switch (ctx->a[0]) + { + case __MIPS_UHI_BF_CACHE: + WRITE ("L2 cache configuration error\n"); + break; + default: + WRITE ("Unknown boot failure error\n"); + break; + } + + /* These are unrecoverable. Abort. */ + ctx->epc = (sreg_t)(long)&__exit; + /* Exit code of 255 */ + ctx->a[0] = 0xff; + return; + } + + if (((long) __use_excpt_boot == 2 + || ((long) __use_excpt_boot == 1 + && __get_startup_BEV + && __get_startup_BEV () == 0)) + && __chain_uhi_excpt) + /* This will not return. */ + __chain_uhi_excpt (ctx); + else + __uhi_indirect (ctx); + return; + case EXC_BP: + /* Return from exception handler if breakpoint is handled. */ + if (__uhi_break && __uhi_break (ctx)) + return; + PUTSNS ("Breakpoint @0x", ctx->epc, "\n"); + break; + case EXC_RI: + PUTSNS ("Illegal instruction @0x", ctx->epc, "\n"); + break; + case EXC_CPU: + PUTSNS ("Coprocessor unusable @0x", ctx->epc, "\n"); + break; + case EXC_OVF: + WRITE ("Overflow\n"); + break; + case EXC_TRAP: + WRITE ("Trap\n"); + break; + case EXC_MSAFPE: +#if MIPS_MSA_USABLE + if (__flush_to_zero + && (msa_getsr () & FPA_CSR_UNI_X) + && (msa_getsr () & FPA_CSR_FS) == 0) + { + unsigned int sr = msa_getsr (); + sr &= ~FPA_CSR_UNI_X; + sr |= FPA_CSR_FS; + msa_setsr (sr); + return; + } +#endif + WRITE ("MSA Floating point error\n"); + break; + case EXC_FPE: + /* Turn on flush to zero the first time we hit an unimplemented + operation. If we hit it again then stop. */ + if (__flush_to_zero + && (fpa_getsr () & FPA_CSR_UNI_X) + && (fpa_getsr () & FPA_CSR_FS) == 0) + { + unsigned int sr = fpa_getsr (); + sr &= ~FPA_CSR_UNI_X; + sr |= FPA_CSR_FS; + fpa_setsr (sr); + + return; + } + WRITE ("Floating point error\n"); + break; + case EXC_IS1: + WRITE ("Implementation specific exception (16)\n"); + break; + case EXC_IS2: + WRITE ("Implementation specific exception (17)\n"); + break; + case EXC_C2E: + WRITE ("Precise Coprocessor 2 exception\n"); + break; + case EXC_TLBRI: + WRITE ("TLB read inhibit exception\n"); + break; + case EXC_TLBXI: + WRITE ("TLB execute inhibit exception\n"); + break; + case EXC_MSAU: + PUTSNS ("MSA unusable @0x", ctx->epc, "\n"); + break; + case EXC_MDMX: + PUTSNS ("MDMX exception @0x", ctx->epc, "\n"); + break; + case EXC_WATCH: + PUTSNS ("Watchpoint @0x", ctx->epc, "\n"); + break; + case EXC_MCHECK: + WRITE ("Machine check error\n"); + break; + case EXC_THREAD: + WRITE ("Thread exception\n"); + break; + case EXC_DSPU: + WRITE ("DSP unusable\n"); + break; + case EXC_RES30: + WRITE ("Cache error\n"); + break; + default: + PUTSNS ("Unhandled exception ", exception, "\n"); + } + + /* Dump registers */ + PUTSNS (" 0:\t", 0, "\t"); + PUTSNS ("at:\t", ctx->at, "\t"); + PUTSNS ("v0:\t", ctx->v[0], "\t"); + PUTSNS ("v1:\t", ctx->v[1], "\n"); + + PUTSNS ("a0:\t", ctx->a[0], "\t"); + PUTSNS ("a1:\t", ctx->a[1], "\t"); + PUTSNS ("a2:\t", ctx->a[2], "\t"); + PUTSNS ("a3:\t", ctx->a[3], "\n"); + + PUTSNS ("t0:\t", ctx->t[0], "\t"); + PUTSNS ("t1:\t", ctx->t[1], "\t"); + PUTSNS ("t2:\t", ctx->t[2], "\t"); + PUTSNS ("t3:\t", ctx->t[3], "\n"); + + PUTSNS ("t4:\t", ctx->t[4], "\t"); + PUTSNS ("t5:\t", ctx->t[5], "\t"); + PUTSNS ("t6:\t", ctx->t[6], "\t"); + PUTSNS ("t7:\t", ctx->t[7], "\n"); + + PUTSNS ("s0:\t", ctx->s[0], "\t"); + PUTSNS ("s1:\t", ctx->s[1], "\t"); + PUTSNS ("s2:\t", ctx->s[2], "\t"); + PUTSNS ("s3:\t", ctx->s[3], "\n"); + + PUTSNS ("s4:\t", ctx->s[4], "\t"); + PUTSNS ("s5:\t", ctx->s[5], "\t"); + PUTSNS ("s6:\t", ctx->s[6], "\t"); + PUTSNS ("s7:\t", ctx->s[7], "\n"); + + PUTSNS ("t8:\t", ctx->t2[0], "\t"); + PUTSNS ("t9:\t", ctx->t2[1], "\t"); + PUTSNS ("k0:\t", ctx->k[0], "\t"); + PUTSNS ("k1:\t", ctx->k[1], "\n"); + + PUTSNS ("gp:\t", ctx->gp, "\t"); + PUTSNS ("sp:\t", ctx->sp, "\t"); + PUTSNS ("fp:\t", ctx->fp, "\t"); + PUTSNS ("ra:\t", ctx->ra, "\n"); + +#if __mips_isa_rev < 6 + PUTSNS ("hi:\t", ctx->hi, "\t"); + PUTSNS ("lo:\t", ctx->lo, "\n"); +#endif + + PUTSNS ("epc: \t", ctx->epc, "\n"); + PUTSNS ("BadVAddr:\t", ctx->badvaddr, "\n"); + + PUTSNDS ("Status: \t", ctx->status, 8, "\n"); + PUTSNDS ("Cause: \t", ctx->cause, 8, "\n"); + PUTSNDS ("BadInstr: \t", ctx->badinstr, 8, "\n"); + PUTSNDS ("BadPInstr:\t", ctx->badpinstr, 8, "\n"); + + /* Raise UHI exception which may or may not return. */ + if (__uhi_exception (ctx, UHI_ABI) != 0) + { + /* The exception was acknowledged but not handled. Abort. */ + ctx->epc = (sreg_t)(long)&__exit; + /* Exit code of 255 */ + ctx->a[0] = 0xff; + } +} |