[PATCH 9/9] arm: add vectors support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add support for tests to manage exception handlers. Now we need kvm.

Signed-off-by: Andrew Jones <drjones@xxxxxxxxxx>
---
 arm/boot.c            | 29 +++++++++++++++++++----
 arm/cstart.S          | 46 ++++++++++++++++++++++++++++++++++++
 arm/run               |  2 +-
 arm/unittests.cfg     |  6 +++++
 config/config-arm.mak |  1 +
 lib/arm/bootinfo.c    |  2 --
 lib/arm/processor.h   | 45 +++++++++++++++++++++++++++++++++++
 lib/arm/vectors.c     | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/arm/vectors.h     | 37 +++++++++++++++++++++++++++++
 lib/libcflat.h        |  2 ++
 10 files changed, 227 insertions(+), 8 deletions(-)
 create mode 100644 lib/arm/processor.h
 create mode 100644 lib/arm/vectors.c
 create mode 100644 lib/arm/vectors.h

diff --git a/arm/boot.c b/arm/boot.c
index 375e8708a7c54..5103499b83155 100644
--- a/arm/boot.c
+++ b/arm/boot.c
@@ -1,5 +1,10 @@
 #include "libcflat.h"
 #include "arm/bootinfo.h"
+#include "arm/vectors.h"
+
+#define die(msg...) printf(msg), exit(1)
+
+static bool svc_works;
 
 static bool info_check(u32 var, char *expected)
 {
@@ -10,18 +15,32 @@ static bool info_check(u32 var, char *expected)
     return !strcmp(var_str, expected);
 }
 
+static void svc_check(struct ex_regs *regs __unused)
+{
+    svc_works = true;
+}
+
+static bool vectors_check(void)
+{
+    handle_exception(V_SVC, svc_check);
+    asm volatile("svc #123");
+    return svc_works;
+}
+
 int main(int argc, char **argv)
 {
     int ret = 0;
 
-    if (argc < 3) {
-	printf("Not enough arguments. Can't test\n");
-	return 1;
-    }
+    if (argc < 1)
+	die("boot: No test name appended to qemu command line\n");
 
-    if (!strcmp(argv[0], "info"))
+    if (!strcmp(argv[0], "info")) {
+	if (argc < 3)
+	    die("boot info: Not enough arguments for test\n");
 	ret = !info_check(mem32.size, argv[1])
 		|| !info_check(core.pagesize, argv[2]);
+    } else if (!strcmp(argv[0], "vectors"))
+	ret = !vectors_check();
 
     return ret;
 }
diff --git a/arm/cstart.S b/arm/cstart.S
index a65809824d4f1..0907c620bd83f 100644
--- a/arm/cstart.S
+++ b/arm/cstart.S
@@ -1,5 +1,6 @@
 
 #define CR_B	(1 << 7)
+#define CR_V	(1 << 13)
 
 .arm
 
@@ -12,6 +13,13 @@ start:
 	push	{ r0-r3 }		@push r3 too for 8-byte alignment
 
 	mrc	p15, 0, r8, c1, c0, 0	@r8 = sctrl
+
+	/* set up vector table */
+	bic	r8, #CR_V		@sctrl.V = 0
+	mcr	p15, 0, r8, c1, c0, 0
+	ldr	r0, =vector_table	@vbar = vector_table
+	mcr     p15, 0, r0, c12, c0, 0
+
 	bl	get_endianness
 	bl	io_init
 
@@ -41,6 +49,44 @@ halt:
 1:	wfi
 	b	1b
 
+vector_common:
+	add	r2, sp, #(14 * 4)
+	mrs	r3, spsr
+	push	{ r0-r3 }	@push r0 too for padding
+	add	r0, sp, #4	@skip pad
+	bl	do_handle_exception
+	pop	{ r0-r3 }
+	msr	spsr_fsxc, r3
+	ldm	sp!, { r0-r12,pc }^
+
+.macro m_vector, v
+	push	{ r0-r12,lr }
+	mov	r1, \v
+	b	vector_common
+.endm
+
+reset:		m_vector #0
+undef:		m_vector #1
+svc:		m_vector #2
+prefetch:	m_vector #3
+data:		m_vector #4
+impossible:	m_vector #5
+irq:		m_vector #6
+fiq:		m_vector #7
+
+.section .text.ex
+.align 5
+
+vector_table:
+	b	reset
+	b	undef
+	b	svc
+	b	prefetch
+	b	data
+	b	impossible
+	b	irq
+	b	fiq
+
 .data
 
 .globl cpu_is_be
