patch-2.4.21 linux-2.4.21/arch/x86_64/kernel/traps.c
Next file: linux-2.4.21/arch/x86_64/kernel/vsyscall.c
Previous file: linux-2.4.21/arch/x86_64/kernel/time.c
Back to the patch index
Back to the overall index
- Lines: 353
- Date:
2003-06-13 07:51:32.000000000 -0700
- Orig file:
linux-2.4.20/arch/x86_64/kernel/traps.c
- Orig date:
2002-11-28 15:53:12.000000000 -0800
diff -urN linux-2.4.20/arch/x86_64/kernel/traps.c linux-2.4.21/arch/x86_64/kernel/traps.c
@@ -7,7 +7,7 @@
* Pentium III FXSR, SSE support
* Gareth Hughes <gareth@valinux.com>, May 2000
*
- * $Id: traps.c,v 1.51 2002/09/12 12:57:46 ak Exp $
+ * $Id: traps.c,v 1.62 2003/03/14 16:06:35 ak Exp $
*/
/*
@@ -71,6 +71,12 @@
asmlinkage void spurious_interrupt_bug(void);
asmlinkage void call_debug(void);
+static inline void conditional_sti(struct pt_regs *regs)
+{
+ if (regs->eflags & X86_EFLAGS_IF)
+ __sti();
+}
+
extern char iret_address[];
struct notifier_block *die_chain;
@@ -95,7 +101,7 @@
}
if (!strcmp(modname, "kernel"))
modname = delim = "";
- return printk("[%016lx%s%s%s%s%+ld]",
+ return printk("[<%016lx>]{%s%s%s%s%+ld}",
address,delim,modname,delim,symname,address-symstart);
}
#else
@@ -143,7 +149,7 @@
#endif
-static inline unsigned long *in_exception_stack(int cpu, unsigned long stack)
+unsigned long *in_exception_stack(int cpu, unsigned long stack)
{
int k;
for (k = 0; k < N_EXCEPTION_STACKS; k++) {
@@ -159,13 +165,12 @@
{
unsigned long addr;
unsigned long *irqstack, *irqstack_end, *estack_end;
- /* FIXME: should read the cpuid from the APIC; to still work with bogus %gs */
- const int cpu = smp_processor_id();
+ const int cpu = safe_smp_processor_id();
int i;
printk("\nCall Trace: ");
- i = 1;
+ i = 12;
estack_end = in_exception_stack(cpu, (unsigned long)stack);
if (estack_end) {
while (stack < estack_end) {
@@ -243,7 +248,7 @@
{
unsigned long *stack;
int i;
- const int cpu = smp_processor_id();
+ const int cpu = safe_smp_processor_id();
unsigned long *irqstack_end = (unsigned long *) (cpu_pda[cpu].irqstackptr);
unsigned long *irqstack = (unsigned long *) (cpu_pda[cpu].irqstackptr - IRQSTACKSIZE);
@@ -271,22 +276,12 @@
show_trace((unsigned long *)rsp);
}
-void dump_stack(void)
-{
- show_stack(0);
-}
-
void show_registers(struct pt_regs *regs)
{
int i;
int in_kernel = 1;
unsigned long rsp;
-#ifdef CONFIG_SMP
- /* For SMP should get the APIC id here, just to protect against corrupted GS */
- const int cpu = smp_processor_id();
-#else
- const int cpu = 0;
-#endif
+ const int cpu = safe_smp_processor_id();
struct task_struct *cur = cpu_pda[cpu].pcurrent;
rsp = (unsigned long) (®s->rsp);
@@ -350,13 +345,12 @@
void die(const char * str, struct pt_regs * regs, long err)
{
int cpu;
- struct die_args args = { regs, str, err };
console_verbose();
- notifier_call_chain(&die_chain, DIE_DIE, &args);
bust_spinlocks(1);
handle_BUG(regs);
printk(KERN_EMERG "%s: %04lx\n", str, err & 0xffff);
- cpu = smp_processor_id();
+ notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
+ cpu = safe_smp_processor_id();
/* racy, but better than risking deadlock. */
__cli();
if (!spin_trylock(&die_lock)) {
@@ -369,7 +363,6 @@
show_registers(regs);
bust_spinlocks(0);
spin_unlock_irq(&die_lock);
- notify_die(DIE_OOPS, (char *)str, regs, err);
do_exit(SIGSEGV);
}
@@ -391,10 +384,12 @@
static void do_trap(int trapnr, int signr, char *str,
struct pt_regs * regs, long error_code, siginfo_t *info)
{
+ conditional_sti(regs);
+
#if defined(CONFIG_CHECKING) && defined(CONFIG_LOCAL_APIC)
{
unsigned long gs;
- struct x8664_pda *pda = cpu_pda + hard_smp_processor_id();
+ struct x8664_pda *pda = cpu_pda + safe_smp_processor_id();
rdmsrl(MSR_GS_BASE, gs);
if (gs != (unsigned long)pda) {
wrmsrl(MSR_GS_BASE, pda);
@@ -407,7 +402,7 @@
struct task_struct *tsk = current;
tsk->thread.error_code = error_code;
tsk->thread.trap_no = trapnr;
- if (exception_trace)
+ if (exception_trace && trapnr != 3)
printk("%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n",
tsk->comm, tsk->pid, str,
regs->rip,regs->rsp,error_code);
@@ -424,11 +419,6 @@
unsigned long fixup = search_exception_table(regs->rip);
if (fixup) {
extern int exception_trace;
- if (0 && exception_trace)
- printk(KERN_ERR
- "%s: fixed kernel exception at %lx err:%ld\n",
- current->comm, regs->rip, error_code);
-
regs->rip = fixup;
} else
die(str, regs, error_code);
@@ -439,6 +429,8 @@
#define DO_ERROR(trapnr, signr, str, name) \
asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
{ \
+ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \
+ return; \
do_trap(trapnr, signr, str, regs, error_code, NULL); \
}
@@ -450,10 +442,13 @@
info.si_errno = 0; \
info.si_code = sicode; \
info.si_addr = (void *)siaddr; \
+ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)==NOTIFY_BAD) \
+ return; \
do_trap(trapnr, signr, str, regs, error_code, &info); \
}
DO_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->rip)
+DO_ERROR( 3, SIGTRAP, "int3", int3);
DO_ERROR( 4, SIGSEGV, "overflow", overflow)
DO_ERROR( 5, SIGSEGV, "bounds", bounds)
DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, ILL_ILLOPN, regs->rip)
@@ -466,25 +461,25 @@
DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2())
DO_ERROR(18, SIGSEGV, "reserved", reserved)
-asmlinkage void do_int3(struct pt_regs * regs, long error_code)
-{
- if (notify_die(DIE_INT3, "int3", regs, error_code) == NOTIFY_BAD)
- return;
- do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
-}
-
extern void dump_pagetable(unsigned long);
asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
{
+ conditional_sti(regs);
+
#ifdef CONFIG_CHECKING
{
unsigned long gs;
- struct x8664_pda *pda = cpu_pda + stack_smp_processor_id();
+ struct x8664_pda *pda = cpu_pda + safe_smp_processor_id();
rdmsrl(MSR_GS_BASE, gs);
if (gs != (unsigned long)pda) {
wrmsrl(MSR_GS_BASE, pda);
+ /* Avoid wakeup in printk in case this was triggered
+ by the segment reloads in __switch_to. Otherwise
+ the wake_up could deadlock on scheduler locks. */
+ oops_in_progress++;
printk("general protection handler: wrong gs %lx expected %p\n", gs, pda);
+ oops_in_progress--;
}
}
#endif
@@ -505,15 +500,11 @@
unsigned long fixup;
fixup = search_exception_table(regs->rip);
if (fixup) {
- extern int exception_trace;
- if (exception_trace)
- printk(KERN_ERR
- "%s: fixed kernel exception at %lx err:%ld\n",
- current->comm, regs->rip, error_code);
-
regs->rip = fixup;
return;
}
+ notify_die(DIE_GPF, "general protection fault", regs, error_code,
+ 13, SIGSEGV);
die("general protection fault", regs, error_code);
}
}
@@ -552,7 +543,7 @@
{
unsigned char reason = inb(0x61);
- ++nmi_count(smp_processor_id());
+ ++nmi_count(safe_smp_processor_id());
if (!(reason & 0xc0)) {
#if CONFIG_X86_LOCAL_APIC
@@ -561,16 +552,14 @@
* so it must be the NMI watchdog.
*/
if (nmi_watchdog) {
- nmi_watchdog_tick(regs);
+ nmi_watchdog_tick(regs, reason);
return;
}
#endif
- if (notify_die(DIE_NMI, "nmi", regs, reason) == NOTIFY_BAD)
- return;
unknown_nmi_error(reason, regs);
return;
}
- if (notify_die(DIE_NMI, "nmi", regs, reason) == NOTIFY_BAD)
+ if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_BAD)
return;
if (reason & 0x80)
mem_parity_error(reason, regs);
@@ -593,10 +582,15 @@
struct task_struct *tsk = current;
siginfo_t info;
+ asm("movq %%db6,%0" : "=r" (condition));
+
+ conditional_sti(regs);
+
#ifdef CONFIG_CHECKING
{
+ /* XXX: interaction with debugger - could destroy gs */
unsigned long gs;
- struct x8664_pda *pda = cpu_pda + stack_smp_processor_id();
+ struct x8664_pda *pda = cpu_pda + safe_smp_processor_id();
rdmsrl(MSR_GS_BASE, gs);
if (gs != (unsigned long)pda) {
wrmsrl(MSR_GS_BASE, pda);
@@ -605,16 +599,6 @@
}
#endif
- asm("movq %%db6,%0" : "=r" (condition));
-
- if (notify_die(DIE_DEBUG, "debug", regs, error_code) == NOTIFY_BAD)
- return;
-
- /* If the user set TF, it's simplest to clear it right away. */
- /* AK: dubious check, likely wrong */
- if ((regs->cs & 3) == 0 && (regs->eflags & TF_MASK))
- goto clear_TF;
-
/* Mask out spurious debug traps due to lazy DR7 setting */
if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
if (!tsk->thread.debugreg[7]) {
@@ -647,14 +631,19 @@
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TRAP_BRKPT;
- info.si_addr = ((regs->cs & 3) == 0) ? (void *)tsk->thread.rip :
- (void *)regs->rip;
+ if ((regs->cs & 3) == 0)
+ goto clear_dr7;
+
+ info.si_addr = (void *)regs->rip;
force_sig_info(SIGTRAP, &info, tsk);
clear_dr7:
- asm("movq %0,%%db7"::"r"(0UL));
+ asm volatile("movq %0,%%db7"::"r"(0UL));
+ notify_die(DIE_DEBUG, "debug", regs, error_code, 1, SIGTRAP);
return;
clear_TF:
+ /* XXX: could cause spurious errors */
+ if (notify_die(DIE_DEBUG, "debug2", regs, error_code, 1, SIGTRAP) != NOTIFY_BAD)
regs->eflags &= ~TF_MASK;
return;
}
@@ -721,6 +710,7 @@
asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
{
+ conditional_sti(regs);
math_error((void *)regs->rip);
}
@@ -780,6 +770,7 @@
asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs,
long error_code)
{
+ conditional_sti(regs);
simd_math_error((void *)regs->rip);
}
@@ -800,7 +791,7 @@
clts(); /* Allow maths ops (or we recurse) */
if (!me->used_math)
- init_fpu();
+ init_fpu(me);
restore_fpu_checking(&me->thread.i387.fxsave);
me->flags |= PF_USEDFPU; /* So we fxsave on switch_to() */
}
@@ -812,7 +803,7 @@
void do_call_debug(struct pt_regs *regs)
{
- notify_die(DIE_CALL, "debug call", regs, 0);
+ notify_die(DIE_CALL, "debug call", regs, 0, 255, SIGINT);
}
#ifndef CONFIG_MCE
@@ -849,10 +840,6 @@
set_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
#endif
- set_intr_gate(KDB_VECTOR, call_debug);
-
- notify_die(DIE_TRAPINIT, "traps initialized", 0, 0);
-
/*
* Should be a barrier for any external CPU state.
*/
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)