| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: trap.c,v 1.168 2011/07/30 19:29:12 martin Exp $ */ | | 1 | /* $NetBSD: trap.c,v 1.168.8.1 2012/03/21 16:10:21 riz Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1996-2002 Eduardo Horvath. All rights reserved. | | 4 | * Copyright (c) 1996-2002 Eduardo Horvath. All rights reserved. |
5 | * Copyright (c) 1996 | | 5 | * Copyright (c) 1996 |
6 | * The President and Fellows of Harvard College. All rights reserved. | | 6 | * The President and Fellows of Harvard College. All rights reserved. |
7 | * Copyright (c) 1992, 1993 | | 7 | * Copyright (c) 1992, 1993 |
8 | * The Regents of the University of California. All rights reserved. | | 8 | * The Regents of the University of California. All rights reserved. |
9 | * | | 9 | * |
10 | * This software was developed by the Computer Systems Engineering group | | 10 | * This software was developed by the Computer Systems Engineering group |
11 | * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and | | 11 | * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and |
12 | * contributed to Berkeley. | | 12 | * contributed to Berkeley. |
13 | * | | 13 | * |
14 | * All advertising materials mentioning features or use of this software | | 14 | * All advertising materials mentioning features or use of this software |
| @@ -40,27 +40,27 @@ | | | @@ -40,27 +40,27 @@ |
40 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 40 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
41 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 41 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
42 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 42 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
43 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 43 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
44 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 44 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
45 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 45 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
46 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 46 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
47 | * SUCH DAMAGE. | | 47 | * SUCH DAMAGE. |
48 | * | | 48 | * |
49 | * @(#)trap.c 8.4 (Berkeley) 9/23/93 | | 49 | * @(#)trap.c 8.4 (Berkeley) 9/23/93 |
50 | */ | | 50 | */ |
51 | | | 51 | |
52 | #include <sys/cdefs.h> | | 52 | #include <sys/cdefs.h> |
53 | __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.168 2011/07/30 19:29:12 martin Exp $"); | | 53 | __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.168.8.1 2012/03/21 16:10:21 riz Exp $"); |
54 | | | 54 | |
55 | #include "opt_ddb.h" | | 55 | #include "opt_ddb.h" |
56 | #include "opt_multiprocessor.h" | | 56 | #include "opt_multiprocessor.h" |
57 | #include "opt_compat_svr4.h" | | 57 | #include "opt_compat_svr4.h" |
58 | #include "opt_compat_netbsd32.h" | | 58 | #include "opt_compat_netbsd32.h" |
59 | | | 59 | |
60 | #include <sys/param.h> | | 60 | #include <sys/param.h> |
61 | #include <sys/systm.h> | | 61 | #include <sys/systm.h> |
62 | #include <sys/pool.h> | | 62 | #include <sys/pool.h> |
63 | #include <sys/proc.h> | | 63 | #include <sys/proc.h> |
64 | #include <sys/ras.h> | | 64 | #include <sys/ras.h> |
65 | #include <sys/sa.h> | | 65 | #include <sys/sa.h> |
66 | #include <sys/savar.h> | | 66 | #include <sys/savar.h> |
| @@ -84,26 +84,28 @@ __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.1 | | | @@ -84,26 +84,28 @@ __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.1 |
84 | | | 84 | |
85 | #ifdef DDB | | 85 | #ifdef DDB |
86 | #include <machine/db_machdep.h> | | 86 | #include <machine/db_machdep.h> |
87 | #else | | 87 | #else |
88 | #include <machine/frame.h> | | 88 | #include <machine/frame.h> |
89 | #endif | | 89 | #endif |
90 | #ifdef COMPAT_SVR4 | | 90 | #ifdef COMPAT_SVR4 |
91 | #include <machine/svr4_machdep.h> | | 91 | #include <machine/svr4_machdep.h> |
92 | #endif | | 92 | #endif |
93 | #ifdef COMPAT_SVR4_32 | | 93 | #ifdef COMPAT_SVR4_32 |
94 | #include <machine/svr4_32_machdep.h> | | 94 | #include <machine/svr4_32_machdep.h> |
95 | #endif | | 95 | #endif |
96 | | | 96 | |
| | | 97 | #include <sparc64/sparc64/cache.h> |
| | | 98 | |
97 | #include <sparc/fpu/fpu_extern.h> | | 99 | #include <sparc/fpu/fpu_extern.h> |
98 | | | 100 | |
99 | #ifndef offsetof | | 101 | #ifndef offsetof |
100 | #define offsetof(s, f) ((size_t)&((s *)0)->f) | | 102 | #define offsetof(s, f) ((size_t)&((s *)0)->f) |
101 | #endif | | 103 | #endif |
102 | | | 104 | |
103 | #ifdef TRAPSTATS | | 105 | #ifdef TRAPSTATS |
104 | /* trapstats */ | | 106 | /* trapstats */ |
105 | int protfix = 0; | | 107 | int protfix = 0; |
106 | int udmiss = 0; /* Number of normal/nucleus data/text miss/protection faults */ | | 108 | int udmiss = 0; /* Number of normal/nucleus data/text miss/protection faults */ |
107 | int udhit = 0; | | 109 | int udhit = 0; |
108 | int udprot = 0; | | 110 | int udprot = 0; |
109 | int utmiss = 0; | | 111 | int utmiss = 0; |
| @@ -149,26 +151,30 @@ int trapdebug = 0/*|TDB_SYSCALL|TDB_STOP | | | @@ -149,26 +151,30 @@ int trapdebug = 0/*|TDB_SYSCALL|TDB_STOP |
149 | #endif | | 151 | #endif |
150 | | | 152 | |
151 | #ifdef DDB | | 153 | #ifdef DDB |
152 | #if 1 | | 154 | #if 1 |
153 | #define DEBUGGER(t,f) do { kdb_trap(t,f); } while (0) | | 155 | #define DEBUGGER(t,f) do { kdb_trap(t,f); } while (0) |
154 | #else | | 156 | #else |
155 | #define DEBUGGER(t,f) Debugger() | | 157 | #define DEBUGGER(t,f) Debugger() |
156 | #endif | | 158 | #endif |
157 | #else | | 159 | #else |
158 | #define DEBUGGER(t,f) | | 160 | #define DEBUGGER(t,f) |
159 | #define Debugger() | | 161 | #define Debugger() |
160 | #endif | | 162 | #endif |
161 | | | 163 | |
| | | 164 | struct evcnt ecc_corrected = |
| | | 165 | EVCNT_INITIALIZER(EVCNT_TYPE_MISC,0,"ECC","corrected"); |
| | | 166 | EVCNT_ATTACH_STATIC(ecc_corrected); |
| | | 167 | |
162 | /* | | 168 | /* |
163 | * Initial FPU state is all registers == all 1s, everything else == all 0s. | | 169 | * Initial FPU state is all registers == all 1s, everything else == all 0s. |
164 | * This makes every floating point register a signalling NaN, with sign bit | | 170 | * This makes every floating point register a signalling NaN, with sign bit |
165 | * set, no matter how it is interpreted. Appendix N of the Sparc V8 document | | 171 | * set, no matter how it is interpreted. Appendix N of the Sparc V8 document |
166 | * seems to imply that we should do this, and it does make sense. | | 172 | * seems to imply that we should do this, and it does make sense. |
167 | */ | | 173 | */ |
168 | const struct fpstate64 initfpstate __aligned(SPARC64_BLOCK_SIZE) = { | | 174 | const struct fpstate64 initfpstate __aligned(SPARC64_BLOCK_SIZE) = { |
169 | .fs_regs = | | 175 | .fs_regs = |
170 | { ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, | | 176 | { ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, |
171 | ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, | | 177 | ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, |
172 | ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, | | 178 | ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, |
173 | ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0 }, | | 179 | ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0 }, |
174 | .fs_qsize = 0 | | 180 | .fs_qsize = 0 |
| @@ -361,26 +367,27 @@ const char *trap_type[] = { | | | @@ -361,26 +367,27 @@ const char *trap_type[] = { |
361 | }; | | 367 | }; |
362 | | | 368 | |
363 | #define N_TRAP_TYPES (sizeof trap_type / sizeof *trap_type) | | 369 | #define N_TRAP_TYPES (sizeof trap_type / sizeof *trap_type) |
364 | | | 370 | |
365 | void trap(struct trapframe64 *, unsigned int, vaddr_t, long); | | 371 | void trap(struct trapframe64 *, unsigned int, vaddr_t, long); |
366 | void data_access_fault(struct trapframe64 *, unsigned int, vaddr_t, vaddr_t, | | 372 | void data_access_fault(struct trapframe64 *, unsigned int, vaddr_t, vaddr_t, |
367 | vaddr_t, u_long); | | 373 | vaddr_t, u_long); |
368 | void data_access_error(struct trapframe64 *, unsigned int, vaddr_t, u_long, | | 374 | void data_access_error(struct trapframe64 *, unsigned int, vaddr_t, u_long, |
369 | vaddr_t, u_long); | | 375 | vaddr_t, u_long); |
370 | void text_access_fault(struct trapframe64 *tf, unsigned int type, vaddr_t pc, | | 376 | void text_access_fault(struct trapframe64 *tf, unsigned int type, vaddr_t pc, |
371 | u_long sfsr); | | 377 | u_long sfsr); |
372 | void text_access_error(struct trapframe64 *, unsigned int, vaddr_t, u_long, | | 378 | void text_access_error(struct trapframe64 *, unsigned int, vaddr_t, u_long, |
373 | vaddr_t, u_long); | | 379 | vaddr_t, u_long); |
| | | 380 | void ecc_corrected_error(unsigned int type, vaddr_t pc); |
374 | | | 381 | |
375 | #ifdef DEBUG | | 382 | #ifdef DEBUG |
376 | void print_trapframe(struct trapframe64 *); | | 383 | void print_trapframe(struct trapframe64 *); |
377 | | | 384 | |
378 | void | | 385 | void |
379 | print_trapframe(struct trapframe64 *tf) | | 386 | print_trapframe(struct trapframe64 *tf) |
380 | { | | 387 | { |
381 | | | 388 | |
382 | printf("Trapframe %p:\ttstate: %lx\tpc: %lx\tnpc: %lx\n", | | 389 | printf("Trapframe %p:\ttstate: %lx\tpc: %lx\tnpc: %lx\n", |
383 | tf, (u_long)tf->tf_tstate, (u_long)tf->tf_pc, (u_long)tf->tf_npc); | | 390 | tf, (u_long)tf->tf_tstate, (u_long)tf->tf_pc, (u_long)tf->tf_npc); |
384 | printf("fault: %p\ty: %x\t", | | 391 | printf("fault: %p\ty: %x\t", |
385 | (void *)(u_long)tf->tf_fault, (int)tf->tf_y); | | 392 | (void *)(u_long)tf->tf_fault, (int)tf->tf_y); |
386 | printf("pil: %d\toldpil: %d\ttt: %x\tGlobals:\n", | | 393 | printf("pil: %d\toldpil: %d\ttt: %x\tGlobals:\n", |
| @@ -530,26 +537,29 @@ trap(struct trapframe64 *tf, unsigned in | | | @@ -530,26 +537,29 @@ trap(struct trapframe64 *tf, unsigned in |
530 | fplwp = NULL; | | 537 | fplwp = NULL; |
531 | } | | 538 | } |
532 | rstintr(); | | 539 | rstintr(); |
533 | /* If we have an allocated fpstate, load it */ | | 540 | /* If we have an allocated fpstate, load it */ |
534 | if (newfplwp->l_md.md_fpstate != NULL) { | | 541 | if (newfplwp->l_md.md_fpstate != NULL) { |
535 | fplwp = newfplwp; | | 542 | fplwp = newfplwp; |
536 | loadfpstate(fplwp->l_md.md_fpstate); | | 543 | loadfpstate(fplwp->l_md.md_fpstate); |
537 | } else | | 544 | } else |
538 | fplwp = NULL; | | 545 | fplwp = NULL; |
539 | } | | 546 | } |
540 | /* Enable the FPU */ | | 547 | /* Enable the FPU */ |
541 | tf->tf_tstate |= TSTATE_PEF; | | 548 | tf->tf_tstate |= TSTATE_PEF; |
542 | return; | | 549 | return; |
| | | 550 | } else if (type == T_ECCERR) { |
| | | 551 | ecc_corrected_error(type, pc); |
| | | 552 | return; |
543 | } | | 553 | } |
544 | goto dopanic; | | 554 | goto dopanic; |
545 | } | | 555 | } |
546 | l = curlwp; | | 556 | l = curlwp; |
547 | p = l->l_proc; | | 557 | p = l->l_proc; |
548 | LWP_CACHE_CREDS(l, p); | | 558 | LWP_CACHE_CREDS(l, p); |
549 | sticks = p->p_sticks; | | 559 | sticks = p->p_sticks; |
550 | pcb = lwp_getpcb(l); | | 560 | pcb = lwp_getpcb(l); |
551 | l->l_md.md_tf = tf; /* for ptrace/signals */ | | 561 | l->l_md.md_tf = tf; /* for ptrace/signals */ |
552 | | | 562 | |
553 | sig = 0; | | 563 | sig = 0; |
554 | | | 564 | |
555 | switch (type) { | | 565 | switch (type) { |
| @@ -845,26 +855,29 @@ badtrap: | | | @@ -845,26 +855,29 @@ badtrap: |
845 | l->l_proc->p_md.md_flags |= MDP_FIXALIGN; | | 855 | l->l_proc->p_md.md_flags |= MDP_FIXALIGN; |
846 | ADVANCE; | | 856 | ADVANCE; |
847 | break; | | 857 | break; |
848 | | | 858 | |
849 | case T_INTOF: | | 859 | case T_INTOF: |
850 | uprintf("T_INTOF\n"); /* XXX */ | | 860 | uprintf("T_INTOF\n"); /* XXX */ |
851 | ADVANCE; | | 861 | ADVANCE; |
852 | sig = SIGFPE; | | 862 | sig = SIGFPE; |
853 | KSI_INIT_TRAP(&ksi); | | 863 | KSI_INIT_TRAP(&ksi); |
854 | ksi.ksi_trap = type; | | 864 | ksi.ksi_trap = type; |
855 | ksi.ksi_code = FPE_INTOVF; | | 865 | ksi.ksi_code = FPE_INTOVF; |
856 | ksi.ksi_addr = (void *)pc; | | 866 | ksi.ksi_addr = (void *)pc; |
857 | break; | | 867 | break; |
| | | 868 | case T_ECCERR: |
| | | 869 | ecc_corrected_error(type, pc); |
| | | 870 | break; |
858 | } | | 871 | } |
859 | if (sig != 0) { | | 872 | if (sig != 0) { |
860 | ksi.ksi_signo = sig; | | 873 | ksi.ksi_signo = sig; |
861 | trapsignal(l, &ksi); | | 874 | trapsignal(l, &ksi); |
862 | } | | 875 | } |
863 | userret(l, pc, sticks); | | 876 | userret(l, pc, sticks); |
864 | share_fpu(l, tf); | | 877 | share_fpu(l, tf); |
865 | #undef ADVANCE | | 878 | #undef ADVANCE |
866 | #ifdef DEBUG | | 879 | #ifdef DEBUG |
867 | if (trapdebug & (TDB_FOLLOW | TDB_TRAP)) { | | 880 | if (trapdebug & (TDB_FOLLOW | TDB_TRAP)) { |
868 | printf("trap: done\n"); | | 881 | printf("trap: done\n"); |
869 | /* if (type != T_BREAKPOINT) Debugger(); */ | | 882 | /* if (type != T_BREAKPOINT) Debugger(); */ |
870 | } | | 883 | } |
| @@ -1612,13 +1625,58 @@ text_access_error(struct trapframe64 *tf | | | @@ -1612,13 +1625,58 @@ text_access_error(struct trapframe64 *tf |
1612 | out: | | 1625 | out: |
1613 | if ((tstate & TSTATE_PRIV) == 0) { | | 1626 | if ((tstate & TSTATE_PRIV) == 0) { |
1614 | userret(l, pc, sticks); | | 1627 | userret(l, pc, sticks); |
1615 | share_fpu(l, tf); | | 1628 | share_fpu(l, tf); |
1616 | } | | 1629 | } |
1617 | #ifdef DEBUG | | 1630 | #ifdef DEBUG |
1618 | if (trapdebug & (TDB_TXTFLT | TDB_FOLLOW)) | | 1631 | if (trapdebug & (TDB_TXTFLT | TDB_FOLLOW)) |
1619 | printf("text_access_error: done\n"); | | 1632 | printf("text_access_error: done\n"); |
1620 | if (trapdebug & TDB_FRAME) { | | 1633 | if (trapdebug & TDB_FRAME) { |
1621 | print_trapframe(tf); | | 1634 | print_trapframe(tf); |
1622 | } | | 1635 | } |
1623 | #endif | | 1636 | #endif |
1624 | } | | 1637 | } |
| | | 1638 | |
| | | 1639 | /* |
| | | 1640 | * Handle an ECC corrected event. |
| | | 1641 | */ |
| | | 1642 | void |
| | | 1643 | ecc_corrected_error(unsigned int type, vaddr_t pc) |
| | | 1644 | { |
| | | 1645 | uint64_t eeer, afar, afsr; |
| | | 1646 | char buf[128]; |
| | | 1647 | int s; |
| | | 1648 | |
| | | 1649 | /* Clear the error */ |
| | | 1650 | eeer = ldxa(0, ASI_ERROR_EN_REG); |
| | | 1651 | s = intr_disable(); |
| | | 1652 | stxa(0, ASI_ERROR_EN_REG, |
| | | 1653 | eeer & ~(P_EER_NCEEN | P_EER_CEEN)); |
| | | 1654 | membar_Sync(); |
| | | 1655 | intr_restore(s); |
| | | 1656 | |
| | | 1657 | /* Flush the caches in order ensure no corrupt data got installed. */ |
| | | 1658 | blast_dcache(); |
| | | 1659 | blast_icache(); |
| | | 1660 | |
| | | 1661 | #if 0 |
| | | 1662 | /* Ensure the caches are still turned on (should be). */ |
| | | 1663 | cache_enable(PCPU_GET(impl)); |
| | | 1664 | #endif |
| | | 1665 | |
| | | 1666 | /* Grab the current AFSR/AFAR, and clear the error from the AFSR. */ |
| | | 1667 | afar = ldxa(0, ASI_AFAR); |
| | | 1668 | afsr = ldxa(0, ASI_AFSR); |
| | | 1669 | s = intr_disable(); |
| | | 1670 | stxa(0, ASI_AFSR, ldxa(0, ASI_AFSR)); |
| | | 1671 | membar_Sync(); |
| | | 1672 | intr_restore(s); |
| | | 1673 | ecc_corrected.ev_count++; |
| | | 1674 | snprintb(buf, sizeof(buf), AFSR_BITS, afsr); |
| | | 1675 | printf("corrected ECC error: pc %p afsr %"PRIx64" (%s) addr %"PRIx64"\n", (void *)pc, afsr, buf, afar); |
| | | 1676 | |
| | | 1677 | /* Turn (non-)correctable error reporting back on. */ |
| | | 1678 | s = intr_disable(); |
| | | 1679 | stxa(0, ASI_ERROR_EN_REG, eeer); |
| | | 1680 | membar_Sync(); |
| | | 1681 | intr_restore(s); |
| | | 1682 | } |