NMIs and cross-core trapframe inspection
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 19 May 2011 20:50:11 +0000 (13:50 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:36:03 +0000 (17:36 -0700)
x86 can send NMIs, the handler for which prints the trapframe and what
function the EIP is in.  Use it from the monitor with:

ROS(Core 0)> trace coretf OS_COREID

It will work regardless of whether or not IRQs are disabled or whether
or not the core is in the kernel or userspace.

Sparc doesn't have this yet, though the stubs are there.

kern/arch/i686/apic.h
kern/arch/i686/kdebug.c
kern/arch/i686/trap.c
kern/arch/sparc/trap.c
kern/include/trap.h
kern/src/monitor.c

index 380e989..4ee3ac1 100644 (file)
@@ -125,6 +125,7 @@ static inline void send_broadcast_ipi(uint8_t vector);
 static inline void send_all_others_ipi(uint8_t vector);
 static inline void send_ipi(uint8_t hw_coreid, uint8_t vector);
 static inline void send_group_ipi(uint8_t hw_groupid, uint8_t vector);
+static inline void __send_nmi(uint8_t os_coreid);
 static inline bool ipi_is_pending(uint8_t vector);
 
 #define mask_lapic_lvt(entry) \
@@ -258,6 +259,15 @@ static inline void send_group_ipi(uint8_t hw_groupid, uint8_t vector)
        lapic_wait_to_send();
 }
 
+static inline void __send_nmi(uint8_t hw_coreid)
+{
+       if (hw_coreid == 255)
+               return;
+       write_mmreg32(LAPIC_IPI_ICR_UPPER, hw_coreid << 24);
+       write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00004400);
+       lapic_wait_to_send();
+}
+
 /* This works for any interrupt that goes through the LAPIC, but not things like
  * ExtInts.  To prevent abuse, we'll use it just for IPIs for now. */
 static inline bool ipi_is_pending(uint8_t vector)
index 48af7b4..370cc6a 100644 (file)
@@ -147,6 +147,9 @@ debuginfo_eip(uintptr_t addr, eipdebuginfo_t *NONNULL info)
                stabstr_end = __STABSTR_END__;
                stabstr = __STABSTR_BEGIN__;
        } else {
+               /* TODO: short circuiting this, til our user space apps pack stab data
+                * the kernel knows about */
+               return -1;
                // The user-application linker script, user/user.ld,
                // puts information about the application's stabs (equivalent
                // to __STAB_BEGIN__, __STAB_END__, __STABSTR_BEGIN__, and
index c94ab96..172d6a9 100644 (file)
@@ -19,6 +19,8 @@
 #include <stdio.h>
 #include <slab.h>
 #include <syscall.h>
+#include <kdebug.h>
+#include <kmalloc.h>
 
 taskstate_t RO ts;
 
@@ -120,6 +122,14 @@ void pop_kernel_tf(struct trapframe *tf)
        panic("ret failed");                            /* mostly to placate your mom */
 }
 
+/* Sends a non-maskable interrupt; the handler will print a trapframe. */
+void send_nmi(uint32_t os_coreid)
+{
+       /* NMI / IPI for x86 are limited to 8 bits */
+       uint8_t hw_core = (uint8_t)get_hw_coreid(os_coreid);
+       __send_nmi(hw_core);
+}
+
 void idt_init(void)
 {
        extern segdesc_t (RO gdt)[];
@@ -224,11 +234,16 @@ print_trapframe(trapframe_t *tf)
        spin_unlock_irqsave(&ptf_lock);
 }
 
-static void
-trap_dispatch(trapframe_t *tf)
+static void trap_dispatch(struct trapframe *tf)
 {
        // Handle processor exceptions.
        switch(tf->tf_trapno) {
+               case T_NMI:
+                       print_trapframe(tf);
+                       char *fn_name = get_fn_name(tf->tf_eip);
+                       printk("Core %d is at %08p (%s)\n", core_id(), tf->tf_eip, fn_name);
+                       kfree(fn_name);
+                       break;
                case T_BRKPT:
                        monitor(tf);
                        break;
index 13746a1..d35364f 100644 (file)
@@ -108,6 +108,11 @@ void pop_kernel_tf(struct trapframe *tf)
        panic("Not implemented.  =(");
 }
 
+/* Does nothing on sparc... */
+void send_nmi(uint32_t os_coreid)
+{
+}
+
 void
 idt_init(void)
 {
index 8315e8e..ec9737a 100644 (file)
@@ -52,6 +52,9 @@ static inline void save_kernel_tf(struct trapframe *tf)
                    __attribute__((always_inline));
 void pop_kernel_tf(struct trapframe *tf) __attribute__((noreturn));
 
+/* Sends a non-maskable interrupt, which we have print a trapframe. */
+void send_nmi(uint32_t os_coreid);
+
 /* Kernel messages.  Each arch implements them in their own way.  Both should be
  * guaranteeing in-order delivery.  Kept here in trap.h, since sparc is using
  * trap.h for KMs.  Eventually, both arches will use the same implementation.
index ff6a656..486d811 100644 (file)
@@ -26,6 +26,7 @@
 #include <kmalloc.h>
 #include <elf.h>
 #include <event.h>
+#include <trap.h>
 
 #include <ros/timer.h>
 #include <ros/memlayout.h>
@@ -58,7 +59,7 @@ static command_t (RO commands)[] = {
        { "kfunc", "Run a kernel function directly (!!!)", mon_kfunc},
        { "notify", "Notify a process.  Vcoreid will skip their prefs", mon_notify},
        { "measure", "Run a specific measurement", mon_measure},
-       { "trace", "Run a specific measurement", mon_trace},
+       { "trace", "Run some tracing functions", mon_trace},
        { "monitor", "Run the monitor on another core", mon_monitor},
        { "fs", "Filesystem Diagnostics", mon_fs},
        { "bb", "Try to run busybox (ash)", mon_bb},
@@ -631,10 +632,12 @@ int mon_measure(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
 
 int mon_trace(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
 {
+       uint32_t core;
        if (argc < 2) {
                printk("Usage: trace OPTION\n");
                printk("\tsyscall start [silent] [pid]: starts tracing\n");
                printk("\tsyscall stop: stops tracing, prints if it was silent\n");
+               printk("\tcoretf COREID: cause the other core to print its TF (NMI)\n");
                return 1;
        }
        if (!strcmp(argv[1], "syscall")) {
@@ -666,6 +669,18 @@ int mon_trace(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
                        systrace_print(TRUE, 0);
                        systrace_clear_buffer();
                }
+       } else if (!strcmp(argv[1], "coretf")) {
+               if (argc != 3) {
+                       printk("Need a coreid, fool.\n");
+                       return 1;
+               }
+               core = strtol(argv[2], 0, 0);
+               if (core >= num_cpus) {
+                       printk("No such core!  Maybe it's in another cell...\n");
+                       return 1;
+               }
+               send_nmi(core);
+               udelay(1000000);
        } else if (!strcmp(argv[1], "opt2")) {
                if (argc != 3) {
                        printk("ERRRRRRRRRR.\n");