diff -r e3fdd9b1ab5b xen/arch/x86/acpi/cpu_idle.c --- a/xen/arch/x86/acpi/cpu_idle.c Fri Jul 31 14:15:14 2009 +0100 +++ b/xen/arch/x86/acpi/cpu_idle.c Fri Jul 31 14:24:32 2009 +0100 @@ -111,7 +111,7 @@ static int __init cpu_idle_key_init(void) { register_keyhandler( - 'c', dump_cx, "dump ACPI Cx structures"); + 'c', 1, dump_cx, "dump ACPI Cx structures"); return 0; } __initcall(cpu_idle_key_init); diff -r e3fdd9b1ab5b xen/arch/x86/hvm/svm/vmcb.c --- a/xen/arch/x86/hvm/svm/vmcb.c Fri Jul 31 14:15:14 2009 +0100 +++ b/xen/arch/x86/hvm/svm/vmcb.c Fri Jul 31 14:24:32 2009 +0100 @@ -397,7 +397,7 @@ void setup_vmcb_dump(void) { - register_keyhandler('v', vmcb_dump, "dump AMD-V VMCBs"); + register_keyhandler('v', 1, vmcb_dump, "dump AMD-V VMCBs"); } /* diff -r e3fdd9b1ab5b xen/arch/x86/hvm/vmx/vmcs.c --- a/xen/arch/x86/hvm/vmx/vmcs.c Fri Jul 31 14:15:14 2009 +0100 +++ b/xen/arch/x86/hvm/vmx/vmcs.c Fri Jul 31 14:24:32 2009 +0100 @@ -1145,7 +1145,7 @@ void setup_vmcs_dump(void) { - register_keyhandler('v', vmcs_dump, "dump Intel's VMCS"); + register_keyhandler('v', 1, vmcs_dump, "dump Intel's VMCS"); } diff -r e3fdd9b1ab5b xen/arch/x86/io_apic.c --- a/xen/arch/x86/io_apic.c Fri Jul 31 14:15:14 2009 +0100 +++ b/xen/arch/x86/io_apic.c Fri Jul 31 14:24:32 2009 +0100 @@ -1810,7 +1810,7 @@ print_IO_APIC(); ioapic_pm_state_alloc(); - register_keyhandler('z', print_IO_APIC_keyhandler, "print ioapic info"); + register_keyhandler('z', 1, print_IO_APIC_keyhandler, "print ioapic info"); } void ioapic_suspend(void) diff -r e3fdd9b1ab5b xen/arch/x86/irq.c --- a/xen/arch/x86/irq.c Fri Jul 31 14:15:14 2009 +0100 +++ b/xen/arch/x86/irq.c Fri Jul 31 14:24:32 2009 +0100 @@ -1141,7 +1141,7 @@ static int __init setup_dump_irqs(void) { - register_keyhandler('i', dump_irqs, "dump interrupt bindings"); + register_keyhandler('i', 1, dump_irqs, "dump interrupt bindings"); return 0; } __initcall(setup_dump_irqs); diff -r e3fdd9b1ab5b xen/arch/x86/mm/shadow/common.c --- a/xen/arch/x86/mm/shadow/common.c Fri Jul 31 14:15:14 2009 +0100 +++ b/xen/arch/x86/mm/shadow/common.c Fri Jul 31 14:24:32 2009 +0100 @@ -97,7 +97,7 @@ static int __init shadow_audit_key_init(void) { register_keyhandler( - 'O', shadow_audit_key, "toggle shadow audits"); + 'O', 0, shadow_audit_key, "toggle shadow audits"); return 0; } __initcall(shadow_audit_key_init); @@ -1485,7 +1485,8 @@ /* Register this function in the Xen console keypress table */ static __init int shadow_blow_tables_keyhandler_init(void) { - register_keyhandler('S', shadow_blow_all_tables,"reset shadow pagetables"); + register_keyhandler('S', 0, shadow_blow_all_tables, + "reset shadow pagetables"); return 0; } __initcall(shadow_blow_tables_keyhandler_init); diff -r e3fdd9b1ab5b xen/arch/x86/nmi.c --- a/xen/arch/x86/nmi.c Fri Jul 31 14:15:14 2009 +0100 +++ b/xen/arch/x86/nmi.c Fri Jul 31 14:24:32 2009 +0100 @@ -477,8 +477,8 @@ static __init int register_nmi_trigger(void) { - register_keyhandler('n', do_nmi_trigger, "trigger an NMI"); - register_keyhandler('N', do_nmi_stats, "NMI statistics"); + register_keyhandler('n', 0, do_nmi_trigger, "trigger an NMI"); + register_keyhandler('N', 1, do_nmi_stats, "NMI statistics"); return 0; } __initcall(register_nmi_trigger); diff -r e3fdd9b1ab5b xen/arch/x86/numa.c --- a/xen/arch/x86/numa.c Fri Jul 31 14:15:14 2009 +0100 +++ b/xen/arch/x86/numa.c Fri Jul 31 14:24:32 2009 +0100 @@ -327,7 +327,7 @@ static __init int register_numa_trigger(void) { - register_keyhandler('u', dump_numa, "dump numa info"); + register_keyhandler('u', 1, dump_numa, "dump numa info"); return 0; } __initcall(register_numa_trigger); diff -r e3fdd9b1ab5b xen/common/event_channel.c --- a/xen/common/event_channel.c Fri Jul 31 14:15:14 2009 +0100 +++ b/xen/common/event_channel.c Fri Jul 31 14:24:32 2009 +0100 @@ -1137,7 +1137,7 @@ static int __init dump_evtchn_info_key_init(void) { - register_keyhandler('e', dump_evtchn_info, "dump evtchn info"); + register_keyhandler('e', 1, dump_evtchn_info, "dump evtchn info"); return 0; } __initcall(dump_evtchn_info_key_init); diff -r e3fdd9b1ab5b xen/common/kexec.c --- a/xen/common/kexec.c Fri Jul 31 14:15:14 2009 +0100 +++ b/xen/common/kexec.c Fri Jul 31 14:24:32 2009 +0100 @@ -135,7 +135,7 @@ static __init int register_crashdump_trigger(void) { - register_keyhandler('C', do_crashdump_trigger, "trigger a crashdump"); + register_keyhandler('C', 0, do_crashdump_trigger, "trigger a crashdump"); return 0; } __initcall(register_crashdump_trigger); diff -r e3fdd9b1ab5b xen/common/keyhandler.c --- a/xen/common/keyhandler.c Fri Jul 31 14:15:14 2009 +0100 +++ b/xen/common/keyhandler.c Fri Jul 31 14:24:32 2009 +0100 @@ -29,6 +29,7 @@ } key_table[KEY_MAX]; #define KEYHANDLER_IRQ_CALLBACK 0x1 +#define KEYHANDLER_DIAGNOSTIC 0x2 static unsigned char keypress_key; @@ -63,20 +64,22 @@ } void register_keyhandler( - unsigned char key, keyhandler_t *handler, char *desc) + unsigned char key, int diagnostic, keyhandler_t *handler, char *desc) { ASSERT(key_table[key].u.handler == NULL); key_table[key].u.handler = handler; - key_table[key].flags = 0; + key_table[key].flags = diagnostic ? KEYHANDLER_DIAGNOSTIC : 0; safe_strcpy(key_table[key].desc, desc); } void register_irq_keyhandler( - unsigned char key, irq_keyhandler_t *handler, char *desc) + unsigned char key, int diagnostic, irq_keyhandler_t *handler, char *desc) { ASSERT(key_table[key].u.irq_handler == NULL); key_table[key].u.irq_handler = handler; key_table[key].flags = KEYHANDLER_IRQ_CALLBACK; + if ( diagnostic ) + key_table[key].flags |= KEYHANDLER_DIAGNOSTIC; safe_strcpy(key_table[key].desc, desc); } @@ -321,6 +324,50 @@ extern void perfc_reset(unsigned char key); #endif +static void run_all_nonirq_keyhandlers(unsigned long unused) +{ + /* Fire all the non-IRQ-context diagnostic keyhandlers */ + int k; + keyhandler_t *h; + + console_start_log_everything(); + for ( k = 0; k < KEY_MAX; k++ ) + if ( (key_table[k].flags & KEYHANDLER_DIAGNOSTIC) + && !(key_table[k].flags & KEYHANDLER_IRQ_CALLBACK) + && (h = key_table[k].u.handler) != NULL ) + { + printk("[%c: %s]\n", k, key_table[k].desc); + (*h)(k); + } + console_end_log_everything(); +} + +static DECLARE_TASKLET(run_all_keyhandlers_tasklet, + run_all_nonirq_keyhandlers, 0); + +static void run_all_keyhandlers(unsigned char key, struct cpu_user_regs *regs) +{ + int k; + irq_keyhandler_t *h; + + printk("'%c' pressed -> firing all diagnostic keyhandlers\n", key); + + /* Fire all the IRQ-context diangostic keyhandlers now */ + console_start_log_everything(); + for ( k = 0; k < KEY_MAX; k++ ) + if ( (key_table[k].flags & KEYHANDLER_DIAGNOSTIC) + && (key_table[k].flags & KEYHANDLER_IRQ_CALLBACK) + && (h = key_table[k].u.irq_handler) != NULL ) + { + printk("[%c: %s]\n", k, key_table[k].desc); + (*h)(k, regs); + } + console_end_log_everything(); + + /* Trigger the others from a tasklet in non-IRQ context */ + tasklet_schedule(&run_all_keyhandlers_tasklet); +} + static void do_debug_key(unsigned char key, struct cpu_user_regs *regs) { printk("'%c' pressed -> trapping into debugger\n", key); @@ -333,30 +380,33 @@ void __init initialize_keytable(void) { register_irq_keyhandler( - 'd', dump_registers, "dump registers"); + 'd', 1, dump_registers, "dump registers"); register_keyhandler( - 'h', show_handlers, "show this message"); + 'h', 0, show_handlers, "show this message"); register_keyhandler( - 'q', dump_domains, "dump domain (and guest debug) info"); + 'q', 1, dump_domains, "dump domain (and guest debug) info"); register_keyhandler( - 'r', dump_runq, "dump run queues"); + 'r', 1, dump_runq, "dump run queues"); register_irq_keyhandler( - 'R', halt_machine, "reboot machine"); + 'R', 0, halt_machine, "reboot machine"); register_keyhandler( - 't', read_clocks, "display multi-cpu clock info"); + 't', 1, read_clocks, "display multi-cpu clock info"); #ifdef PERF_COUNTERS register_keyhandler( - 'p', perfc_printall, "print performance counters"); + 'p', 1, perfc_printall, "print performance counters"); register_keyhandler( - 'P', perfc_reset, "reset performance counters"); + 'P', 0, perfc_reset, "reset performance counters"); #endif register_keyhandler( - '0', dump_dom0_registers, "dump Dom0 registers"); + '0', 1, dump_dom0_registers, "dump Dom0 registers"); - register_irq_keyhandler('%', do_debug_key, "Trap to xendbg"); + register_irq_keyhandler('%', 0, do_debug_key, "Trap to xendbg"); + + register_irq_keyhandler( + '*', 0, run_all_keyhandlers, "print all diagnostics"); } /* diff -r e3fdd9b1ab5b xen/common/page_alloc.c --- a/xen/common/page_alloc.c Fri Jul 31 14:15:14 2009 +0100 +++ b/xen/common/page_alloc.c Fri Jul 31 14:24:32 2009 +0100 @@ -1222,7 +1222,7 @@ static __init int pagealloc_keyhandler_init(void) { - register_keyhandler('m', pagealloc_keyhandler, "memory info"); + register_keyhandler('m', 1, pagealloc_keyhandler, "memory info"); return 0; } __initcall(pagealloc_keyhandler_init); @@ -1263,7 +1263,7 @@ static __init int register_heap_trigger(void) { - register_keyhandler('H', dump_heap, "dump heap info"); + register_keyhandler('H', 1, dump_heap, "dump heap info"); return 0; } __initcall(register_heap_trigger); diff -r e3fdd9b1ab5b xen/common/timer.c --- a/xen/common/timer.c Fri Jul 31 14:15:14 2009 +0100 +++ b/xen/common/timer.c Fri Jul 31 14:24:32 2009 +0100 @@ -535,7 +535,7 @@ per_cpu(timers, i).heap = &dummy_heap; } - register_keyhandler('a', dump_timerq, "dump timer queues"); + register_keyhandler('a', 1, dump_timerq, "dump timer queues"); } /* diff -r e3fdd9b1ab5b xen/drivers/char/console.c --- a/xen/drivers/char/console.c Fri Jul 31 14:15:14 2009 +0100 +++ b/xen/drivers/char/console.c Fri Jul 31 14:24:32 2009 +0100 @@ -943,7 +943,7 @@ debugtrace_bytes = bytes; register_keyhandler( - 'T', debugtrace_key, "toggle debugtrace to console/buffer"); + 'T', 0, debugtrace_key, "toggle debugtrace to console/buffer"); return 0; } diff -r e3fdd9b1ab5b xen/drivers/passthrough/pci.c --- a/xen/drivers/passthrough/pci.c Fri Jul 31 14:15:14 2009 +0100 +++ b/xen/drivers/passthrough/pci.c Fri Jul 31 14:24:32 2009 +0100 @@ -417,7 +417,7 @@ static int __init setup_dump_pcidevs(void) { - register_keyhandler('Q', dump_pci_devices, "dump PCI devices"); + register_keyhandler('Q', 1, dump_pci_devices, "dump PCI devices"); return 0; } __initcall(setup_dump_pcidevs); diff -r e3fdd9b1ab5b xen/drivers/passthrough/vtd/iommu.c --- a/xen/drivers/passthrough/vtd/iommu.c Fri Jul 31 14:15:14 2009 +0100 +++ b/xen/drivers/passthrough/vtd/iommu.c Fri Jul 31 14:24:32 2009 +0100 @@ -1759,7 +1759,7 @@ if ( init_vtd_hw() ) goto error; - register_keyhandler('V', dump_iommu_info, "dump iommu info"); + register_keyhandler('V', 1, dump_iommu_info, "dump iommu info"); return 0; diff -r e3fdd9b1ab5b xen/include/xen/keyhandler.h --- a/xen/include/xen/keyhandler.h Fri Jul 31 14:15:14 2009 +0100 +++ b/xen/include/xen/keyhandler.h Fri Jul 31 14:24:32 2009 +0100 @@ -16,10 +16,12 @@ /* * Register a callback function for key @key. The callback occurs in * softirq context with no locks held and interrupts enabled. + * If 'diagnostic' is 1, the keyhandler will be included in the + * "dump everything" keyhandler, so must not have any side-effects. */ typedef void keyhandler_t(unsigned char key); extern void register_keyhandler( - unsigned char key, keyhandler_t *handler, char *desc); + unsigned char key, int diagnostic, keyhandler_t *handler, char *desc); /* * Register an IRQ callback function for key @key. The callback occurs @@ -28,7 +30,7 @@ */ typedef void irq_keyhandler_t(unsigned char key, struct cpu_user_regs *regs); extern void register_irq_keyhandler( - unsigned char key, irq_keyhandler_t *handler, char *desc); + unsigned char key, int diagnostic, irq_keyhandler_t *handler, char *desc); /* Inject a keypress into the key-handling subsystem. */ extern void handle_keypress(unsigned char key, struct cpu_user_regs *regs);