summaryrefslogtreecommitdiff
path: root/arch/mips/lib/traps.c
diff options
context:
space:
mode:
authorDaniel Schwierzeck <daniel.schwierzeck@gmail.com>2016-01-09 18:34:14 +0100
committerDaniel Schwierzeck <daniel.schwierzeck@gmail.com>2016-11-30 16:12:17 +0100
commit6c59363004e6d3f860623daa330eef17fbccd8cd (patch)
treefc01f1fd2046ed2c4bdc896f76a974fa40ca4bb7 /arch/mips/lib/traps.c
parentbd60252811c3c81dd0a32c0871b9116ba160190f (diff)
MIPS: add handling for generic and EJTAG exceptions
Add exception handlers for generic and EJTAG exceptions. Most of the assembly code is imported from Linux kernel and adapted to U-Boot. The exception vector table will be reserved above the stack before U-Boot is relocated. The exception handlers will be installed and activated after relocation in the initr_traps hook function. Generic exceptions are handled by showing a CPU register dump similar to Linux kernel. For example: malta # md 1 00000001: Ooops: $ 0 : 00000000 00000000 00000009 00000004 $ 4 : 8ff7e108 00000000 0000003a 00000000 $ 8 : 00000008 00000001 8ff7cd18 00000004 $12 : 00000002 00000000 00000005 0000003a $16 : 00000004 00000040 00000001 00000001 $20 : 00000000 8fff53c0 00000008 00000004 $24 : ffffffff 8ffdea44 $28 : 90001650 8ff7cd00 00000004 8ffe6818 Hi : 00000000 Lo : 00000004 epc : 8ffe6848 (text bfc28848) ra : 8ffe6818 (text bfc28818) Status: 00000006 Cause : 00000410 (ExcCode 04) BadVA : 8ff9e928 PrId : 00019300 ### ERROR ### Please RESET the board ### EJTAG exceptions are checked for SDBBP and delegated to the SDBBP handler if necessary. Otherwise the debug mode will simply be exited. The SDBBP handler currently prints the contents of registers c0_depc and c0_debug. This could be extended in the future to handle semi-hosting according to the MIPS UHI specification. Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com> Reviewed-by: Paul Burton <paul.burton@imgtec.com> Tested-by: Paul Burton <paul.burton@imgtec.com>
Diffstat (limited to 'arch/mips/lib/traps.c')
-rw-r--r--arch/mips/lib/traps.c106
1 files changed, 106 insertions, 0 deletions
diff --git a/arch/mips/lib/traps.c b/arch/mips/lib/traps.c
new file mode 100644
index 0000000000..18622c223d
--- /dev/null
+++ b/arch/mips/lib/traps.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 1994 - 1999, 2000, 01, 06 Ralf Baechle
+ * Copyright (C) 1995, 1996 Paul M. Antoine
+ * Copyright (C) 1998 Ulf Carlsson
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2002, 2003, 2004, 2005, 2007 Maciej W. Rozycki
+ * Copyright (C) 2000, 2001, 2012 MIPS Technologies, Inc. All rights reserved.
+ * Copyright (C) 2014, Imagination Technologies Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <asm/system.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void show_regs(const struct pt_regs *regs)
+{
+ const int field = 2 * sizeof(unsigned long);
+ unsigned int cause = regs->cp0_cause;
+ unsigned int exccode;
+ int i;
+
+ /*
+ * Saved main processor registers
+ */
+ for (i = 0; i < 32; ) {
+ if ((i % 4) == 0)
+ printf("$%2d :", i);
+ if (i == 0)
+ printf(" %0*lx", field, 0UL);
+ else if (i == 26 || i == 27)
+ printf(" %*s", field, "");
+ else
+ printf(" %0*lx", field, regs->regs[i]);
+
+ i++;
+ if ((i % 4) == 0)
+ puts("\n");
+ }
+
+ printf("Hi : %0*lx\n", field, regs->hi);
+ printf("Lo : %0*lx\n", field, regs->lo);
+
+ /*
+ * Saved cp0 registers
+ */
+ printf("epc : %0*lx (text %0*lx)\n", field, regs->cp0_epc,
+ field, regs->cp0_epc - gd->reloc_off);
+ printf("ra : %0*lx (text %0*lx)\n", field, regs->regs[31],
+ field, regs->regs[31] - gd->reloc_off);
+
+ printf("Status: %08x\n", (uint32_t) regs->cp0_status);
+
+ exccode = (cause & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE;
+ printf("Cause : %08x (ExcCode %02x)\n", cause, exccode);
+
+ if (1 <= exccode && exccode <= 5)
+ printf("BadVA : %0*lx\n", field, regs->cp0_badvaddr);
+
+ printf("PrId : %08x\n", read_c0_prid());
+}
+
+void do_reserved(const struct pt_regs *regs)
+{
+ puts("\nOoops:\n");
+ show_regs(regs);
+ hang();
+}
+
+void do_ejtag_debug(const struct pt_regs *regs)
+{
+ const int field = 2 * sizeof(unsigned long);
+ unsigned long depc;
+ unsigned int debug;
+
+ depc = read_c0_depc();
+ debug = read_c0_debug();
+
+ printf("SDBBP EJTAG debug exception: c0_depc = %0*lx, DEBUG = %08x\n",
+ field, depc, debug);
+}
+
+static void set_handler(unsigned long offset, void *addr, unsigned long size)
+{
+ unsigned long ebase = gd->irq_sp;
+
+ memcpy((void *)(ebase + offset), addr, size);
+ flush_cache(ebase + offset, size);
+}
+
+void trap_init(ulong reloc_addr)
+{
+ unsigned long ebase = gd->irq_sp;
+
+ set_handler(0x180, &except_vec3_generic, 0x80);
+ set_handler(0x280, &except_vec_ejtag_debug, 0x80);
+
+ write_c0_ebase(ebase);
+ clear_c0_status(ST0_BEV);
+ execution_hazard_barrier();
+}