[PATCH] MIPS: add initial exceptions handling

Antony Pavlov antonynpavlov at gmail.com
Wed Jul 25 18:00:27 EDT 2012


Checking exception handling:

    $ make qemu-malta_defconfig
    $ make

    ...

    $ qemu-system-mips -nodefaults -M malta -m 256 \
       -nographic -serial stdio -bios ./barebox.bin

    ...

    barebox:/ md -l 0x03

    Ooops, address error on load or ifetch!
    EPC = 0xa082783c
    CP0_STATUS = 0x00000006
    CP0_CAUSE = 0x00000410
    CP0_CONFIG = 0x80008482

    ### ERROR ### Please RESET the board ###

Signed-off-by: Antony Pavlov <antonynpavlov at gmail.com>
---
 arch/mips/boot/main_entry.c       |   47 ++++++++++++++++
 arch/mips/include/asm/addrspace.h |  109 +++++++++++++++++++++++++++++++++++++
 arch/mips/lib/Makefile            |    2 +
 arch/mips/lib/genex.S             |   31 +++++++++++
 arch/mips/lib/traps.c             |  107 ++++++++++++++++++++++++++++++++++++
 5 files changed, 296 insertions(+)
 create mode 100644 arch/mips/include/asm/addrspace.h
 create mode 100644 arch/mips/lib/genex.S
 create mode 100644 arch/mips/lib/traps.c

diff --git a/arch/mips/boot/main_entry.c b/arch/mips/boot/main_entry.c
index 8f5f6fc..a38ad31 100644
--- a/arch/mips/boot/main_entry.c
+++ b/arch/mips/boot/main_entry.c
@@ -25,11 +25,56 @@
 #include <string.h>
 #include <asm/sections.h>
 #include <asm/cpu-features.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
 
 extern void start_barebox(void);
+extern void handle_reserved(void);
 
 void main_entry(void);
 
