| @@ -1,1016 +1,1016 @@ | | | @@ -1,1016 +1,1016 @@ |
1 | /* $NetBSD: trap.c,v 1.217 2008/10/15 06:51:18 wrstuden Exp $ */ | | 1 | /* $NetBSD: trap.c,v 1.218 2009/08/06 23:07:55 matt Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1992, 1993 | | 4 | * Copyright (c) 1992, 1993 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to Berkeley by | | 7 | * This code is derived from software contributed to Berkeley by |
8 | * the Systems Programming Group of the University of Utah Computer | | 8 | * the Systems Programming Group of the University of Utah Computer |
9 | * Science Department and Ralph Campbell. | | 9 | * Science Department and Ralph Campbell. |
10 | * | | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | | 11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions | | 12 | * modification, are permitted provided that the following conditions |
13 | * are met: | | 13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright | | 14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions and the following disclaimer. | | 15 | * notice, this list of conditions and the following disclaimer. |
16 | * 2. Redistributions in binary form must reproduce the above copyright | | 16 | * 2. Redistributions in binary form must reproduce the above copyright |
17 | * notice, this list of conditions and the following disclaimer in the | | 17 | * notice, this list of conditions and the following disclaimer in the |
18 | * documentation and/or other materials provided with the distribution. | | 18 | * documentation and/or other materials provided with the distribution. |
19 | * 3. Neither the name of the University nor the names of its contributors | | 19 | * 3. Neither the name of the University nor the names of its contributors |
20 | * may be used to endorse or promote products derived from this software | | 20 | * may be used to endorse or promote products derived from this software |
21 | * without specific prior written permission. | | 21 | * without specific prior written permission. |
22 | * | | 22 | * |
23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
33 | * SUCH DAMAGE. | | 33 | * SUCH DAMAGE. |
34 | * | | 34 | * |
35 | * from: Utah Hdr: trap.c 1.32 91/04/06 | | 35 | * from: Utah Hdr: trap.c 1.32 91/04/06 |
36 | * | | 36 | * |
37 | * @(#)trap.c 8.5 (Berkeley) 1/11/94 | | 37 | * @(#)trap.c 8.5 (Berkeley) 1/11/94 |
38 | */ | | 38 | */ |
39 | /* | | 39 | /* |
40 | * Copyright (c) 1988 University of Utah. | | 40 | * Copyright (c) 1988 University of Utah. |
41 | * | | 41 | * |
42 | * This code is derived from software contributed to Berkeley by | | 42 | * This code is derived from software contributed to Berkeley by |
43 | * the Systems Programming Group of the University of Utah Computer | | 43 | * the Systems Programming Group of the University of Utah Computer |
44 | * Science Department and Ralph Campbell. | | 44 | * Science Department and Ralph Campbell. |
45 | * | | 45 | * |
46 | * Redistribution and use in source and binary forms, with or without | | 46 | * Redistribution and use in source and binary forms, with or without |
47 | * modification, are permitted provided that the following conditions | | 47 | * modification, are permitted provided that the following conditions |
48 | * are met: | | 48 | * are met: |
49 | * 1. Redistributions of source code must retain the above copyright | | 49 | * 1. Redistributions of source code must retain the above copyright |
50 | * notice, this list of conditions and the following disclaimer. | | 50 | * notice, this list of conditions and the following disclaimer. |
51 | * 2. Redistributions in binary form must reproduce the above copyright | | 51 | * 2. Redistributions in binary form must reproduce the above copyright |
52 | * notice, this list of conditions and the following disclaimer in the | | 52 | * notice, this list of conditions and the following disclaimer in the |
53 | * documentation and/or other materials provided with the distribution. | | 53 | * documentation and/or other materials provided with the distribution. |
54 | * 3. All advertising materials mentioning features or use of this software | | 54 | * 3. All advertising materials mentioning features or use of this software |
55 | * must display the following acknowledgement: | | 55 | * must display the following acknowledgement: |
56 | * This product includes software developed by the University of | | 56 | * This product includes software developed by the University of |
57 | * California, Berkeley and its contributors. | | 57 | * California, Berkeley and its contributors. |
58 | * 4. Neither the name of the University nor the names of its contributors | | 58 | * 4. Neither the name of the University nor the names of its contributors |
59 | * may be used to endorse or promote products derived from this software | | 59 | * may be used to endorse or promote products derived from this software |
60 | * without specific prior written permission. | | 60 | * without specific prior written permission. |
61 | * | | 61 | * |
62 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 62 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
63 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 63 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
64 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 64 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
65 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 65 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
66 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 66 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
67 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 67 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
68 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 68 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
69 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 69 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
70 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 70 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
71 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 71 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
72 | * SUCH DAMAGE. | | 72 | * SUCH DAMAGE. |
73 | * | | 73 | * |
74 | * from: Utah Hdr: trap.c 1.32 91/04/06 | | 74 | * from: Utah Hdr: trap.c 1.32 91/04/06 |
75 | * | | 75 | * |
76 | * @(#)trap.c 8.5 (Berkeley) 1/11/94 | | 76 | * @(#)trap.c 8.5 (Berkeley) 1/11/94 |
77 | */ | | 77 | */ |
78 | | | 78 | |
79 | #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ | | 79 | #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ |
80 | | | 80 | |
81 | __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.217 2008/10/15 06:51:18 wrstuden Exp $"); | | 81 | __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.218 2009/08/06 23:07:55 matt Exp $"); |
82 | | | 82 | |
83 | #include "opt_cputype.h" /* which mips CPU levels do we support? */ | | 83 | #include "opt_cputype.h" /* which mips CPU levels do we support? */ |
84 | #include "opt_ddb.h" | | 84 | #include "opt_ddb.h" |
85 | #include "opt_kgdb.h" | | 85 | #include "opt_kgdb.h" |
86 | | | 86 | |
87 | #include <sys/param.h> | | 87 | #include <sys/param.h> |
88 | #include <sys/systm.h> | | 88 | #include <sys/systm.h> |
89 | #include <sys/kernel.h> | | 89 | #include <sys/kernel.h> |
90 | #include <sys/proc.h> | | 90 | #include <sys/proc.h> |
91 | #include <sys/ras.h> | | 91 | #include <sys/ras.h> |
92 | #include <sys/signalvar.h> | | 92 | #include <sys/signalvar.h> |
93 | #include <sys/syscall.h> | | 93 | #include <sys/syscall.h> |
94 | #include <sys/user.h> | | 94 | #include <sys/user.h> |
95 | #include <sys/buf.h> | | 95 | #include <sys/buf.h> |
96 | #include <sys/ktrace.h> | | 96 | #include <sys/ktrace.h> |
97 | #include <sys/sa.h> | | 97 | #include <sys/sa.h> |
98 | #include <sys/savar.h> | | 98 | #include <sys/savar.h> |
99 | #include <sys/kauth.h> | | 99 | #include <sys/kauth.h> |
100 | #include <sys/cpu.h> | | 100 | #include <sys/cpu.h> |
101 | | | 101 | |
102 | #include <mips/cache.h> | | 102 | #include <mips/cache.h> |
103 | #include <mips/locore.h> | | 103 | #include <mips/locore.h> |
104 | #include <mips/mips_opcode.h> | | 104 | #include <mips/mips_opcode.h> |
105 | | | 105 | |
106 | #include <uvm/uvm_extern.h> | | 106 | #include <uvm/uvm_extern.h> |
107 | | | 107 | |
108 | #include <machine/cpu.h> | | 108 | #include <machine/cpu.h> |
109 | #include <mips/trap.h> | | 109 | #include <mips/trap.h> |
110 | #include <mips/reg.h> | | 110 | #include <mips/reg.h> |
111 | #include <mips/regnum.h> /* symbolic register indices */ | | 111 | #include <mips/regnum.h> /* symbolic register indices */ |
112 | #include <mips/pte.h> | | 112 | #include <mips/pte.h> |
113 | #include <mips/psl.h> | | 113 | #include <mips/psl.h> |
114 | #include <mips/userret.h> | | 114 | #include <mips/userret.h> |
115 | | | 115 | |
116 | #ifdef DDB | | 116 | #ifdef DDB |
117 | #include <machine/db_machdep.h> | | 117 | #include <machine/db_machdep.h> |
118 | #include <ddb/db_sym.h> | | 118 | #include <ddb/db_sym.h> |
119 | #endif | | 119 | #endif |
120 | | | 120 | |
121 | #ifdef KGDB | | 121 | #ifdef KGDB |
122 | #include <sys/kgdb.h> | | 122 | #include <sys/kgdb.h> |
123 | #endif | | 123 | #endif |
124 | | | 124 | |
125 | const char *trap_type[] = { | | 125 | const char *trap_type[] = { |
126 | "external interrupt", | | 126 | "external interrupt", |
127 | "TLB modification", | | 127 | "TLB modification", |
128 | "TLB miss (load or instr. fetch)", | | 128 | "TLB miss (load or instr. fetch)", |
129 | "TLB miss (store)", | | 129 | "TLB miss (store)", |
130 | "address error (load or I-fetch)", | | 130 | "address error (load or I-fetch)", |
131 | "address error (store)", | | 131 | "address error (store)", |
132 | "bus error (I-fetch)", | | 132 | "bus error (I-fetch)", |
133 | "bus error (load or store)", | | 133 | "bus error (load or store)", |
134 | "system call", | | 134 | "system call", |
135 | "breakpoint", | | 135 | "breakpoint", |
136 | "reserved instruction", | | 136 | "reserved instruction", |
137 | "coprocessor unusable", | | 137 | "coprocessor unusable", |
138 | "arithmetic overflow", | | 138 | "arithmetic overflow", |
139 | "r4k trap/r3k reserved 13", | | 139 | "r4k trap/r3k reserved 13", |
140 | "r4k virtual coherency instruction/r3k reserved 14", | | 140 | "r4k virtual coherency instruction/r3k reserved 14", |
141 | "r4k floating point/ r3k reserved 15", | | 141 | "r4k floating point/ r3k reserved 15", |
142 | "reserved 16", | | 142 | "reserved 16", |
143 | "reserved 17", | | 143 | "reserved 17", |
144 | "mipsNN cp2 exception", | | 144 | "mipsNN cp2 exception", |
145 | "reserved 19", | | 145 | "reserved 19", |
146 | "reserved 20", | | 146 | "reserved 20", |
147 | "reserved 21", | | 147 | "reserved 21", |
148 | "mips64 MDMX", | | 148 | "mips64 MDMX", |
149 | "r4k watch", | | 149 | "r4k watch", |
150 | "mipsNN machine check", | | 150 | "mipsNN machine check", |
151 | "reserved 25", | | 151 | "reserved 25", |
152 | "reserved 26", | | 152 | "reserved 26", |
153 | "reserved 27", | | 153 | "reserved 27", |
154 | "reserved 28", | | 154 | "reserved 28", |
155 | "reserved 29", | | 155 | "reserved 29", |
156 | "mipsNN cache error", | | 156 | "mipsNN cache error", |
157 | "r4000 virtual coherency data", | | 157 | "r4000 virtual coherency data", |
158 | }; | | 158 | }; |
159 | | | 159 | |
160 | void trap(unsigned int, unsigned int, vaddr_t, vaddr_t, struct trapframe *); | | 160 | void trap(unsigned int, unsigned int, vaddr_t, vaddr_t, struct trapframe *); |
161 | void ast(unsigned int); | | 161 | void ast(unsigned int); |
162 | | | 162 | |
163 | vaddr_t MachEmulateBranch(struct frame *, vaddr_t, unsigned int, int); /* XXX */ | | 163 | vaddr_t MachEmulateBranch(struct frame *, vaddr_t, unsigned int, int); /* XXX */ |
164 | void MachEmulateInst(u_int32_t, u_int32_t, vaddr_t, struct frame *); /* XXX */ | | 164 | void MachEmulateInst(u_int32_t, u_int32_t, vaddr_t, struct frame *); /* XXX */ |
165 | void MachFPTrap(u_int32_t, u_int32_t, vaddr_t, struct frame *); /* XXX */ | | 165 | void MachFPTrap(u_int32_t, u_int32_t, vaddr_t, struct frame *); /* XXX */ |
166 | | | 166 | |
167 | #define DELAYBRANCH(x) ((int)(x)<0) | | 167 | #define DELAYBRANCH(x) ((int)(x)<0) |
168 | | | 168 | |
169 | /* | | 169 | /* |
170 | * fork syscall returns directly to user process via lwp_trampoline(), | | 170 | * fork syscall returns directly to user process via lwp_trampoline(), |
171 | * which will be called the very first time when child gets running. | | 171 | * which will be called the very first time when child gets running. |
172 | */ | | 172 | */ |
173 | void | | 173 | void |
174 | child_return(void *arg) | | 174 | child_return(void *arg) |
175 | { | | 175 | { |
176 | struct lwp *l = arg; | | 176 | struct lwp *l = arg; |
177 | struct frame *frame = (struct frame *)l->l_md.md_regs; | | 177 | struct frame *frame = (struct frame *)l->l_md.md_regs; |
178 | | | 178 | |
179 | frame->f_regs[_R_V0] = 0; | | 179 | frame->f_regs[_R_V0] = 0; |
180 | frame->f_regs[_R_V1] = 1; | | 180 | frame->f_regs[_R_V1] = 1; |
181 | frame->f_regs[_R_A3] = 0; | | 181 | frame->f_regs[_R_A3] = 0; |
182 | userret(l); | | 182 | userret(l); |
183 | ktrsysret(SYS_fork, 0, 0); | | 183 | ktrsysret(SYS_fork, 0, 0); |
184 | } | | 184 | } |
185 | | | 185 | |
186 | #ifdef MIPS3_PLUS | | 186 | #ifdef MIPS3_PLUS |
187 | #define TRAPTYPE(x) (((x) & MIPS3_CR_EXC_CODE) >> MIPS_CR_EXC_CODE_SHIFT) | | 187 | #define TRAPTYPE(x) (((x) & MIPS3_CR_EXC_CODE) >> MIPS_CR_EXC_CODE_SHIFT) |
188 | #else | | 188 | #else |
189 | #define TRAPTYPE(x) (((x) & MIPS1_CR_EXC_CODE) >> MIPS_CR_EXC_CODE_SHIFT) | | 189 | #define TRAPTYPE(x) (((x) & MIPS1_CR_EXC_CODE) >> MIPS_CR_EXC_CODE_SHIFT) |
190 | #endif | | 190 | #endif |
191 | #define KERNLAND(x) ((intptr_t)(x) < 0) | | 191 | #define KERNLAND(x) ((intptr_t)(x) < 0) |
192 | | | 192 | |
193 | /* | | 193 | /* |
194 | * Trap is called from locore to handle most types of processor traps. | | 194 | * Trap is called from locore to handle most types of processor traps. |
195 | * System calls are broken out for efficiency. MIPS can handle software | | 195 | * System calls are broken out for efficiency. MIPS can handle software |
196 | * interrupts as a part of real interrupt processing. | | 196 | * interrupts as a part of real interrupt processing. |
197 | */ | | 197 | */ |
198 | void | | 198 | void |
199 | trap(unsigned int status, unsigned int cause, vaddr_t vaddr, vaddr_t opc, | | 199 | trap(unsigned int status, unsigned int cause, vaddr_t vaddr, vaddr_t opc, |
200 | struct trapframe *frame) | | 200 | struct trapframe *frame) |
201 | { | | 201 | { |
202 | int type; | | 202 | int type; |
203 | struct lwp *l = curlwp; | | 203 | struct lwp *l = curlwp; |
204 | struct proc *p = curproc; | | 204 | struct proc *p = curproc; |
205 | vm_prot_t ftype; | | 205 | vm_prot_t ftype; |
206 | ksiginfo_t ksi; | | 206 | ksiginfo_t ksi; |
207 | struct frame *fp; | | 207 | struct frame *fp; |
208 | extern void fswintrberr(void); | | 208 | extern void fswintrberr(void); |
209 | KSI_INIT_TRAP(&ksi); | | 209 | KSI_INIT_TRAP(&ksi); |
210 | | | 210 | |
211 | uvmexp.traps++; | | 211 | uvmexp.traps++; |
212 | type = TRAPTYPE(cause); | | 212 | type = TRAPTYPE(cause); |
213 | if (USERMODE(status)) { | | 213 | if (USERMODE(status)) { |
214 | type |= T_USER; | | 214 | type |= T_USER; |
215 | LWP_CACHE_CREDS(l, p); | | 215 | LWP_CACHE_CREDS(l, p); |
216 | } | | 216 | } |
217 | | | 217 | |
218 | if (status & ((CPUISMIPS3) ? MIPS_SR_INT_IE : MIPS1_SR_INT_ENA_PREV)) { | | 218 | if (status & ((CPUISMIPS3) ? MIPS_SR_INT_IE : MIPS1_SR_INT_ENA_PREV)) { |
219 | if (type != T_BREAK) { | | 219 | if (type != T_BREAK) { |
220 | #ifdef IPL_ICU_MASK | | 220 | #ifdef IPL_ICU_MASK |
221 | spllowersofthigh(); | | 221 | spllowersofthigh(); |
222 | #else | | 222 | #else |
223 | _splset((status & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE); | | 223 | _splset((status & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE); |
224 | #endif | | 224 | #endif |
225 | } | | 225 | } |
226 | } | | 226 | } |
227 | | | 227 | |
228 | switch (type) { | | 228 | switch (type) { |
229 | default: | | 229 | default: |
230 | dopanic: | | 230 | dopanic: |
231 | (void)splhigh(); | | 231 | (void)splhigh(); |
232 | printf("trap: %s in %s mode\n", | | 232 | printf("trap: %s in %s mode\n", |
233 | trap_type[TRAPTYPE(cause)], | | 233 | trap_type[TRAPTYPE(cause)], |
234 | USERMODE(status) ? "user" : "kernel"); | | 234 | USERMODE(status) ? "user" : "kernel"); |
235 | printf("status=0x%x, cause=0x%x, epc=%#lx, vaddr=%#lx\n", | | 235 | printf("status=0x%x, cause=0x%x, epc=%#lx, vaddr=%#lx\n", |
236 | status, cause, opc, vaddr); | | 236 | status, cause, opc, vaddr); |
237 | if (curlwp != NULL) { | | 237 | if (curlwp != NULL) { |
238 | fp = (struct frame *)l->l_md.md_regs; | | 238 | fp = (struct frame *)l->l_md.md_regs; |
239 | printf("pid=%d cmd=%s usp=0x%x ", | | 239 | printf("pid=%d cmd=%s usp=0x%x ", |
240 | p->p_pid, p->p_comm, (int)fp->f_regs[_R_SP]); | | 240 | p->p_pid, p->p_comm, (int)fp->f_regs[_R_SP]); |
241 | } else | | 241 | } else |
242 | printf("curlwp == NULL "); | | 242 | printf("curlwp == NULL "); |
243 | printf("ksp=%p\n", &status); | | 243 | printf("ksp=%p ra=%#x\n", &status, (int)frame->tf_regs[TF_RA]); |
244 | #if defined(DDB) | | 244 | #if defined(DDB) |
245 | kdb_trap(type, (mips_reg_t *) frame); | | 245 | kdb_trap(type, (mips_reg_t *) frame); |
246 | /* XXX force halt XXX */ | | 246 | /* XXX force halt XXX */ |
247 | #elif defined(KGDB) | | 247 | #elif defined(KGDB) |
248 | { | | 248 | { |
249 | struct frame *f = (struct frame *)&ddb_regs; | | 249 | struct frame *f = (struct frame *)&ddb_regs; |
250 | extern mips_reg_t kgdb_cause, kgdb_vaddr; | | 250 | extern mips_reg_t kgdb_cause, kgdb_vaddr; |
251 | kgdb_cause = cause; | | 251 | kgdb_cause = cause; |
252 | kgdb_vaddr = vaddr; | | 252 | kgdb_vaddr = vaddr; |
253 | | | 253 | |
254 | /* | | 254 | /* |
255 | * init global ddb_regs, used in db_interface.c routines | | 255 | * init global ddb_regs, used in db_interface.c routines |
256 | * shared between ddb and gdb. Send ddb_regs to gdb so | | 256 | * shared between ddb and gdb. Send ddb_regs to gdb so |
257 | * that db_machdep.h macros will work with it, and | | 257 | * that db_machdep.h macros will work with it, and |
258 | * allow gdb to alter the PC. | | 258 | * allow gdb to alter the PC. |
259 | */ | | 259 | */ |
260 | db_set_ddb_regs(type, (mips_reg_t *) frame); | | 260 | db_set_ddb_regs(type, (mips_reg_t *) frame); |
261 | PC_BREAK_ADVANCE(f); | | 261 | PC_BREAK_ADVANCE(f); |
262 | if (kgdb_trap(type, &ddb_regs)) { | | 262 | if (kgdb_trap(type, &ddb_regs)) { |
263 | ((mips_reg_t *)frame)[21] = f->f_regs[_R_PC]; | | 263 | ((mips_reg_t *)frame)[21] = f->f_regs[_R_PC]; |
264 | return; | | 264 | return; |
265 | } | | 265 | } |
266 | } | | 266 | } |
267 | #else | | 267 | #else |
268 | panic("trap"); | | 268 | panic("trap"); |
269 | #endif | | 269 | #endif |
270 | /*NOTREACHED*/ | | 270 | /*NOTREACHED*/ |
271 | case T_TLB_MOD: | | 271 | case T_TLB_MOD: |
272 | if (KERNLAND(vaddr)) { | | 272 | if (KERNLAND(vaddr)) { |
273 | pt_entry_t *pte; | | 273 | pt_entry_t *pte; |
274 | unsigned entry; | | 274 | unsigned entry; |
275 | paddr_t pa; | | 275 | paddr_t pa; |
276 | | | 276 | |
277 | pte = kvtopte(vaddr); | | 277 | pte = kvtopte(vaddr); |
278 | entry = pte->pt_entry; | | 278 | entry = pte->pt_entry; |
279 | if (!mips_pg_v(entry) || (entry & mips_pg_m_bit())) { | | 279 | if (!mips_pg_v(entry) || (entry & mips_pg_m_bit())) { |
280 | panic("ktlbmod: invalid pte"); | | 280 | panic("ktlbmod: invalid pte"); |
281 | } | | 281 | } |
282 | if (entry & mips_pg_ro_bit()) { | | 282 | if (entry & mips_pg_ro_bit()) { |
283 | /* write to read only page in the kernel */ | | 283 | /* write to read only page in the kernel */ |
284 | ftype = VM_PROT_WRITE; | | 284 | ftype = VM_PROT_WRITE; |
285 | goto kernelfault; | | 285 | goto kernelfault; |
286 | } | | 286 | } |
287 | entry |= mips_pg_m_bit(); | | 287 | entry |= mips_pg_m_bit(); |
288 | pte->pt_entry = entry; | | 288 | pte->pt_entry = entry; |
289 | vaddr &= ~PGOFSET; | | 289 | vaddr &= ~PGOFSET; |
290 | MachTLBUpdate(vaddr, entry); | | 290 | MachTLBUpdate(vaddr, entry); |
291 | pa = mips_tlbpfn_to_paddr(entry); | | 291 | pa = mips_tlbpfn_to_paddr(entry); |
292 | if (!IS_VM_PHYSADDR(pa)) { | | 292 | if (!IS_VM_PHYSADDR(pa)) { |
293 | printf("ktlbmod: va %#lx pa %#llx\n", | | 293 | printf("ktlbmod: va %#lx pa %#llx\n", |
294 | vaddr, (long long)pa); | | 294 | vaddr, (long long)pa); |
295 | panic("ktlbmod: unmanaged page"); | | 295 | panic("ktlbmod: unmanaged page"); |
296 | } | | 296 | } |
297 | pmap_set_modified(pa); | | 297 | pmap_set_modified(pa); |
298 | return; /* KERN */ | | 298 | return; /* KERN */ |
299 | } | | 299 | } |
300 | /*FALLTHROUGH*/ | | 300 | /*FALLTHROUGH*/ |
301 | case T_TLB_MOD+T_USER: | | 301 | case T_TLB_MOD+T_USER: |
302 | { | | 302 | { |
303 | pt_entry_t *pte; | | 303 | pt_entry_t *pte; |
304 | unsigned entry; | | 304 | unsigned entry; |
305 | paddr_t pa; | | 305 | paddr_t pa; |
306 | pmap_t pmap; | | 306 | pmap_t pmap; |
307 | | | 307 | |
308 | pmap = p->p_vmspace->vm_map.pmap; | | 308 | pmap = p->p_vmspace->vm_map.pmap; |
309 | if (!(pte = pmap_segmap(pmap, vaddr))) | | 309 | if (!(pte = pmap_segmap(pmap, vaddr))) |
310 | panic("utlbmod: invalid segmap"); | | 310 | panic("utlbmod: invalid segmap"); |
311 | pte += (vaddr >> PGSHIFT) & (NPTEPG - 1); | | 311 | pte += (vaddr >> PGSHIFT) & (NPTEPG - 1); |
312 | entry = pte->pt_entry; | | 312 | entry = pte->pt_entry; |
313 | if (!mips_pg_v(entry) || (entry & mips_pg_m_bit())) | | 313 | if (!mips_pg_v(entry) || (entry & mips_pg_m_bit())) |
314 | panic("utlbmod: invalid pte"); | | 314 | panic("utlbmod: invalid pte"); |
315 | | | 315 | |
316 | if (entry & mips_pg_ro_bit()) { | | 316 | if (entry & mips_pg_ro_bit()) { |
317 | /* write to read only page */ | | 317 | /* write to read only page */ |
318 | ftype = VM_PROT_WRITE; | | 318 | ftype = VM_PROT_WRITE; |
319 | goto pagefault; | | 319 | goto pagefault; |
320 | } | | 320 | } |
321 | entry |= mips_pg_m_bit(); | | 321 | entry |= mips_pg_m_bit(); |
322 | pte->pt_entry = entry; | | 322 | pte->pt_entry = entry; |
323 | vaddr = (vaddr & ~PGOFSET) | | | 323 | vaddr = (vaddr & ~PGOFSET) | |
324 | (pmap->pm_asid << MIPS_TLB_PID_SHIFT); | | 324 | (pmap->pm_asid << MIPS_TLB_PID_SHIFT); |
325 | MachTLBUpdate(vaddr, entry); | | 325 | MachTLBUpdate(vaddr, entry); |
326 | pa = mips_tlbpfn_to_paddr(entry); | | 326 | pa = mips_tlbpfn_to_paddr(entry); |
327 | if (!IS_VM_PHYSADDR(pa)) { | | 327 | if (!IS_VM_PHYSADDR(pa)) { |
328 | printf("utlbmod: va %#lx pa %#llx\n", | | 328 | printf("utlbmod: va %#lx pa %#llx\n", |
329 | vaddr, (long long)pa); | | 329 | vaddr, (long long)pa); |
330 | panic("utlbmod: unmanaged page"); | | 330 | panic("utlbmod: unmanaged page"); |
331 | } | | 331 | } |
332 | pmap_set_modified(pa); | | 332 | pmap_set_modified(pa); |
333 | if (type & T_USER) | | 333 | if (type & T_USER) |
334 | userret(l); | | 334 | userret(l); |
335 | return; /* GEN */ | | 335 | return; /* GEN */ |
336 | } | | 336 | } |
337 | case T_TLB_LD_MISS: | | 337 | case T_TLB_LD_MISS: |
338 | case T_TLB_ST_MISS: | | 338 | case T_TLB_ST_MISS: |
339 | ftype = (type == T_TLB_LD_MISS) ? VM_PROT_READ : VM_PROT_WRITE; | | 339 | ftype = (type == T_TLB_LD_MISS) ? VM_PROT_READ : VM_PROT_WRITE; |
340 | if (KERNLAND(vaddr)) | | 340 | if (KERNLAND(vaddr)) |
341 | goto kernelfault; | | 341 | goto kernelfault; |
342 | /* | | 342 | /* |
343 | * It is an error for the kernel to access user space except | | 343 | * It is an error for the kernel to access user space except |
344 | * through the copyin/copyout routines. | | 344 | * through the copyin/copyout routines. |
345 | */ | | 345 | */ |
346 | if (l == NULL || l->l_addr->u_pcb.pcb_onfault == NULL) | | 346 | if (l == NULL || l->l_addr->u_pcb.pcb_onfault == NULL) |
347 | goto dopanic; | | 347 | goto dopanic; |
348 | /* check for fuswintr() or suswintr() getting a page fault */ | | 348 | /* check for fuswintr() or suswintr() getting a page fault */ |
349 | if (l->l_addr->u_pcb.pcb_onfault == (void *)fswintrberr) { | | 349 | if (l->l_addr->u_pcb.pcb_onfault == (void *)fswintrberr) { |
350 | frame->tf_regs[TF_EPC] = (int)fswintrberr; | | 350 | frame->tf_regs[TF_EPC] = (int)fswintrberr; |
351 | return; /* KERN */ | | 351 | return; /* KERN */ |
352 | } | | 352 | } |
353 | goto pagefault; | | 353 | goto pagefault; |
354 | case T_TLB_LD_MISS+T_USER: | | 354 | case T_TLB_LD_MISS+T_USER: |
355 | ftype = VM_PROT_READ; | | 355 | ftype = VM_PROT_READ; |
356 | goto pagefault; | | 356 | goto pagefault; |
357 | case T_TLB_ST_MISS+T_USER: | | 357 | case T_TLB_ST_MISS+T_USER: |
358 | ftype = VM_PROT_WRITE; | | 358 | ftype = VM_PROT_WRITE; |
359 | pagefault: ; | | 359 | pagefault: ; |
360 | { | | 360 | { |
361 | vaddr_t va; | | 361 | vaddr_t va; |
362 | struct vmspace *vm; | | 362 | struct vmspace *vm; |
363 | struct vm_map *map; | | 363 | struct vm_map *map; |
364 | int rv; | | 364 | int rv; |
365 | | | 365 | |
366 | vm = p->p_vmspace; | | 366 | vm = p->p_vmspace; |
367 | map = &vm->vm_map; | | 367 | map = &vm->vm_map; |
368 | va = trunc_page(vaddr); | | 368 | va = trunc_page(vaddr); |
369 | | | 369 | |
370 | if ((l->l_flag & LW_SA) && (~l->l_pflag & LP_SA_NOBLOCK)) { | | 370 | if ((l->l_flag & LW_SA) && (~l->l_pflag & LP_SA_NOBLOCK)) { |
371 | l->l_savp->savp_faultaddr = (vaddr_t)vaddr; | | 371 | l->l_savp->savp_faultaddr = (vaddr_t)vaddr; |
372 | l->l_pflag |= LP_SA_PAGEFAULT; | | 372 | l->l_pflag |= LP_SA_PAGEFAULT; |
373 | } | | 373 | } |
374 | | | 374 | |
375 | if (p->p_emul->e_fault) | | 375 | if (p->p_emul->e_fault) |
376 | rv = (*p->p_emul->e_fault)(p, va, ftype); | | 376 | rv = (*p->p_emul->e_fault)(p, va, ftype); |
377 | else | | 377 | else |
378 | rv = uvm_fault(map, va, ftype); | | 378 | rv = uvm_fault(map, va, ftype); |
379 | #ifdef VMFAULT_TRACE | | 379 | #ifdef VMFAULT_TRACE |
380 | printf( | | 380 | printf( |
381 | "uvm_fault(%p (pmap %p), %lx (0x%x), %d) -> %d at pc %p\n", | | 381 | "uvm_fault(%p (pmap %p), %lx (0x%x), %d) -> %d at pc %p\n", |
382 | map, vm->vm_map.pmap, va, vaddr, ftype, rv, (void*)opc); | | 382 | map, vm->vm_map.pmap, va, vaddr, ftype, rv, (void*)opc); |
383 | #endif | | 383 | #endif |
384 | /* | | 384 | /* |
385 | * If this was a stack access we keep track of the maximum | | 385 | * If this was a stack access we keep track of the maximum |
386 | * accessed stack size. Also, if vm_fault gets a protection | | 386 | * accessed stack size. Also, if vm_fault gets a protection |
387 | * failure it is due to accessing the stack region outside | | 387 | * failure it is due to accessing the stack region outside |
388 | * the current limit and we need to reflect that as an access | | 388 | * the current limit and we need to reflect that as an access |
389 | * error. | | 389 | * error. |
390 | */ | | 390 | */ |
391 | if ((void *)va >= vm->vm_maxsaddr) { | | 391 | if ((void *)va >= vm->vm_maxsaddr) { |
392 | if (rv == 0) | | 392 | if (rv == 0) |
393 | uvm_grow(p, va); | | 393 | uvm_grow(p, va); |
394 | else if (rv == EACCES) | | 394 | else if (rv == EACCES) |
395 | rv = EFAULT; | | 395 | rv = EFAULT; |
396 | } | | 396 | } |
397 | l->l_pflag &= ~LP_SA_PAGEFAULT; | | 397 | l->l_pflag &= ~LP_SA_PAGEFAULT; |
398 | if (rv == 0) { | | 398 | if (rv == 0) { |
399 | if (type & T_USER) { | | 399 | if (type & T_USER) { |
400 | userret(l); | | 400 | userret(l); |
401 | } | | 401 | } |
402 | return; /* GEN */ | | 402 | return; /* GEN */ |
403 | } | | 403 | } |
404 | if ((type & T_USER) == 0) | | 404 | if ((type & T_USER) == 0) |
405 | goto copyfault; | | 405 | goto copyfault; |
406 | if (rv == ENOMEM) { | | 406 | if (rv == ENOMEM) { |
407 | printf("UVM: pid %d (%s), uid %d killed: out of swap\n", | | 407 | printf("UVM: pid %d (%s), uid %d killed: out of swap\n", |
408 | p->p_pid, p->p_comm, | | 408 | p->p_pid, p->p_comm, |
409 | l->l_cred ? | | 409 | l->l_cred ? |
410 | kauth_cred_geteuid(l->l_cred) : (uid_t) -1); | | 410 | kauth_cred_geteuid(l->l_cred) : (uid_t) -1); |
411 | ksi.ksi_signo = SIGKILL; | | 411 | ksi.ksi_signo = SIGKILL; |
412 | ksi.ksi_code = 0; | | 412 | ksi.ksi_code = 0; |
413 | } else { | | 413 | } else { |
414 | if (rv == EACCES) { | | 414 | if (rv == EACCES) { |
415 | ksi.ksi_signo = SIGBUS; | | 415 | ksi.ksi_signo = SIGBUS; |
416 | ksi.ksi_code = BUS_OBJERR; | | 416 | ksi.ksi_code = BUS_OBJERR; |
417 | } else { | | 417 | } else { |
418 | ksi.ksi_signo = SIGSEGV; | | 418 | ksi.ksi_signo = SIGSEGV; |
419 | ksi.ksi_code = SEGV_MAPERR; | | 419 | ksi.ksi_code = SEGV_MAPERR; |
420 | } | | 420 | } |
421 | } | | 421 | } |
422 | ksi.ksi_trap = type & ~T_USER; | | 422 | ksi.ksi_trap = type & ~T_USER; |
423 | ksi.ksi_addr = (void *)vaddr; | | 423 | ksi.ksi_addr = (void *)vaddr; |
424 | break; /* SIGNAL */ | | 424 | break; /* SIGNAL */ |
425 | } | | 425 | } |
426 | kernelfault: ; | | 426 | kernelfault: ; |
427 | { | | 427 | { |
428 | vaddr_t va; | | 428 | vaddr_t va; |
429 | int rv; | | 429 | int rv; |
430 | | | 430 | |
431 | va = trunc_page(vaddr); | | 431 | va = trunc_page(vaddr); |
432 | rv = uvm_fault(kernel_map, va, ftype); | | 432 | rv = uvm_fault(kernel_map, va, ftype); |
433 | if (rv == 0) | | 433 | if (rv == 0) |
434 | return; /* KERN */ | | 434 | return; /* KERN */ |
435 | /*FALLTHROUGH*/ | | 435 | /*FALLTHROUGH*/ |
436 | } | | 436 | } |
437 | case T_ADDR_ERR_LD: /* misaligned access */ | | 437 | case T_ADDR_ERR_LD: /* misaligned access */ |
438 | case T_ADDR_ERR_ST: /* misaligned access */ | | 438 | case T_ADDR_ERR_ST: /* misaligned access */ |
439 | case T_BUS_ERR_LD_ST: /* BERR asserted to CPU */ | | 439 | case T_BUS_ERR_LD_ST: /* BERR asserted to CPU */ |
440 | copyfault: | | 440 | copyfault: |
441 | if (l == NULL || l->l_addr->u_pcb.pcb_onfault == NULL) | | 441 | if (l == NULL || l->l_addr->u_pcb.pcb_onfault == NULL) |
442 | goto dopanic; | | 442 | goto dopanic; |
443 | frame->tf_regs[TF_EPC] = (intptr_t)l->l_addr->u_pcb.pcb_onfault; | | 443 | frame->tf_regs[TF_EPC] = (intptr_t)l->l_addr->u_pcb.pcb_onfault; |
444 | return; /* KERN */ | | 444 | return; /* KERN */ |
445 | | | 445 | |
446 | case T_ADDR_ERR_LD+T_USER: /* misaligned or kseg access */ | | 446 | case T_ADDR_ERR_LD+T_USER: /* misaligned or kseg access */ |
447 | case T_ADDR_ERR_ST+T_USER: /* misaligned or kseg access */ | | 447 | case T_ADDR_ERR_ST+T_USER: /* misaligned or kseg access */ |
448 | case T_BUS_ERR_IFETCH+T_USER: /* BERR asserted to CPU */ | | 448 | case T_BUS_ERR_IFETCH+T_USER: /* BERR asserted to CPU */ |
449 | case T_BUS_ERR_LD_ST+T_USER: /* BERR asserted to CPU */ | | 449 | case T_BUS_ERR_LD_ST+T_USER: /* BERR asserted to CPU */ |
450 | ksi.ksi_trap = type & ~T_USER; | | 450 | ksi.ksi_trap = type & ~T_USER; |
451 | ksi.ksi_signo = SIGSEGV; /* XXX */ | | 451 | ksi.ksi_signo = SIGSEGV; /* XXX */ |
452 | ksi.ksi_addr = (void *)vaddr; | | 452 | ksi.ksi_addr = (void *)vaddr; |
453 | ksi.ksi_code = SEGV_MAPERR; /* XXX */ | | 453 | ksi.ksi_code = SEGV_MAPERR; /* XXX */ |
454 | break; /* SIGNAL */ | | 454 | break; /* SIGNAL */ |
455 | | | 455 | |
456 | case T_BREAK: | | 456 | case T_BREAK: |
457 | #if defined(DDB) | | 457 | #if defined(DDB) |
458 | kdb_trap(type, (mips_reg_t *) frame); | | 458 | kdb_trap(type, (mips_reg_t *) frame); |
459 | return; /* KERN */ | | 459 | return; /* KERN */ |
460 | #elif defined(KGDB) | | 460 | #elif defined(KGDB) |
461 | { | | 461 | { |
462 | struct frame *f = (struct frame *)&ddb_regs; | | 462 | struct frame *f = (struct frame *)&ddb_regs; |
463 | extern mips_reg_t kgdb_cause, kgdb_vaddr; | | 463 | extern mips_reg_t kgdb_cause, kgdb_vaddr; |
464 | kgdb_cause = cause; | | 464 | kgdb_cause = cause; |
465 | kgdb_vaddr = vaddr; | | 465 | kgdb_vaddr = vaddr; |
466 | | | 466 | |
467 | /* | | 467 | /* |
468 | * init global ddb_regs, used in db_interface.c routines | | 468 | * init global ddb_regs, used in db_interface.c routines |
469 | * shared between ddb and gdb. Send ddb_regs to gdb so | | 469 | * shared between ddb and gdb. Send ddb_regs to gdb so |
470 | * that db_machdep.h macros will work with it, and | | 470 | * that db_machdep.h macros will work with it, and |
471 | * allow gdb to alter the PC. | | 471 | * allow gdb to alter the PC. |
472 | */ | | 472 | */ |
473 | db_set_ddb_regs(type, (mips_reg_t *) frame); | | 473 | db_set_ddb_regs(type, (mips_reg_t *) frame); |
474 | PC_BREAK_ADVANCE(f); | | 474 | PC_BREAK_ADVANCE(f); |
475 | if (!kgdb_trap(type, &ddb_regs)) | | 475 | if (!kgdb_trap(type, &ddb_regs)) |
476 | printf("kgdb: ignored %s\n", | | 476 | printf("kgdb: ignored %s\n", |
477 | trap_type[TRAPTYPE(cause)]); | | 477 | trap_type[TRAPTYPE(cause)]); |
478 | else | | 478 | else |
479 | ((mips_reg_t *)frame)[21] = f->f_regs[_R_PC]; | | 479 | ((mips_reg_t *)frame)[21] = f->f_regs[_R_PC]; |
480 | | | 480 | |
481 | return; | | 481 | return; |
482 | } | | 482 | } |
483 | #else | | 483 | #else |
484 | goto dopanic; | | 484 | goto dopanic; |
485 | #endif | | 485 | #endif |
486 | case T_BREAK+T_USER: | | 486 | case T_BREAK+T_USER: |
487 | { | | 487 | { |
488 | vaddr_t va; | | 488 | vaddr_t va; |
489 | uint32_t instr; | | 489 | uint32_t instr; |
490 | int rv; | | 490 | int rv; |
491 | | | 491 | |
492 | /* compute address of break instruction */ | | 492 | /* compute address of break instruction */ |
493 | va = (DELAYBRANCH(cause)) ? opc + sizeof(int) : opc; | | 493 | va = (DELAYBRANCH(cause)) ? opc + sizeof(int) : opc; |
494 | | | 494 | |
495 | /* read break instruction */ | | 495 | /* read break instruction */ |
496 | instr = fuiword((void *)va); | | 496 | instr = fuiword((void *)va); |
497 | | | 497 | |
498 | if (l->l_md.md_ss_addr != va || instr != MIPS_BREAK_SSTEP) { | | 498 | if (l->l_md.md_ss_addr != va || instr != MIPS_BREAK_SSTEP) { |
499 | ksi.ksi_trap = type & ~T_USER; | | 499 | ksi.ksi_trap = type & ~T_USER; |
500 | ksi.ksi_signo = SIGTRAP; | | 500 | ksi.ksi_signo = SIGTRAP; |
501 | ksi.ksi_addr = (void *)va; | | 501 | ksi.ksi_addr = (void *)va; |
502 | ksi.ksi_code = TRAP_TRACE; | | 502 | ksi.ksi_code = TRAP_TRACE; |
503 | break; | | 503 | break; |
504 | } | | 504 | } |
505 | /* | | 505 | /* |
506 | * Restore original instruction and clear BP | | 506 | * Restore original instruction and clear BP |
507 | */ | | 507 | */ |
508 | rv = suiword((void *)va, l->l_md.md_ss_instr); | | 508 | rv = suiword((void *)va, l->l_md.md_ss_instr); |
509 | if (rv < 0) { | | 509 | if (rv < 0) { |
510 | vaddr_t sa, ea; | | 510 | vaddr_t sa, ea; |
511 | sa = trunc_page(va); | | 511 | sa = trunc_page(va); |
512 | ea = round_page(va + sizeof(int) - 1); | | 512 | ea = round_page(va + sizeof(int) - 1); |
513 | rv = uvm_map_protect(&p->p_vmspace->vm_map, | | 513 | rv = uvm_map_protect(&p->p_vmspace->vm_map, |
514 | sa, ea, VM_PROT_ALL, false); | | 514 | sa, ea, VM_PROT_ALL, false); |
515 | if (rv == 0) { | | 515 | if (rv == 0) { |
516 | rv = suiword((void *)va, l->l_md.md_ss_instr); | | 516 | rv = suiword((void *)va, l->l_md.md_ss_instr); |
517 | (void)uvm_map_protect(&p->p_vmspace->vm_map, | | 517 | (void)uvm_map_protect(&p->p_vmspace->vm_map, |
518 | sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, false); | | 518 | sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, false); |
519 | } | | 519 | } |
520 | } | | 520 | } |
521 | mips_icache_sync_all(); /* XXXJRT -- necessary? */ | | 521 | mips_icache_sync_all(); /* XXXJRT -- necessary? */ |
522 | mips_dcache_wbinv_all(); /* XXXJRT -- necessary? */ | | 522 | mips_dcache_wbinv_all(); /* XXXJRT -- necessary? */ |
523 | | | 523 | |
524 | if (rv < 0) | | 524 | if (rv < 0) |
525 | printf("Warning: can't restore instruction at 0x%lx: 0x%x\n", | | 525 | printf("Warning: can't restore instruction at 0x%lx: 0x%x\n", |
526 | l->l_md.md_ss_addr, l->l_md.md_ss_instr); | | 526 | l->l_md.md_ss_addr, l->l_md.md_ss_instr); |
527 | l->l_md.md_ss_addr = 0; | | 527 | l->l_md.md_ss_addr = 0; |
528 | ksi.ksi_trap = type & ~T_USER; | | 528 | ksi.ksi_trap = type & ~T_USER; |
529 | ksi.ksi_signo = SIGTRAP; | | 529 | ksi.ksi_signo = SIGTRAP; |
530 | ksi.ksi_addr = (void *)va; | | 530 | ksi.ksi_addr = (void *)va; |
531 | ksi.ksi_code = TRAP_BRKPT; | | 531 | ksi.ksi_code = TRAP_BRKPT; |
532 | break; /* SIGNAL */ | | 532 | break; /* SIGNAL */ |
533 | } | | 533 | } |
534 | case T_RES_INST+T_USER: | | 534 | case T_RES_INST+T_USER: |
535 | case T_COP_UNUSABLE+T_USER: | | 535 | case T_COP_UNUSABLE+T_USER: |
536 | #if !defined(SOFTFLOAT) && !defined(NOFPU) | | 536 | #if !defined(SOFTFLOAT) && !defined(NOFPU) |
537 | if ((cause & MIPS_CR_COP_ERR) == 0x10000000) { | | 537 | if ((cause & MIPS_CR_COP_ERR) == 0x10000000) { |
538 | struct frame *f; | | 538 | struct frame *f; |
539 | | | 539 | |
540 | f = (struct frame *)l->l_md.md_regs; | | 540 | f = (struct frame *)l->l_md.md_regs; |
541 | savefpregs(fpcurlwp); /* yield FPA */ | | 541 | savefpregs(fpcurlwp); /* yield FPA */ |
542 | loadfpregs(l); /* load FPA */ | | 542 | loadfpregs(l); /* load FPA */ |
543 | fpcurlwp = l; | | 543 | fpcurlwp = l; |
544 | l->l_md.md_flags |= MDP_FPUSED; | | 544 | l->l_md.md_flags |= MDP_FPUSED; |
545 | f->f_regs[_R_SR] |= MIPS_SR_COP_1_BIT; | | 545 | f->f_regs[_R_SR] |= MIPS_SR_COP_1_BIT; |
546 | } else | | 546 | } else |
547 | #endif | | 547 | #endif |
548 | { | | 548 | { |
549 | MachEmulateInst(status, cause, opc, l->l_md.md_regs); | | 549 | MachEmulateInst(status, cause, opc, l->l_md.md_regs); |
550 | } | | 550 | } |
551 | userret(l); | | 551 | userret(l); |
552 | return; /* GEN */ | | 552 | return; /* GEN */ |
553 | case T_FPE+T_USER: | | 553 | case T_FPE+T_USER: |
554 | #if defined(SOFTFLOAT) | | 554 | #if defined(SOFTFLOAT) |
555 | MachEmulateInst(status, cause, opc, l->l_md.md_regs); | | 555 | MachEmulateInst(status, cause, opc, l->l_md.md_regs); |
556 | #elif !defined(NOFPU) | | 556 | #elif !defined(NOFPU) |
557 | MachFPTrap(status, cause, opc, l->l_md.md_regs); | | 557 | MachFPTrap(status, cause, opc, l->l_md.md_regs); |
558 | #endif | | 558 | #endif |
559 | userret(l); | | 559 | userret(l); |
560 | return; /* GEN */ | | 560 | return; /* GEN */ |
561 | case T_OVFLOW+T_USER: | | 561 | case T_OVFLOW+T_USER: |
562 | case T_TRAP+T_USER: | | 562 | case T_TRAP+T_USER: |
563 | ksi.ksi_trap = type & ~T_USER; | | 563 | ksi.ksi_trap = type & ~T_USER; |
564 | ksi.ksi_signo = SIGFPE; | | 564 | ksi.ksi_signo = SIGFPE; |
565 | fp = (struct frame *)l->l_md.md_regs; | | 565 | fp = (struct frame *)l->l_md.md_regs; |
566 | ksi.ksi_addr = (void *)fp->f_regs[_R_PC]; | | 566 | ksi.ksi_addr = (void *)fp->f_regs[_R_PC]; |
567 | ksi.ksi_code = FPE_FLTOVF; /* XXX */ | | 567 | ksi.ksi_code = FPE_FLTOVF; /* XXX */ |
568 | break; /* SIGNAL */ | | 568 | break; /* SIGNAL */ |
569 | } | | 569 | } |
570 | fp = (struct frame *)l->l_md.md_regs; | | 570 | fp = (struct frame *)l->l_md.md_regs; |
571 | fp->f_regs[_R_CAUSE] = cause; | | 571 | fp->f_regs[_R_CAUSE] = cause; |
572 | fp->f_regs[_R_BADVADDR] = vaddr; | | 572 | fp->f_regs[_R_BADVADDR] = vaddr; |
573 | (*p->p_emul->e_trapsignal)(l, &ksi); | | 573 | (*p->p_emul->e_trapsignal)(l, &ksi); |
574 | if ((type & T_USER) == 0) | | 574 | if ((type & T_USER) == 0) |
575 | panic("trapsignal"); | | 575 | panic("trapsignal"); |
576 | userret(l); | | 576 | userret(l); |
577 | return; | | 577 | return; |
578 | } | | 578 | } |
579 | | | 579 | |
580 | /* | | 580 | /* |
581 | * Handle asynchronous software traps. | | 581 | * Handle asynchronous software traps. |
582 | * This is called from MachUserIntr() either to deliver signals or | | 582 | * This is called from MachUserIntr() either to deliver signals or |
583 | * to make involuntary context switch (preemption). | | 583 | * to make involuntary context switch (preemption). |
584 | */ | | 584 | */ |
585 | void | | 585 | void |
586 | ast(unsigned pc) /* pc is program counter where to continue */ | | 586 | ast(unsigned pc) /* pc is program counter where to continue */ |
587 | { | | 587 | { |
588 | struct lwp *l = curlwp; | | 588 | struct lwp *l = curlwp; |
589 | | | 589 | |
590 | while (l->l_md.md_astpending) { | | 590 | while (l->l_md.md_astpending) { |
591 | uvmexp.softs++; | | 591 | uvmexp.softs++; |
592 | l->l_md.md_astpending = 0; | | 592 | l->l_md.md_astpending = 0; |
593 | | | 593 | |
594 | if (l->l_pflag & LP_OWEUPC) { | | 594 | if (l->l_pflag & LP_OWEUPC) { |
595 | l->l_pflag &= ~LP_OWEUPC; | | 595 | l->l_pflag &= ~LP_OWEUPC; |
596 | ADDUPROF(l); | | 596 | ADDUPROF(l); |
597 | } | | 597 | } |
598 | | | 598 | |
599 | userret(l); | | 599 | userret(l); |
600 | | | 600 | |
601 | if (curcpu()->ci_want_resched) { | | 601 | if (curcpu()->ci_want_resched) { |
602 | /* | | 602 | /* |
603 | * We are being preempted. | | 603 | * We are being preempted. |
604 | */ | | 604 | */ |
605 | preempt(); | | 605 | preempt(); |
606 | } | | 606 | } |
607 | } | | 607 | } |
608 | } | | 608 | } |
609 | | | 609 | |
610 | | | 610 | |
611 | /* XXX need to rewrite acient comment XXX | | 611 | /* XXX need to rewrite acient comment XXX |
612 | * This routine is called by procxmt() to single step one instruction. | | 612 | * This routine is called by procxmt() to single step one instruction. |
613 | * We do this by storing a break instruction after the current instruction, | | 613 | * We do this by storing a break instruction after the current instruction, |
614 | * resuming execution, and then restoring the old instruction. | | 614 | * resuming execution, and then restoring the old instruction. |
615 | */ | | 615 | */ |
616 | int | | 616 | int |
617 | mips_singlestep(struct lwp *l) | | 617 | mips_singlestep(struct lwp *l) |
618 | { | | 618 | { |
619 | struct frame *f = (struct frame *)l->l_md.md_regs; | | 619 | struct frame *f = (struct frame *)l->l_md.md_regs; |
620 | struct proc *p = l->l_proc; | | 620 | struct proc *p = l->l_proc; |
621 | vaddr_t pc, va; | | 621 | vaddr_t pc, va; |
622 | int rv; | | 622 | int rv; |
623 | | | 623 | |
624 | if (l->l_md.md_ss_addr) { | | 624 | if (l->l_md.md_ss_addr) { |
625 | printf("SS %s (%d): breakpoint already set at %lx\n", | | 625 | printf("SS %s (%d): breakpoint already set at %lx\n", |
626 | p->p_comm, p->p_pid, l->l_md.md_ss_addr); | | 626 | p->p_comm, p->p_pid, l->l_md.md_ss_addr); |
627 | return EFAULT; | | 627 | return EFAULT; |
628 | } | | 628 | } |
629 | pc = (vaddr_t)f->f_regs[_R_PC]; | | 629 | pc = (vaddr_t)f->f_regs[_R_PC]; |
630 | if (fuiword((void *)pc) != 0) /* not a NOP instruction */ | | 630 | if (fuiword((void *)pc) != 0) /* not a NOP instruction */ |
631 | va = MachEmulateBranch(f, pc, PCB_FSR(&l->l_addr->u_pcb), 1); | | 631 | va = MachEmulateBranch(f, pc, PCB_FSR(&l->l_addr->u_pcb), 1); |
632 | else | | 632 | else |
633 | va = pc + sizeof(int); | | 633 | va = pc + sizeof(int); |
634 | | | 634 | |
635 | /* | | 635 | /* |
636 | * We can't single-step into a RAS. Check if we're in | | 636 | * We can't single-step into a RAS. Check if we're in |
637 | * a RAS, and set the breakpoint just past it. | | 637 | * a RAS, and set the breakpoint just past it. |
638 | */ | | 638 | */ |
639 | if (p->p_raslist != NULL) { | | 639 | if (p->p_raslist != NULL) { |
640 | while (ras_lookup(p, (void *)va) != (void *)-1) | | 640 | while (ras_lookup(p, (void *)va) != (void *)-1) |
641 | va += sizeof(int); | | 641 | va += sizeof(int); |
642 | } | | 642 | } |
643 | | | 643 | |
644 | l->l_md.md_ss_addr = va; | | 644 | l->l_md.md_ss_addr = va; |
645 | l->l_md.md_ss_instr = fuiword((void *)va); | | 645 | l->l_md.md_ss_instr = fuiword((void *)va); |
646 | rv = suiword((void *)va, MIPS_BREAK_SSTEP); | | 646 | rv = suiword((void *)va, MIPS_BREAK_SSTEP); |
647 | if (rv < 0) { | | 647 | if (rv < 0) { |
648 | vaddr_t sa, ea; | | 648 | vaddr_t sa, ea; |
649 | sa = trunc_page(va); | | 649 | sa = trunc_page(va); |
650 | ea = round_page(va + sizeof(int) - 1); | | 650 | ea = round_page(va + sizeof(int) - 1); |
651 | rv = uvm_map_protect(&p->p_vmspace->vm_map, | | 651 | rv = uvm_map_protect(&p->p_vmspace->vm_map, |
652 | sa, ea, VM_PROT_ALL, false); | | 652 | sa, ea, VM_PROT_ALL, false); |
653 | if (rv == 0) { | | 653 | if (rv == 0) { |
654 | rv = suiword((void *)va, MIPS_BREAK_SSTEP); | | 654 | rv = suiword((void *)va, MIPS_BREAK_SSTEP); |
655 | (void)uvm_map_protect(&p->p_vmspace->vm_map, | | 655 | (void)uvm_map_protect(&p->p_vmspace->vm_map, |
656 | sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, false); | | 656 | sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, false); |
657 | } | | 657 | } |
658 | } | | 658 | } |
659 | #if 0 | | 659 | #if 0 |
660 | printf("SS %s (%d): breakpoint set at %x: %x (pc %x) br %x\n", | | 660 | printf("SS %s (%d): breakpoint set at %x: %x (pc %x) br %x\n", |
661 | p->p_comm, p->p_pid, p->p_md.md_ss_addr, | | 661 | p->p_comm, p->p_pid, p->p_md.md_ss_addr, |
662 | p->p_md.md_ss_instr, pc, fuword((void *)va)); /* XXX */ | | 662 | p->p_md.md_ss_instr, pc, fuword((void *)va)); /* XXX */ |
663 | #endif | | 663 | #endif |
664 | return 0; | | 664 | return 0; |
665 | } | | 665 | } |
666 | | | 666 | |
667 | | | 667 | |
668 | #ifndef DDB_TRACE | | 668 | #ifndef DDB_TRACE |
669 | | | 669 | |
670 | #if defined(DEBUG) || defined(DDB) || defined(KGDB) || defined(geo) | | 670 | #if defined(DEBUG) || defined(DDB) || defined(KGDB) || defined(geo) |
671 | mips_reg_t kdbrpeek(vaddr_t); | | 671 | mips_reg_t kdbrpeek(vaddr_t); |
672 | | | 672 | |
673 | int | | 673 | int |
674 | kdbpeek(vaddr_t addr) | | 674 | kdbpeek(vaddr_t addr) |
675 | { | | 675 | { |
676 | int rc; | | 676 | int rc; |
677 | | | 677 | |
678 | if (addr & 3) { | | 678 | if (addr & 3) { |
679 | printf("kdbpeek: unaligned address %lx\n", addr); | | 679 | printf("kdbpeek: unaligned address %lx\n", addr); |
680 | /* We might have been called from DDB, so do not go there. */ | | 680 | /* We might have been called from DDB, so do not go there. */ |
681 | stacktrace(); | | 681 | stacktrace(); |
682 | rc = -1 ; | | 682 | rc = -1 ; |
683 | } else if (addr == 0) { | | 683 | } else if (addr == 0) { |
684 | printf("kdbpeek: NULL\n"); | | 684 | printf("kdbpeek: NULL\n"); |
685 | rc = 0xdeadfeed; | | 685 | rc = 0xdeadfeed; |
686 | } else { | | 686 | } else { |
687 | rc = *(int *)addr; | | 687 | rc = *(int *)addr; |
688 | } | | 688 | } |
689 | return rc; | | 689 | return rc; |
690 | } | | 690 | } |
691 | | | 691 | |
692 | mips_reg_t | | 692 | mips_reg_t |
693 | kdbrpeek(vaddr_t addr) | | 693 | kdbrpeek(vaddr_t addr) |
694 | { | | 694 | { |
695 | mips_reg_t rc; | | 695 | mips_reg_t rc; |
696 | | | 696 | |
697 | if (addr & (sizeof(mips_reg_t) - 1)) { | | 697 | if (addr & (sizeof(mips_reg_t) - 1)) { |
698 | printf("kdbrpeek: unaligned address %lx\n", addr); | | 698 | printf("kdbrpeek: unaligned address %lx\n", addr); |
699 | /* We might have been called from DDB, so do not go there. */ | | 699 | /* We might have been called from DDB, so do not go there. */ |
700 | stacktrace(); | | 700 | stacktrace(); |
701 | rc = -1 ; | | 701 | rc = -1 ; |
702 | } else if (addr == 0) { | | 702 | } else if (addr == 0) { |
703 | printf("kdbrpeek: NULL\n"); | | 703 | printf("kdbrpeek: NULL\n"); |
704 | rc = 0xdeadfeed; | | 704 | rc = 0xdeadfeed; |
705 | } else { | | 705 | } else { |
706 | rc = *(mips_reg_t *)addr; | | 706 | rc = *(mips_reg_t *)addr; |
707 | } | | 707 | } |
708 | return rc; | | 708 | return rc; |
709 | } | | 709 | } |
710 | | | 710 | |
711 | extern char start[], edata[], verylocore[]; | | 711 | extern char start[], edata[], verylocore[]; |
712 | extern char mips1_KernGenException[]; | | 712 | extern char mips1_KernGenException[]; |
713 | extern char mips1_UserGenException[]; | | 713 | extern char mips1_UserGenException[]; |
714 | extern char mips1_KernIntr[]; | | 714 | extern char mips1_KernIntr[]; |
715 | extern char mips1_UserIntr[]; | | 715 | extern char mips1_UserIntr[]; |
716 | extern char mips1_SystemCall[]; | | 716 | extern char mips1_SystemCall[]; |
717 | extern char mips3_KernGenException[]; | | 717 | extern char mips3_KernGenException[]; |
718 | extern char mips3_UserGenException[]; | | 718 | extern char mips3_UserGenException[]; |
719 | extern char mips3_KernIntr[]; | | 719 | extern char mips3_KernIntr[]; |
720 | extern char mips3_UserIntr[]; | | 720 | extern char mips3_UserIntr[]; |
721 | extern char mips3_SystemCall[]; | | 721 | extern char mips3_SystemCall[]; |
722 | int main(void *); /* XXX */ | | 722 | int main(void *); /* XXX */ |
723 | | | 723 | |
724 | /* | | 724 | /* |
725 | * stack trace code, also useful to DDB one day | | 725 | * stack trace code, also useful to DDB one day |
726 | */ | | 726 | */ |
727 | | | 727 | |
728 | /* forward */ | | 728 | /* forward */ |
729 | const char *fn_name(vaddr_t addr); | | 729 | const char *fn_name(vaddr_t addr); |
730 | void stacktrace_subr(int, int, int, int, u_int, u_int, u_int, u_int, | | 730 | void stacktrace_subr(int, int, int, int, u_int, u_int, u_int, u_int, |
731 | void (*)(const char*, ...)); | | 731 | void (*)(const char*, ...)); |
732 | | | 732 | |
733 | #define MIPS_JR_RA 0x03e00008 /* instruction code for jr ra */ | | 733 | #define MIPS_JR_RA 0x03e00008 /* instruction code for jr ra */ |
734 | #define MIPS_JR_K0 0x03400008 /* instruction code for jr k0 */ | | 734 | #define MIPS_JR_K0 0x03400008 /* instruction code for jr k0 */ |
735 | #define MIPS_ERET 0x42000018 /* instruction code for eret */ | | 735 | #define MIPS_ERET 0x42000018 /* instruction code for eret */ |
736 | | | 736 | |
737 | /* | | 737 | /* |
738 | * Do a stack backtrace. | | 738 | * Do a stack backtrace. |
739 | * (*printfn)() prints the output to either the system log, | | 739 | * (*printfn)() prints the output to either the system log, |
740 | * the console, or both. | | 740 | * the console, or both. |
741 | */ | | 741 | */ |
742 | void | | 742 | void |
743 | stacktrace_subr(int a0, int a1, int a2, int a3, | | 743 | stacktrace_subr(int a0, int a1, int a2, int a3, |
744 | u_int pc, u_int sp, u_int fp, u_int ra, | | 744 | u_int pc, u_int sp, u_int fp, u_int ra, |
745 | void (*printfn)(const char*, ...)) | | 745 | void (*printfn)(const char*, ...)) |
746 | { | | 746 | { |
747 | vaddr_t va, subr; | | 747 | vaddr_t va, subr; |
748 | unsigned instr, mask; | | 748 | unsigned instr, mask; |
749 | InstFmt i; | | 749 | InstFmt i; |
750 | int more, stksize; | | 750 | int more, stksize; |
751 | unsigned int frames = 0; | | 751 | unsigned int frames = 0; |
752 | int foundframesize = 0; | | 752 | int foundframesize = 0; |
753 | #ifdef DDB | | 753 | #ifdef DDB |
754 | db_expr_t diff; | | 754 | db_expr_t diff; |
755 | db_sym_t sym; | | 755 | db_sym_t sym; |
756 | #endif | | 756 | #endif |
757 | | | 757 | |
758 | /* Jump here when done with a frame, to start a new one */ | | 758 | /* Jump here when done with a frame, to start a new one */ |
759 | loop: | | 759 | loop: |
760 | stksize = 0; | | 760 | stksize = 0; |
761 | subr = 0; | | 761 | subr = 0; |
762 | if (frames++ > 100) { | | 762 | if (frames++ > 100) { |
763 | (*printfn)("\nstackframe count exceeded\n"); | | 763 | (*printfn)("\nstackframe count exceeded\n"); |
764 | /* return breaks stackframe-size heuristics with gcc -O2 */ | | 764 | /* return breaks stackframe-size heuristics with gcc -O2 */ |
765 | goto finish; /*XXX*/ | | 765 | goto finish; /*XXX*/ |
766 | } | | 766 | } |
767 | | | 767 | |
768 | /* check for bad SP: could foul up next frame */ | | 768 | /* check for bad SP: could foul up next frame */ |
769 | if (sp & 3 || sp < 0x80000000) { | | 769 | if (sp & 3 || sp < 0x80000000) { |
770 | (*printfn)("SP 0x%x: not in kernel\n", sp); | | 770 | (*printfn)("SP 0x%x: not in kernel\n", sp); |
771 | ra = 0; | | 771 | ra = 0; |
772 | subr = 0; | | 772 | subr = 0; |
773 | goto done; | | 773 | goto done; |
774 | } | | 774 | } |
775 | | | 775 | |
776 | /* Check for bad PC */ | | 776 | /* Check for bad PC */ |
777 | if (pc & 3 || pc < 0x80000000 || pc >= (unsigned)edata) { | | 777 | if (pc & 3 || pc < 0x80000000 || pc >= (unsigned)edata) { |
778 | (*printfn)("PC 0x%x: not in kernel space\n", pc); | | 778 | (*printfn)("PC 0x%x: not in kernel space\n", pc); |
779 | ra = 0; | | 779 | ra = 0; |
780 | goto done; | | 780 | goto done; |
781 | } | | 781 | } |
782 | | | 782 | |
783 | #ifdef DDB | | 783 | #ifdef DDB |
784 | /* | | 784 | /* |
785 | * Check the kernel symbol table to see the beginning of | | 785 | * Check the kernel symbol table to see the beginning of |
786 | * the current subroutine. | | 786 | * the current subroutine. |
787 | */ | | 787 | */ |
788 | diff = 0; | | 788 | diff = 0; |
789 | sym = db_search_symbol(pc, DB_STGY_ANY, &diff); | | 789 | sym = db_search_symbol(pc, DB_STGY_ANY, &diff); |
790 | if (sym != DB_SYM_NULL && diff == 0) { | | 790 | if (sym != DB_SYM_NULL && diff == 0) { |
791 | /* check func(foo) __attribute__((__noreturn__)) case */ | | 791 | /* check func(foo) __attribute__((__noreturn__)) case */ |
792 | instr = kdbpeek(pc - 2 * sizeof(int)); | | 792 | instr = kdbpeek(pc - 2 * sizeof(int)); |
793 | i.word = instr; | | 793 | i.word = instr; |
794 | if (i.JType.op == OP_JAL) { | | 794 | if (i.JType.op == OP_JAL) { |
795 | sym = db_search_symbol(pc - sizeof(int), | | 795 | sym = db_search_symbol(pc - sizeof(int), |
796 | DB_STGY_ANY, &diff); | | 796 | DB_STGY_ANY, &diff); |
797 | if (sym != DB_SYM_NULL && diff != 0) | | 797 | if (sym != DB_SYM_NULL && diff != 0) |
798 | diff += sizeof(int); | | 798 | diff += sizeof(int); |
799 | } | | 799 | } |
800 | } | | 800 | } |
801 | if (sym == DB_SYM_NULL) { | | 801 | if (sym == DB_SYM_NULL) { |
802 | ra = 0; | | 802 | ra = 0; |
803 | goto done; | | 803 | goto done; |
804 | } | | 804 | } |
805 | va = pc - diff; | | 805 | va = pc - diff; |
806 | #else | | 806 | #else |
807 | /* | | 807 | /* |
808 | * Find the beginning of the current subroutine by scanning backwards | | 808 | * Find the beginning of the current subroutine by scanning backwards |
809 | * from the current PC for the end of the previous subroutine. | | 809 | * from the current PC for the end of the previous subroutine. |
810 | * | | 810 | * |
811 | * XXX This won't work well because nowadays gcc is so aggressive | | 811 | * XXX This won't work well because nowadays gcc is so aggressive |
812 | * as to reorder instruction blocks for branch-predict. | | 812 | * as to reorder instruction blocks for branch-predict. |
813 | * (i.e. 'jr ra' wouldn't indicate the end of subroutine) | | 813 | * (i.e. 'jr ra' wouldn't indicate the end of subroutine) |
814 | */ | | 814 | */ |
815 | va = pc; | | 815 | va = pc; |
816 | do { | | 816 | do { |
817 | va -= sizeof(int); | | 817 | va -= sizeof(int); |
818 | if (va <= (unsigned)verylocore) | | 818 | if (va <= (unsigned)verylocore) |
819 | goto finish; | | 819 | goto finish; |
820 | instr = kdbpeek(va); | | 820 | instr = kdbpeek(va); |
821 | if (instr == MIPS_ERET) | | 821 | if (instr == MIPS_ERET) |
822 | goto mips3_eret; | | 822 | goto mips3_eret; |
823 | } while (instr != MIPS_JR_RA && instr != MIPS_JR_K0); | | 823 | } while (instr != MIPS_JR_RA && instr != MIPS_JR_K0); |
824 | /* skip back over branch & delay slot */ | | 824 | /* skip back over branch & delay slot */ |
825 | va += sizeof(int); | | 825 | va += sizeof(int); |
826 | mips3_eret: | | 826 | mips3_eret: |
827 | va += sizeof(int); | | 827 | va += sizeof(int); |
828 | /* skip over nulls which might separate .o files */ | | 828 | /* skip over nulls which might separate .o files */ |
829 | while ((instr = kdbpeek(va)) == 0) | | 829 | while ((instr = kdbpeek(va)) == 0) |
830 | va += sizeof(int); | | 830 | va += sizeof(int); |
831 | #endif | | 831 | #endif |
832 | subr = va; | | 832 | subr = va; |
833 | | | 833 | |
834 | /* scan forwards to find stack size and any saved registers */ | | 834 | /* scan forwards to find stack size and any saved registers */ |
835 | stksize = 0; | | 835 | stksize = 0; |
836 | more = 3; | | 836 | more = 3; |
837 | mask = 0; | | 837 | mask = 0; |
838 | foundframesize = 0; | | 838 | foundframesize = 0; |
839 | for (va = subr; more; va += sizeof(int), | | 839 | for (va = subr; more; va += sizeof(int), |
840 | more = (more == 3) ? 3 : more - 1) { | | 840 | more = (more == 3) ? 3 : more - 1) { |
841 | /* stop if hit our current position */ | | 841 | /* stop if hit our current position */ |
842 | if (va >= pc) | | 842 | if (va >= pc) |
843 | break; | | 843 | break; |
844 | instr = kdbpeek(va); | | 844 | instr = kdbpeek(va); |
845 | i.word = instr; | | 845 | i.word = instr; |
846 | switch (i.JType.op) { | | 846 | switch (i.JType.op) { |
847 | case OP_SPECIAL: | | 847 | case OP_SPECIAL: |
848 | switch (i.RType.func) { | | 848 | switch (i.RType.func) { |
849 | case OP_JR: | | 849 | case OP_JR: |
850 | case OP_JALR: | | 850 | case OP_JALR: |
851 | more = 2; /* stop after next instruction */ | | 851 | more = 2; /* stop after next instruction */ |
852 | break; | | 852 | break; |
853 | | | 853 | |
854 | case OP_SYSCALL: | | 854 | case OP_SYSCALL: |
855 | case OP_BREAK: | | 855 | case OP_BREAK: |
856 | more = 1; /* stop now */ | | 856 | more = 1; /* stop now */ |
857 | }; | | 857 | }; |
858 | break; | | 858 | break; |
859 | | | 859 | |
860 | case OP_BCOND: | | 860 | case OP_BCOND: |
861 | case OP_J: | | 861 | case OP_J: |
862 | case OP_JAL: | | 862 | case OP_JAL: |
863 | case OP_BEQ: | | 863 | case OP_BEQ: |
864 | case OP_BNE: | | 864 | case OP_BNE: |
865 | case OP_BLEZ: | | 865 | case OP_BLEZ: |
866 | case OP_BGTZ: | | 866 | case OP_BGTZ: |
867 | more = 2; /* stop after next instruction */ | | 867 | more = 2; /* stop after next instruction */ |
868 | break; | | 868 | break; |
869 | | | 869 | |
870 | case OP_COP0: | | 870 | case OP_COP0: |
871 | case OP_COP1: | | 871 | case OP_COP1: |
872 | case OP_COP2: | | 872 | case OP_COP2: |
873 | case OP_COP3: | | 873 | case OP_COP3: |
874 | switch (i.RType.rs) { | | 874 | switch (i.RType.rs) { |
875 | case OP_BCx: | | 875 | case OP_BCx: |
876 | case OP_BCy: | | 876 | case OP_BCy: |
877 | more = 2; /* stop after next instruction */ | | 877 | more = 2; /* stop after next instruction */ |
878 | }; | | 878 | }; |
879 | break; | | 879 | break; |
880 | | | 880 | |
881 | case OP_SW: | | 881 | case OP_SW: |
882 | /* look for saved registers on the stack */ | | 882 | /* look for saved registers on the stack */ |
883 | if (i.IType.rs != 29) | | 883 | if (i.IType.rs != 29) |
884 | break; | | 884 | break; |
885 | /* only restore the first one */ | | 885 | /* only restore the first one */ |
886 | if (mask & (1 << i.IType.rt)) | | 886 | if (mask & (1 << i.IType.rt)) |
887 | break; | | 887 | break; |
888 | mask |= (1 << i.IType.rt); | | 888 | mask |= (1 << i.IType.rt); |
889 | switch (i.IType.rt) { | | 889 | switch (i.IType.rt) { |
890 | case 4: /* a0 */ | | 890 | case 4: /* a0 */ |
891 | a0 = kdbpeek(sp + (short)i.IType.imm); | | 891 | a0 = kdbpeek(sp + (short)i.IType.imm); |
892 | break; | | 892 | break; |
893 | | | 893 | |
894 | case 5: /* a1 */ | | 894 | case 5: /* a1 */ |
895 | a1 = kdbpeek(sp + (short)i.IType.imm); | | 895 | a1 = kdbpeek(sp + (short)i.IType.imm); |
896 | break; | | 896 | break; |
897 | | | 897 | |
898 | case 6: /* a2 */ | | 898 | case 6: /* a2 */ |
899 | a2 = kdbpeek(sp + (short)i.IType.imm); | | 899 | a2 = kdbpeek(sp + (short)i.IType.imm); |
900 | break; | | 900 | break; |
901 | | | 901 | |
902 | case 7: /* a3 */ | | 902 | case 7: /* a3 */ |
903 | a3 = kdbpeek(sp + (short)i.IType.imm); | | 903 | a3 = kdbpeek(sp + (short)i.IType.imm); |
904 | break; | | 904 | break; |
905 | | | 905 | |
906 | case 30: /* fp */ | | 906 | case 30: /* fp */ |
907 | fp = kdbpeek(sp + (short)i.IType.imm); | | 907 | fp = kdbpeek(sp + (short)i.IType.imm); |
908 | break; | | 908 | break; |
909 | | | 909 | |
910 | case 31: /* ra */ | | 910 | case 31: /* ra */ |
911 | ra = kdbpeek(sp + (short)i.IType.imm); | | 911 | ra = kdbpeek(sp + (short)i.IType.imm); |
912 | } | | 912 | } |
913 | break; | | 913 | break; |
914 | | | 914 | |
915 | case OP_ADDI: | | 915 | case OP_ADDI: |
916 | case OP_ADDIU: | | 916 | case OP_ADDIU: |
917 | /* look for stack pointer adjustment */ | | 917 | /* look for stack pointer adjustment */ |
918 | if (i.IType.rs != 29 || i.IType.rt != 29) | | 918 | if (i.IType.rs != 29 || i.IType.rt != 29) |
919 | break; | | 919 | break; |
920 | /* don't count pops for mcount */ | | 920 | /* don't count pops for mcount */ |
921 | if (!foundframesize) { | | 921 | if (!foundframesize) { |
922 | stksize = - ((short)i.IType.imm); | | 922 | stksize = - ((short)i.IType.imm); |
923 | foundframesize = 1; | | 923 | foundframesize = 1; |
924 | } | | 924 | } |
925 | } | | 925 | } |
926 | } | | 926 | } |
927 | done: | | 927 | done: |
928 | (*printfn)("%s+%x (%x,%x,%x,%x) ra %x sz %d\n", | | 928 | (*printfn)("%s+%x (%x,%x,%x,%x) ra %x sz %d\n", |
929 | fn_name(subr), pc - subr, a0, a1, a2, a3, ra, stksize); | | 929 | fn_name(subr), pc - subr, a0, a1, a2, a3, ra, stksize); |
930 | | | 930 | |
931 | if (ra) { | | 931 | if (ra) { |
932 | if (pc == ra && stksize == 0) | | 932 | if (pc == ra && stksize == 0) |
933 | (*printfn)("stacktrace: loop!\n"); | | 933 | (*printfn)("stacktrace: loop!\n"); |
934 | else { | | 934 | else { |
935 | pc = ra; | | 935 | pc = ra; |
936 | sp += stksize; | | 936 | sp += stksize; |
937 | ra = 0; | | 937 | ra = 0; |
938 | goto loop; | | 938 | goto loop; |
939 | } | | 939 | } |
940 | } else { | | 940 | } else { |
941 | finish: | | 941 | finish: |
942 | if (curlwp) | | 942 | if (curlwp) |
943 | (*printfn)("User-level: pid %d.%d\n", | | 943 | (*printfn)("User-level: pid %d.%d\n", |
944 | curlwp->l_proc->p_pid, curlwp->l_lid); | | 944 | curlwp->l_proc->p_pid, curlwp->l_lid); |
945 | else | | 945 | else |
946 | (*printfn)("User-level: curlwp NULL\n"); | | 946 | (*printfn)("User-level: curlwp NULL\n"); |
947 | } | | 947 | } |
948 | } | | 948 | } |
949 | | | 949 | |
950 | /* | | 950 | /* |
951 | * Functions ``special'' enough to print by name | | 951 | * Functions ``special'' enough to print by name |
952 | */ | | 952 | */ |
953 | #ifdef __STDC__ | | 953 | #ifdef __STDC__ |
954 | #define Name(_fn) { (void*)_fn, # _fn } | | 954 | #define Name(_fn) { (void*)_fn, # _fn } |
955 | #else | | 955 | #else |
956 | #define Name(_fn) { _fn, "_fn"} | | 956 | #define Name(_fn) { _fn, "_fn"} |
957 | #endif | | 957 | #endif |
958 | static struct { void *addr; const char *name;} names[] = { | | 958 | static struct { void *addr; const char *name;} names[] = { |
959 | Name(stacktrace), | | 959 | Name(stacktrace), |
960 | Name(stacktrace_subr), | | 960 | Name(stacktrace_subr), |
961 | Name(main), | | 961 | Name(main), |
962 | Name(trap), | | 962 | Name(trap), |
963 | | | 963 | |
964 | #ifdef MIPS1 /* r2000 family (mips-I CPU) */ | | 964 | #ifdef MIPS1 /* r2000 family (mips-I CPU) */ |
965 | Name(mips1_KernGenException), | | 965 | Name(mips1_KernGenException), |
966 | Name(mips1_UserGenException), | | 966 | Name(mips1_UserGenException), |
967 | Name(mips1_SystemCall), | | 967 | Name(mips1_SystemCall), |
968 | Name(mips1_KernIntr), | | 968 | Name(mips1_KernIntr), |
969 | Name(mips1_UserIntr), | | 969 | Name(mips1_UserIntr), |
970 | #endif /* MIPS1 */ | | 970 | #endif /* MIPS1 */ |
971 | | | 971 | |
972 | /* XXX simonb: need mips32 and mips64 checks here too */ | | 972 | /* XXX simonb: need mips32 and mips64 checks here too */ |
973 | #if defined(MIPS3) && !defined(MIPS3_5900) /* r4000 family (mips-III CPU) */ | | 973 | #if defined(MIPS3) && !defined(MIPS3_5900) /* r4000 family (mips-III CPU) */ |
974 | Name(mips3_KernGenException), | | 974 | Name(mips3_KernGenException), |
975 | Name(mips3_UserGenException), | | 975 | Name(mips3_UserGenException), |
976 | Name(mips3_SystemCall), | | 976 | Name(mips3_SystemCall), |
977 | Name(mips3_KernIntr), | | 977 | Name(mips3_KernIntr), |
978 | Name(mips3_UserIntr), | | 978 | Name(mips3_UserIntr), |
979 | #endif /* MIPS3 && !MIPS3_5900 */ | | 979 | #endif /* MIPS3 && !MIPS3_5900 */ |
980 | | | 980 | |
981 | Name(cpu_idle), | | 981 | Name(cpu_idle), |
982 | Name(cpu_switchto), | | 982 | Name(cpu_switchto), |
983 | {0, 0} | | 983 | {0, 0} |
984 | }; | | 984 | }; |
985 | | | 985 | |
986 | /* | | 986 | /* |
987 | * Map a function address to a string name, if known; or a hex string. | | 987 | * Map a function address to a string name, if known; or a hex string. |
988 | */ | | 988 | */ |
989 | const char * | | 989 | const char * |
990 | fn_name(vaddr_t addr) | | 990 | fn_name(vaddr_t addr) |
991 | { | | 991 | { |
992 | static char buf[17]; | | 992 | static char buf[17]; |
993 | int i = 0; | | 993 | int i = 0; |
994 | #ifdef DDB | | 994 | #ifdef DDB |
995 | db_expr_t diff; | | 995 | db_expr_t diff; |
996 | db_sym_t sym; | | 996 | db_sym_t sym; |
997 | const char *symname; | | 997 | const char *symname; |
998 | #endif | | 998 | #endif |
999 | | | 999 | |
1000 | #ifdef DDB | | 1000 | #ifdef DDB |
1001 | diff = 0; | | 1001 | diff = 0; |
1002 | symname = NULL; | | 1002 | symname = NULL; |
1003 | sym = db_search_symbol(addr, DB_STGY_ANY, &diff); | | 1003 | sym = db_search_symbol(addr, DB_STGY_ANY, &diff); |
1004 | db_symbol_values(sym, &symname, 0); | | 1004 | db_symbol_values(sym, &symname, 0); |
1005 | if (symname && diff == 0) | | 1005 | if (symname && diff == 0) |
1006 | return (symname); | | 1006 | return (symname); |
1007 | #endif | | 1007 | #endif |
1008 | for (i = 0; names[i].name; i++) | | 1008 | for (i = 0; names[i].name; i++) |
1009 | if (names[i].addr == (void*)addr) | | 1009 | if (names[i].addr == (void*)addr) |
1010 | return (names[i].name); | | 1010 | return (names[i].name); |
1011 | sprintf(buf, "%lx", addr); | | 1011 | sprintf(buf, "%lx", addr); |
1012 | return (buf); | | 1012 | return (buf); |
1013 | } | | 1013 | } |
1014 | | | 1014 | |
1015 | #endif /* DEBUG */ | | 1015 | #endif /* DEBUG */ |
1016 | #endif /* DDB_TRACE */ | | 1016 | #endif /* DDB_TRACE */ |