| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: undefined.c,v 1.53 2014/03/15 05:58:30 ozaki-r Exp $ */ | | 1 | /* $NetBSD: undefined.c,v 1.54 2014/03/28 21:44:35 matt Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2001 Ben Harris. | | 4 | * Copyright (c) 2001 Ben Harris. |
5 | * Copyright (c) 1995 Mark Brinicombe. | | 5 | * Copyright (c) 1995 Mark Brinicombe. |
6 | * Copyright (c) 1995 Brini. | | 6 | * Copyright (c) 1995 Brini. |
7 | * All rights reserved. | | 7 | * All rights reserved. |
8 | * | | 8 | * |
9 | * This code is derived from software written for Brini by Mark Brinicombe | | 9 | * This code is derived from software written for Brini by Mark Brinicombe |
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 |
| @@ -45,27 +45,27 @@ | | | @@ -45,27 +45,27 @@ |
45 | */ | | 45 | */ |
46 | | | 46 | |
47 | #define FAST_FPE | | 47 | #define FAST_FPE |
48 | | | 48 | |
49 | #include "opt_ddb.h" | | 49 | #include "opt_ddb.h" |
50 | #include "opt_kgdb.h" | | 50 | #include "opt_kgdb.h" |
51 | #include "opt_dtrace.h" | | 51 | #include "opt_dtrace.h" |
52 | | | 52 | |
53 | #include <sys/param.h> | | 53 | #include <sys/param.h> |
54 | #ifdef KGDB | | 54 | #ifdef KGDB |
55 | #include <sys/kgdb.h> | | 55 | #include <sys/kgdb.h> |
56 | #endif | | 56 | #endif |
57 | | | 57 | |
58 | __KERNEL_RCSID(0, "$NetBSD: undefined.c,v 1.53 2014/03/15 05:58:30 ozaki-r Exp $"); | | 58 | __KERNEL_RCSID(0, "$NetBSD: undefined.c,v 1.54 2014/03/28 21:44:35 matt Exp $"); |
59 | | | 59 | |
60 | #include <sys/kmem.h> | | 60 | #include <sys/kmem.h> |
61 | #include <sys/queue.h> | | 61 | #include <sys/queue.h> |
62 | #include <sys/signal.h> | | 62 | #include <sys/signal.h> |
63 | #include <sys/systm.h> | | 63 | #include <sys/systm.h> |
64 | #include <sys/proc.h> | | 64 | #include <sys/proc.h> |
65 | #include <sys/syslog.h> | | 65 | #include <sys/syslog.h> |
66 | #include <sys/vmmeter.h> | | 66 | #include <sys/vmmeter.h> |
67 | #include <sys/cpu.h> | | 67 | #include <sys/cpu.h> |
68 | #ifdef FAST_FPE | | 68 | #ifdef FAST_FPE |
69 | #include <sys/acct.h> | | 69 | #include <sys/acct.h> |
70 | #endif | | 70 | #endif |
71 | #include <sys/userret.h> | | 71 | #include <sys/userret.h> |
| @@ -114,30 +114,26 @@ install_coproc_handler_static(int coproc | | | @@ -114,30 +114,26 @@ install_coproc_handler_static(int coproc |
114 | | | 114 | |
115 | LIST_INSERT_HEAD(&undefined_handlers[coproc], uh, uh_link); | | 115 | LIST_INSERT_HEAD(&undefined_handlers[coproc], uh, uh_link); |
116 | } | | 116 | } |
117 | | | 117 | |
118 | void | | 118 | void |
119 | remove_coproc_handler(void *cookie) | | 119 | remove_coproc_handler(void *cookie) |
120 | { | | 120 | { |
121 | struct undefined_handler *uh = cookie; | | 121 | struct undefined_handler *uh = cookie; |
122 | | | 122 | |
123 | LIST_REMOVE(uh, uh_link); | | 123 | LIST_REMOVE(uh, uh_link); |
124 | kmem_free(uh, sizeof(*uh)); | | 124 | kmem_free(uh, sizeof(*uh)); |
125 | } | | 125 | } |
126 | | | 126 | |
127 | static struct evcnt cp15_ev = | | | |
128 | EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, NULL, "cpu0", "undefined cp15 insn traps"); | | | |
129 | EVCNT_ATTACH_STATIC(cp15_ev); | | | |
130 | | | | |
131 | static int | | 127 | static int |
132 | cp15_trapper(u_int addr, u_int insn, struct trapframe *tf, int code) | | 128 | cp15_trapper(u_int addr, u_int insn, struct trapframe *tf, int code) |
133 | { | | 129 | { |
134 | struct lwp * const l = curlwp; | | 130 | struct lwp * const l = curlwp; |
135 | | | 131 | |
136 | #if defined(THUMB_CODE) && !defined(CPU_ARMV7) | | 132 | #if defined(THUMB_CODE) && !defined(CPU_ARMV7) |
137 | if (tf->tf_spsr & PSR_T_bit) | | 133 | if (tf->tf_spsr & PSR_T_bit) |
138 | return 1; | | 134 | return 1; |
139 | #endif | | 135 | #endif |
140 | if (code != FAULT_USER) | | 136 | if (code != FAULT_USER) |
141 | return 1; | | 137 | return 1; |
142 | | | 138 | |
143 | /* | | 139 | /* |
| @@ -148,41 +144,41 @@ cp15_trapper(u_int addr, u_int insn, str | | | @@ -148,41 +144,41 @@ cp15_trapper(u_int addr, u_int insn, str |
148 | return 1; | | 144 | return 1; |
149 | | | 145 | |
150 | /* | | 146 | /* |
151 | * Get a pointer to the register used in the instruction to be emulated. | | 147 | * Get a pointer to the register used in the instruction to be emulated. |
152 | */ | | 148 | */ |
153 | register_t * const regp = &tf->tf_r0 + regno; | | 149 | register_t * const regp = &tf->tf_r0 + regno; |
154 | | | 150 | |
155 | /* | | 151 | /* |
156 | * Handle MRC p15, 0, <Rd>, c13, c0, 3 (Read User read-only thread id) | | 152 | * Handle MRC p15, 0, <Rd>, c13, c0, 3 (Read User read-only thread id) |
157 | */ | | 153 | */ |
158 | if ((insn & 0xffff0fff) == 0xee1d0f70) { | | 154 | if ((insn & 0xffff0fff) == 0xee1d0f70) { |
159 | *regp = (uintptr_t)l->l_private; | | 155 | *regp = (uintptr_t)l->l_private; |
160 | tf->tf_pc += INSN_SIZE; | | 156 | tf->tf_pc += INSN_SIZE; |
161 | cp15_ev.ev_count++; | | 157 | curcpu()->ci_und_cp15_ev.ev_count++; |
162 | return 0; | | 158 | return 0; |
163 | } | | 159 | } |
164 | | | 160 | |
165 | /* | | 161 | /* |
166 | * Handle {MRC,MCR} p15, 0, <Rd>, c13, c0, 2 (User read/write thread id) | | 162 | * Handle {MRC,MCR} p15, 0, <Rd>, c13, c0, 2 (User read/write thread id) |
167 | */ | | 163 | */ |
168 | if ((insn & 0xffef0fff) == 0xee0d0f50) { | | 164 | if ((insn & 0xffef0fff) == 0xee0d0f50) { |
169 | struct pcb * const pcb = lwp_getpcb(l); | | 165 | struct pcb * const pcb = lwp_getpcb(l); |
170 | if (insn & 0x00100000) | | 166 | if (insn & 0x00100000) |
171 | *regp = pcb->pcb_user_pid_rw; | | 167 | *regp = pcb->pcb_user_pid_rw; |
172 | else | | 168 | else |
173 | pcb->pcb_user_pid_rw = *regp; | | 169 | pcb->pcb_user_pid_rw = *regp; |
174 | tf->tf_pc += INSN_SIZE; | | 170 | tf->tf_pc += INSN_SIZE; |
175 | cp15_ev.ev_count++; | | 171 | curcpu()->ci_und_cp15_ev.ev_count++; |
176 | return 0; | | 172 | return 0; |
177 | } | | 173 | } |
178 | | | 174 | |
179 | return 1; | | 175 | return 1; |
180 | } | | 176 | } |
181 | | | 177 | |
182 | static int | | 178 | static int |
183 | gdb_trapper(u_int addr, u_int insn, struct trapframe *tf, int code) | | 179 | gdb_trapper(u_int addr, u_int insn, struct trapframe *tf, int code) |
184 | { | | 180 | { |
185 | struct lwp * const l = curlwp; | | 181 | struct lwp * const l = curlwp; |
186 | | | 182 | |
187 | #ifdef THUMB_CODE | | 183 | #ifdef THUMB_CODE |
188 | if (tf->tf_spsr & PSR_T_bit) { | | 184 | if (tf->tf_spsr & PSR_T_bit) { |
| @@ -272,45 +268,41 @@ undefined_init(void) | | | @@ -272,45 +268,41 @@ undefined_init(void) |
272 | /* Install handler for CP15 emulation */ | | 268 | /* Install handler for CP15 emulation */ |
273 | cp15_uh.uh_handler = cp15_trapper; | | 269 | cp15_uh.uh_handler = cp15_trapper; |
274 | install_coproc_handler_static(SYSTEM_COPROC, &cp15_uh); | | 270 | install_coproc_handler_static(SYSTEM_COPROC, &cp15_uh); |
275 | | | 271 | |
276 | /* Install handler for GDB breakpoints */ | | 272 | /* Install handler for GDB breakpoints */ |
277 | gdb_uh.uh_handler = gdb_trapper; | | 273 | gdb_uh.uh_handler = gdb_trapper; |
278 | install_coproc_handler_static(CORE_UNKNOWN_HANDLER, &gdb_uh); | | 274 | install_coproc_handler_static(CORE_UNKNOWN_HANDLER, &gdb_uh); |
279 | #ifdef THUMB_CODE | | 275 | #ifdef THUMB_CODE |
280 | gdb_uh_thumb.uh_handler = gdb_trapper; | | 276 | gdb_uh_thumb.uh_handler = gdb_trapper; |
281 | install_coproc_handler_static(THUMB_UNKNOWN_HANDLER, &gdb_uh_thumb); | | 277 | install_coproc_handler_static(THUMB_UNKNOWN_HANDLER, &gdb_uh_thumb); |
282 | #endif | | 278 | #endif |
283 | } | | 279 | } |
284 | | | 280 | |
285 | static struct evcnt und_ev = | | | |
286 | EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, NULL, "cpu0", "undefined insn traps"); | | | |
287 | EVCNT_ATTACH_STATIC(und_ev); | | | |
288 | | | | |
289 | void | | 281 | void |
290 | undefinedinstruction(trapframe_t *tf) | | 282 | undefinedinstruction(trapframe_t *tf) |
291 | { | | 283 | { |
292 | struct lwp *l; | | 284 | struct lwp *l; |
293 | vaddr_t fault_pc; | | 285 | vaddr_t fault_pc; |
294 | int fault_instruction; | | 286 | int fault_instruction; |
295 | int fault_code; | | 287 | int fault_code; |
296 | int coprocessor; | | 288 | int coprocessor; |
297 | int user; | | 289 | int user; |
298 | struct undefined_handler *uh; | | 290 | struct undefined_handler *uh; |
299 | #ifdef VERBOSE_ARM32 | | 291 | #ifdef VERBOSE_ARM32 |
300 | int s; | | 292 | int s; |
301 | #endif | | 293 | #endif |
302 | | | 294 | |
303 | und_ev.ev_count++; | | 295 | curcpu()->ci_und_ev.ev_count++; |
304 | | | 296 | |
305 | #ifdef KDTRACE_HOOKS | | 297 | #ifdef KDTRACE_HOOKS |
306 | if ((tf->tf_spsr & PSR_MODE) != PSR_USR32_MODE) { | | 298 | if ((tf->tf_spsr & PSR_MODE) != PSR_USR32_MODE) { |
307 | tf->tf_pc -= INSN_SIZE; | | 299 | tf->tf_pc -= INSN_SIZE; |
308 | if (dtrace_trapper(tf->tf_pc, tf) == 0) | | 300 | if (dtrace_trapper(tf->tf_pc, tf) == 0) |
309 | return; | | 301 | return; |
310 | tf->tf_pc += INSN_SIZE; /* Reset for the rest code */ | | 302 | tf->tf_pc += INSN_SIZE; /* Reset for the rest code */ |
311 | } | | 303 | } |
312 | #endif | | 304 | #endif |
313 | | | 305 | |
314 | /* Enable interrupts if they were enabled before the exception. */ | | 306 | /* Enable interrupts if they were enabled before the exception. */ |
315 | #ifdef acorn26 | | 307 | #ifdef acorn26 |
316 | if ((tf->tf_r15 & R15_IRQ_DISABLE) == 0) | | 308 | if ((tf->tf_r15 & R15_IRQ_DISABLE) == 0) |