1 /* $NetBSD: trap.c,v 1.30 2024/11/25 22:04:14 skrll Exp $ */ 2 3 /*- 4 * Copyright (c) 2014 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matt Thomas of 3am Software Foundry. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 34 #define __PMAP_PRIVATE 35 #define __UFETCHSTORE_PRIVATE 36 37 __RCSID("$NetBSD: trap.c,v 1.30 2024/11/25 22:04:14 skrll Exp $"); 38 39 #include <sys/param.h> 40 41 #include <sys/atomic.h> 42 #include <sys/cpu.h> 43 #include <sys/kauth.h> 44 #include <sys/signal.h> 45 #include <sys/signalvar.h> 46 #include <sys/siginfo.h> 47 #include <sys/systm.h> 48 49 #include <uvm/uvm.h> 50 51 #include <machine/locore.h> 52 #include <machine/machdep.h> 53 #include <machine/db_machdep.h> 54 #include <machine/userret.h> 55 56 #define MACHINE_ECALL_TRAP_MASK (__BIT(CAUSE_MACHINE_ECALL)) 57 58 #define SUPERVISOR_ECALL_TRAP_MASK \ 59 (__BIT(CAUSE_SUPERVISOR_ECALL)) 60 61 #define USER_ECALL_TRAP_MASK (__BIT(CAUSE_USER_ECALL)) 62 63 #define SYSCALL_TRAP_MASK (__BIT(CAUSE_SYSCALL)) 64 65 #define BREAKPOINT_TRAP_MASK (__BIT(CAUSE_BREAKPOINT)) 66 67 #define INSTRUCTION_TRAP_MASK (__BIT(CAUSE_ILLEGAL_INSTRUCTION)) 68 69 #define FAULT_TRAP_MASK (__BIT(CAUSE_FETCH_ACCESS) \ 70 |__BIT(CAUSE_LOAD_ACCESS) \ 71 |__BIT(CAUSE_STORE_ACCESS) \ 72 |__BIT(CAUSE_FETCH_PAGE_FAULT) \ 73 |__BIT(CAUSE_LOAD_PAGE_FAULT) \ 74 |__BIT(CAUSE_STORE_PAGE_FAULT)) 75 76 #define MISALIGNED_TRAP_MASK (__BIT(CAUSE_FETCH_MISALIGNED) \ 77 |__BIT(CAUSE_LOAD_MISALIGNED) \ 78 |__BIT(CAUSE_STORE_MISALIGNED)) 79 80 static const char * const causenames[] = { 81 [CAUSE_FETCH_MISALIGNED] = "misaligned fetch", 82 [CAUSE_LOAD_MISALIGNED] = "misaligned load", 83 [CAUSE_STORE_MISALIGNED] = "misaligned store", 84 [CAUSE_FETCH_ACCESS] = "fetch", 85 [CAUSE_LOAD_ACCESS] = "load", 86 [CAUSE_STORE_ACCESS] = "store", 87 [CAUSE_ILLEGAL_INSTRUCTION] = "illegal instruction", 88 [CAUSE_BREAKPOINT] = "breakpoint", 89 [CAUSE_SYSCALL] = "syscall", 90 [CAUSE_FETCH_PAGE_FAULT] = "instruction page fault", 91 [CAUSE_LOAD_PAGE_FAULT] = "load page fault", 92 [CAUSE_STORE_PAGE_FAULT] = "store page fault", 93 }; 94 95 96 void 97 cpu_jump_onfault(struct trapframe *tf, const struct faultbuf *fb, int error) 98 { 99 tf->tf_a0 = error; 100 tf->tf_ra = fb->fb_reg[FB_RA]; 101 tf->tf_s0 = fb->fb_reg[FB_S0]; 102 tf->tf_s1 = fb->fb_reg[FB_S1]; 103 tf->tf_s2 = fb->fb_reg[FB_S2]; 104 tf->tf_s3 = fb->fb_reg[FB_S3]; 105 tf->tf_s4 = fb->fb_reg[FB_S4]; 106 tf->tf_s5 = fb->fb_reg[FB_S5]; 107 tf->tf_s6 = fb->fb_reg[FB_S6]; 108 tf->tf_s7 = fb->fb_reg[FB_S7]; 109 tf->tf_s8 = fb->fb_reg[FB_S8]; 110 tf->tf_s9 = fb->fb_reg[FB_S9]; 111 tf->tf_s10 = fb->fb_reg[FB_S10]; 112 tf->tf_s11 = fb->fb_reg[FB_S11]; 113 tf->tf_sp = fb->fb_reg[FB_SP]; 114 tf->tf_pc = fb->fb_reg[FB_RA]; 115 } 116 117 118 int 119 copyin(const void *uaddr, void *kaddr, size_t len) 120 { 121 struct faultbuf fb; 122 int error; 123 124 if (__predict_false(len == 0)) { 125 return 0; 126 } 127 128 // XXXNH cf. VM_MIN_ADDRESS and user_va0_disable 129 if (uaddr == NULL) 130 return EFAULT; 131 132 const vaddr_t uva = (vaddr_t)uaddr; 133 if (uva > VM_MAXUSER_ADDRESS - len) 134 return EFAULT; 135 136 csr_sstatus_set(SR_SUM); 137 if ((error = cpu_set_onfault(&fb)) == 0) { 138 memcpy(kaddr, uaddr, len); 139 cpu_unset_onfault(); 140 } 141 csr_sstatus_clear(SR_SUM); 142 143 return error; 144 } 145 146 int 147 copyout(const void *kaddr, void *uaddr, size_t len) 148 { 149 struct faultbuf fb; 150 int error; 151 152 if (__predict_false(len == 0)) { 153 return 0; 154 } 155 156 // XXXNH cf. VM_MIN_ADDRESS and user_va0_disable 157 if (uaddr == NULL) 158 return EFAULT; 159 160 const vaddr_t uva = (vaddr_t)uaddr; 161 if (uva > VM_MAXUSER_ADDRESS - len) 162 return EFAULT; 163 164 csr_sstatus_set(SR_SUM); 165 if ((error = cpu_set_onfault(&fb)) == 0) { 166 memcpy(uaddr, kaddr, len); 167 cpu_unset_onfault(); 168 } 169 csr_sstatus_clear(SR_SUM); 170 171 return error; 172 } 173 174 int 175 kcopy(const void *kfaddr, void *kdaddr, size_t len) 176 { 177 struct faultbuf fb; 178 int error; 179 180 if ((error = cpu_set_onfault(&fb)) == 0) { 181 memcpy(kdaddr, kfaddr, len); 182 cpu_unset_onfault(); 183 } 184 185 return error; 186 } 187 188 int 189 copyinstr(const void *uaddr, void *kaddr, size_t len, size_t *done) 190 { 191 struct faultbuf fb; 192 size_t retlen; 193 int error; 194 195 if (__predict_false(len == 0)) { 196 return 0; 197 } 198 199 if (__predict_false(uaddr == NULL)) 200 return EFAULT; 201 /* 202 * Can only check if starting user address is out of range here. 203 * The string may end before uva + len. 204 */ 205 const vaddr_t uva = (vaddr_t)uaddr; 206 if (uva > VM_MAXUSER_ADDRESS) 207 return EFAULT; 208 209 csr_sstatus_set(SR_SUM); 210 if ((error = cpu_set_onfault(&fb)) == 0) { 211 retlen = strlcpy(kaddr, uaddr, len); 212 cpu_unset_onfault(); 213 if (retlen >= len) { 214 error = ENAMETOOLONG; 215 } else if (done != NULL) { 216 *done = retlen + 1; 217 } 218 } 219 csr_sstatus_clear(SR_SUM); 220 221 return error; 222 } 223 224 int 225 copyoutstr(const void *kaddr, void *uaddr, size_t len, size_t *done) 226 { 227 struct faultbuf fb; 228 size_t retlen; 229 int error; 230 231 if (__predict_false(len == 0)) { 232 return 0; 233 } 234 235 if (__predict_false(uaddr == NULL)) 236 return EFAULT; 237 /* 238 * Can only check if starting user address is out of range here. 239 * The string may end before uva + len. 240 */ 241 const vaddr_t uva = (vaddr_t)uaddr; 242 if (uva > VM_MAXUSER_ADDRESS) 243 return EFAULT; 244 245 csr_sstatus_set(SR_SUM); 246 if ((error = cpu_set_onfault(&fb)) == 0) { 247 retlen = strlcpy(uaddr, kaddr, len); 248 cpu_unset_onfault(); 249 if (retlen >= len) { 250 error = ENAMETOOLONG; 251 } else if (done != NULL) { 252 *done = retlen + 1; 253 } 254 } 255 csr_sstatus_clear(SR_SUM); 256 257 return error; 258 } 259 260 static const char * 261 cause_name(register_t cause) 262 { 263 if (CAUSE_INTERRUPT_P(cause)) 264 return "interrupt"; 265 const char *name = "(unk)"; 266 if (cause < __arraycount(causenames) && causenames[cause] != NULL) 267 name = causenames[cause]; 268 269 return name; 270 } 271 272 void 273 dump_trapframe(const struct trapframe *tf, void (*pr)(const char *, ...)) 274 { 275 const char *name = cause_name(tf->tf_cause); 276 static const char *regname[] = { 277 "ra", "sp", "gp", // x0, x1, x2, x3, 278 "tp", "t0", "t1", "t2", // x4, x5, x6, x7, 279 "s0", "s1", "a0", "a1", // x8, x9, x10, x11, 280 "a2", "a3", "a4", "a5", // x12, x13, x14, x15, 281 "a6", "a7", "s2", "s3", // x16, x17, x18, x19, 282 "s4", "s5", "s6", "s7", // x20, x21, x22, x23, 283 "s8", "s9", "s10", "s11", // x24, x25, x26, x27, 284 "t3", "t4", "t5", "t6", // x28, x29, x30, x31, 285 }; 286 287 (*pr)("Trapframe @ %p " 288 "(cause=%d (%s), status=%#x, pc=%#18" PRIxREGISTER 289 ", va=%#" PRIxREGISTER "):\n", 290 tf, tf->tf_cause, name, tf->tf_sr, tf->tf_pc, tf->tf_tval); 291 292 (*pr)(" "); 293 for (unsigned reg = 1; reg < 32; reg++) { 294 (*pr)("%-3s=%#18" PRIxREGISTER " ", 295 regname[reg - 1], 296 tf->tf_regs.r_reg[reg - 1]); 297 if (reg % 4 == 3) 298 (*pr)("\n"); 299 } 300 } 301 302 static inline void 303 trap_ksi_init(ksiginfo_t *ksi, int signo, int code, vaddr_t addr, 304 register_t cause) 305 { 306 KSI_INIT_TRAP(ksi); 307 ksi->ksi_signo = signo; 308 ksi->ksi_code = code; 309 ksi->ksi_addr = (void *)addr; 310 ksi->ksi_trap = cause; 311 } 312 313 static void 314 cpu_trapsignal(struct trapframe *tf, ksiginfo_t *ksi) 315 { 316 if (cpu_printfataltraps) { 317 dump_trapframe(tf, printf); 318 } 319 (*curlwp->l_proc->p_emul->e_trapsignal)(curlwp, ksi); 320 } 321 322 static inline vm_prot_t 323 get_faulttype(register_t cause) 324 { 325 if (cause == CAUSE_LOAD_ACCESS || cause == CAUSE_LOAD_PAGE_FAULT) 326 return VM_PROT_READ; 327 if (cause == CAUSE_STORE_ACCESS || cause == CAUSE_STORE_PAGE_FAULT) 328 return VM_PROT_WRITE; 329 KASSERT(cause == CAUSE_FETCH_ACCESS || cause == CAUSE_FETCH_PAGE_FAULT); 330 return VM_PROT_EXECUTE; 331 } 332 333 static bool 334 trap_pagefault_fixup(struct trapframe *tf, struct pmap *pmap, register_t cause, 335 intptr_t addr) 336 { 337 pt_entry_t * const ptep = pmap_pte_lookup(pmap, addr); 338 struct vm_page *pg; 339 340 if (ptep == NULL) 341 return false; 342 343 pt_entry_t opte = *ptep; 344 if (!pte_valid_p(opte)) 345 return false; 346 347 pt_entry_t npte; 348 u_int attr; 349 do { 350 /* TODO: PTE_G is just the kernel PTE, but all pages 351 * can fault for CAUSE_LOAD_PAGE_FAULT and 352 * CAUSE_STORE_PAGE_FAULT...*/ 353 /* if ((opte & ~PTE_G) == 0) */ 354 /* return false; */ 355 356 pg = PHYS_TO_VM_PAGE(pte_to_paddr(opte)); 357 if (pg == NULL) 358 return false; 359 360 attr = 0; 361 npte = opte; 362 363 switch (cause) { 364 case CAUSE_LOAD_PAGE_FAULT: 365 if ((npte & PTE_R) == 0) { 366 npte |= PTE_A; 367 attr |= VM_PAGEMD_REFERENCED; 368 } 369 break; 370 case CAUSE_STORE_ACCESS: 371 if ((npte & PTE_W) != 0) { 372 npte |= PTE_A | PTE_D; 373 attr |= VM_PAGEMD_MODIFIED; 374 } 375 break; 376 case CAUSE_STORE_PAGE_FAULT: 377 if ((npte & PTE_D) == 0) { 378 npte |= PTE_A | PTE_D; 379 attr |= VM_PAGEMD_REFERENCED | VM_PAGEMD_MODIFIED; 380 } 381 break; 382 case CAUSE_FETCH_ACCESS: 383 case CAUSE_FETCH_PAGE_FAULT: 384 #if 0 385 if ((npte & PTE_NX) != 0) { 386 npte &= ~PTE_NX; 387 attr |= VM_PAGEMD_EXECPAGE; 388 } 389 #endif 390 break; 391 default: 392 panic("%s: Unhandled cause (%#" PRIxREGISTER 393 ") for addr %lx", __func__, cause, addr); 394 } 395 if (attr == 0) 396 return false; 397 } while (opte != atomic_cas_pte(ptep, opte, npte)); 398 399 pmap_page_set_attributes(VM_PAGE_TO_MD(pg), attr); 400 pmap_tlb_update_addr(pmap, addr, npte, 0); 401 402 if (attr & VM_PAGEMD_EXECPAGE) 403 pmap_md_page_syncicache(VM_PAGE_TO_MD(pg), 404 curcpu()->ci_kcpuset); 405 406 return true; 407 } 408 409 static bool 410 trap_pagefault(struct trapframe *tf, register_t epc, register_t status, 411 register_t cause, register_t tval, bool usertrap_p, ksiginfo_t *ksi) 412 { 413 struct proc * const p = curlwp->l_proc; 414 const intptr_t addr = trunc_page(tval); 415 416 if (__predict_false(usertrap_p 417 && (false 418 // Make this address is not trying to access kernel space. 419 || addr < 0 420 #ifdef _LP64 421 // If this is a process using a 32-bit address space, make 422 // sure the address is a signed 32-bit number. 423 || ((p->p_flag & PK_32) && (int32_t) addr != addr) 424 #endif 425 || false))) { 426 trap_ksi_init(ksi, SIGSEGV, SEGV_MAPERR, addr, cause); 427 return false; 428 } 429 430 struct vm_map * const map = (addr >= 0 ? 431 &p->p_vmspace->vm_map : kernel_map); 432 433 // See if this fault is for reference/modified/execpage tracking 434 if (trap_pagefault_fixup(tf, map->pmap, cause, addr)) 435 return true; 436 437 #ifdef PMAP_FAULTINFO 438 struct pcb * const pcb = lwp_getpcb(curlwp); 439 struct pcb_faultinfo * const pfi = &pcb->pcb_faultinfo; 440 441 if (p->p_pid == pfi->pfi_lastpid && addr == pfi->pfi_faultaddr) { 442 if (++pfi->pfi_repeats > 4) { 443 tlb_asid_t asid = tlb_get_asid(); 444 pt_entry_t *ptep = pfi->pfi_faultptep; 445 printf("%s: fault #%u (%s) for %#" PRIxVADDR 446 "(%#"PRIxVADDR") at pc %#"PRIxVADDR" curpid=%u/%u " 447 "ptep@%p=%#"PRIxPTE")\n", __func__, 448 pfi->pfi_repeats, cause_name(tf->tf_cause), 449 tval, addr, epc, map->pmap->pm_pai[0].pai_asid, 450 asid, ptep, ptep ? pte_value(*ptep) : 0); 451 if (pfi->pfi_repeats >= 4) { 452 cpu_Debugger(); 453 } else { 454 pfi->pfi_cause = cause; 455 } 456 } 457 } else { 458 pfi->pfi_lastpid = p->p_pid; 459 pfi->pfi_faultaddr = addr; 460 pfi->pfi_repeats = 0; 461 pfi->pfi_faultptep = NULL; 462 pfi->pfi_cause = cause; 463 } 464 #endif /* PMAP_FAULTINFO */ 465 466 const vm_prot_t ftype = get_faulttype(cause); 467 468 if (usertrap_p) { 469 int error = uvm_fault(&p->p_vmspace->vm_map, addr, ftype); 470 if (error) { 471 int signo = SIGSEGV; 472 int code = SEGV_MAPERR; 473 474 switch (error) { 475 case ENOMEM: { 476 struct lwp * const l = curlwp; 477 printf("UVM: pid %d (%s), uid %d killed: " 478 "out of swap\n", 479 l->l_proc->p_pid, l->l_proc->p_comm, 480 l->l_cred ? 481 kauth_cred_geteuid(l->l_cred) : -1); 482 signo = SIGKILL; 483 code = 0; 484 break; 485 } 486 case EACCES: 487 KASSERT(signo == SIGSEGV); 488 code = SEGV_ACCERR; 489 break; 490 case EINVAL: 491 signo = SIGBUS; 492 code = BUS_ADRERR; 493 break; 494 } 495 496 trap_ksi_init(ksi, signo, code, (intptr_t)tval, cause); 497 return false; 498 } 499 uvm_grow(p, addr); 500 501 return true; 502 } 503 504 // Page faults are not allowed while dealing with interrupts 505 if (cpu_intr_p()) 506 return false; 507 508 struct faultbuf * const fb = cpu_disable_onfault(); 509 int error = uvm_fault(map, addr, ftype); 510 cpu_enable_onfault(fb); 511 512 if (error == 0) { 513 if (map != kernel_map) { 514 uvm_grow(p, addr); 515 } 516 return true; 517 } 518 519 if (fb == NULL) { 520 return false; 521 } 522 523 cpu_jump_onfault(tf, fb, error); 524 return true; 525 } 526 527 static bool 528 trap_instruction(struct trapframe *tf, register_t epc, register_t status, 529 register_t cause, register_t tval, bool usertrap_p, ksiginfo_t *ksi) 530 { 531 if (usertrap_p) { 532 if (__SHIFTOUT(tf->tf_sr, SR_FS) == SR_FS_OFF) { 533 fpu_load(); 534 return true; 535 } 536 537 trap_ksi_init(ksi, SIGILL, ILL_ILLOPC, 538 (intptr_t)tval, cause); 539 } 540 return false; 541 } 542 543 static bool 544 trap_misalignment(struct trapframe *tf, register_t epc, register_t status, 545 register_t cause, register_t tval, bool usertrap_p, ksiginfo_t *ksi) 546 { 547 if (usertrap_p) { 548 trap_ksi_init(ksi, SIGBUS, BUS_ADRALN, 549 (intptr_t)tval, cause); 550 } 551 return false; 552 } 553 554 static bool 555 trap_breakpoint(struct trapframe *tf, register_t epc, register_t status, 556 register_t cause, register_t tval, bool usertrap_p, ksiginfo_t *ksi) 557 { 558 if (usertrap_p) { 559 trap_ksi_init(ksi, SIGTRAP, TRAP_BRKPT, 560 (intptr_t)tval, cause); 561 } else { 562 dump_trapframe(tf, printf); 563 #if defined(DDB) 564 kdb_trap(cause, tf); 565 PC_BREAK_ADVANCE(tf); 566 #else 567 panic("%s: unknown kernel trap", __func__); 568 #endif 569 return true; 570 } 571 return false; 572 } 573 574 void 575 cpu_trap(struct trapframe *tf, register_t epc, register_t status, 576 register_t cause, register_t tval) 577 { 578 const register_t code = CAUSE_CODE(cause); 579 const register_t fault_mask = __BIT(code); 580 const intptr_t addr = tval; 581 const bool usertrap_p = (status & SR_SPP) == 0; 582 bool ok = true; 583 ksiginfo_t ksi; 584 585 KASSERT(!CAUSE_INTERRUPT_P(cause)); 586 KASSERT(__SHIFTOUT(tf->tf_sr, SR_SIE) == 0); 587 588 /* We can allow interrupts now */ 589 csr_sstatus_set(SR_SIE); 590 591 if (__predict_true(fault_mask & FAULT_TRAP_MASK)) { 592 #ifndef _LP64 593 #if 0 594 // This fault may be cause the kernel's page table got a new 595 // page table page and this pmap's page table doesn't know 596 // about it. See 597 struct pmap * const pmap = curlwp->l_proc->p_vmspace->vm_map.pmap; 598 if ((intptr_t) addr < 0 599 && pmap != pmap_kernel() 600 && pmap_pdetab_fixup(pmap, addr)) { 601 return; 602 } 603 #endif 604 #endif 605 ok = trap_pagefault(tf, epc, status, cause, addr, 606 usertrap_p, &ksi); 607 } else if (fault_mask & INSTRUCTION_TRAP_MASK) { 608 ok = trap_instruction(tf, epc, status, cause, addr, 609 usertrap_p, &ksi); 610 } else if (fault_mask & SYSCALL_TRAP_MASK) { 611 panic("cpu_exception_handler failure"); 612 } else if (fault_mask & MISALIGNED_TRAP_MASK) { 613 ok = trap_misalignment(tf, epc, status, cause, addr, 614 usertrap_p, &ksi); 615 } else if (fault_mask & BREAKPOINT_TRAP_MASK) { 616 ok = trap_breakpoint(tf, epc, status, cause, addr, 617 usertrap_p, &ksi); 618 } 619 620 if (usertrap_p) { 621 if (!ok) 622 cpu_trapsignal(tf, &ksi); 623 624 userret(curlwp); 625 } else if (!ok) { 626 dump_trapframe(tf, printf); 627 panic("%s: fatal kernel trap", __func__); 628 } 629 /* 630 * Ensure interrupts are disabled in sstatus, and that interrupts 631 * will get enabled on 'sret' for userland. 632 */ 633 KASSERT(__SHIFTOUT(tf->tf_sr, SR_SIE) == 0); 634 KASSERT(__SHIFTOUT(tf->tf_sr, SR_SPIE) != 0 || 635 __SHIFTOUT(tf->tf_sr, SR_SPP) != 0); 636 } 637 638 void 639 cpu_ast(struct trapframe *tf) 640 { 641 struct lwp * const l = curlwp; 642 643 /* 644 * allow to have a chance of context switch just prior to user 645 * exception return. 646 */ 647 #ifdef __HAVE_PREEMPTION 648 kpreempt_disable(); 649 #endif 650 struct cpu_info * const ci = curcpu(); 651 652 ci->ci_data.cpu_ntrap++; 653 654 KDASSERT(ci->ci_cpl == IPL_NONE); 655 #ifdef __HAVE_PREEMPTION 656 kpreempt_enable(); 657 #endif 658 659 if (curlwp->l_pflag & LP_OWEUPC) { 660 curlwp->l_pflag &= ~LP_OWEUPC; 661 ADDUPROF(curlwp); 662 } 663 664 userret(l); 665 } 666 667 668 static int 669 fetch_user_data(const void *uaddr, void *valp, size_t size) 670 { 671 struct faultbuf fb; 672 int error; 673 674 const vaddr_t uva = (vaddr_t)uaddr; 675 if (__predict_false(uva > VM_MAXUSER_ADDRESS - size)) 676 return EFAULT; 677 678 if ((error = cpu_set_onfault(&fb)) != 0) 679 return error; 680 681 csr_sstatus_set(SR_SUM); 682 switch (size) { 683 case 1: 684 *(uint8_t *)valp = *(volatile const uint8_t *)uaddr; 685 break; 686 case 2: 687 *(uint16_t *)valp = *(volatile const uint16_t *)uaddr; 688 break; 689 case 4: 690 *(uint32_t *)valp = *(volatile const uint32_t *)uaddr; 691 break; 692 #ifdef _LP64 693 case 8: 694 *(uint64_t *)valp = *(volatile const uint64_t *)uaddr; 695 break; 696 #endif /* _LP64 */ 697 default: 698 error = EINVAL; 699 } 700 csr_sstatus_clear(SR_SUM); 701 702 cpu_unset_onfault(); 703 704 return error; 705 } 706 707 int 708 _ufetch_8(const uint8_t *uaddr, uint8_t *valp) 709 { 710 return fetch_user_data(uaddr, valp, sizeof(*valp)); 711 } 712 713 int 714 _ufetch_16(const uint16_t *uaddr, uint16_t *valp) 715 { 716 return fetch_user_data(uaddr, valp, sizeof(*valp)); 717 } 718 719 int 720 _ufetch_32(const uint32_t *uaddr, uint32_t *valp) 721 { 722 return fetch_user_data(uaddr, valp, sizeof(*valp)); 723 } 724 725 #ifdef _LP64 726 int 727 _ufetch_64(const uint64_t *uaddr, uint64_t *valp) 728 { 729 return fetch_user_data(uaddr, valp, sizeof(*valp)); 730 } 731 #endif /* _LP64 */ 732 733 static int 734 store_user_data(void *uaddr, const void *valp, size_t size) 735 { 736 struct faultbuf fb; 737 int error; 738 739 const vaddr_t uva = (vaddr_t)uaddr; 740 if (__predict_false(uva > VM_MAXUSER_ADDRESS - size)) 741 return EFAULT; 742 743 if ((error = cpu_set_onfault(&fb)) != 0) 744 return error; 745 746 csr_sstatus_set(SR_SUM); 747 switch (size) { 748 case 1: 749 *(volatile uint8_t *)uaddr = *(const uint8_t *)valp; 750 break; 751 case 2: 752 *(volatile uint16_t *)uaddr = *(const uint8_t *)valp; 753 break; 754 case 4: 755 *(volatile uint32_t *)uaddr = *(const uint32_t *)valp; 756 break; 757 #ifdef _LP64 758 case 8: 759 *(volatile uint64_t *)uaddr = *(const uint64_t *)valp; 760 break; 761 #endif /* _LP64 */ 762 default: 763 error = EINVAL; 764 } 765 csr_sstatus_clear(SR_SUM); 766 767 cpu_unset_onfault(); 768 769 return error; 770 } 771 772 int 773 _ustore_8(uint8_t *uaddr, uint8_t val) 774 { 775 return store_user_data(uaddr, &val, sizeof(val)); 776 } 777 778 int 779 _ustore_16(uint16_t *uaddr, uint16_t val) 780 { 781 return store_user_data(uaddr, &val, sizeof(val)); 782 } 783 784 int 785 _ustore_32(uint32_t *uaddr, uint32_t val) 786 { 787 return store_user_data(uaddr, &val, sizeof(val)); 788 } 789 790 #ifdef _LP64 791 int 792 _ustore_64(uint64_t *uaddr, uint64_t val) 793 { 794 return store_user_data(uaddr, &val, sizeof(val)); 795 } 796 #endif /* _LP64 */ 797