Commit 9138d581 authored by Keith Owens's avatar Keith Owens Committed by Tony Luck

[IA64] Extend notify_die() hooks for IA64

notify_die() added for MCA_{MONARCH,SLAVE,RENDEZVOUS}_{ENTER,PROCESS,LEAVE} and
INIT_{MONARCH,SLAVE}_{ENTER,PROCESS,LEAVE}.  We need multiple
notification points for these events because they can take many seconds
to run which has nasty effects on the behaviour of the rest of the
system.

DIE_SS replaced by a generic DIE_FAULT which checks the vector number,
to allow interception of faults other than SS.

DIE_MACHINE_{HALT,RESTART} added to allow last minute close down
processing, especially when the halt/restart routines are called from
error handlers.

DIE_OOPS added.

The check for kprobe's break numbers has been moved from traps.c to
kprobes.c, allowing DIE_BREAK to be used for any additional break
numbers, i.e. it is no longer kprobes specific.

Hooks for kernel debuggers and kernel dumpers added, ENTER and LEAVE.
Both of these disable the system for long periods which impact on
watchdogs and heartbeat systems in general.  More patches to come that
use these events to reset watchdogs and heartbeats.

unregister_die_notifier() added and both routines exported.  Requested
by Dean Nelson.

Lock removed from {un,}register_die_notifier.  notifier_chain_register()
already takes a lock.  Also the generic notifier chain locking is being
reworked to distinguish between callbacks that can block and those that
cannot, the lock in {un,}register_die_notifier would interfere with
that change.  http://marc.theaimsgroup.com/?l=linux-kernel&m=113018709002036&w=2

Leading white space removed from arch/ia64/kernel/kprobes.c.