diff --git a/arm/run b/arm/run
index 64446e8907564..b512880e28cb7 100755
--- a/arm/run
+++ b/arm/run
@@ -10,7 +10,7 @@ fi
 
 command="$qemu -device $testdev -display none -serial stdio "
 command+="-M virt -cpu cortex-a15 "
-#command+="-enable-kvm "
+command+="-enable-kvm "
 command+="-kernel"
 echo $command "$@"
 $command "$@"
diff --git a/arm/unittests.cfg b/arm/unittests.cfg
index fb78cd906839a..9c4faa600e9c5 100644
--- a/arm/unittests.cfg
+++ b/arm/unittests.cfg
@@ -9,3 +9,9 @@
 [boot_info]
 file = boot.flat
 extra_params = -m 256 -append 'info 0x10000000 0x1000'
+groups = boot
+
+[boot_vectors]
+file = boot.flat
+extra_params = -append 'vectors'
+groups = boot
diff --git a/config/config-arm.mak b/config/config-arm.mak
index 066b1f725c5b3..87d61872ab16a 100644
--- a/config/config-arm.mak
+++ b/config/config-arm.mak
@@ -15,6 +15,7 @@ cflatobjs += \
 	lib/iomaps.o \
 	lib/virtio-testdev.o \
 	lib/arm/io.o \
+	lib/arm/vectors.o \
 	lib/arm/bootinfo.o
 
 $(libcflat): LDFLAGS += -nostdlib
diff --git a/lib/arm/bootinfo.c b/lib/arm/bootinfo.c
index c362064f661d9..fd74fac2c5a2f 100644
--- a/lib/arm/bootinfo.c
+++ b/lib/arm/bootinfo.c
@@ -49,8 +49,6 @@ static void read_atags(u32 id, u32 *info)
 	}
 }
 
