--- arch/x86/kernel/ipipe.c | 88 +++++++++++++++++++++++++++++++----------------- include/linux/ipipe.h | 13 +++++++ kernel/ipipe/core.c | 35 +++++++++++++++++++ 3 files changed, 106 insertions(+), 30 deletions(-) Index: b/arch/x86/kernel/ipipe.c =================================================================== --- a/arch/x86/kernel/ipipe.c +++ b/arch/x86/kernel/ipipe.c @@ -697,8 +697,10 @@ static __ipipe_exptr __ipipe_std_extable #endif }; -#ifdef CONFIG_KGDB +#if defined(CONFIG_KGDB) || defined(CONFIG_KGDB_MODULE) #include +#include +#include static int __ipipe_xlate_signo[] = { @@ -746,24 +748,34 @@ int __ipipe_handle_exception(struct pt_r barrier(); } -#ifdef CONFIG_KGDB - /* catch exception KGDB is interested in over non-root domains */ - if (!ipipe_root_domain_p && - __ipipe_xlate_signo[vector] >= 0 && - !kgdb_handle_exception(vector, __ipipe_xlate_signo[vector], error_code, regs)) { - if (!flags) - __clear_bit(IPIPE_STALL_FLAG, - &ipipe_root_cpudom_var(status)); - return 1; +#if defined(CONFIG_KGDB) || defined(CONFIG_KGDB_MODULE) + if (unlikely(__ipipe_kgdb_notify)) { + const struct exception_table_entry *fixup; + struct die_args args; + + /* Fixup kgdb-own faults immediately. */ + if (*__ipipe_kgdb_may_fault) { + fixup = search_exception_tables(regs->ip); + BUG_ON(!fixup); + regs->ip = fixup->fixup; + goto exit_stop; + } + + /* Catch any exception over non-root domains that + * kgdb might be interested in. */ + if (!ipipe_root_domain_p && __ipipe_xlate_signo[vector] >= 0) { + args.regs = regs; + args.err = error_code; + args.trapnr = vector; + args.signr = __ipipe_xlate_signo[vector]; + if (__ipipe_kgdb_notify(NULL, DIE_TRAP, &args) == NOTIFY_STOP) + goto exit_stop; + } } #endif /* CONFIG_KGDB */ - if (unlikely(ipipe_trap_notify(vector, regs))) { - if (!flags) - __clear_bit(IPIPE_STALL_FLAG, - &ipipe_root_cpudom_var(status)); - return 1; - } + if (unlikely(ipipe_trap_notify(vector, regs))) + goto exit_stop; /* Detect unhandled faults over non-root domains. */ @@ -800,23 +812,31 @@ int __ipipe_handle_exception(struct pt_r __fixup_if(regs); return 0; + +exit_stop: + if (!flags) + __clear_bit(IPIPE_STALL_FLAG, &ipipe_root_cpudom_var(status)); + return 1; } int __ipipe_divert_exception(struct pt_regs *regs, int vector) { -#ifdef CONFIG_KGDB - /* catch int1 and int3 over non-root domains */ -#ifdef CONFIG_X86_32 - if (!ipipe_root_domain_p && vector != ex_do_device_not_available) { -#else - if (!ipipe_root_domain_p) { -#endif - unsigned int condition = 0; - - if (vector == 1) - get_debugreg(condition, 6); - if (!kgdb_handle_exception(vector, SIGTRAP, condition, regs)) - return 1; +#if defined(CONFIG_KGDB) || defined(CONFIG_KGDB_MODULE) + /* Catch debug and breakpoint exception over non-root domains. */ + if (__ipipe_kgdb_notify && !ipipe_root_domain_p) { + struct die_args args = { .regs = regs, .signr = SIGTRAP }; + + if (vector == 1) { + get_debugreg(args.err, 6); + args.trapnr = 0; + if (__ipipe_kgdb_notify(NULL, DIE_DEBUG, &args) == NOTIFY_STOP) + return 1; + } else if (vector == 3) { + args.err = 0; + args.trapnr = 3; + if (__ipipe_kgdb_notify(NULL, DIE_INT3, &args) == NOTIFY_STOP) + return 1; + } } #endif /* CONFIG_KGDB */ @@ -865,8 +885,16 @@ int __ipipe_handle_irq(struct pt_regs *r irq = vector; m_ack = 1; } - #endif /* !CONFIG_X86_32 */ + +#if defined(CONFIG_KGDB) || defined(CONFIG_KGDB_MODULE) + if (unlikely(irq == __ipipe_kgdb_irq)) { + ipipe_root_domain->irqs[irq].acknowledge(irq); + __ipipe_kgdb_irq_handler(irq, NULL); + irq_desc[irq].ipipe_end(irq, &irq_desc[irq]); + goto finalize_nosync; + } +#endif /* CONFIG_KGDB */ head = __ipipe_pipeline.next; next_domain = list_entry(head, struct ipipe_domain, p_link); if (likely(test_bit(IPIPE_WIRED_FLAG, &next_domain->irqs[irq].control))) { Index: b/include/linux/ipipe.h =================================================================== --- a/include/linux/ipipe.h +++ b/include/linux/ipipe.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -512,6 +513,18 @@ static inline void local_irq_restore_nos #define ipipe_root_domain_p (ipipe_current_domain == ipipe_root_domain) +extern int *__ipipe_kgdb_may_fault; +extern int (*__ipipe_kgdb_notify)(struct notifier_block *, unsigned long, void *); + +extern int __ipipe_kgdb_irq; +extern int (*__ipipe_kgdb_irq_handler)(int, void *); + +#define IPIPE_KGDB_IRQ_NONE -1 + +void ipipe_kgdb_set_fault_handler(int *kgdb_may_fault, + int (*handler)(struct notifier_block *, unsigned long, void *)); +void ipipe_kgdb_set_irq_handler(int irq, int (*handler)(int, void *)); + #else /* !CONFIG_IPIPE */ #define ipipe_init() do { } while(0) Index: b/kernel/ipipe/core.c =================================================================== --- a/kernel/ipipe/core.c +++ b/kernel/ipipe/core.c @@ -1586,6 +1586,41 @@ void ipipe_check_context(struct ipipe_do EXPORT_SYMBOL(ipipe_check_context); #endif /* CONFIG_IPIPE_DEBUG_CONTEXT */ +#if defined(CONFIG_KGDB) || defined(CONFIG_KGDB_MODULE) +int *__ipipe_kgdb_may_fault = NULL; +int (*__ipipe_kgdb_notify)(struct notifier_block *, unsigned long, void *); + +void ipipe_kgdb_set_fault_handler(int *kgdb_may_fault, + int (*handler)(struct notifier_block *, unsigned long, void *)) +{ + unsigned long flags; + + flags = ipipe_critical_enter(NULL); + + __ipipe_kgdb_may_fault = kgdb_may_fault; + __ipipe_kgdb_notify = handler; + + ipipe_critical_exit(flags); +} +EXPORT_SYMBOL_GPL(ipipe_kgdb_set_fault_handler); + +int __ipipe_kgdb_irq = IPIPE_KGDB_IRQ_NONE; +irq_handler_t __ipipe_kgdb_irq_handler; + +void ipipe_kgdb_set_irq_handler(int irq, irq_handler_t handler) +{ + unsigned long flags; + + flags = ipipe_critical_enter(NULL); + + __ipipe_kgdb_irq = irq; + __ipipe_kgdb_irq_handler = handler; + + ipipe_critical_exit(flags); +} +EXPORT_SYMBOL_GPL(ipipe_kgdb_set_irq_handler); +#endif /* CONFIG_KGDB */ + EXPORT_SYMBOL(ipipe_virtualize_irq); EXPORT_SYMBOL(ipipe_control_irq); EXPORT_SYMBOL(ipipe_suspend_domain);