Typo in mca.c in original version of this patch found & fixed by Dean
Nelson.
Signed-off-by: default avatarKeith Owens <kaos@sgi.com>
Acked-by: default avatarDean Nelson <dcn@sgi.com>
Acked-by: default avatarAnil Keshavamurthy <anil.s.keshavamurthy@intel.com>
Signed-off-by: default avatarTony Luck <tony.luck@intel.com>
parent 5b2f7ffc
...@@ -347,7 +347,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) ...@@ -347,7 +347,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
((struct fnptr *)kretprobe_trampoline)->ip; ((struct fnptr *)kretprobe_trampoline)->ip;
spin_lock_irqsave(&kretprobe_lock, flags); spin_lock_irqsave(&kretprobe_lock, flags);
head = kretprobe_inst_table_head(current); head = kretprobe_inst_table_head(current);
/* /*
* It is possible to have multiple instances associated with a given * It is possible to have multiple instances associated with a given
...@@ -363,9 +363,9 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) ...@@ -363,9 +363,9 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
* kretprobe_trampoline * kretprobe_trampoline
*/ */
hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
if (ri->task != current) if (ri->task != current)
/* another task is sharing our hash bucket */ /* another task is sharing our hash bucket */
continue; continue;
if (ri->rp && ri->rp->handler) if (ri->rp && ri->rp->handler)
ri->rp->handler(ri, regs); ri->rp->handler(ri, regs);
...@@ -394,7 +394,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) ...@@ -394,7 +394,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
* kprobe_handler() that we don't want the post_handler * kprobe_handler() that we don't want the post_handler
* to run (and have re-enabled preemption) * to run (and have re-enabled preemption)
*/ */
return 1; return 1;
} }
/* Called with kretprobe_lock held */ /* Called with kretprobe_lock held */
...@@ -739,12 +739,16 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, ...@@ -739,12 +739,16 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
switch(val) { switch(val) {
case DIE_BREAK: case DIE_BREAK:
if (pre_kprobes_handler(args)) /* err is break number from ia64_bad_break() */
ret = NOTIFY_STOP; if (args->err == 0x80200 || args->err == 0x80300)
if (pre_kprobes_handler(args))
ret = NOTIFY_STOP;
break; break;
case DIE_SS: case DIE_FAULT:
if (post_kprobes_handler(args->regs)) /* err is vector number from ia64_fault() */
ret = NOTIFY_STOP; if (args->err == 36)
if (post_kprobes_handler(args->regs))
ret = NOTIFY_STOP;
break; break;
case DIE_PAGE_FAULT: case DIE_PAGE_FAULT:
/* kprobe_running() needs smp_processor_id() */ /* kprobe_running() needs smp_processor_id() */
......
...@@ -51,6 +51,9 @@ ...@@ -51,6 +51,9 @@
* *
* 2005-08-12 Keith Owens <kaos@sgi.com> * 2005-08-12 Keith Owens <kaos@sgi.com>
* Convert MCA/INIT handlers to use per event stacks and SAL/OS state. * Convert MCA/INIT handlers to use per event stacks and SAL/OS state.
*
* 2005-10-07 Keith Owens <kaos@sgi.com>
* Add notify_die() hooks.
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -58,7 +61,6 @@ ...@@ -58,7 +61,6 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/kallsyms.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/acpi.h> #include <linux/acpi.h>
...@@ -69,6 +71,7 @@ ...@@ -69,6 +71,7 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <asm/delay.h> #include <asm/delay.h>
#include <asm/kdebug.h>
#include <asm/machvec.h> #include <asm/machvec.h>
#include <asm/meminit.h> #include <asm/meminit.h>
#include <asm/page.h> #include <asm/page.h>
...@@ -132,6 +135,14 @@ extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe); ...@@ -132,6 +135,14 @@ extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe);
static int mca_init; static int mca_init;
static void inline
ia64_mca_spin(const char *func)
{
printk(KERN_EMERG "%s: spinning here, not returning to SAL\n", func);
while (1)
cpu_relax();
}
/* /*
* IA64_MCA log support * IA64_MCA log support
*/ */
...@@ -526,13 +537,16 @@ ia64_mca_wakeup_all(void) ...@@ -526,13 +537,16 @@ ia64_mca_wakeup_all(void)
* Outputs : None * Outputs : None
*/ */
static irqreturn_t static irqreturn_t
ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs) ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *regs)
{ {
unsigned long flags; unsigned long flags;
int cpu = smp_processor_id(); int cpu = smp_processor_id();
/* Mask all interrupts */ /* Mask all interrupts */
local_irq_save(flags); local_irq_save(flags);
if (notify_die(DIE_MCA_RENDZVOUS_ENTER, "MCA", regs, 0, 0, 0)
== NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_DONE; ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_DONE;
/* Register with the SAL monarch that the slave has /* Register with the SAL monarch that the slave has
...@@ -540,10 +554,18 @@ ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs) ...@@ -540,10 +554,18 @@ ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs)
*/ */
ia64_sal_mc_rendez(); ia64_sal_mc_rendez();
if (notify_die(DIE_MCA_RENDZVOUS_PROCESS, "MCA", regs, 0, 0, 0)
== NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
/* Wait for the monarch cpu to exit. */ /* Wait for the monarch cpu to exit. */
while (monarch_cpu != -1) while (monarch_cpu != -1)
cpu_relax(); /* spin until monarch leaves */ cpu_relax(); /* spin until monarch leaves */
if (notify_die(DIE_MCA_RENDZVOUS_LEAVE, "MCA", regs, 0, 0, 0)
== NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
/* Enable all interrupts */ /* Enable all interrupts */
local_irq_restore(flags); local_irq_restore(flags);
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -933,6 +955,9 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, ...@@ -933,6 +955,9 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */ oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */
previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA"); previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA");
monarch_cpu = cpu; monarch_cpu = cpu;
if (notify_die(DIE_MCA_MONARCH_ENTER, "MCA", regs, 0, 0, 0)
== NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
ia64_wait_for_slaves(cpu); ia64_wait_for_slaves(cpu);
/* Wakeup all the processors which are spinning in the rendezvous loop. /* Wakeup all the processors which are spinning in the rendezvous loop.
...@@ -942,6 +967,9 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, ...@@ -942,6 +967,9 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
* spinning in SAL does not work. * spinning in SAL does not work.
*/ */
ia64_mca_wakeup_all(); ia64_mca_wakeup_all();
if (notify_die(DIE_MCA_MONARCH_PROCESS, "MCA", regs, 0, 0, 0)
== NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
/* Get the MCA error record and log it */ /* Get the MCA error record and log it */
ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
...@@ -960,6 +988,9 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, ...@@ -960,6 +988,9 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
ia64_sal_clear_state_info(SAL_INFO_TYPE_MCA); ia64_sal_clear_state_info(SAL_INFO_TYPE_MCA);
sos->os_status = IA64_MCA_CORRECTED; sos->os_status = IA64_MCA_CORRECTED;
} }
if (notify_die(DIE_MCA_MONARCH_LEAVE, "MCA", regs, 0, 0, recover)
== NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
set_curr_task(cpu, previous_current); set_curr_task(cpu, previous_current);
monarch_cpu = -1; monarch_cpu = -1;
...@@ -1188,6 +1219,37 @@ ia64_mca_cpe_poll (unsigned long dummy) ...@@ -1188,6 +1219,37 @@ ia64_mca_cpe_poll (unsigned long dummy)
#endif /* CONFIG_ACPI */ #endif /* CONFIG_ACPI */
static int
default_monarch_init_process(struct notifier_block *self, unsigned long val, void *data)
{
int c;
struct task_struct *g, *t;
if (val != DIE_INIT_MONARCH_PROCESS)
return NOTIFY_DONE;
printk(KERN_ERR "Processes interrupted by INIT -");
for_each_online_cpu(c) {
struct ia64_sal_os_state *s;
t = __va(__per_cpu_mca[c] + IA64_MCA_CPU_INIT_STACK_OFFSET);
s = (struct ia64_sal_os_state *)((char *)t + MCA_SOS_OFFSET);
g = s->prev_task;
if (g) {
if (g->pid)
printk(" %d", g->pid);
else
printk(" %d (cpu %d task 0x%p)", g->pid, task_cpu(g), g);
}
}
printk("\n\n");
if (read_trylock(&tasklist_lock)) {
do_each_thread (g, t) {
printk("\nBacktrace of pid %d (%s)\n", t->pid, t->comm);
show_stack(t, NULL);
} while_each_thread (g, t);
read_unlock(&tasklist_lock);
}
return NOTIFY_DONE;
}
/* /*
* C portion of the OS INIT handler * C portion of the OS INIT handler
* *
...@@ -1212,8 +1274,7 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw, ...@@ -1212,8 +1274,7 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw,
static atomic_t slaves; static atomic_t slaves;
static atomic_t monarchs; static atomic_t monarchs;
task_t *previous_current; task_t *previous_current;
int cpu = smp_processor_id(), c; int cpu = smp_processor_id();
struct task_struct *g, *t;
oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */ oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */
console_loglevel = 15; /* make sure printks make it to console */ console_loglevel = 15; /* make sure printks make it to console */
...@@ -1253,8 +1314,17 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw, ...@@ -1253,8 +1314,17 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw,
ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_INIT; ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_INIT;
while (monarch_cpu == -1) while (monarch_cpu == -1)
cpu_relax(); /* spin until monarch enters */ cpu_relax(); /* spin until monarch enters */
if (notify_die(DIE_INIT_SLAVE_ENTER, "INIT", regs, 0, 0, 0)
== NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
if (notify_die(DIE_INIT_SLAVE_PROCESS, "INIT", regs, 0, 0, 0)
== NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
while (monarch_cpu != -1) while (monarch_cpu != -1)
cpu_relax(); /* spin until monarch leaves */ cpu_relax(); /* spin until monarch leaves */
if (notify_die(DIE_INIT_SLAVE_LEAVE, "INIT", regs, 0, 0, 0)
== NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
printk("Slave on cpu %d returning to normal service.\n", cpu); printk("Slave on cpu %d returning to normal service.\n", cpu);
set_curr_task(cpu, previous_current); set_curr_task(cpu, previous_current);
ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
...@@ -1263,6 +1333,9 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw, ...@@ -1263,6 +1333,9 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw,
} }
monarch_cpu = cpu; monarch_cpu = cpu;
if (notify_die(DIE_INIT_MONARCH_ENTER, "INIT", regs, 0, 0, 0)
== NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
/* /*
* Wait for a bit. On some machines (e.g., HP's zx2000 and zx6000, INIT can be * Wait for a bit. On some machines (e.g., HP's zx2000 and zx6000, INIT can be
...@@ -1273,27 +1346,16 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw, ...@@ -1273,27 +1346,16 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw,
printk("Delaying for 5 seconds...\n"); printk("Delaying for 5 seconds...\n");
udelay(5*1000000); udelay(5*1000000);
ia64_wait_for_slaves(cpu); ia64_wait_for_slaves(cpu);
printk(KERN_ERR "Processes interrupted by INIT -"); /* If nobody intercepts DIE_INIT_MONARCH_PROCESS then we drop through
for_each_online_cpu(c) { * to default_monarch_init_process() above and just print all the
struct ia64_sal_os_state *s; * tasks.
t = __va(__per_cpu_mca[c] + IA64_MCA_CPU_INIT_STACK_OFFSET); */
s = (struct ia64_sal_os_state *)((char *)t + MCA_SOS_OFFSET); if (notify_die(DIE_INIT_MONARCH_PROCESS, "INIT", regs, 0, 0, 0)
g = s->prev_task; == NOTIFY_STOP)
if (g) { ia64_mca_spin(__FUNCTION__);
if (g->pid) if (notify_die(DIE_INIT_MONARCH_LEAVE, "INIT", regs, 0, 0, 0)
printk(" %d", g->pid); == NOTIFY_STOP)
else ia64_mca_spin(__FUNCTION__);
printk(" %d (cpu %d task 0x%p)", g->pid, task_cpu(g), g);
}
}
printk("\n\n");
if (read_trylock(&tasklist_lock)) {
do_each_thread (g, t) {
printk("\nBacktrace of pid %d (%s)\n", t->pid, t->comm);
show_stack(t, NULL);
} while_each_thread (g, t);
read_unlock(&tasklist_lock);
}
printk("\nINIT dump complete. Monarch on cpu %d returning to normal service.\n", cpu); printk("\nINIT dump complete. Monarch on cpu %d returning to normal service.\n", cpu);
atomic_dec(&monarchs); atomic_dec(&monarchs);
set_curr_task(cpu, previous_current); set_curr_task(cpu, previous_current);
...@@ -1462,6 +1524,10 @@ ia64_mca_init(void) ...@@ -1462,6 +1524,10 @@ ia64_mca_init(void)
s64 rc; s64 rc;
struct ia64_sal_retval isrv; struct ia64_sal_retval isrv;
u64 timeout = IA64_MCA_RENDEZ_TIMEOUT; /* platform specific */ u64 timeout = IA64_MCA_RENDEZ_TIMEOUT; /* platform specific */
static struct notifier_block default_init_monarch_nb = {
.notifier_call = default_monarch_init_process,
.priority = 0/* we need to notified last */
};
IA64_MCA_DEBUG("%s: begin\n", __FUNCTION__); IA64_MCA_DEBUG("%s: begin\n", __FUNCTION__);
...@@ -1555,6 +1621,10 @@ ia64_mca_init(void) ...@@ -1555,6 +1621,10 @@ ia64_mca_init(void)
"(status %ld)\n", rc); "(status %ld)\n", rc);
return; return;
} }
if (register_die_notifier(&default_init_monarch_nb)) {
printk(KERN_ERR "Failed to register default monarch INIT process\n");
return;
}
IA64_MCA_DEBUG("%s: registered OS INIT handler with SAL\n", __FUNCTION__); IA64_MCA_DEBUG("%s: registered OS INIT handler with SAL\n", __FUNCTION__);
......
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
* Copyright (C) 1998-2003 Hewlett-Packard Co * Copyright (C) 1998-2003 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
* 04/11/17 Ashok Raj <ashok.raj@intel.com> Added CPU Hotplug Support * 04/11/17 Ashok Raj <ashok.raj@intel.com> Added CPU Hotplug Support
*
* 2005-10-07 Keith Owens <kaos@sgi.com>
* Add notify_die() hooks.
*/ */
#define __KERNEL_SYSCALLS__ /* see <asm/unistd.h> */ #define __KERNEL_SYSCALLS__ /* see <asm/unistd.h> */
#include <linux/config.h> #include <linux/config.h>
...@@ -34,6 +37,7 @@ ...@@ -34,6 +37,7 @@
#include <asm/elf.h> #include <asm/elf.h>
#include <asm/ia32.h> #include <asm/ia32.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/kdebug.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/sal.h> #include <asm/sal.h>
...@@ -804,12 +808,14 @@ cpu_halt (void) ...@@ -804,12 +808,14 @@ cpu_halt (void)
void void
machine_restart (char *restart_cmd) machine_restart (char *restart_cmd)
{ {
(void) notify_die(DIE_MACHINE_RESTART, restart_cmd, NULL, 0, 0, 0);
(*efi.reset_system)(EFI_RESET_WARM, 0, 0, NULL); (*efi.reset_system)(EFI_RESET_WARM, 0, 0, NULL);
} }
void void
machine_halt (void) machine_halt (void)
{ {
(void) notify_die(DIE_MACHINE_HALT, "", NULL, 0, 0, 0);
cpu_halt(); cpu_halt();
} }
......
...@@ -30,17 +30,20 @@ fpswa_interface_t *fpswa_interface; ...@@ -30,17 +30,20 @@ fpswa_interface_t *fpswa_interface;
EXPORT_SYMBOL(fpswa_interface); EXPORT_SYMBOL(fpswa_interface);
struct notifier_block *ia64die_chain; struct notifier_block *ia64die_chain;
static DEFINE_SPINLOCK(die_notifier_lock);
int register_die_notifier(struct notifier_block *nb) int
register_die_notifier(struct notifier_block *nb)
{ {
int err = 0; return notifier_chain_register(&ia64die_chain, nb);
unsigned long flags;
spin_lock_irqsave(&die_notifier_lock, flags);
err = notifier_chain_register(&ia64die_chain, nb);
spin_unlock_irqrestore(&die_notifier_lock, flags);
return err;
} }
EXPORT_SYMBOL_GPL(register_die_notifier);
int
unregister_die_notifier(struct notifier_block *nb)
{
return notifier_chain_unregister(&ia64die_chain, nb);
}
EXPORT_SYMBOL_GPL(unregister_die_notifier);
void __init void __init
trap_init (void) trap_init (void)
...@@ -105,6 +108,7 @@ die (const char *str, struct pt_regs *regs, long err) ...@@ -105,6 +108,7 @@ die (const char *str, struct pt_regs *regs, long err)
if (++die.lock_owner_depth < 3) { if (++die.lock_owner_depth < 3) {
printk("%s[%d]: %s %ld [%d]\n", printk("%s[%d]: %s %ld [%d]\n",
current->comm, current->pid, str, err, ++die_counter); current->comm, current->pid, str, err, ++die_counter);
(void) notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
show_regs(regs); show_regs(regs);
} else } else
printk(KERN_ERR "Recursive die() failure, output suppressed\n"); printk(KERN_ERR "Recursive die() failure, output suppressed\n");
...@@ -155,9 +159,8 @@ __kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs) ...@@ -155,9 +159,8 @@ __kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
switch (break_num) { switch (break_num) {
case 0: /* unknown error (used by GCC for __builtin_abort()) */ case 0: /* unknown error (used by GCC for __builtin_abort()) */
if (notify_die(DIE_BREAK, "break 0", regs, break_num, TRAP_BRKPT, SIGTRAP) if (notify_die(DIE_BREAK, "break 0", regs, break_num, TRAP_BRKPT, SIGTRAP)
== NOTIFY_STOP) { == NOTIFY_STOP)
return; return;
}
die_if_kernel("bugcheck!", regs, break_num); die_if_kernel("bugcheck!", regs, break_num);
sig = SIGILL; code = ILL_ILLOPC; sig = SIGILL; code = ILL_ILLOPC;
break; break;
...@@ -210,15 +213,6 @@ __kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs) ...@@ -210,15 +213,6 @@ __kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
sig = SIGILL; code = __ILL_BNDMOD; sig = SIGILL; code = __ILL_BNDMOD;
break; break;
case 0x80200:
case 0x80300:
if (notify_die(DIE_BREAK, "kprobe", regs, break_num, TRAP_BRKPT, SIGTRAP)
== NOTIFY_STOP) {
return;
}
sig = SIGTRAP; code = TRAP_BRKPT;
break;
default: default:
if (break_num < 0x40000 || break_num > 0x100000) if (break_num < 0x40000 || break_num > 0x100000)
die_if_kernel("Bad break", regs, break_num); die_if_kernel("Bad break", regs, break_num);
...@@ -226,6 +220,9 @@ __kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs) ...@@ -226,6 +220,9 @@ __kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
if (break_num < 0x80000) { if (break_num < 0x80000) {
sig = SIGILL; code = __ILL_BREAK; sig = SIGILL; code = __ILL_BREAK;
} else { } else {
if (notify_die(DIE_BREAK, "bad break", regs, break_num, TRAP_BRKPT, SIGTRAP)
== NOTIFY_STOP)
return;
sig = SIGTRAP; code = TRAP_BRKPT; sig = SIGTRAP; code = TRAP_BRKPT;
} }
} }
...@@ -578,12 +575,11 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, ...@@ -578,12 +575,11 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
#endif #endif
break; break;
case 35: siginfo.si_code = TRAP_BRANCH; ifa = 0; break; case 35: siginfo.si_code = TRAP_BRANCH; ifa = 0; break;
case 36: case 36: siginfo.si_code = TRAP_TRACE; ifa = 0; break;
if (notify_die(DIE_SS, "ss", &regs, vector,
vector, SIGTRAP) == NOTIFY_STOP)
return;
siginfo.si_code = TRAP_TRACE; ifa = 0; break;
} }
if (notify_die(DIE_FAULT, "ia64_fault", &regs, vector, siginfo.si_code, SIGTRAP)
== NOTIFY_STOP)
return;
siginfo.si_signo = SIGTRAP; siginfo.si_signo = SIGTRAP;
siginfo.si_errno = 0; siginfo.si_errno = 0;
siginfo.si_addr = (void __user *) ifa; siginfo.si_addr = (void __user *) ifa;
......
...@@ -22,6 +22,9 @@ ...@@ -22,6 +22,9 @@
* 2005-Apr Rusty Lynch <rusty.lynch@intel.com> and Anil S Keshavamurthy * 2005-Apr Rusty Lynch <rusty.lynch@intel.com> and Anil S Keshavamurthy
* <anil.s.keshavamurthy@intel.com> adopted from * <anil.s.keshavamurthy@intel.com> adopted from
* include/asm-x86_64/kdebug.h * include/asm-x86_64/kdebug.h
*
* 2005-Oct Keith Owens <kaos@sgi.com>. Expand notify_die to cover more
* events.
*/ */
#include <linux/notifier.h> #include <linux/notifier.h>
...@@ -35,13 +38,36 @@ struct die_args { ...@@ -35,13 +38,36 @@ struct die_args {
int signr; int signr;
}; };
int register_die_notifier(struct notifier_block *nb); extern int register_die_notifier(struct notifier_block *);
extern int unregister_die_notifier(struct notifier_block *);
extern struct notifier_block *ia64die_chain; extern struct notifier_block *ia64die_chain;
enum die_val { enum die_val {
DIE_BREAK = 1, DIE_BREAK = 1,
DIE_SS, DIE_FAULT,
DIE_OOPS,
DIE_PAGE_FAULT, DIE_PAGE_FAULT,
DIE_MACHINE_HALT,
DIE_MACHINE_RESTART,
DIE_MCA_MONARCH_ENTER,
DIE_MCA_MONARCH_PROCESS,
DIE_MCA_MONARCH_LEAVE,
DIE_MCA_SLAVE_ENTER,
DIE_MCA_SLAVE_PROCESS,
DIE_MCA_SLAVE_LEAVE,
DIE_MCA_RENDZVOUS_ENTER,
DIE_MCA_RENDZVOUS_PROCESS,
DIE_MCA_RENDZVOUS_LEAVE,
DIE_INIT_MONARCH_ENTER,
DIE_INIT_MONARCH_PROCESS,
DIE_INIT_MONARCH_LEAVE,
DIE_INIT_SLAVE_ENTER,
DIE_INIT_SLAVE_PROCESS,
DIE_INIT_SLAVE_LEAVE,
DIE_KDEBUG_ENTER,
DIE_KDEBUG_LEAVE,
DIE_KDUMP_ENTER,
DIE_KDUMP_LEAVE,
}; };
static inline int notify_die(enum die_val val, char *str, struct pt_regs *regs, static inline int notify_die(enum die_val val, char *str, struct pt_regs *regs,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment