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

[Xen-devel] [PATCH ARM v4 08/12] mini-os: arm: show registers, stack and exception vector on fault



Signed-off-by: Thomas Leonard <talex5@xxxxxxxxx>
---
 extras/mini-os/ARM-TODO.txt          |  1 -
 extras/mini-os/arch/arm/arm32.S      | 81 ++++++++++++++++++++++++++---
 extras/mini-os/arch/arm/panic.c      | 99 ++++++++++++++++++++++++++++++++++++
 extras/mini-os/include/arm/arch_mm.h |  2 +-
 extras/mini-os/include/arm/os.h      |  2 +-
 5 files changed, 175 insertions(+), 10 deletions(-)
 create mode 100644 extras/mini-os/arch/arm/panic.c

diff --git a/extras/mini-os/ARM-TODO.txt b/extras/mini-os/ARM-TODO.txt
index 3d9be10..8f4f1da 100644
--- a/extras/mini-os/ARM-TODO.txt
+++ b/extras/mini-os/ARM-TODO.txt
@@ -1,4 +1,3 @@
-* support abort exception handling ( and others )
 * scheduling!
 * gic request_irq implementation, currently all IRQs all hardcoded in gic irq 
handler.
 * use device tree instead of the currently hardcoded values
diff --git a/extras/mini-os/arch/arm/arm32.S b/extras/mini-os/arch/arm/arm32.S
index 4f953ec..29fba72 100644
--- a/extras/mini-os/arch/arm/arm32.S
+++ b/extras/mini-os/arch/arm/arm32.S
@@ -80,16 +80,83 @@ shared_info_page:
 
 .align 3
 .globl stack
+.globl stack_end
 stack:
        .fill (4*1024), 4, 0x0
 stack_end:
 
 .align 3
+.globl irqstack
+.globl irqstack_end
 irqstack:
        .fill (1024), 4, 0x0
 irqstack_end:
+
+fault_dump:
+       .fill 18, 4, 0x0                @ On fault, we save the registers + 
CPSR + handler address
+
 .popsection
 
