exception.c revision 1.69
1/* $NetBSD: exception.c,v 1.69 2019/11/29 18:27:33 ad 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.69 2019/11/29 18:27:33 ad 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/proc.h> 91#include <sys/signal.h> 92 93#ifdef DDB 94#include <sh3/db_machdep.h> 95#endif 96#ifdef KGDB 97#include <sys/kgdb.h> 98#endif 99 100#include <uvm/uvm_extern.h> 101 102#include <sh3/cpu.h> 103#include <sh3/mmu.h> 104#include <sh3/pcb.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 = __arraycount(exp_type); 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 struct pcb *pcb; 144 ksiginfo_t ksi; 145 uint32_t trapcode; 146#ifdef DDB 147 uint32_t code; 148#endif 149 150 curcpu()->ci_data.cpu_ntrap++; 151 152 /* 153 * Read trap code from TRA before enabling interrupts, 154 * otherwise it can be clobbered by a ddb breakpoint in an 155 * interrupt handler. 156 */ 157 trapcode = _reg_read_4(SH_(TRA)) >> 2; 158 159 splx(tf->tf_ssr & PSL_IMASK); 160 161 if (l == NULL) 162 goto do_panic; 163 164 if (usermode) { 165 KDASSERT(l->l_md.md_regs == tf); /* check exception depth */ 166 expevt |= EXP_USER; 167 LWP_CACHE_CREDS(l, l->l_proc); 168 } 169 170 switch (expevt) { 171 case EXPEVT_TRAPA | EXP_USER: 172 /* Check for debugger break */ 173 if (trapcode == _SH_TRA_BREAK) { 174 tf->tf_spc -= 2; /* back to the breakpoint address */ 175 KSI_INIT_TRAP(&ksi); 176 ksi.ksi_signo = SIGTRAP; 177 ksi.ksi_code = TRAP_BRKPT; 178 ksi.ksi_addr = (void *)tf->tf_spc; 179 goto trapsignal; 180 } else { 181 /* XXX: we shouldn't treat *any* TRAPA as a syscall */ 182 (*l->l_proc->p_md.md_syscall)(l, tf); 183 return; 184 } 185 break; 186 187 case EXPEVT_BREAK | EXP_USER: 188 l->l_md.md_flags &= ~MDL_SSTEP; 189 KSI_INIT_TRAP(&ksi); 190 ksi.ksi_signo = SIGTRAP; 191 ksi.ksi_code = TRAP_TRACE; 192 ksi.ksi_addr = (void *)tf->tf_spc; 193 goto trapsignal; 194 195 case EXPEVT_ADDR_ERR_LD: /* FALLTHROUGH */ 196 case EXPEVT_ADDR_ERR_ST: 197 pcb = lwp_getpcb(l); 198 KDASSERT(pcb->pcb_onfault != NULL); 199 tf->tf_spc = (int)pcb->pcb_onfault; 200 tf->tf_r0 = EFAULT; 201 if (tf->tf_spc == 0) 202 goto do_panic; 203 break; 204 205 case EXPEVT_ADDR_ERR_LD | EXP_USER: /* FALLTHROUGH */ 206 case EXPEVT_ADDR_ERR_ST | EXP_USER: 207 KSI_INIT_TRAP(&ksi); 208 if (((int)va) < 0) { 209 ksi.ksi_signo = SIGSEGV; 210 ksi.ksi_code = SEGV_ACCERR; 211 } else { 212 ksi.ksi_signo = SIGBUS; 213 ksi.ksi_code = BUS_ADRALN; 214 } 215 ksi.ksi_addr = (void *)va; 216 goto trapsignal; 217 218 case EXPEVT_RES_INST | EXP_USER: /* FALLTHROUGH */ 219 case EXPEVT_SLOT_INST | EXP_USER: 220 KSI_INIT_TRAP(&ksi); 221 ksi.ksi_signo = SIGILL; 222 ksi.ksi_code = ILL_ILLOPC; /* XXX: could be ILL_PRVOPC */ 223 ksi.ksi_addr = (void *)tf->tf_spc; 224 goto trapsignal; 225 226 default: 227 goto do_panic; 228 } 229 230 if (usermode) 231 userret(l); 232 return; 233 234 trapsignal: 235 ksi.ksi_trap = tf->tf_expevt; 236 trapsignal(l, &ksi); 237 userret(l); 238 return; 239 240 do_panic: 241#ifdef DDB 242 switch (expevt & ~EXP_USER) { 243 case EXPEVT_TRAPA: 244 code = trapcode; 245 break; 246 default: 247 code = 0; 248 break; 249 } 250 if (kdb_trap(expevt, code, tf)) 251 return; 252#endif 253#ifdef KGDB 254 if (kgdb_trap(EXPEVT_BREAK, tf)) 255 return; 256#endif 257 if (expevt >> 5 < exp_types) 258 printf("fatal %s", exp_type[expevt >> 5]); 259 else 260 printf("EXPEVT 0x%03x", expevt); 261 printf(" in %s mode\n", usermode ? "user" : "kernel"); 262 printf(" spc %x ssr %x \n", tf->tf_spc, tf->tf_ssr); 263 264 panic("general_exception"); 265 /* NOTREACHED */ 266} 267 268 269/* 270 * void tlb_exception(struct lwp *l, struct trapframe *tf, uint32_t va): 271 * l ... curlwp when exception occur. 272 * tf ... full user context. 273 * va ... fault address. 274 */ 275void 276tlb_exception(struct lwp *l, struct trapframe *tf, uint32_t va) 277{ 278 struct vm_map *map; 279 struct pcb *pcb; 280 pmap_t pmap; 281 void *onfault; 282 ksiginfo_t ksi; 283 bool usermode; 284 int err, track, ftype; 285 const char *panic_msg; 286 287 pcb = lwp_getpcb(l); 288 onfault = pcb->pcb_onfault; 289 290#define TLB_ASSERT(assert, msg) \ 291 do { \ 292 if (!(assert)) { \ 293 panic_msg = msg; \ 294 goto tlb_panic; \ 295 } \ 296 } while(/*CONSTCOND*/0) 297 298 splx(tf->tf_ssr & PSL_IMASK); 299 300 usermode = !KERNELMODE(tf->tf_ssr); 301 if (usermode) { 302 KDASSERT(l->l_md.md_regs == tf); 303 LWP_CACHE_CREDS(l, l->l_proc); 304 } else { 305#if 0 /* FIXME: probably wrong for yamt-idlelwp */ 306 KDASSERT(l == NULL || /* idle */ 307 l == &lwp0 || /* kthread */ 308 l->l_md.md_regs != tf); /* other */ 309#endif 310 } 311 312 switch (tf->tf_expevt) { 313 case EXPEVT_TLB_MISS_LD: 314 track = PVH_REFERENCED; 315 ftype = VM_PROT_READ; 316 break; 317 case EXPEVT_TLB_MISS_ST: 318 track = PVH_REFERENCED; 319 ftype = VM_PROT_WRITE; 320 break; 321 case EXPEVT_TLB_MOD: 322 track = PVH_REFERENCED | PVH_MODIFIED; 323 ftype = VM_PROT_WRITE; 324 break; 325 case EXPEVT_TLB_PROT_LD: 326 TLB_ASSERT((int)va > 0, 327 "kernel virtual protection fault (load)"); 328 if (usermode) { 329 KSI_INIT_TRAP(&ksi); 330 ksi.ksi_signo = SIGSEGV; 331 ksi.ksi_code = SEGV_ACCERR; 332 ksi.ksi_addr = (void *)va; 333 goto user_fault; 334 } else { 335 TLB_ASSERT(l && onfault != NULL, 336 "no copyin/out fault handler (load protection)"); 337 tf->tf_spc = (int)onfault; 338 tf->tf_r0 = EFAULT; 339 } 340 return; 341 342 case EXPEVT_TLB_PROT_ST: 343 track = 0; /* call uvm_fault first. (COW) */ 344 ftype = VM_PROT_WRITE; 345 break; 346 347 default: 348 TLB_ASSERT(0, "impossible expevt"); 349 } 350 351 /* Select address space */ 352 if (usermode) { 353 TLB_ASSERT(l != NULL, "no curlwp"); 354 map = &l->l_proc->p_vmspace->vm_map; 355 pmap = map->pmap; 356 } else { 357 if ((int)va < 0) { 358 map = kernel_map; 359 pmap = pmap_kernel(); 360 } else { 361 TLB_ASSERT(l != NULL && onfault != NULL, 362 "invalid user-space access from kernel mode"); 363 if (va == 0) { 364 tf->tf_spc = (int)onfault; 365 tf->tf_r0 = EFAULT; 366 return; 367 } 368 map = &l->l_proc->p_vmspace->vm_map; 369 pmap = map->pmap; 370 } 371 } 372 373 /* Lookup page table. if entry found, load it. */ 374 if (track && __pmap_pte_load(pmap, va, track)) { 375 if (usermode) 376 userret(l); 377 return; 378 } 379 380 /* Page not found. call fault handler */ 381 pcb->pcb_onfault = NULL; 382 err = uvm_fault(map, va, ftype); 383 pcb->pcb_onfault = onfault; 384 385 /* User stack extension */ 386 if (map != kernel_map && 387 (va >= (vaddr_t)l->l_proc->p_vmspace->vm_maxsaddr) && 388 (va < (vaddr_t)l->l_proc->p_vmspace->vm_minsaddr)) { 389 if (err == 0) { 390 struct vmspace *vm = l->l_proc->p_vmspace; 391 uint32_t nss; 392 nss = btoc((vaddr_t)vm->vm_minsaddr - va); 393 if (nss > vm->vm_ssize) 394 vm->vm_ssize = nss; 395 } else if (err == EACCES) { 396 err = EFAULT; 397 } 398 } 399 400 /* Page in. load PTE to TLB. */ 401 if (err == 0) { 402 bool loaded = __pmap_pte_load(pmap, va, track); 403 TLB_ASSERT(loaded, "page table entry not found"); 404 if (usermode) 405 userret(l); 406 return; 407 } 408 409 /* Page not found. */ 410 if (usermode) { 411 KSI_INIT_TRAP(&ksi); 412 ksi.ksi_addr = (void *)va; 413 414 switch (err) { 415 case ENOMEM: 416 ksi.ksi_signo = SIGKILL; 417 break; 418 case EINVAL: 419 ksi.ksi_signo = SIGBUS; 420 ksi.ksi_code = BUS_ADRERR; 421 break; 422 case EACCES: 423 ksi.ksi_signo = SIGSEGV; 424 ksi.ksi_code = SEGV_ACCERR; 425 break; 426 default: 427 ksi.ksi_signo = SIGSEGV; 428 ksi.ksi_code = SEGV_MAPERR; 429 break; 430 } 431 goto user_fault; 432 } else { 433 TLB_ASSERT(onfault, 434 "no copyin/out fault handler (page not found)"); 435 tf->tf_spc = (int)onfault; 436 tf->tf_r0 = err; 437 } 438 return; 439 440 user_fault: 441 ksi.ksi_trap = tf->tf_expevt; 442 trapsignal(l, &ksi); 443 userret(l); 444 ast(l, tf); 445 return; 446 447 tlb_panic: 448 panic("tlb_exception: %s\n" 449 "expevt=%x va=%08x ssr=%08x spc=%08x lwp=%p onfault=%p", 450 panic_msg, tf->tf_expevt, va, tf->tf_ssr, tf->tf_spc, 451 l, pcb->pcb_onfault); 452#undef TLB_ASSERT 453} 454 455 456/* 457 * void ast(struct lwp *l, struct trapframe *tf): 458 * l ... curlwp when exception occur. 459 * tf ... full user context. 460 * This is called when exception return. if return from kernel to user, 461 * handle asynchronous software traps and context switch if needed. 462 */ 463void 464ast(struct lwp *l, struct trapframe *tf) 465{ 466 467 if (KERNELMODE(tf->tf_ssr)) { 468 return; 469 } 470 471 KDASSERT(l != NULL); 472 KDASSERT(l->l_md.md_regs == tf); 473 474 userret(l); 475} 476