exception.c revision 1.44
1/* $NetBSD: exception.c,v 1.44 2008/01/08 01:25:13 uwe Exp $ */ 2 3/*- 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. All rights reserved. 5 * Copyright (c) 1990 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * the University of Utah, and William Jolitz. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 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 21 * without specific prior written permission. 22 * 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 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 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 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 33 * SUCH DAMAGE. 34 * 35 * @(#)trap.c 7.4 (Berkeley) 5/13/91 36 */ 37 38/*- 39 * Copyright (c) 1995 Charles M. Hannum. All rights reserved. 40 * 41 * This code is derived from software contributed to Berkeley by 42 * the University of Utah, and William Jolitz. 43 * 44 * Redistribution and use in source and binary forms, with or without 45 * modification, are permitted provided that the following conditions 46 * are met: 47 * 1. Redistributions of source code must retain the above copyright 48 * notice, this list of conditions and the following disclaimer. 49 * 2. Redistributions in binary form must reproduce the above copyright 50 * notice, this list of conditions and the following disclaimer in the 51 * documentation and/or other materials provided with the distribution. 52 * 3. All advertising materials mentioning features or use of this software 53 * must display the following acknowledgement: 54 * This product includes software developed by the University of 55 * California, Berkeley and its contributors. 56 * 4. Neither the name of the University nor the names of its contributors 57 * may be used to endorse or promote products derived from this software 58 * without specific prior written permission. 59 * 60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 70 * SUCH DAMAGE. 71 * 72 * @(#)trap.c 7.4 (Berkeley) 5/13/91 73 */ 74 75/* 76 * SH3 Trap and System call handling 77 * 78 * T.Horiuchi 1998.06.8 79 */ 80 81#include <sys/cdefs.h> 82__KERNEL_RCSID(0, "$NetBSD: exception.c,v 1.44 2008/01/08 01:25:13 uwe Exp $"); 83 84#include "opt_ddb.h" 85#include "opt_kgdb.h" 86 87#include <sys/param.h> 88#include <sys/systm.h> 89#include <sys/kernel.h> 90#include <sys/user.h> 91#include <sys/proc.h> 92#include <sys/signal.h> 93 94#ifdef DDB 95#include <sh3/db_machdep.h> 96#endif 97#ifdef KGDB 98#include <sys/kgdb.h> 99#endif 100 101#include <uvm/uvm_extern.h> 102 103#include <sh3/cpu.h> 104#include <sh3/mmu.h> 105#include <sh3/exception.h> 106#include <sh3/userret.h> 107 108const char * const exp_type[] = { 109 "--", /* 0x000 (reset vector) */ 110 "--", /* 0x020 (reset vector) */ 111 "TLB miss/invalid (load)", /* 0x040 EXPEVT_TLB_MISS_LD */ 112 "TLB miss/invalid (store)", /* 0x060 EXPEVT_TLB_MISS_ST */ 113 "initial page write", /* 0x080 EXPEVT_TLB_MOD */ 114 "TLB protection violation (load)", /* 0x0a0 EXPEVT_TLB_PROT_LD */ 115 "TLB protection violation (store)", /* 0x0c0 EXPEVT_TLB_PROT_ST */ 116 "address error (load)", /* 0x0e0 EXPEVT_ADDR_ERR_LD */ 117 "address error (store)", /* 0x100 EXPEVT_ADDR_ERR_ST */ 118 "FPU", /* 0x120 EXPEVT_FPU */ 119 "--", /* 0x140 (reset vector) */ 120 "unconditional trap (TRAPA)", /* 0x160 EXPEVT_TRAPA */ 121 "reserved instruction code exception", /* 0x180 EXPEVT_RES_INST */ 122 "illegal slot instruction exception", /* 0x1a0 EXPEVT_SLOT_INST */ 123 "--", /* 0x1c0 (external interrupt) */ 124 "user break point trap", /* 0x1e0 EXPEVT_BREAK */ 125}; 126const int exp_types = sizeof exp_type / sizeof exp_type[0]; 127 128void general_exception(struct lwp *, struct trapframe *, uint32_t); 129void tlb_exception(struct lwp *, struct trapframe *, uint32_t); 130void ast(struct lwp *, struct trapframe *); 131 132/* 133 * void general_exception(struct lwp *l, struct trapframe *tf): 134 * l ... curlwp when exception occur. 135 * tf ... full user context. 136 * va ... fault va for user mode EXPEVT_ADDR_ERR_{LD,ST} 137 */ 138void 139general_exception(struct lwp *l, struct trapframe *tf, uint32_t va) 140{ 141 int expevt = tf->tf_expevt; 142 bool usermode = !KERNELMODE(tf->tf_ssr); 143 ksiginfo_t ksi; 144 145 uvmexp.traps++; 146 147 splx(tf->tf_ssr & PSL_IMASK); 148 149 if (l == NULL) 150 goto do_panic; 151 152 if (usermode) { 153 KDASSERT(l->l_md.md_regs == tf); /* check exception depth */ 154 expevt |= EXP_USER; 155 LWP_CACHE_CREDS(l, l->l_proc); 156 } 157 158 switch (expevt) { 159 case EXPEVT_TRAPA | EXP_USER: 160 /* Check for debugger break */ 161 if (_reg_read_4(SH_(TRA)) == (_SH_TRA_BREAK << 2)) { 162 tf->tf_spc -= 2; /* back to the breakpoint address */ 163 KSI_INIT_TRAP(&ksi); 164 ksi.ksi_signo = SIGTRAP; 165 ksi.ksi_code = TRAP_BRKPT; 166 ksi.ksi_addr = (void *)tf->tf_spc; 167 goto trapsignal; 168 } else { 169 /* XXX: we shouldn't treat *any* TRAPA as a syscall */ 170 (*l->l_proc->p_md.md_syscall)(l, tf); 171 return; 172 } 173 break; 174 175 case EXPEVT_ADDR_ERR_LD: /* FALLTHROUGH */ 176 case EXPEVT_ADDR_ERR_ST: 177 KDASSERT(l->l_md.md_pcb->pcb_onfault != NULL); 178 tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault; 179 if (tf->tf_spc == 0) 180 goto do_panic; 181 break; 182 183 case EXPEVT_ADDR_ERR_LD | EXP_USER: /* FALLTHROUGH */ 184 case EXPEVT_ADDR_ERR_ST | EXP_USER: 185 KSI_INIT_TRAP(&ksi); 186 if (((int)va) < 0) { 187 ksi.ksi_signo = SIGSEGV; 188 ksi.ksi_code = SEGV_ACCERR; 189 } else { 190 ksi.ksi_signo = SIGBUS; 191 ksi.ksi_code = BUS_ADRALN; 192 } 193 ksi.ksi_addr = (void *)va; 194 goto trapsignal; 195 196 case EXPEVT_RES_INST | EXP_USER: /* FALLTHROUGH */ 197 case EXPEVT_SLOT_INST | EXP_USER: 198 KSI_INIT_TRAP(&ksi); 199 ksi.ksi_signo = SIGILL; 200 ksi.ksi_code = ILL_ILLOPC; /* XXX: could be ILL_PRVOPC */ 201 ksi.ksi_addr = (void *)tf->tf_spc; 202 goto trapsignal; 203 204 case EXPEVT_BREAK | EXP_USER: 205 KSI_INIT_TRAP(&ksi); 206 ksi.ksi_signo = SIGTRAP; 207 ksi.ksi_code = TRAP_TRACE; 208 ksi.ksi_addr = (void *)tf->tf_spc; 209 goto trapsignal; 210 211 default: 212 goto do_panic; 213 } 214 215 if (usermode) 216 userret(l); 217 return; 218 219 trapsignal: 220 ksi.ksi_trap = tf->tf_expevt; 221 KERNEL_LOCK(l, 1); 222 trapsignal(l, &ksi); 223 KERNEL_UNLOCK_LAST(l); 224 userret(l); 225 return; 226 227 do_panic: 228 if (expevt >> 5 < exp_types) 229 printf("fatal %s", exp_type[expevt >> 5]); 230 else 231 printf("EXPEVT 0x%03x", expevt); 232 printf(" in %s mode\n", expevt & EXP_USER ? "user" : "kernel"); 233 printf(" spc %x ssr %x \n", tf->tf_spc, tf->tf_ssr); 234#ifdef DDB 235 if (kdb_trap(expevt, 0, tf)) 236 return; 237#endif 238#ifdef KGDB 239 if (kgdb_trap(EXPEVT_BREAK, tf)) 240 return; 241#endif 242 243 panic("general_exception"); 244 /* NOTREACHED */ 245} 246 247 248/* 249 * void tlb_exception(struct lwp *l, struct trapframe *tf, uint32_t va): 250 * l ... curlwp when exception occur. 251 * tf ... full user context. 252 * va ... fault address. 253 */ 254void 255tlb_exception(struct lwp *l, struct trapframe *tf, uint32_t va) 256{ 257 struct vm_map *map; 258 pmap_t pmap; 259 ksiginfo_t ksi; 260 bool usermode; 261 int err, track, ftype; 262 const char *panic_msg; 263 264#define TLB_ASSERT(assert, msg) \ 265 do { \ 266 if (!(assert)) { \ 267 panic_msg = msg; \ 268 goto tlb_panic; \ 269 } \ 270 } while(/*CONSTCOND*/0) 271 272 splx(tf->tf_ssr & PSL_IMASK); 273 274 usermode = !KERNELMODE(tf->tf_ssr); 275 if (usermode) { 276 KDASSERT(l->l_md.md_regs == tf); 277 LWP_CACHE_CREDS(l, l->l_proc); 278 } else { 279#if 0 /* FIXME: probably wrong for yamt-idlelwp */ 280 KDASSERT(l == NULL || /* idle */ 281 l == &lwp0 || /* kthread */ 282 l->l_md.md_regs != tf); /* other */ 283#endif 284 } 285 286 switch (tf->tf_expevt) { 287 case EXPEVT_TLB_MISS_LD: 288 track = PVH_REFERENCED; 289 ftype = VM_PROT_READ; 290 break; 291 case EXPEVT_TLB_MISS_ST: 292 track = PVH_REFERENCED; 293 ftype = VM_PROT_WRITE; 294 break; 295 case EXPEVT_TLB_MOD: 296 track = PVH_REFERENCED | PVH_MODIFIED; 297 ftype = VM_PROT_WRITE; 298 break; 299 case EXPEVT_TLB_PROT_LD: 300 TLB_ASSERT((int)va > 0, 301 "kernel virtual protection fault (load)"); 302 if (usermode) { 303 KSI_INIT_TRAP(&ksi); 304 ksi.ksi_signo = SIGSEGV; 305 ksi.ksi_code = SEGV_ACCERR; 306 ksi.ksi_addr = (void *)va; 307 goto user_fault; 308 } else { 309 TLB_ASSERT(l && l->l_md.md_pcb->pcb_onfault != NULL, 310 "no copyin/out fault handler (load protection)"); 311 tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault; 312 } 313 return; 314 315 case EXPEVT_TLB_PROT_ST: 316 track = 0; /* call uvm_fault first. (COW) */ 317 ftype = VM_PROT_WRITE; 318 break; 319 320 default: 321 TLB_ASSERT(0, "impossible expevt"); 322 } 323 324 /* Select address space */ 325 if (usermode) { 326 TLB_ASSERT(l != NULL, "no curlwp"); 327 map = &l->l_proc->p_vmspace->vm_map; 328 pmap = map->pmap; 329 } else { 330 if ((int)va < 0) { 331 map = kernel_map; 332 pmap = pmap_kernel(); 333 } else { 334 TLB_ASSERT(l != NULL && 335 l->l_md.md_pcb->pcb_onfault != NULL, 336 "invalid user-space access from kernel mode"); 337 if (va == 0) { 338 tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault; 339 return; 340 } 341 map = &l->l_proc->p_vmspace->vm_map; 342 pmap = map->pmap; 343 } 344 } 345 346 /* Lookup page table. if entry found, load it. */ 347 if (track && __pmap_pte_load(pmap, va, track)) { 348 if (usermode) 349 userret(l); 350 return; 351 } 352 353 /* Page not found. call fault handler */ 354 if (!usermode && pmap != pmap_kernel() && 355 l->l_md.md_pcb->pcb_faultbail) { 356 TLB_ASSERT(l->l_md.md_pcb->pcb_onfault != NULL, 357 "no copyin/out fault handler (interrupt context)"); 358 tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault; 359 return; 360 } 361 362 err = uvm_fault(map, va, ftype); 363 364 /* User stack extension */ 365 if (map != kernel_map && 366 (va >= (vaddr_t)l->l_proc->p_vmspace->vm_maxsaddr) && 367 (va < USRSTACK)) { 368 if (err == 0) { 369 struct vmspace *vm = l->l_proc->p_vmspace; 370 uint32_t nss; 371 nss = btoc(USRSTACK - va); 372 if (nss > vm->vm_ssize) 373 vm->vm_ssize = nss; 374 } else if (err == EACCES) { 375 err = EFAULT; 376 } 377 } 378 379 /* Page in. load PTE to TLB. */ 380 if (err == 0) { 381 bool loaded = __pmap_pte_load(pmap, va, track); 382 TLB_ASSERT(loaded, "page table entry not found"); 383 if (usermode) 384 userret(l); 385 return; 386 } 387 388 /* Page not found. */ 389 if (usermode) { 390 KSI_INIT_TRAP(&ksi); 391 if (err == ENOMEM) 392 ksi.ksi_signo = SIGKILL; 393 else { 394 ksi.ksi_signo = SIGSEGV; 395 ksi.ksi_code = SEGV_MAPERR; 396 } 397 goto user_fault; 398 } else { 399 TLB_ASSERT(l->l_md.md_pcb->pcb_onfault, 400 "no copyin/out fault handler (page not found)"); 401 tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault; 402 } 403 return; 404 405 user_fault: 406 ksi.ksi_trap = tf->tf_expevt 407 KERNEL_LOCK(l, 1); 408 trapsignal(l, &ksi); 409 KERNEL_UNLOCK_LAST(l); 410 userret(l); 411 ast(l, tf); 412 return; 413 414 tlb_panic: 415 panic("tlb_exception: %s\n" 416 "expevt=%x va=%08x ssr=%08x spc=%08x lwp=%p onfault=%p", 417 panic_msg, tf->tf_expevt, va, tf->tf_ssr, tf->tf_spc, 418 l, l ? l->l_md.md_pcb->pcb_onfault : NULL); 419#undef TLB_ASSERT 420} 421 422 423/* 424 * void ast(struct lwp *l, struct trapframe *tf): 425 * l ... curlwp when exception occur. 426 * tf ... full user context. 427 * This is called when exception return. if return from kernel to user, 428 * handle asynchronous software traps and context switch if needed. 429 */ 430void 431ast(struct lwp *l, struct trapframe *tf) 432{ 433 434 if (KERNELMODE(tf->tf_ssr)) { 435 return; 436 } 437 438 KDASSERT(l != NULL); 439 KDASSERT(l->l_md.md_regs == tf); 440 441 while (l->l_md.md_astpending) { 442 uvmexp.softs++; 443 l->l_md.md_astpending = 0; 444 445 if (l->l_pflag & LP_OWEUPC) { 446 l->l_pflag &= ~LP_OWEUPC; 447 ADDUPROF(p); 448 } 449 450 if (l->l_cpu->ci_want_resched) { 451 /* We are being preempted. */ 452 preempt(); 453 } 454 455 userret(l); 456 } 457} 458