+fault:
+       cpsid   aif                     @ Disable interrupts
+
+       ldr     r13, =fault_dump
+       stmia   r13, {r0-r12}           @ Dump the non-banked registers 
directly (well, unless from FIQ mode)
+       str     r14, [r13, #15 << 2]    @ Our r14 is the faulting r15
+       mov     r0, r13
+
+       @ Save the caller's CPSR (our SPSR) too.
+       mrs     r1, SPSR
+       str     r1, [r13, #16 << 2]
+
+       @ Switch to the mode we came from to get r13 and r14.
+       @ If coming from user mode, use System mode instead so we're still
+       @ privileged.
+       and     r1, r1, #0x1f           @ r1 = SPSR mode
+       cmp     r1, #0x10               @ If from User mode
+       moveq   r1, #0x1f               @ Then use System mode instead
+
+       mrs     r3, CPSR                @ r3 = our CPSR
+       bic     r2, r3, #0x1f
+       orr     r2, r2, r1
+       msr     CPSR, r2                @ Change to mode r1
+
+       @ Save old mode's r13, r14
+       str     r13, [r0, #13 << 2]
+       str     r14, [r0, #14 << 2]
+
+       msr     CPSR, r3                @ Back to fault mode
+
+       ldr     r1, [r0, #17 << 2]
+       sub     r1, r1, #12             @ Fix to point at start of handler
+       str     r1, [r0, #17 << 2]
+
+       @ Call C code to format the register dump.
+       @ Clobbers the stack, but we're not going to return anyway.
+       ldr     r13, =stack_end
+       bl      dump_registers
+1:
+       wfi
+       b       1b
+
+@ We want to store a unique value to identify this handler, without corrupting
+@ any of the registers. So, we store r15 (which will point just after the 
branch).
+@ Later, we subtract 12 so the user gets pointed at the start of the exception
+@ handler.
+#define FAULT(name)                    \
+.globl fault_##name;                   \
+fault_##name:                          \
+       ldr     r13, =fault_dump;       \
+       str     r15, [r13, #17 << 2];   \
+       b       fault
+
+FAULT(reset)
+FAULT(undefined_instruction)
+FAULT(svc)
+FAULT(prefetch_call)
+FAULT(prefetch_abort)
+FAULT(data_abort)
+
 @ exception base address
 .align 5
 .globl exception_vector_table
@@ -99,13 +166,13 @@ irqstack_end:
 @  instruction to clear an existing tag is required on context switches."
 @ -- ARM Cortex-A Series Programmerâs Guide (Version: 4.0)
 exception_vector_table:
-       b       . @ reset
-       b       . @ undefined instruction
-       b       . @ supervisor call
-       b       . @ prefetch call
-       b       . @ prefetch abort
-       b       . @ data abort
-       b       irq_handler @ irq
+       b       fault_reset
+       b       fault_undefined_instruction
+       b       fault_svc
+       b       fault_prefetch_call
+       b       fault_prefetch_abort
+       b       fault_data_abort
+       b       irq_handler @ IRQ
        .word 0xe7f000f0    @ abort on FIQ
 
 irq_handler:
diff --git a/extras/mini-os/arch/arm/panic.c b/extras/mini-os/arch/arm/panic.c
new file mode 100644
index 0000000..12735d6
--- /dev/null
+++ b/extras/mini-os/arch/arm/panic.c
@@ -0,0 +1,99 @@
+/******************************************************************************
+ * panic.c
+ *
+ * Displays a register dump and stack trace for debugging.
+ *
+ * Copyright (c) 2014, Thomas Leonard
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <mini-os/os.h>
+#include <arch_mm.h>
+
+extern int stack[];
+extern int stack_end[];
+extern int irqstack[];
+extern int irqstack_end[];
+
+typedef void handler(void);
+
+extern handler fault_reset;
+extern handler fault_undefined_instruction;
+extern handler fault_svc;
+extern handler fault_prefetch_call;
+extern handler fault_prefetch_abort;
+extern handler fault_data_abort;
+
+void dump_registers(int *saved_registers) {
+    static int in_dump = 0;
+    int *sp, *stack_top, *x;
+    char *fault_name;
+    void *fault_handler;
+    int i;
+
+    if (in_dump)
+    {
+        printk("Crash while in dump_registers! Not generating a second 
report.\n");
+        return;
+    }
+
+    in_dump = 1;
+
+    fault_handler = (handler *) saved_registers[17];
+    if (fault_handler == fault_reset)
+        fault_name = "reset";
+    else if (fault_handler == fault_undefined_instruction)
+        fault_name = "undefined_instruction";
+    else if (fault_handler == fault_svc)
+        fault_name = "svc";
+    else if (fault_handler == fault_prefetch_call)
+        fault_name = "prefetch_call";
+    else if (fault_handler == fault_prefetch_abort)
+        fault_name = "prefetch_abort";
+    else if (fault_handler == fault_data_abort)
+        fault_name = "data_abort";
+    else
+        fault_name = "unknown fault type!";
+
+    printk("Fault handler at %x called (%s)\n", fault_handler, fault_name);
+
+    for (i = 0; i < 16; i++) {
+        printk("r%d = %x\n", i, saved_registers[i]);
+    }
+    printk("CPSR = %x\n", saved_registers[16]);
+
+    printk("Stack dump (innermost last)\n");
+    sp = (int *) saved_registers[13];
+
+    if (sp >= stack && sp <= stack_end)
+        stack_top = stack_end;                          /* The small boot 
stack */
+    else if (sp >= irqstack && sp <= irqstack_end)
+        stack_top = irqstack_end;                       /* The small IRQ stack 
*/
+    else
+        stack_top = (int *) ((((unsigned long) sp) | (__STACK_SIZE-1)) + 1);   
     /* A normal thread stack */
+
+    for (x = stack_top - 1; x >= sp; x--)
+    {
+        printk("  [%8p] %8x\n", x, *x);
+    }
+    printk("End of stack\n");
+
+    in_dump = 0;
+}
diff --git a/extras/mini-os/include/arm/arch_mm.h 
b/extras/mini-os/include/arm/arch_mm.h
index be14ada..e943a9b 100644
--- a/extras/mini-os/include/arm/arch_mm.h
+++ b/extras/mini-os/include/arm/arch_mm.h
@@ -2,7 +2,7 @@
 #define _ARCH_MM_H_
 
 extern char _text, _etext, _erodata, _edata, _end, __bss_start;
-extern char stack[];
+extern int stack[];
 
 #define PAGE_SHIFT        12
 #define PAGE_SIZE        (1 << PAGE_SHIFT)
diff --git a/extras/mini-os/include/arm/os.h b/extras/mini-os/include/arm/os.h
index 21e9276..8d76089 100644
--- a/extras/mini-os/include/arm/os.h
+++ b/extras/mini-os/include/arm/os.h
@@ -10,7 +10,7 @@
 void arch_fini(void);
 void timer_handler(evtchn_port_t port, struct pt_regs *regs, void *ign);
 
-#define BUG() while(1){}
+#define BUG() while(1){asm volatile (".word 0xe7f000f0\n");} /* Undefined 
instruction; will call our fault handler. */
 
 #define smp_processor_id() 0
 
-- 
2.0.0


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.