-#define __unused __attribute__((__unused__))
-
 void read_bootinfo(u32 arg __unused, u32 id, u32 *info)
 {
     u32 *atags = NULL;
diff --git a/lib/arm/processor.h b/lib/arm/processor.h
new file mode 100644
index 0000000000000..32e1778477be2
--- /dev/null
+++ b/lib/arm/processor.h
@@ -0,0 +1,45 @@
+#ifndef _PROCESSOR_H_
+#define _PROCESSOR_H_
+#include "libcflat.h"
+
+#define __stringify_1(x...)	#x
+#define __stringify(x...)	__stringify_1(x)
+
+#undef __regfn
+#define __regfn(reg)						\
+static inline u32 read_##reg(void)				\
+{								\
+    u32 val;							\
+    asm volatile("mov %0, " __stringify(reg) : "=r" (val));	\
+    return val;							\
+}
+__regfn(lr)
+
+#undef __regfn
+#define __regfn(reg)						\
+static inline void write_##reg(u32 val)				\
+{								\
+    asm volatile("mov " __stringify(reg) ", %0" :: "r" (val));	\
+}
+__regfn(lr)
+
+#undef __regfn
+#define __regfn(reg)						\
+static inline u32 read_##reg(void)				\
+{								\
+    u32 val;							\
+    asm volatile("mrs %0, " __stringify(reg) : "=r" (val));	\
+    return val;							\
+}
+__regfn(cpsr)
+
+#undef __regfn
+#define __regfn(reg)						\
+static inline void write_##reg(u32 val)				\
+{								\
+    asm volatile("msr " __stringify(reg) ", %0" :: "r" (val));	\
+}
+__regfn(cpsr)
+
+#undef __regfn
+#endif
diff --git a/lib/arm/vectors.c b/lib/arm/vectors.c
new file mode 100644
index 0000000000000..c1e2dea519e56
--- /dev/null
+++ b/lib/arm/vectors.c
@@ -0,0 +1,65 @@
+#include "libcflat.h"
+#include "arm/processor.h"
+#include "arm/vectors.h"
+
+#define abort(msg...) \
+	printf(msg), dump_ex_regs(regs), exit(EINTR)
+
+const char *mode_names[] = {
+    "usr", "fiq", "irq", "svc", NULL, NULL, NULL,
+    "abt", NULL, NULL, NULL, "und",
+};
+
+const char *vector_names[] = {
+    "Reset", "Undefined", "SVC", "Prefetch abort", "Data abort",
+    "Impossible vector 0x14", "IRQ", "FIQ",
+};
+
+void dump_ex_regs(struct ex_regs *regs)
+{
+    u32 cpsr = read_cpsr();
+    u8 mode, smode;
+
+    mode = cpsr & MODE_MASK;
+    smode = ex_reg(regs, R_SPSR) & MODE_MASK;
+
+    printf("vector = %s\n", vector_name(ex_vector(regs)));
+    printf("mode %s to %s\n", mode_name(smode), mode_name(mode));
+    printf("cpsr=%x\n", cpsr);
+    printf(
+	"r0=%x\n" "r1=%x\n" "r2=%x\n" "r3=%x\n"
+	"r4=%x\n" "r5=%x\n" "r6=%x\n" "r7=%x\n"
+	"r8=%x\n" "r9=%x\n" "r10=%x\n" "r11=%x\n"
+	"ip=%x\n" "sp_%s=%x\n" "lr_%s=%x\n" "cpsr_%s=%x\n",
+	ex_reg(regs,0), ex_reg(regs,1), ex_reg(regs,2), ex_reg(regs,3),
+	ex_reg(regs,4), ex_reg(regs,5), ex_reg(regs,6), ex_reg(regs,7),
+	ex_reg(regs,8), ex_reg(regs,9), ex_reg(regs,10), ex_reg(regs,11),
+	ex_reg(regs, R_IP),
+	mode_name(mode), ex_reg(regs, R_SP),
+	mode_name(mode), ex_reg(regs, R_LR),
+	mode_name(mode), ex_reg(regs, R_SPSR)
+    );
+}
+
+static void (*exception_handlers[8])(struct ex_regs *regs);
+
+void handle_exception(u8 v, void (*func)(struct ex_regs *regs))
+{
+    if (v < 8)
+	exception_handlers[v] = func;
+}
+
+void do_handle_exception(struct ex_regs *regs)
+{
+    u8 v;
+
+    if ((v = ex_vector(regs)) > 7)
+	abort("%s called with vector=%d\n", __func__, v);
+
+    if (exception_handlers[v]) {
+	exception_handlers[v](regs);
+	return;
+    }
+
+    abort("Exception %s\n", vector_name(v));
+}
diff --git a/lib/arm/vectors.h b/lib/arm/vectors.h
new file mode 100644
index 0000000000000..ca074aab674a3
--- /dev/null
+++ b/lib/arm/vectors.h
@@ -0,0 +1,37 @@
+#ifndef _VECTORS_H_
+#define _VECTORS_H_
+
+/* modes */
+enum {
+    M_USR = 0x10, M_FIQ = 0x11, M_IRQ = 0x12, M_SVC = 0x13,
+    M_ABT = 0x17, M_UND = 0x1b,
+};
+#define MODE_MASK 0x1f
+extern const char *mode_names[];
+#define mode_name(m) mode_names[(m) - 0x10]
+
+/* vectors */
+enum {
+    V_RESET, V_UNDEF, V_SVC, V_PREFETCH_ABT, V_DATA_ABT,
+    V_IMPOSSIBLE, V_IRQ, V_FIQ,
+};
+extern const char *vector_names[];
+#define vector_name(v) vector_names[v]
+
+#define R_IP	12
+#define R_SP	13
+#define R_LR	14
+#define R_SPSR	16
+#define __ex_reg(n) \
+    ((n) == R_SP ? 1 : (n) == R_LR ? 16 : (n) == R_SPSR ? 2 : ((n)+3))
+#define ex_reg(regs, n) ((regs)->words[__ex_reg(n)])
+#define ex_vector(regs) ((regs)->words[0])
+
+struct ex_regs {
+    /* see cstart.S for the register push order */
+    unsigned long words[18];
+};
+
+void handle_exception(u8 v, void (*func)(struct ex_regs *regs));
+
+#endif
diff --git a/lib/libcflat.h b/lib/libcflat.h
index dce9a0f516e7e..6ebd903a27f46 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -68,6 +68,8 @@ extern long atol(const char *ptr);
 
 #define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
 
+#define __unused __attribute__((__unused__))
+
 #define NULL ((void *)0UL)
 #include "errno.h"
 #endif
-- 
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux