diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2020-10-23 16:54:46 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2020-10-23 16:54:46 +0000 |
commit | 27c20f37a7ac49098c2855d9d3cae544b4981297 (patch) | |
tree | 6cb1299ff814631fc0fcf62c29c3b35e844af179 /sys/arch/sparc64 | |
parent | 522833ae3ed17802c846dd1a722e8d14a378c216 (diff) |
Refactor page fault/error functions, normalizing their operation relative
to other architectures. Kernel lock only the minimum (in preparation for
further unlocking down the line)
ok kettenis
Diffstat (limited to 'sys/arch/sparc64')
-rw-r--r-- | sys/arch/sparc64/sparc64/trap.c | 354 |
1 files changed, 154 insertions, 200 deletions
diff --git a/sys/arch/sparc64/sparc64/trap.c b/sys/arch/sparc64/sparc64/trap.c index 7cc15c50792..2b9e05d0d2f 100644 --- a/sys/arch/sparc64/sparc64/trap.c +++ b/sys/arch/sparc64/sparc64/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.106 2020/10/21 17:54:33 deraadt Exp $ */ +/* $OpenBSD: trap.c,v 1.107 2020/10/23 16:54:35 deraadt Exp $ */ /* $NetBSD: trap.c,v 1.73 2001/08/09 01:03:01 eeh Exp $ */ /* @@ -718,6 +718,21 @@ pmap_unuse_final(struct proc *p) p->p_addr->u_pcb.pcb_nsaved = 0; } +static inline int +accesstype(unsigned int type, u_long sfsr) +{ + /* + * If it was a FAST_DATA_ACCESS_MMU_MISS we have no idea what the + * access was since the SFSR is not set. But we should never get + * here from there. + */ + if (type == T_FDMMU_MISS || (sfsr & SFSR_FV) == 0) + return PROT_READ; + else if (sfsr & SFSR_W) + return PROT_READ | PROT_WRITE; + return PROT_READ; +} + /* * This routine handles MMU generated faults. About half * of them could be recoverable through uvm_fault. @@ -726,40 +741,18 @@ void data_access_fault(struct trapframe64 *tf, unsigned type, vaddr_t pc, vaddr_t addr, vaddr_t sfva, u_long sfsr) { - u_int64_t tstate; - struct proc *p; - struct vmspace *vm; - vaddr_t va; - int rv; - vm_prot_t access_type; + struct proc *p = curproc; + vaddr_t va = trunc_page(addr); + vm_prot_t access_type = accesstype(type, sfsr); vaddr_t onfault; union sigval sv; + int signal, sicode, error; uvmexp.traps++; - if ((p = curproc) == NULL) /* safety check */ + if (p == NULL) /* safety check */ p = &proc0; - tstate = tf->tf_tstate; - - /* Find the faulting va to give to uvm_fault */ - va = trunc_page(addr); - - /* - * Now munch on protections. - * - * If it was a FAST_DATA_ACCESS_MMU_MISS we have no idea what the - * access was since the SFSR is not set. But we should never get - * here from there. - */ - if (type == T_FDMMU_MISS || (sfsr & SFSR_FV) == 0) { - /* Punt */ - access_type = PROT_READ; - } else { - access_type = (sfsr & SFSR_W) ? PROT_READ | PROT_WRITE - : PROT_READ; - } - if (tstate & TSTATE_PRIV) { - KERNEL_LOCK(); + if (tf->tf_tstate & TSTATE_PRIV) { #ifdef DDB extern char Lfsprobe[]; /* @@ -779,11 +772,13 @@ data_access_fault(struct trapframe64 *tf, unsigned type, vaddr_t pc, goto kfault; if (!(addr & TLB_TAG_ACCESS_CTX)) { /* CTXT == NUCLEUS */ - rv = uvm_fault(kernel_map, va, 0, access_type); - if (rv == 0) { - KERNEL_UNLOCK(); + + KERNEL_LOCK(); + error = uvm_fault(kernel_map, va, 0, access_type); + KERNEL_UNLOCK(); + + if (error == 0) return; - } goto kfault; } } else { @@ -793,15 +788,13 @@ data_access_fault(struct trapframe64 *tf, unsigned type, vaddr_t pc, "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n", uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial)) goto out; - - KERNEL_LOCK(); } - vm = p->p_vmspace; - /* alas! must call the horrible vm code */ onfault = (vaddr_t)p->p_addr->u_pcb.pcb_onfault; p->p_addr->u_pcb.pcb_onfault = NULL; - rv = uvm_fault(&vm->vm_map, (vaddr_t)va, 0, access_type); + KERNEL_LOCK(); + error = uvm_fault(&p->p_vmspace->vm_map, (vaddr_t)va, 0, access_type); + KERNEL_UNLOCK(); p->p_addr->u_pcb.pcb_onfault = (void *)onfault; /* @@ -811,58 +804,52 @@ data_access_fault(struct trapframe64 *tf, unsigned type, vaddr_t pc, * the current limit and we need to reflect that as an access * error. */ - if (rv == 0) + if (error == 0) { uvm_grow(p, va); + goto out; + } - if (rv != 0) { - /* - * Pagein failed. If doing copyin/out, return to onfault - * address. Any other page fault in kernel, die; if user - * fault, deliver SIGSEGV. - */ - int signal, sicode; - - if (tstate & TSTATE_PRIV) { + /* + * Pagein failed. If doing copyin/out, return to onfault + * address. Any other page fault in kernel, die; if user + * fault, deliver SIGSEGV. + */ + if (tf->tf_tstate & TSTATE_PRIV) { kfault: - onfault = (long)p->p_addr->u_pcb.pcb_onfault; - if (!onfault) { - (void) splhigh(); - panic("kernel data fault: pc=%lx addr=%lx", - pc, addr); - /* NOTREACHED */ - } - tf->tf_pc = onfault; - tf->tf_npc = onfault + 4; - KERNEL_UNLOCK(); - return; - } - - if (type == T_FDMMU_MISS || (sfsr & SFSR_FV) == 0) - sv.sival_ptr = (void *)va; - else - sv.sival_ptr = (void *)sfva; - - signal = SIGSEGV; - sicode = SEGV_MAPERR; - if (rv == ENOMEM) { - printf("UVM: pid %d (%s), uid %d killed: out of swap\n", - p->p_p->ps_pid, p->p_p->ps_comm, - p->p_ucred ? (int)p->p_ucred->cr_uid : -1); - signal = SIGKILL; - } - if (rv == EACCES) - sicode = SEGV_ACCERR; - if (rv == EIO) { - signal = SIGBUS; - sicode = BUS_OBJERR; + onfault = (long)p->p_addr->u_pcb.pcb_onfault; + if (!onfault) { + (void) splhigh(); + panic("kernel data fault: pc=%lx addr=%lx", + pc, addr); + /* NOTREACHED */ } - trapsignal(p, signal, access_type, sicode, sv); + tf->tf_pc = onfault; + tf->tf_npc = onfault + 4; + return; } - KERNEL_UNLOCK(); + if (type == T_FDMMU_MISS || (sfsr & SFSR_FV) == 0) + sv.sival_ptr = (void *)va; + else + sv.sival_ptr = (void *)sfva; + + signal = SIGSEGV; + sicode = SEGV_MAPERR; + if (error == ENOMEM) { + printf("UVM: pid %d (%s), uid %d killed: out of swap\n", + p->p_p->ps_pid, p->p_p->ps_comm, + p->p_ucred ? (int)p->p_ucred->cr_uid : -1); + signal = SIGKILL; + } else if (error == EACCES) + sicode = SEGV_ACCERR; + else if (error == EIO) { + signal = SIGBUS; + sicode = BUS_OBJERR; + } + trapsignal(p, signal, access_type, sicode, sv); out: - if ((tstate & TSTATE_PRIV) == 0) { + if ((tf->tf_tstate & TSTATE_PRIV) == 0) { userret(p); share_fpu(p, tf); } @@ -879,18 +866,15 @@ void data_access_error(struct trapframe64 *tf, unsigned type, vaddr_t afva, u_long afsr, vaddr_t sfva, u_long sfsr) { + struct proc *p = curproc; u_long pc; - u_int64_t tstate; - struct proc *p; vaddr_t onfault; union sigval sv; uvmexp.traps++; - if ((p = curproc) == NULL) /* safety check */ + if (p == NULL) /* safety check */ p = &proc0; - tstate = tf->tf_tstate; - /* * Catch PCI config space reads. */ @@ -901,19 +885,16 @@ data_access_error(struct trapframe64 *tf, unsigned type, vaddr_t afva, pc = tf->tf_pc; - sv.sival_ptr = (void *)pc; - onfault = (long)p->p_addr->u_pcb.pcb_onfault; printf("data error type %x sfsr=%lx sfva=%lx afsr=%lx afva=%lx tf=%p\n", - type, sfsr, sfva, afsr, afva, tf); + type, sfsr, sfva, afsr, afva, tf); if (afsr == 0 && sfsr == 0) { printf("data_access_error: no fault\n"); goto out; /* No fault. Why were we called? */ } - if (tstate & TSTATE_PRIV) { - + if (tf->tf_tstate & TSTATE_PRIV) { if (!onfault) { (void) splhigh(); panic("data fault: pc=%lx addr=%lx sfsr=%lb", @@ -935,10 +916,11 @@ data_access_error(struct trapframe64 *tf, unsigned type, vaddr_t afva, return; } + sv.sival_ptr = (void *)pc; trapsignal(p, SIGSEGV, PROT_READ | PROT_WRITE, SEGV_MAPERR, sv); out: - if ((tstate & TSTATE_PRIV) == 0) { + if ((tf->tf_tstate & TSTATE_PRIV) == 0) { userret(p); share_fpu(p, tf); } @@ -952,45 +934,34 @@ void text_access_fault(struct trapframe64 *tf, unsigned type, vaddr_t pc, u_long sfsr) { - u_int64_t tstate; - struct proc *p; - struct vmspace *vm; - vaddr_t va; - int rv; - vm_prot_t access_type; + struct proc *p = curproc; + vaddr_t va = trunc_page(pc); + vm_prot_t access_type = PROT_EXEC; union sigval sv; - - sv.sival_ptr = (void *)pc; + int signal, sicode, error; uvmexp.traps++; - if ((p = curproc) == NULL) /* safety check */ + if (p == NULL) /* safety check */ panic("text_access_fault: no curproc"); - tstate = tf->tf_tstate; - - va = trunc_page(pc); - - /* Now munch on protections... */ + sv.sival_ptr = (void *)pc; - access_type = PROT_EXEC; - if (tstate & TSTATE_PRIV) { + if (tf->tf_tstate & TSTATE_PRIV) { (void) splhigh(); panic("kernel text_access_fault: pc=%lx va=%lx", pc, va); /* NOTREACHED */ - } else { - p->p_md.md_tf = tf; - refreshcreds(p); - if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p), - "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n", - uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial)) - goto out; } - KERNEL_LOCK(); + p->p_md.md_tf = tf; + refreshcreds(p); + if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p), + "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n", + uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial)) + goto out; - vm = p->p_vmspace; - /* alas! must call the horrible vm code */ - rv = uvm_fault(&vm->vm_map, va, 0, access_type); + KERNEL_LOCK(); + error = uvm_fault(&p->p_vmspace->vm_map, va, 0, access_type); + KERNEL_UNLOCK(); /* * If this was a stack access we keep track of the maximum @@ -999,37 +970,33 @@ text_access_fault(struct trapframe64 *tf, unsigned type, vaddr_t pc, * the current limit and we need to reflect that as an access * error. */ - if (rv == 0) + if (error == 0) { uvm_grow(p, va); + goto out; + } - if (rv != 0) { - /* - * Pagein failed. Any other page fault in kernel, die; if user - * fault, deliver SIGSEGV. - */ - int signal, sicode; - - if (tstate & TSTATE_PRIV) { - (void) splhigh(); - panic("kernel text fault: pc=%llx", (unsigned long long)pc); - /* NOTREACHED */ - } - - signal = SIGSEGV; - sicode = SEGV_MAPERR; - if (rv == EACCES) - sicode = SEGV_ACCERR; - if (rv == EIO) { - signal = SIGBUS; - sicode = BUS_OBJERR; - } - trapsignal(p, signal, access_type, sicode, sv); + /* + * Pagein failed. Any other page fault in kernel, die; if user + * fault, deliver SIGSEGV. + */ + if (tf->tf_tstate & TSTATE_PRIV) { + (void) splhigh(); + panic("kernel text fault: pc=%llx", (unsigned long long)pc); + /* NOTREACHED */ } - KERNEL_UNLOCK(); + signal = SIGSEGV; + sicode = SEGV_MAPERR; + if (error == EACCES) + sicode = SEGV_ACCERR; + else if (error == EIO) { + signal = SIGBUS; + sicode = BUS_OBJERR; + } + trapsignal(p, signal, access_type, sicode, sv); out: - if ((tstate & TSTATE_PRIV) == 0) { + if ((tf->tf_tstate & TSTATE_PRIV) == 0) { userret(p); share_fpu(p, tf); } @@ -1047,27 +1014,24 @@ void text_access_error(struct trapframe64 *tf, unsigned type, vaddr_t pc, u_long sfsr, vaddr_t afva, u_long afsr) { - int64_t tstate; - struct proc *p; - struct vmspace *vm; - vaddr_t va; - int rv; - vm_prot_t access_type; + struct proc *p = curproc; + vaddr_t va = trunc_page(pc); + vm_prot_t access_type = PROT_EXEC; union sigval sv; + int signal, sicode, error; - sv.sival_ptr = (void *)pc; uvmexp.traps++; - if ((p = curproc) == NULL) /* safety check */ + if (p == NULL) /* safety check */ p = &proc0; - tstate = tf->tf_tstate; + sv.sival_ptr = (void *)pc; if ((afsr) != 0) { printf("text_access_error: memory error...\n"); - printf("text memory error type %d sfsr=%lx sfva=%lx afsr=%lx afva=%lx tf=%p\n", - type, sfsr, pc, afsr, afva, tf); + printf("type %d sfsr=%lx sfva=%lx afsr=%lx afva=%lx tf=%p\n", + type, sfsr, pc, afsr, afva, tf); - if (tstate & TSTATE_PRIV) + if (tf->tf_tstate & TSTATE_PRIV) panic("text_access_error: kernel memory error"); /* User fault -- Berr */ @@ -1077,29 +1041,23 @@ text_access_error(struct trapframe64 *tf, unsigned type, vaddr_t pc, if ((sfsr & SFSR_FV) == 0 || (sfsr & SFSR_FT) == 0) goto out; /* No fault. Why were we called? */ - va = trunc_page(pc); - - /* Now munch on protections... */ - access_type = PROT_EXEC; - if (tstate & TSTATE_PRIV) { + if (tf->tf_tstate & TSTATE_PRIV) { (void) splhigh(); panic("kernel text error: pc=%lx sfsr=%lb", pc, sfsr, SFSR_BITS); /* NOTREACHED */ - } else { - p->p_md.md_tf = tf; - refreshcreds(p); - if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p), - "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n", - uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial)) - goto out; } - KERNEL_LOCK(); + p->p_md.md_tf = tf; + refreshcreds(p); + if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p), + "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n", + uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial)) + goto out; - vm = p->p_vmspace; - /* alas! must call the horrible vm code */ - rv = uvm_fault(&vm->vm_map, va, 0, access_type); + KERNEL_LOCK(); + error = uvm_fault(&p->p_vmspace->vm_map, va, 0, access_type); + KERNEL_UNLOCK(); /* * If this was a stack access we keep track of the maximum @@ -1108,39 +1066,35 @@ text_access_error(struct trapframe64 *tf, unsigned type, vaddr_t pc, * the current limit and we need to reflect that as an access * error. */ - if (rv == 0) + if (error == 0) { uvm_grow(p, va); + goto out; + } - if (rv != 0) { - /* - * Pagein failed. If doing copyin/out, return to onfault - * address. Any other page fault in kernel, die; if user - * fault, deliver SIGSEGV. - */ - int signal, sicode; - - if (tstate & TSTATE_PRIV) { - (void) splhigh(); - panic("kernel text error: pc=%lx sfsr=%lb", pc, - sfsr, SFSR_BITS); - /* NOTREACHED */ - } - - signal = SIGSEGV; - sicode = SEGV_MAPERR; - if (rv == EACCES) - sicode = SEGV_ACCERR; - if (rv == EIO) { - signal = SIGBUS; - sicode = BUS_OBJERR; - } - trapsignal(p, signal, access_type, sicode, sv); + /* + * Pagein failed. If doing copyin/out, return to onfault + * address. Any other page fault in kernel, die; if user + * fault, deliver SIGSEGV. + */ + if (tf->tf_tstate & TSTATE_PRIV) { + (void) splhigh(); + panic("kernel text error: pc=%lx sfsr=%lb", pc, + sfsr, SFSR_BITS); + /* NOTREACHED */ } - KERNEL_UNLOCK(); + signal = SIGSEGV; + sicode = SEGV_MAPERR; + if (error == EACCES) + sicode = SEGV_ACCERR; + else if (error == EIO) { + signal = SIGBUS; + sicode = BUS_OBJERR; + } + trapsignal(p, signal, access_type, sicode, sv); out: - if ((tstate & TSTATE_PRIV) == 0) { + if ((tf->tf_tstate & TSTATE_PRIV) == 0) { userret(p); share_fpu(p, tf); } |