From 482cf40c0cc4fb016ddc91260b54f800ace2014e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 23 Aug 2002 16:07:52 -0700 Subject: [PATCH] SPARC64: Ultra-III+ bug fix and better bad trap logging. - Do not use PC-relative branch/call in Ultra-III+ parity error trap vectors, we patch this into the trap table and then the PC-relative values are wrong. - When we take an irrecoverable trap at tl > 0, save away the full trap stack to the kernel stack, then log it from the C code handler. --- arch/sparc64/kernel/entry.S | 29 ++++++++++++++++++- arch/sparc64/kernel/etrap.S | 52 ++++++++++++++++++++++++++++++++-- arch/sparc64/kernel/traps.c | 56 +++++++++++++++++++++++++++++++++++-- 3 files changed, 131 insertions(+), 6 deletions(-) diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 7ad54be88127..3050ef797c7f 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -774,7 +774,14 @@ __do_instruction_access_exception_tl1: membar #Sync sethi %hi(109f), %g7 ba,pt %xcc, etraptl1 - or %g7, %lo(109f), %g7 ! Merge in below +109: or %g7, %lo(109b), %g7 + mov %l4, %o1 + mov %l5, %o2 + call instruction_access_exception_tl1 + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,pt %xcc, rtrap + clr %l6 + __do_instruction_access_exception: rdpr %pstate, %g4 wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate @@ -1084,6 +1091,15 @@ cheetah_deferred_trap_vector_tl1: .globl cheetah_plus_dcpe_trap_vector, cheetah_plus_dcpe_trap_vector_tl1 cheetah_plus_dcpe_trap_vector: membar #Sync + sethi %hi(do_cheetah_plus_data_parity), %g7 + jmpl %g7 + %lo(do_cheetah_plus_data_parity), %g0 + nop + nop + nop + nop + nop + +do_cheetah_plus_data_parity: ba,pt %xcc, etrap rd %pc, %g7 mov 0x0, %o0 @@ -1091,6 +1107,7 @@ cheetah_plus_dcpe_trap_vector: add %sp, STACK_BIAS + REGWIN_SZ, %o1 ba,pt %xcc, rtrap clr %l6 + cheetah_plus_dcpe_trap_vector_tl1: membar #Sync wrpr PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate @@ -1104,6 +1121,15 @@ cheetah_plus_dcpe_trap_vector_tl1: .globl cheetah_plus_icpe_trap_vector, cheetah_plus_icpe_trap_vector_tl1 cheetah_plus_icpe_trap_vector: membar #Sync + sethi %hi(do_cheetah_plus_insn_parity), %g7 + jmpl %g7 + %lo(do_cheetah_plus_insn_parity), %g0 + nop + nop + nop + nop + nop + +do_cheetah_plus_insn_parity: ba,pt %xcc, etrap rd %pc, %g7 mov 0x1, %o0 @@ -1111,6 +1137,7 @@ cheetah_plus_icpe_trap_vector: add %sp, STACK_BIAS + REGWIN_SZ, %o1 ba,pt %xcc, rtrap clr %l6 + cheetah_plus_icpe_trap_vector_tl1: membar #Sync wrpr PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S index 3b282d5252db..ab202bcbe5a0 100644 --- a/arch/sparc64/kernel/etrap.S +++ b/arch/sparc64/kernel/etrap.S @@ -109,8 +109,56 @@ etrap_irq: stb %g0, [%l4 + %l3] ! Store Group nop -etraptl1: rdpr %tstate, %g1 ! Single Group+4bubbles - sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU1 +etraptl1: /* Save tstate/tpc/tnpc of TL 1-->4 and the tl register itself. + * We place this right after pt_regs on the trap stack. The layout + * is: + * 0x00 TL1's TSTATE + * 0x08 TL1's TPC + * 0x10 TL1's TNPC + * ... + * 0x58 TL4's TNPC + * 0x60 TL + */ + sub %sp, (24 * 8) + 8, %g2 + rdpr %tl, %g1 + + wrpr %g0, 1, %tl + rdpr %tstate, %g3 + stx %g3, [%g2 + STACK_BIAS + 0x00] + rdpr %tpc, %g3 + stx %g3, [%g2 + STACK_BIAS + 0x08] + rdpr %tnpc, %g3 + stx %g3, [%g2 + STACK_BIAS + 0x10] + + wrpr %g0, 2, %tl + rdpr %tstate, %g3 + stx %g3, [%g2 + STACK_BIAS + 0x18] + rdpr %tpc, %g3 + stx %g3, [%g2 + STACK_BIAS + 0x20] + rdpr %tnpc, %g3 + stx %g3, [%g2 + STACK_BIAS + 0x28] + + wrpr %g0, 3, %tl + rdpr %tstate, %g3 + stx %g3, [%g2 + STACK_BIAS + 0x30] + rdpr %tpc, %g3 + stx %g3, [%g2 + STACK_BIAS + 0x38] + rdpr %tnpc, %g3 + stx %g3, [%g2 + STACK_BIAS + 0x40] + + wrpr %g0, 4, %tl + rdpr %tstate, %g3 + stx %g3, [%g2 + STACK_BIAS + 0x48] + rdpr %tpc, %g3 + stx %g3, [%g2 + STACK_BIAS + 0x50] + rdpr %tnpc, %g3 + stx %g3, [%g2 + STACK_BIAS + 0x58] + + wrpr %g1, %tl + stx %g1, [%g2 + STACK_BIAS + 0x60] + + rdpr %tstate, %g1 ! Single Group+4bubbles + sub %g2, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU1 ba,pt %xcc, 1b ! CTI Group andcc %g1, TSTATE_PRIV, %g0 ! IEU0 diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index d52e9a2dee6e..972a2716b21c 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -37,6 +37,33 @@ #include #endif +/* When an irrecoverable trap occurs at tl > 0, the trap entry + * code logs the trap state registers at every level in the trap + * stack. It is found at (pt_regs + sizeof(pt_regs)) and the layout + * is as follows: + */ +struct tl1_traplog { + struct { + unsigned long tstate; + unsigned long tpc; + unsigned long tnpc; + } trapstack[4]; + unsigned long tl; +}; + +static void dump_tl1_traplog(struct tl1_traplog *p) +{ + int i; + + printk("TRAPLOG: Error at trap level 0x%lx, dumping track stack.\n", + p->tl); + for (i = 0; i < 4; i++) { + printk("TRAPLOG: Trap level %d TSTATE[%016lx] TPC[%016lx] TNPC[%016lx]\n", + i + 1, + p->trapstack[i].tstate, p->trapstack[i].tpc, p->trapstack[i].tnpc); + } +} + void bad_trap (struct pt_regs *regs, long lvl) { char buffer[32]; @@ -66,8 +93,10 @@ void bad_trap (struct pt_regs *regs, long lvl) void bad_trap_tl1 (struct pt_regs *regs, long lvl) { - char buffer[24]; + char buffer[32]; + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); + sprintf (buffer, "Bad trap %lx at tl>0", lvl); die_if_kernel (buffer, regs); } @@ -80,8 +109,8 @@ void do_BUG(const char *file, int line) } #endif -void instruction_access_exception (struct pt_regs *regs, - unsigned long sfsr, unsigned long sfar) +void instruction_access_exception(struct pt_regs *regs, + unsigned long sfsr, unsigned long sfar) { siginfo_t info; @@ -102,6 +131,13 @@ void instruction_access_exception (struct pt_regs *regs, force_sig_info(SIGSEGV, &info, current); } +void instruction_access_exception_tl1(struct pt_regs *regs, + unsigned long sfsr, unsigned long sfar) +{ + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); + instruction_access_exception(regs, sfsr, sfar); +} + void data_access_exception (struct pt_regs *regs, unsigned long sfsr, unsigned long sfar) { @@ -1689,56 +1725,67 @@ void do_cee(struct pt_regs *regs) void do_cee_tl1(struct pt_regs *regs) { + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); die_if_kernel("TL1: Cache Error Exception", regs); } void do_dae_tl1(struct pt_regs *regs) { + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); die_if_kernel("TL1: Data Access Exception", regs); } void do_iae_tl1(struct pt_regs *regs) { + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); die_if_kernel("TL1: Instruction Access Exception", regs); } void do_div0_tl1(struct pt_regs *regs) { + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); die_if_kernel("TL1: DIV0 Exception", regs); } void do_fpdis_tl1(struct pt_regs *regs) { + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); die_if_kernel("TL1: FPU Disabled", regs); } void do_fpieee_tl1(struct pt_regs *regs) { + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); die_if_kernel("TL1: FPU IEEE Exception", regs); } void do_fpother_tl1(struct pt_regs *regs) { + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); die_if_kernel("TL1: FPU Other Exception", regs); } void do_ill_tl1(struct pt_regs *regs) { + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); die_if_kernel("TL1: Illegal Instruction Exception", regs); } void do_irq_tl1(struct pt_regs *regs) { + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); die_if_kernel("TL1: IRQ Exception", regs); } void do_lddfmna_tl1(struct pt_regs *regs) { + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); die_if_kernel("TL1: LDDF Exception", regs); } void do_stdfmna_tl1(struct pt_regs *regs) { + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); die_if_kernel("TL1: STDF Exception", regs); } @@ -1749,6 +1796,7 @@ void do_paw(struct pt_regs *regs) void do_paw_tl1(struct pt_regs *regs) { + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); die_if_kernel("TL1: Phys Watchpoint Exception", regs); } @@ -1759,11 +1807,13 @@ void do_vaw(struct pt_regs *regs) void do_vaw_tl1(struct pt_regs *regs) { + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); die_if_kernel("TL1: Virt Watchpoint Exception", regs); } void do_tof_tl1(struct pt_regs *regs) { + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); die_if_kernel("TL1: Tag Overflow Exception", regs); } -- 2.39.5