From ead0ae619b71fe35ef7d8789ec87af916f2ba5bd Mon Sep 17 00:00:00 2001 From: deraadt Date: Sat, 15 May 2021 20:12:24 +0000 Subject: [PATCH] Reorganize kernel & user fault handling into seperate functions like on other architectures. During refactoring, found missing calls to important functions and incorrect parameter passing... ok kettenis drahn --- sys/arch/riscv64/riscv64/trap.c | 163 +++++++++++++++++++------------- 1 file changed, 95 insertions(+), 68 deletions(-) diff --git a/sys/arch/riscv64/riscv64/trap.c b/sys/arch/riscv64/riscv64/trap.c index 67b7482ca6a..5ce5381d4a8 100644 --- a/sys/arch/riscv64/riscv64/trap.c +++ b/sys/arch/riscv64/riscv64/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.10 2021/05/15 14:05:36 deraadt Exp $ */ +/* $OpenBSD: trap.c,v 1.11 2021/05/15 20:12:24 deraadt Exp $ */ /* * Copyright (c) 2020 Shivam Waghela @@ -34,7 +34,8 @@ void do_trap_supervisor(struct trapframe *); void do_trap_user(struct trapframe *); -static void data_abort(struct trapframe *, int); +static void udata_abort(struct trapframe *); +static void kdata_abort(struct trapframe *); static void dump_regs(struct trapframe *frame) @@ -83,7 +84,7 @@ do_trap_supervisor(struct trapframe *frame) case EXCP_FAULT_FETCH: case EXCP_STORE_PAGE_FAULT: case EXCP_LOAD_PAGE_FAULT: - data_abort(frame, 0); + kdata_abort(frame); break; case EXCP_BREAKPOINT: #ifdef DDB @@ -91,17 +92,17 @@ do_trap_supervisor(struct trapframe *frame) db_trapper(frame->tf_sepc,0/*XXX*/, frame, exception); #else dump_regs(frame); - panic("No debugger in kernel.\n"); + panic("No debugger in kernel."); #endif break; case EXCP_ILLEGAL_INSTRUCTION: dump_regs(frame); - panic("Illegal instruction at 0x%016lx\n", frame->tf_sepc); + panic("Illegal instruction at 0x%016lx", frame->tf_sepc); break; default: dump_regs(frame); - panic("Unknown kernel exception %llx trap value %lx\n", - exception, frame->tf_stval); + panic("Unknown kernel exception %llx trap value pc 0x%lx stval %lx", + exception, frame->tf_sepc, frame->tf_stval); } } @@ -147,6 +148,8 @@ do_trap_user(struct trapframe *frame) curcpu()->ci_curproc, frame->tf_sepc, frame->tf_ra, frame); #endif + refreshcreds(p); + switch (exception) { case EXCP_FAULT_LOAD: case EXCP_FAULT_STORE: @@ -154,7 +157,7 @@ do_trap_user(struct trapframe *frame) case EXCP_STORE_PAGE_FAULT: case EXCP_LOAD_PAGE_FAULT: case EXCP_INST_PAGE_FAULT: - data_abort(frame, 1); + udata_abort(frame); break; case EXCP_USER_ECALL: frame->tf_sepc += 4; /* Next instruction */ @@ -170,17 +173,15 @@ do_trap_user(struct trapframe *frame) frame->tf_scause, frame->tf_stval); sv.sival_ptr = (void *)frame->tf_stval; trapsignal(p, SIGILL, 0, ILL_ILLTRP, sv); - userret(p); break; case EXCP_BREAKPOINT: printf("BREAKPOINT\n"); sv.sival_ptr = (void *)frame->tf_stval; trapsignal(p, SIGTRAP, 0, TRAP_BRKPT, sv); - userret(p); break; default: dump_regs(frame); - panic("Unknown userland exception %llx, trap value %lx\n", + panic("Unknown userland exception %llx, trap value %lx", exception, frame->tf_stval); } @@ -193,91 +194,117 @@ do_trap_user(struct trapframe *frame) //printf ("FPU enabled userland %p %p\n", // pcb->pcb_fpcpu, curcpu()->ci_fpuproc); } + + userret(p); +} + +static inline vm_prot_t +accesstype(struct trapframe *frame) +{ + vm_prot_t access_type; + + if ((frame->tf_scause == EXCP_FAULT_STORE) || + (frame->tf_scause == EXCP_STORE_PAGE_FAULT)) { + access_type = PROT_WRITE; + } else if (frame->tf_scause == EXCP_INST_PAGE_FAULT) { + access_type = PROT_EXEC; + } else { + access_type = PROT_READ; + } + return access_type; } static void -data_abort(struct trapframe *frame, int usermode) +udata_abort(struct trapframe *frame) { struct vm_map *map; - uint64_t stval; + uint64_t stval = frame->tf_stval; union sigval sv; struct pcb *pcb; - vm_prot_t ftype; + vm_prot_t access_type = accesstype(frame); vaddr_t va; struct proc *p; - int error, sig, code, access_type; + int error, sig, code; pcb = curcpu()->ci_curpcb; p = curcpu()->ci_curproc; - stval = frame->tf_stval; va = trunc_page(stval); - //if (va >= VM_MAXUSER_ADDRESS) - // curcpu()->ci_flush_bp(); + map = &p->p_vmspace->vm_map; - if ((frame->tf_scause == EXCP_FAULT_STORE) || - (frame->tf_scause == EXCP_STORE_PAGE_FAULT)) { - access_type = PROT_WRITE; - } else if (frame->tf_scause == EXCP_INST_PAGE_FAULT) { - access_type = PROT_EXEC; + 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)) + return; + + /* Handle referenced/modified emulation */ + if (pmap_fault_fixup(map->pmap, va, access_type)) + return; + + error = uvm_fault(map, va, 0, access_type); + + if (error == 0) { + uvm_grow(p, va); + return; + } + + if (error == ENOMEM) { + sig = SIGKILL; + code = 0; + } else if (error == EIO) { + sig = SIGBUS; + code = BUS_OBJERR; + } else if (error == EACCES) { + sig = SIGSEGV; + code = SEGV_ACCERR; } else { - access_type = PROT_READ; + sig = SIGSEGV; + code = SEGV_MAPERR; } + sv.sival_ptr = (void *)stval; + trapsignal(p, sig, 0, code, sv); +} - ftype = VM_FAULT_INVALID; // should check for failed permissions. +static void +kdata_abort(struct trapframe *frame) +{ + struct vm_map *map; + uint64_t stval = frame->tf_stval; + struct pcb *pcb; + vm_prot_t access_type = accesstype(frame); + vaddr_t va; + struct proc *p; + int error; - if (usermode) - map = &p->p_vmspace->vm_map; - else if (stval >= VM_MAX_USER_ADDRESS) + pcb = curcpu()->ci_curpcb; + p = curcpu()->ci_curproc; + + va = trunc_page(stval); + + if (stval >= VM_MAX_USER_ADDRESS) map = kernel_map; else { - if (pcb->pcb_onfault == 0) - goto fatal; map = &p->p_vmspace->vm_map; } - if (pmap_fault_fixup(map->pmap, va, ftype)) - goto done; + /* Handle referenced/modified emulation */ + if (!pmap_fault_fixup(map->pmap, va, access_type)) { + error = uvm_fault(map, va, 0, access_type); - KERNEL_LOCK(); - error = uvm_fault(map, va, ftype, access_type); - KERNEL_UNLOCK(); + if (error == 0 && map != kernel_map) + uvm_grow(p, va); + } if (error != 0) { - if (usermode) { - if (error == ENOMEM) { - sig = SIGKILL; - code = 0; - } else if (error == EIO) { - sig = SIGBUS; - code = BUS_OBJERR; - } else if (error == EACCES) { - sig = SIGSEGV; - code = SEGV_ACCERR; - } else { - sig = SIGSEGV; - code = SEGV_MAPERR; - } - sv.sival_ptr = (void *)stval; - trapsignal(p, sig, 0, code, sv); - } else { - if (curcpu()->ci_idepth == 0 && pcb->pcb_onfault != 0) { - frame->tf_a[0] = error; - frame->tf_sepc = (register_t)pcb->pcb_onfault; - return; - } - goto fatal; + if (curcpu()->ci_idepth == 0 && + pcb->pcb_onfault != 0) { + frame->tf_a[0] = error; + frame->tf_sepc = (register_t)pcb->pcb_onfault; + return; } + dump_regs(frame); + panic("Fatal page fault at %#lx: %#08lx", frame->tf_sepc, + (vaddr_t)stval); } - -done: - if (usermode) - userret(p); - return; - -fatal: - dump_regs(frame); - panic("Fatal page fault at %#lx: %#08lx", frame->tf_sepc, - (vaddr_t)sv.sival_ptr); } -- 2.20.1