x86: add option to display last exception records during register dumps
authorKeir Fraser <keir@xensource.com>
Wed, 17 Oct 2007 14:37:36 +0000 (15:37 +0100)
committerKeir Fraser <keir@xensource.com>
Wed, 17 Oct 2007 14:37:36 +0000 (15:37 +0100)
Signed-off-by: Jan Beulich <jbeulich@novell.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/setup.c
xen/arch/x86/smpboot.c
xen/arch/x86/traps.c
xen/arch/x86/x86_32/traps.c
xen/arch/x86/x86_64/traps.c
xen/include/asm-x86/msr.h
xen/include/asm-x86/system.h

index c2247918d9f92ed4934234ba6db2619859c920f8..a9c1beeba892cee79b1229177638a9f55a8cb061 100644 (file)
@@ -104,7 +104,6 @@ unsigned long xenheap_phys_start, xenheap_phys_end;
 
 extern void arch_init_memory(void);
 extern void init_IRQ(void);
-extern void trap_init(void);
 extern void early_time_init(void);
 extern void early_cpu_init(void);
 extern void vesa_init(void);
index 9ffa664789ba47c3853117654e53404e10d0faaf..0ed832d511109243b0e6482dea8d06340c30523d 100644 (file)
@@ -492,8 +492,6 @@ void __devinit start_secondary(void *unused)
         */
        unsigned int cpu = booting_cpu;
 
-       extern void percpu_traps_init(void);
-
        set_processor_id(cpu);
        set_current(idle_vcpu[cpu]);
        this_cpu(curr_vcpu) = idle_vcpu[cpu];
index 51d84739e941a15428f6741939a527730efbb483..6d085784e29b8bf4dde2c10754d5fd0a69167fab 100644 (file)
@@ -76,6 +76,8 @@ char opt_nmi[10] = "fatal";
 #endif
 string_param("nmi", opt_nmi);
 
+DEFINE_PER_CPU(u32, ler_msr);
+
 /* Master table, used by CPU0. */
 idt_entry_t idt_table[IDT_ENTRIES];
 
@@ -112,6 +114,9 @@ unsigned long do_get_debugreg(int reg);
 static int debug_stack_lines = 20;
 integer_param("debug_stack_lines", debug_stack_lines);
 
+static int opt_ler;
+boolean_param("ler", opt_ler);
+
 #ifdef CONFIG_X86_32
 #define stack_words_per_line 8
 #define ESP_BEFORE_EXCEPTION(regs) ((unsigned long *)&regs->esp)
@@ -2098,9 +2103,12 @@ asmlinkage int do_debug(struct cpu_user_regs *regs)
     /* Save debug status register where guest OS can peek at it */
     v->arch.guest_context.debugreg[6] = condition;
 
+    ler_enable();
+
     return do_guest_trap(TRAP_debug, regs, 0);
 
  out:
+    ler_enable();
     return EXCRET_not_a_fault;
 }
 
@@ -2146,10 +2154,43 @@ void set_tss_desc(unsigned int n, void *addr)
 #endif
 }
 
-void __init trap_init(void)
+void __devinit percpu_traps_init(void)
 {
-    extern void percpu_traps_init(void);
+    subarch_percpu_traps_init();
+
+    if ( !opt_ler )
+        return;
+
+    switch ( boot_cpu_data.x86_vendor )
+    {
+    case X86_VENDOR_INTEL:
+        switch ( boot_cpu_data.x86 )
+        {
+        case 6:
+            this_cpu(ler_msr) = MSR_IA32_LASTINTFROMIP;
+            break;
+        case 15:
+            this_cpu(ler_msr) = MSR_P4_LER_FROM_LIP;
+            break;
+        }
+        break;
+    case X86_VENDOR_AMD:
+        switch ( boot_cpu_data.x86 )
+        {
+        case 6:
+        case 15:
+        case 16:
+            this_cpu(ler_msr) = MSR_IA32_LASTINTFROMIP;
+            break;
+        }
+        break;
+    }
+
+    ler_enable();
+}
 
+void __init trap_init(void)
+{
     /*
      * Note that interrupt gates are always used, rather than trap gates. We 
      * must have interrupts disabled until DS/ES/FS/GS are saved because the 
index bcbc14908c02c89368065ba180f44f7f29dc4d1b..3d77813e1beefa68d22ed840c4c2dcaf4417ccc2 100644 (file)
@@ -104,6 +104,14 @@ void show_registers(struct cpu_user_regs *regs)
            "ss: %04x   cs: %04x\n",
            fault_regs.ds, fault_regs.es, fault_regs.fs,
            fault_regs.gs, fault_regs.ss, fault_regs.cs);
+
+    if ( this_cpu(ler_msr) && !guest_mode(regs) )
+    {
+        u32 from, to, hi;
+        rdmsr(this_cpu(ler_msr), from, hi);
+        rdmsr(this_cpu(ler_msr) + 1, to, hi);
+        printk("ler: %08x -> %08x\n", from, to);
+    }
 }
 
 void show_page_walk(unsigned long addr)
@@ -250,7 +258,7 @@ unsigned long do_iret(void)
     return 0;
 }
 
-void __devinit percpu_traps_init(void)
+void __devinit subarch_percpu_traps_init(void)
 {
     struct tss_struct *tss = &doublefault_tss;
     asmlinkage int hypercall(void);
index 992bf8d45cb63da64831368c067acce51c8cdc8b..79c704314685ba0df0ee10c19e980069f8bd17c3 100644 (file)
@@ -112,6 +112,14 @@ void show_registers(struct cpu_user_regs *regs)
            "ss: %04x   cs: %04x\n",
            fault_regs.ds, fault_regs.es, fault_regs.fs,
            fault_regs.gs, fault_regs.ss, fault_regs.cs);
+
+    if ( this_cpu(ler_msr) && !guest_mode(regs) )
+    {
+        u64 from, to;
+        rdmsrl(this_cpu(ler_msr), from);
+        rdmsrl(this_cpu(ler_msr) + 1, to);
+        printk("ler: %016lx -> %016lx\n", from, to);
+    }
 }
 
 void show_page_walk(unsigned long addr)
@@ -302,7 +310,7 @@ static int write_stack_trampoline(
     return 34;
 }
 
-void __devinit percpu_traps_init(void)
+void __devinit subarch_percpu_traps_init(void)
 {
     char *stack_bottom, *stack;
     int   cpu = smp_processor_id();
index 393bafa40a4e3b005b376a6b339b8a65c954780c..79d37a33adff9b9cc485443dfd38c3faa00d92bd 100644 (file)
@@ -105,6 +105,19 @@ static inline void write_efer(__u64 val)
     wrmsrl(MSR_EFER, val);
 }
 
+DECLARE_PER_CPU(u32, ler_msr);
+
+static inline void ler_enable(void)
+{
+    u64 debugctl;
+    
+    if ( !this_cpu(ler_msr) )
+        return;
+
+    rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
+    wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl | 1);
+}
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __ASM_MSR_H */
index 2241795552d3752418b1e6dc8179ca34aec4976b..c464e1d454e7fc79fcac0fdeff6f8a7c304d6382 100644 (file)
@@ -314,4 +314,8 @@ static inline int local_irq_is_enabled(void)
 #define BROKEN_ACPI_Sx         0x0001
 #define BROKEN_INIT_AFTER_S1   0x0002
 
+void trap_init(void);
+void percpu_traps_init(void);
+void subarch_percpu_traps_init(void);
+
 #endif