Add panic_hwtf() for kernel faults
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 18 Jul 2018 02:12:00 +0000 (22:12 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 18 Jul 2018 02:28:57 +0000 (22:28 -0400)
When the kernel faults, we would print the HWTF and maybe a backtrace,
and then panic.  These prints were not serialized like other panic
prints.  The new panic() would also print a backtrace of whoever called
panic, which isn't useful for faults (the stack frame was just the
handler).

panic_hwtf() will take a trapframe and print + backtrace that hw_tf
instead of backtracing the calling context.  This output will be
serialized, so the debug output from concurrent faults across multiple
cores won't be interleaved.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/x86/trap.c
kern/include/assert.h
kern/include/init.h
kern/src/init.c

index 0e326a2..82089b4 100644 (file)
@@ -273,9 +273,8 @@ static bool __handler_kernel_page_fault(struct hw_trapframe *hw_tf,
                /* This only runs from test_uaccess(), where it is expected to fail. */
                if (try_handle_exception_fixup(hw_tf))
                        return TRUE;
-               print_trapframe(hw_tf);
-               backtrace_hwtf(hw_tf);
-               panic("Proc-less Page Fault in the Kernel at %p!", fault_va);
+               panic_hwtf(hw_tf, "Proc-less Page Fault in the Kernel at %p!",
+                          fault_va);
        }
        /* TODO - handle kernel page faults.  This is dangerous, since we might be
         * holding locks in the kernel and could deadlock when we HPF.  For now, I'm
@@ -300,8 +299,6 @@ static bool __handler_kernel_page_fault(struct hw_trapframe *hw_tf,
        if (err) {
                if (try_handle_exception_fixup(hw_tf))
                        return TRUE;
-               print_trapframe(hw_tf);
-               backtrace_hwtf(hw_tf);
                /* Turn this on to help debug bad function pointers */
                printd("rsp %p\n\t 0(rsp): %p\n\t 8(rsp): %p\n\t 16(rsp): %p\n"
                       "\t24(rsp): %p\n", hw_tf->tf_rsp,
@@ -309,7 +306,7 @@ static bool __handler_kernel_page_fault(struct hw_trapframe *hw_tf,
                       *(uintptr_t*)(hw_tf->tf_rsp +  8),
                       *(uintptr_t*)(hw_tf->tf_rsp + 16),
                       *(uintptr_t*)(hw_tf->tf_rsp + 24));
-               panic("Proc-ful Page Fault in the Kernel at %p!", fault_va);
+               panic_hwtf(hw_tf, "Proc-ful Page Fault in the Kernel at %p!", fault_va);
                /* if we want to do something like kill a process or other code, be
                 * aware we are in a sort of irq-like context, meaning the main
                 * kernel code we 'interrupted' could be holding locks - even
@@ -537,9 +534,7 @@ void handle_nmi(struct hw_trapframe *hw_tf)
 
 void handle_double_fault(struct hw_trapframe *hw_tf)
 {
-       print_trapframe(hw_tf);
-       backtrace_hwtf(hw_tf);
-       panic("Double fault!  Check the kernel stack pointer; you likely ran off the end of the stack.");
+       panic_hwtf(hw_tf, "Double fault!  Check the kernel stack pointer; you likely ran off the end of the stack.");
 }
 
 /* Certain traps want IRQs enabled, such as the syscall.  Others can't handle
@@ -608,10 +603,8 @@ static void trap_dispatch(struct hw_trapframe *hw_tf)
        }
 
        if (!handled) {
-               if (in_kernel(hw_tf)) {
-                       print_trapframe(hw_tf);
-                       panic("Damn Damn!  Unhandled trap in the kernel!");
-               }
+               if (in_kernel(hw_tf))
+                       panic_hwtf(hw_tf, "Damn Damn!  Unhandled trap in the kernel!");
                reflect_unhandled_trap(hw_tf->tf_trapno, hw_tf->tf_err, aux);
        }
 }
@@ -668,10 +661,8 @@ void trap(struct hw_trapframe *hw_tf)
        }
        printd("Incoming TRAP %d on core %d, TF at %p\n", hw_tf->tf_trapno,
               core_id(), hw_tf);
-       if ((hw_tf->tf_cs & ~3) != GD_UT && (hw_tf->tf_cs & ~3) != GD_KT) {
-               print_trapframe(hw_tf);
-               panic("Trapframe with invalid CS!");
-       }
+       if ((hw_tf->tf_cs & ~3) != GD_UT && (hw_tf->tf_cs & ~3) != GD_KT)
+               panic_hwtf(hw_tf, "Trapframe with invalid CS!");
        trap_dispatch(hw_tf);
        /* Return to the current process, which should be runnable.  If we're the
         * kernel, we should just return naturally.  Note that current and tf need
index 2b64c36..a2d9994 100644 (file)
@@ -4,16 +4,18 @@
 
 #include <compiler.h>
 
-void ( _warn)(const char *, int, const char *, ...);
-void ( _panic)(const char *, int, const char *, ...)
+void _warn(const char *, int, const char *, ...);
+struct hw_trapframe;
+void _panic(struct hw_trapframe *, const char *, int, const char *, ...)
        __attribute__((noreturn));
 
 #define warn(...) _warn(__FILE__, __LINE__, __VA_ARGS__)
 #define warn_once(...) run_once_racy(warn(__VA_ARGS__))
 #define warn_on(x) do { if (x) warn(#x);} while (0)
 #define warn_on_once(x) do { if (x) warn_once(#x);} while (0)
-#define panic(...) _panic(__FILE__, __LINE__, __VA_ARGS__)
-#define exhausted(...) _panic(__FILE__, __LINE__, __VA_ARGS__)
+#define panic(...) _panic(NULL, __FILE__, __LINE__, __VA_ARGS__)
+#define panic_hwtf(x, ...) _panic(x, __FILE__, __LINE__, __VA_ARGS__)
+#define exhausted(...) _panic(NULL, __FILE__, __LINE__, __VA_ARGS__)
 
 #define assert(x)              \
        do { if (unlikely(!(x))) panic("assertion failed: %s", #x); } while (0)
index 789e724..3e32f3f 100644 (file)
@@ -31,6 +31,3 @@ extern bool booting;
  */
 const char *get_boot_option(const char *base, const char *option, char *param,
                                                        size_t max_param);
-
-void _panic(const char *file, int line, const char *fmt, ...);
-void _warn(const char *file, int line, const char *fmt, ...);
index 5d27a3c..28b8e06 100644 (file)
@@ -241,7 +241,8 @@ static DEFINE_PERCPU(int, panic_depth);
  * Panic is called on unresolvable fatal errors.
  * It prints "panic: mesg", and then enters the kernel monitor.
  */
-void _panic(const char *file, int line, const char *fmt,...)
+void _panic(struct hw_trapframe *hw_tf, const char *file, int line,
+            const char *fmt, ...)
 {
        va_list ap;
        struct per_cpu_info *pcpui;
@@ -264,11 +265,17 @@ void _panic(const char *file, int line, const char *fmt,...)
        va_end(ap);
        /* Recursive panics are usually backtrace problems.  Possibly printk.
         * Locking panics might recurse forever. */
-       if (PERCPU_VAR(panic_depth) == 1)
-               backtrace();
-       else
+       if (PERCPU_VAR(panic_depth) == 1) {
+               if (hw_tf) {
+                       print_trapframe(hw_tf);
+                       backtrace_hwtf(hw_tf);
+               } else {
+                       backtrace();
+               }
+       } else {
                printk("\tRecursive kernel panic on core %d (depth %d)\n",
                       core_id_early(), PERCPU_VAR(panic_depth));
+       }
        printk("\n");
 
        /* If we're here, we panicked and currently hold the lock.  We might have