exception.c revision 1.31
1/* $NetBSD: exception.c,v 1.31 2006/07/22 22:43:43 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.31 2006/07/22 22:43:43 uwe Exp $"); 83 84#include "opt_ddb.h" 85#include "opt_kgdb.h" 86#include "opt_ktrace.h" 87 88#include <sys/param.h> 89#include <sys/systm.h> 90#include <sys/proc.h> 91#include <sys/pool.h> 92#include <sys/user.h> 93#include <sys/kernel.h> 94#include <sys/signal.h> 95#include <sys/syscall.h> 96#include <sys/sa.h> 97#include <sys/savar.h> 98 99#ifdef KTRACE 100#include <sys/ktrace.h> 101#endif 102#ifdef DDB 103#include <sh3/db_machdep.h> 104#endif 105#ifdef KGDB 106#include <sys/kgdb.h> 107#endif 108 109#include <uvm/uvm_extern.h> 110 111#include <sh3/cpu.h> 112#include <sh3/mmu.h> 113#include <sh3/exception.h> 114#include <sh3/userret.h> 115 116const char * const exp_type[] = { 117 "--", /* 0x000 (reset vector) */ 118 "--", /* 0x020 (reset vector) */ 119 "TLB miss/invalid (load)", /* 0x040 EXPEVT_TLB_MISS_LD */ 120 "TLB miss/invalid (store)", /* 0x060 EXPEVT_TLB_MISS_ST */ 121 "initial page write", /* 0x080 EXPEVT_TLB_MOD */ 122 "TLB protection violation (load)", /* 0x0a0 EXPEVT_TLB_PROT_LD */ 123 "TLB protection violation (store)", /* 0x0c0 EXPEVT_TLB_PROT_ST */ 124 "address error (load)", /* 0x0e0 EXPEVT_ADDR_ERR_LD */ 125 "address error (store)", /* 0x100 EXPEVT_ADDR_ERR_ST */ 126 "FPU", /* 0x120 EXPEVT_FPU */ 127 "--", /* 0x140 (reset vector) */ 128 "unconditional trap (TRAPA)", /* 0x160 EXPEVT_TRAPA */ 129 "reserved instruction code exception", /* 0x180 EXPEVT_RES_INST */ 130 "illegal slot instruction exception", /* 0x1a0 EXPEVT_SLOT_INST */ 131 "--", /* 0x1c0 (external interrupt) */ 132 "user break point trap", /* 0x1e0 EXPEVT_BREAK */ 133}; 134const int exp_types = sizeof exp_type / sizeof exp_type[0]; 135 136void general_exception(struct lwp *, struct trapframe *, uint32_t); 137void tlb_exception(struct lwp *, struct trapframe *, uint32_t); 138void ast(struct lwp *, struct trapframe *); 139 140/* 141 * void general_exception(struct lwp *l, struct trapframe *tf): 142 * l ... curlwp when exception occur. 143 * tf ... full user context. 144 * va ... fault va for user mode EXPEVT_ADDR_ERR_{LD,ST} 145 */ 146void 147general_exception(struct lwp *l, struct trapframe *tf, uint32_t va) 148{ 149 int expevt = tf->tf_expevt; 150 boolean_t usermode = !KERNELMODE(tf->tf_ssr); 151 ksiginfo_t ksi; 152 153 uvmexp.traps++; 154 155 if (l == NULL) 156 goto do_panic; 157 158 if (usermode) { 159 KDASSERT(l->l_md.md_regs == tf); /* check exception depth */ 160 expevt |= EXP_USER; 161 LWP_CACHE_CREDS(l, l->l_proc); 162 } 163 164 switch (expevt) { 165 case EXPEVT_TRAPA | EXP_USER: 166 /* Check for debugger break */ 167 if (_reg_read_4(SH_(TRA)) == (_SH_TRA_BREAK << 2)) { 168 tf->tf_spc -= 2; /* back to the breakpoint address */ 169 KSI_INIT_TRAP(&ksi); 170 ksi.ksi_signo = SIGTRAP; 171 ksi.ksi_code = TRAP_BRKPT; 172 ksi.ksi_addr = (void *)tf->tf_spc; 173 goto trapsignal; 174 } else { 175 /* XXX: we shouldn't treat *any* TRAPA as a syscall */ 176 (*l->l_proc->p_md.md_syscall)(l, tf); 177 return; 178 } 179 break; 180 181 case EXPEVT_ADDR_ERR_LD: /* FALLTHROUGH */ 182 case EXPEVT_ADDR_ERR_ST: 183 KDASSERT(l->l_md.md_pcb->pcb_onfault != NULL); 184 tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault; 185 if (tf->tf_spc == 0) 186 goto do_panic; 187 break; 188 189 case EXPEVT_ADDR_ERR_LD | EXP_USER: /* FALLTHROUGH */ 190 case EXPEVT_ADDR_ERR_ST | EXP_USER: 191 KSI_INIT_TRAP(&ksi); 192 if (((int)va) < 0) { 193 ksi.ksi_signo = SIGSEGV; 194 ksi.ksi_code = SEGV_ACCERR; 195 } else { 196 ksi.ksi_signo = SIGBUS; 197 ksi.ksi_code = BUS_ADRALN; 198 } 199 ksi.ksi_addr = (void *)va; 200 goto trapsignal; 201 202 case EXPEVT_RES_INST | EXP_USER: /* FALLTHROUGH */ 203 case EXPEVT_SLOT_INST | EXP_USER: 204 KSI_INIT_TRAP(&ksi); 205 ksi.ksi_signo = SIGILL; 206 ksi.ksi_code = ILL_ILLOPC; /* XXX: could be ILL_PRVOPC */ 207 ksi.ksi_addr = (void *)tf->tf_spc; 208 goto trapsignal; 209 210 case EXPEVT_BREAK | EXP_USER: 211 KSI_INIT_TRAP(&ksi); 212 ksi.ksi_signo = SIGTRAP; 213 ksi.ksi_code = TRAP_TRACE; 214 ksi.ksi_addr = (void *)tf->tf_spc; 215 goto trapsignal; 216 217 default: 218 goto do_panic; 219 } 220 221 if (usermode) 222 userret(l); 223 return; 224 225 trapsignal: 226 ksi.ksi_trap = tf->tf_expevt; 227 KERNEL_PROC_LOCK(l); 228 trapsignal(l, &ksi); 229 KERNEL_PROC_UNLOCK(l); 230 userret(l); 231 return; 232 233 do_panic: 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 if (expevt >> 5 < exp_types) 243 printf("fatal %s", exp_type[expevt >> 5]); 244 else 245 printf("EXPEVT 0x%03x", expevt); 246 printf(" in %s mode\n", expevt & EXP_USER ? "user" : "kernel"); 247 printf(" spc %x ssr %x \n", tf->tf_spc, tf->tf_ssr); 248 249 panic("general_exception"); 250 251 for (;;) 252 continue; 253 /* NOTREACHED */ 254} 255 256 257/* 258 * void tlb_exception(struct lwp *l, struct trapframe *tf, uint32_t va): 259 * l ... curlwp when exception occur. 260 * tf ... full user context. 261 * va ... fault address. 262 */ 263void 264tlb_exception(struct lwp *l, struct trapframe *tf, uint32_t va) 265{ 266 struct vm_map *map; 267 pmap_t pmap; 268 ksiginfo_t ksi; 269 boolean_t usermode; 270 int err, track, ftype; 271 const char *panic_msg; 272 273#define TLB_ASSERT(assert, msg) \ 274 do { \ 275 if (!(assert)) { \ 276 panic_msg = msg; \ 277 goto tlb_panic; \ 278 } \ 279 } while(/*CONSTCOND*/0) 280 281 282 usermode = !KERNELMODE(tf->tf_ssr); 283 if (usermode) { 284 KDASSERT(l->l_md.md_regs == tf); 285 LWP_CACHE_CREDS(l, l->l_proc); 286 } else { 287 KDASSERT(l == NULL || /* idle */ 288 l == &lwp0 || /* kthread */ 289 l->l_md.md_regs != tf); /* other */ 290 } 291 292 switch (tf->tf_expevt) { 293 case EXPEVT_TLB_MISS_LD: 294 track = PVH_REFERENCED; 295 ftype = VM_PROT_READ; 296 break; 297 case EXPEVT_TLB_MISS_ST: 298 track = PVH_REFERENCED; 299 ftype = VM_PROT_WRITE; 300 break; 301 case EXPEVT_TLB_MOD: 302 track = PVH_REFERENCED | PVH_MODIFIED; 303 ftype = VM_PROT_WRITE; 304 break; 305 case EXPEVT_TLB_PROT_LD: 306 TLB_ASSERT((int)va > 0, 307 "kernel virtual protection fault (load)"); 308 if (usermode) { 309 KSI_INIT_TRAP(&ksi); 310 ksi.ksi_signo = SIGSEGV; 311 ksi.ksi_code = SEGV_ACCERR; 312 ksi.ksi_addr = (void *)va; 313 goto user_fault; 314 } else { 315 TLB_ASSERT(l && l->l_md.md_pcb->pcb_onfault != NULL, 316 "no copyin/out fault handler (load protection)"); 317 tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault; 318 } 319 return; 320 321 case EXPEVT_TLB_PROT_ST: 322 track = 0; /* call uvm_fault first. (COW) */ 323 ftype = VM_PROT_WRITE; 324 break; 325 326 default: 327 TLB_ASSERT(0, "impossible expevt"); 328 } 329 330 /* Select address space */ 331 if (usermode) { 332 TLB_ASSERT(l != NULL, "no curlwp"); 333 map = &l->l_proc->p_vmspace->vm_map; 334 pmap = map->pmap; 335 } else { 336 if ((int)va < 0) { 337 map = kernel_map; 338 pmap = pmap_kernel(); 339 } else { 340 TLB_ASSERT(l != NULL && 341 l->l_md.md_pcb->pcb_onfault != NULL, 342 "invalid user-space access from kernel mode"); 343 if (va == 0) { 344 tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault; 345 return; 346 } 347 map = &l->l_proc->p_vmspace->vm_map; 348 pmap = map->pmap; 349 } 350 } 351 352 /* Lookup page table. if entry found, load it. */ 353 if (track && __pmap_pte_load(pmap, va, track)) { 354 if (usermode) 355 userret(l); 356 return; 357 } 358 359 /* Page not found. call fault handler */ 360 if (!usermode && pmap != pmap_kernel() && 361 l->l_md.md_pcb->pcb_faultbail) { 362 TLB_ASSERT(l->l_md.md_pcb->pcb_onfault != NULL, 363 "no copyin/out fault handler (interrupt context)"); 364 tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault; 365 return; 366 } 367 368 if ((map != kernel_map) && (l->l_flag & L_SA)) { 369 l->l_savp->savp_faultaddr = (vaddr_t)va; 370 l->l_flag |= L_SA_PAGEFAULT; 371 } 372 373 err = uvm_fault(map, va, ftype); 374 375 /* User stack extension */ 376 if (map != kernel_map && 377 (va >= (vaddr_t)l->l_proc->p_vmspace->vm_maxsaddr) && 378 (va < USRSTACK)) { 379 if (err == 0) { 380 struct vmspace *vm = l->l_proc->p_vmspace; 381 uint32_t nss; 382 nss = btoc(USRSTACK - va); 383 if (nss > vm->vm_ssize) 384 vm->vm_ssize = nss; 385 } else if (err == EACCES) { 386 err = EFAULT; 387 } 388 } 389 390 if (map != kernel_map) 391 l->l_flag &= ~L_SA_PAGEFAULT; 392 /* Page in. load PTE to TLB. */ 393 if (err == 0) { 394 boolean_t loaded = __pmap_pte_load(pmap, va, track); 395 TLB_ASSERT(loaded, "page table entry not found"); 396 if (usermode) 397 userret(l); 398 return; 399 } 400 401 /* Page not found. */ 402 if (usermode) { 403 KSI_INIT_TRAP(&ksi); 404 if (err == ENOMEM) 405 ksi.ksi_signo = SIGKILL; 406 else { 407 ksi.ksi_signo = SIGSEGV; 408 ksi.ksi_code = SEGV_MAPERR; 409 } 410 goto user_fault; 411 } else { 412 TLB_ASSERT(l->l_md.md_pcb->pcb_onfault, 413 "no copyin/out fault handler (page not found)"); 414 tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault; 415 } 416 return; 417 418 user_fault: 419 ksi.ksi_trap = tf->tf_expevt 420 KERNEL_PROC_LOCK(l); 421 trapsignal(l, &ksi); 422 KERNEL_PROC_UNLOCK(l); 423 userret(l); 424 ast(l, tf); 425 return; 426 427 tlb_panic: 428 panic("tlb_exception: %s\n" 429 "expevt=%x va=%08x ssr=%08x spc=%08x lwp=%p onfault=%p", 430 panic_msg, tf->tf_expevt, va, tf->tf_ssr, tf->tf_spc, 431 l, l ? l->l_md.md_pcb->pcb_onfault : NULL); 432#undef TLB_ASSERT 433} 434 435 436/* 437 * void ast(struct lwp *l, struct trapframe *tf): 438 * l ... curlwp when exception occur. 439 * tf ... full user context. 440 * This is called when exception return. if return from kernel to user, 441 * handle asynchronous software traps and context switch if needed. 442 */ 443void 444ast(struct lwp *l, struct trapframe *tf) 445{ 446 struct proc *p; 447 448 if (KERNELMODE(tf->tf_ssr)) 449 return; 450 KDASSERT(l != NULL); 451 KDASSERT(l->l_md.md_regs == tf); 452 453 p = l->l_proc; 454 455 while (p->p_md.md_astpending) { 456 uvmexp.softs++; 457 p->p_md.md_astpending = 0; 458 459 if (p->p_flag & P_OWEUPC) { 460 p->p_flag &= ~P_OWEUPC; 461 ADDUPROF(p); 462 } 463 464 if (want_resched) { 465 /* We are being preempted. */ 466 preempt(0); 467 } 468 469 userret(l); 470 } 471} 472 473/* 474 * void child_return(void *arg): 475 * 476 * uvm_fork sets this routine to proc_trampoline's service function. 477 * when return from here, jump to user-land. 478 */ 479void 480child_return(void *arg) 481{ 482 struct lwp *l = arg; 483#ifdef KTRACE 484 struct proc *p = l->l_proc; 485#endif 486 struct trapframe *tf = l->l_md.md_regs; 487 488 tf->tf_r0 = 0; 489 tf->tf_ssr |= PSL_TBIT; /* This indicates no error. */ 490 491 userret(l); 492#ifdef KTRACE 493 if (KTRPOINT(p, KTR_SYSRET)) 494 ktrsysret(l, SYS_fork, 0, 0); 495#endif 496} 497 498/* 499 * void startlwp(void *arg): 500 * 501 * Start a new LWP. 502 */ 503void 504startlwp(void *arg) 505{ 506 ucontext_t *uc = arg; 507 struct lwp *l = curlwp; 508 int error; 509 510 error = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags); 511#ifdef DIAGNOSTIC 512 if (error) 513 printf("startlwp: error %d from cpu_setmcontext()", error); 514#endif 515 pool_put(&lwp_uc_pool, uc); 516 517 userret(l); 518} 519 520/* 521 * void upcallret(struct lwp *l): 522 * 523 * Perform userret() for an LWP. 524 * XXX This is a terrible name. 525 */ 526void 527upcallret(struct lwp *l) 528{ 529 530 userret(l); 531} 532