aboutsummaryrefslogtreecommitdiff
path: root/libgloss/mips/hal/mips_excpt_handler.c
diff options
context:
space:
mode:
Diffstat (limited to 'libgloss/mips/hal/mips_excpt_handler.c')
-rw-r--r--libgloss/mips/hal/mips_excpt_handler.c309
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;
+ }
+}