+unsigned long exception_handlers[32];
+
+static void set_except_vector(int n, void *addr)
+{
+	unsigned handler = (unsigned long) addr;
+
+	exception_handlers[n] = handler;
+}
+
+static void trap_init(void)
+{
+	extern char except_vec3_generic;
+	int i;
+
+	unsigned long ebase;
+
+	ebase = CKSEG1;
+
+	/*
+	 * Copy the generic exception handlers to their final destination.
+	 * This will be overriden later as suitable for a particular
+	 * configuration.
+	 */
+	memcpy((void *)(ebase + 0x180), &except_vec3_generic, 0x80);
+
+	/*
+	 * Setup default vectors
+	 */
+	for (i = 0; i <= 31; i++) {
+		set_except_vector(i, &handle_reserved);
+	}
+
+	if (!cpu_has_4kex)
+		memcpy((void *)(ebase + 0x080), &except_vec3_generic, 0x80);
+
+	/* FIXME: handle tlb */
+	memcpy((void *)(ebase), &except_vec3_generic, 0x80);
+
+	/* unset BOOT EXCEPTION VECTOR bit */
+	write_c0_status(read_c0_status() & ~ST0_BEV);
+}
+
 /**
  * Called plainly from assembler code
  *
@@ -48,5 +93,7 @@ void main_entry(void)
 		r4k_cache_init();
 	}
 
+	trap_init();
+
 	start_barebox();
 }
diff --git a/arch/mips/include/asm/addrspace.h b/arch/mips/include/asm/addrspace.h
new file mode 100644
index 0000000..17d480d
--- /dev/null
+++ b/arch/mips/include/asm/addrspace.h
@@ -0,0 +1,109 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1996, 99 Ralf Baechle
+ * Copyright (C) 2000, 2002  Maciej W. Rozycki
+ * Copyright (C) 1990, 1999 by Silicon Graphics, Inc.
+ */
+#ifndef _ASM_ADDRSPACE_H
+#define _ASM_ADDRSPACE_H
+
+/*
+ *  Configure language
+ */
+#ifdef __ASSEMBLY__
+#define _ATYPE_
+#define _ATYPE32_
+#define _ATYPE64_
+#define _CONST64_(x)	x
+#else
+#define _ATYPE_		__PTRDIFF_TYPE__
+#define _ATYPE32_	int
+#define _ATYPE64_	__s64
+#ifdef CONFIG_64BIT
+#define _CONST64_(x)	x ## L
+#else
+#define _CONST64_(x)	x ## LL
+#endif
+#endif
+
+/*
+ *  32-bit MIPS address spaces
+ */
+#ifdef __ASSEMBLY__
+#define _ACAST32_
+#define _ACAST64_
+#else
+#define _ACAST32_		(_ATYPE_)(_ATYPE32_)	/* widen if necessary */
+#define _ACAST64_		(_ATYPE64_)		/* do _not_ narrow */
+#endif
+
+/*
+ * Returns the kernel segment base of a given address
+ */
+#define KSEGX(a)		((_ACAST32_(a)) & 0xe0000000)
+
+/*
+ * Returns the physical address of a CKSEGx / XKPHYS address
+ */
+#define CPHYSADDR(a)		((_ACAST32_(a)) & 0x1fffffff)
+#define XPHYSADDR(a)            ((_ACAST64_(a)) &			\
+				 _CONST64_(0x000000ffffffffff))
+
+#ifdef CONFIG_64BIT
+
+/*
+ * Memory segments (64bit kernel mode addresses)
+ * The compatibility segments use the full 64-bit sign extended value.  Note
+ * the R8000 doesn't have them so don't reference these in generic MIPS code.
+ */
+#define XKUSEG			_CONST64_(0x0000000000000000)
+#define XKSSEG			_CONST64_(0x4000000000000000)
+#define XKPHYS			_CONST64_(0x8000000000000000)
+#define XKSEG			_CONST64_(0xc000000000000000)
+#define CKSEG0			_CONST64_(0xffffffff80000000)
+#define CKSEG1			_CONST64_(0xffffffffa0000000)
+#define CKSSEG			_CONST64_(0xffffffffc0000000)
+#define CKSEG3			_CONST64_(0xffffffffe0000000)
+
+#define CKSEG0ADDR(a)		(CPHYSADDR(a) | CKSEG0)
+#define CKSEG1ADDR(a)		(CPHYSADDR(a) | CKSEG1)
+#define CKSEG2ADDR(a)		(CPHYSADDR(a) | CKSEG2)
+#define CKSEG3ADDR(a)		(CPHYSADDR(a) | CKSEG3)
+
+#else
+
+#define CKSEG0ADDR(a)		(CPHYSADDR(a) | KSEG0)
+#define CKSEG1ADDR(a)		(CPHYSADDR(a) | KSEG1)
+#define CKSEG2ADDR(a)		(CPHYSADDR(a) | KSEG2)
+#define CKSEG3ADDR(a)		(CPHYSADDR(a) | KSEG3)
+
+/*
+ * Map an address to a certain kernel segment
+ */
+#define KSEG0ADDR(a)		(CPHYSADDR(a) | KSEG0)
+#define KSEG1ADDR(a)		(CPHYSADDR(a) | KSEG1)
+#define KSEG2ADDR(a)		(CPHYSADDR(a) | KSEG2)
+#define KSEG3ADDR(a)		(CPHYSADDR(a) | KSEG3)
+
+/*
+ * Memory segments (32bit kernel mode addresses)
+ * These are the traditional names used in the 32-bit universe.
+ */
+#define KUSEG			0x00000000
+#define KSEG0			0x80000000
+#define KSEG1			0xa0000000
+#define KSEG2			0xc0000000
+#define KSEG3			0xe0000000
+
+#define CKUSEG			0x00000000
+#define CKSEG0			0x80000000
+#define CKSEG1			0xa0000000
+#define CKSEG2			0xc0000000
+#define CKSEG3			0xe0000000
+
+#endif
+
+#endif /* _ASM_ADDRSPACE_H */
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index b99bb71..a31046b 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -5,6 +5,8 @@ obj-y += ashldi3.o
 obj-y += ashrdi3.o
 obj-y += memory.o
 obj-y += cpu-probe.o
+obj-y += traps.o
+obj-y += genex.o
 
 obj-$(CONFIG_CPU_MIPS32) += c-r4k.o
 obj-$(CONFIG_CPU_MIPS64) += c-r4k.o
diff --git a/arch/mips/lib/genex.S b/arch/mips/lib/genex.S
new file mode 100644
index 0000000..d6f65a2
--- /dev/null
+++ b/arch/mips/lib/genex.S
@@ -0,0 +1,31 @@
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+
+	.text
+	.set	macro
+	.set	noat
+	.set	noreorder
+	.align	5
+
+/* Exception vector */
+NESTED(handle_reserved, 0, sp)
+	la	k0, barebox_exc_handler
+	jal	k0
+	 move	a0, sp
+	/* will never return here */
+	END(handle_reserved)
+
+/* General exception vector */
+NESTED(except_vec3_generic, 0, sp)
+	.set	noat
+	mfc0	k1, CP0_CAUSE
+	la	k0, exception_handlers
+	andi	k1, k1, 0x7c
+	addu	k0, k0, k1
+	lw	k0, (k0)
+	nop
+	jr	k0
+	 nop
+	END(except_vec3_generic)
+	.set	at
diff --git a/arch/mips/lib/traps.c b/arch/mips/lib/traps.c
new file mode 100644
index 0000000..4e167cc
--- /dev/null
+++ b/arch/mips/lib/traps.c
@@ -0,0 +1,107 @@
+#include <common.h>
+
+#include <asm/mipsregs.h>
+
+void barebox_exc_handler(void *regs);
+
+/*
+ * Trap codes from OpenBSD trap.h
+ */
+#define T_INT			0	/* Interrupt pending */
+#define T_TLB_MOD		1	/* TLB modified fault */
+#define T_TLB_LD_MISS		2	/* TLB miss on load or ifetch */
+#define T_TLB_ST_MISS		3	/* TLB miss on a store */
+#define T_ADDR_ERR_LD		4	/* Address error on a load or ifetch */
+#define T_ADDR_ERR_ST		5	/* Address error on a store */
+#define T_BUS_ERR_IFETCH	6	/* Bus error on an ifetch */
+#define T_BUS_ERR_LD_ST		7	/* Bus error on a load or store */
+#define T_SYSCALL		8	/* System call */
+#define T_BREAK			9	/* Breakpoint */
+#define T_RES_INST		10	/* Reserved instruction exception */
+#define T_COP_UNUSABLE		11	/* Coprocessor unusable */
+#define T_OVFLOW		12	/* Arithmetic overflow */
+#define T_TRAP			13	/* Trap instruction */
+#define T_VCEI			14	/* Virtual coherency instruction */
+#define T_FPE			15	/* Floating point exception */
+#define T_IWATCH		16	/* Inst. Watch address reference */
+#define T_DWATCH		23	/* Data Watch address reference */
+#define T_VCED			31	/* Virtual coherency data */
+
+#define CR_EXC_CODE             0x0000007c
+#define CR_EXC_CODE_SHIFT       2
+
+static char *get_exc_name(u32 cause)
+{
+	switch ((cause & CR_EXC_CODE) >> CR_EXC_CODE_SHIFT) {
+
+	case T_INT:
+		return "interrupt pending";
+
+	case T_TLB_MOD:
+		return "TLB modified";
+
+	case T_TLB_LD_MISS:
+		return "TLB miss on load or ifetch";
+
+	case T_TLB_ST_MISS:
+		return "TLB miss on store";
+
+	case T_ADDR_ERR_LD:
+		return "address error on load or ifetch";
+
+	case T_ADDR_ERR_ST:
+		return "address error on store";
+
+	case T_BUS_ERR_IFETCH:
+		return "bus error on ifetch";
+
+	case T_BUS_ERR_LD_ST:
+		return "bus error on load or store";
+
+	case T_SYSCALL:
+		return "system call";
+
+	case T_BREAK:
+		return "breakpoint";
+
+	case T_RES_INST:
+		return "reserved instruction";
+
+	case T_COP_UNUSABLE:
+		return "coprocessor unusable";
+
+	case T_OVFLOW:
+		return "arithmetic overflow";
+
+	case T_TRAP:
+		return "trap instruction";
+
+	case T_VCEI:
+		return "virtual coherency instruction";
+
+	case T_FPE:
+		return "floating point";
+
+	case T_IWATCH:
+		return "iwatch";
+
+	case T_DWATCH:
+		return "dwatch";
+
+	case T_VCED:
+		return "virtual coherency data";
+	}
+
+	return "unknown exception";
+}
+
+void barebox_exc_handler(void *regs)
+{
+	printf("\nOoops, %s!\n", get_exc_name(read_c0_cause()));
+	printf("EPC = 0x%08x\n", read_c0_epc());
+	printf("CP0_STATUS = 0x%08x\n", read_c0_status());
+	printf("CP0_CAUSE = 0x%08x\n", read_c0_cause());
+	printf("CP0_CONFIG = 0x%08x\n\n", read_c0_config());
+
+	hang();
+}
-- 
1.7.10




More information about the barebox mailing list