locore0.o: ${_archdir}/${_arch}/locore0.S assym.h
copy.o copystr.o copyinout.o: assym.h
pagezero.o: assym.h
-cpuswitch.o trap.o support.o: assym.h
+cpuswitch.o exception.o support.o: assym.h
locore.o trampoline.o: assym.h
hardlink-obsd:
file arch/riscv64/riscv64/locore.S
file arch/riscv64/riscv64/copy.S
file arch/riscv64/riscv64/copystr.S
-file arch/riscv64/riscv64/trap.S
+file arch/riscv64/riscv64/exception.S
file arch/riscv64/riscv64/cpuswitch.S
file arch/riscv64/riscv64/machdep.c
file arch/riscv64/riscv64/intr.c
file arch/riscv64/riscv64/support.S
file arch/riscv64/riscv64/syscall.c
file arch/riscv64/riscv64/pagezero.S
-file arch/riscv64/riscv64/trap_machdep.c
+file arch/riscv64/riscv64/trap.c
file arch/riscv64/riscv64/sbi.c
file arch/riscv64/riscv64/cpufunc_asm.S
file arch/riscv64/riscv64/fpu.c
--- /dev/null
+/*
+ * Copyright (c) 2020 Mengshi Li <mengshi.li.mars@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "assym.h"
+#include <machine/asm.h>
+#include <machine/trap.h>
+#include <machine/riscvreg.h>
+
+.macro save_registers el
+ addi sp, sp, -(TRAPFRAME_SIZEOF)
+
+ sd ra, (TF_RA)(sp)
+
+.if \el == 0 /* We came from userspace. */
+ sd gp, (TF_GP)(sp)
+.option push
+.option norelax
+ /* Load the kernel's global pointer */
+ la gp, __global_pointer$
+.option pop
+
+ /* Load our pcpu */
+ sd tp, (TF_TP)(sp)
+ ld tp, (TRAPFRAME_SIZEOF)(sp)
+.endif
+
+ sd t0, (TF_T + 0 * 8)(sp)
+ sd t1, (TF_T + 1 * 8)(sp)
+ sd t2, (TF_T + 2 * 8)(sp)
+ sd t3, (TF_T + 3 * 8)(sp)
+ sd t4, (TF_T + 4 * 8)(sp)
+ sd t5, (TF_T + 5 * 8)(sp)
+ sd t6, (TF_T + 6 * 8)(sp)
+
+ sd s0, (TF_S + 0 * 8)(sp)
+ sd s1, (TF_S + 1 * 8)(sp)
+ sd s2, (TF_S + 2 * 8)(sp)
+ sd s3, (TF_S + 3 * 8)(sp)
+ sd s4, (TF_S + 4 * 8)(sp)
+ sd s5, (TF_S + 5 * 8)(sp)
+ sd s6, (TF_S + 6 * 8)(sp)
+ sd s7, (TF_S + 7 * 8)(sp)
+ sd s8, (TF_S + 8 * 8)(sp)
+ sd s9, (TF_S + 9 * 8)(sp)
+ sd s10, (TF_S + 10 * 8)(sp)
+ sd s11, (TF_S + 11 * 8)(sp)
+
+ sd a0, (TF_A + 0 * 8)(sp)
+ sd a1, (TF_A + 1 * 8)(sp)
+ sd a2, (TF_A + 2 * 8)(sp)
+ sd a3, (TF_A + 3 * 8)(sp)
+ sd a4, (TF_A + 4 * 8)(sp)
+ sd a5, (TF_A + 5 * 8)(sp)
+ sd a6, (TF_A + 6 * 8)(sp)
+ sd a7, (TF_A + 7 * 8)(sp)
+
+.if \el == 1
+ /* Store kernel sp */
+ li t1, TRAPFRAME_SIZEOF
+ add t0, sp, t1
+ sd t0, (TF_SP)(sp)
+.else
+ /* Store user sp */
+ csrr t0, sscratch
+ sd t0, (TF_SP)(sp)
+.endif
+ li t0, 0
+ csrw sscratch, t0
+ csrr t0, sepc
+ sd t0, (TF_SEPC)(sp)
+ csrr t0, sstatus
+ sd t0, (TF_SSTATUS)(sp)
+ csrr t0, stval
+ sd t0, (TF_STVAL)(sp)
+ csrr t0, scause
+ sd t0, (TF_SCAUSE)(sp)
+.endm
+
+.macro restore_registers el
+ ld t0, (TF_SSTATUS)(sp)
+.if \el == 0
+ /* Ensure user interrupts will be enabled on eret */
+ li t1, SSTATUS_SPIE
+ or t0, t0, t1
+.else
+ /*
+ * Disable interrupts for supervisor mode exceptions.
+ * For user mode exceptions we have already done this
+ * in do_ast.
+ */
+ li t1, ~SSTATUS_SIE
+ and t0, t0, t1
+.endif
+ csrw sstatus, t0
+
+ ld t0, (TF_SEPC)(sp)
+ csrw sepc, t0
+
+.if \el == 0
+ /* We go to userspace. Load user sp */
+ ld t0, (TF_SP)(sp)
+ csrw sscratch, t0
+
+ /* Store our pcpu */
+ sd tp, (TRAPFRAME_SIZEOF)(sp)
+ ld tp, (TF_TP)(sp)
+
+ /* And restore the user's global pointer */
+ ld gp, (TF_GP)(sp)
+.endif
+
+ ld ra, (TF_RA)(sp)
+
+ ld t0, (TF_T + 0 * 8)(sp)
+ ld t1, (TF_T + 1 * 8)(sp)
+ ld t2, (TF_T + 2 * 8)(sp)
+ ld t3, (TF_T + 3 * 8)(sp)
+ ld t4, (TF_T + 4 * 8)(sp)
+ ld t5, (TF_T + 5 * 8)(sp)
+ ld t6, (TF_T + 6 * 8)(sp)
+
+ ld s0, (TF_S + 0 * 8)(sp)
+ ld s1, (TF_S + 1 * 8)(sp)
+ ld s2, (TF_S + 2 * 8)(sp)
+ ld s3, (TF_S + 3 * 8)(sp)
+ ld s4, (TF_S + 4 * 8)(sp)
+ ld s5, (TF_S + 5 * 8)(sp)
+ ld s6, (TF_S + 6 * 8)(sp)
+ ld s7, (TF_S + 7 * 8)(sp)
+ ld s8, (TF_S + 8 * 8)(sp)
+ ld s9, (TF_S + 9 * 8)(sp)
+ ld s10, (TF_S + 10 * 8)(sp)
+ ld s11, (TF_S + 11 * 8)(sp)
+
+ ld a0, (TF_A + 0 * 8)(sp)
+ ld a1, (TF_A + 1 * 8)(sp)
+ ld a2, (TF_A + 2 * 8)(sp)
+ ld a3, (TF_A + 3 * 8)(sp)
+ ld a4, (TF_A + 4 * 8)(sp)
+ ld a5, (TF_A + 5 * 8)(sp)
+ ld a6, (TF_A + 6 * 8)(sp)
+ ld a7, (TF_A + 7 * 8)(sp)
+
+ addi sp, sp, (TRAPFRAME_SIZEOF)
+.endm
+
+.macro do_ast
+ /* Disable interrupts */
+ csrr a4, sstatus
+1:
+ csrci sstatus, (SSTATUS_SIE)
+
+ /* Check for astpending */
+ ld a1, CI_CURPROC(tp)
+ beqz a1, 2f
+ lw a2, P_ASTPENDING(a1)
+ beqz a2, 2f
+
+ sw x0, P_ASTPENDING(a1)
+
+ /* Restore interrupts */
+ csrw sstatus, a4
+
+ /* handle the ast */
+ mv a0, sp
+ la t0, _C_LABEL(ast)
+ jalr t0
+ j 1b
+2:
+.endm
+
+ENTRY(cpu_trap_handler)
+ csrrw sp, sscratch, sp
+ beqz sp, 1f
+ /* User mode detected */
+ j cpu_trap_handler_user
+1:
+ /* Supervisor mode detected */
+ csrrw sp, sscratch, sp
+ j cpu_trap_handler_supervisor
+END(cpu_trap_handler)
+
+ENTRY(cpu_trap_handler_supervisor)
+ save_registers 1
+ mv a0, sp
+ call _C_LABEL(do_trap_supervisor)
+ restore_registers 1
+ sret
+END(cpu_trap_handler_supervisor)
+
+ENTRY(cpu_trap_handler_user)
+ save_registers 0
+ mv a0, sp
+ call _C_LABEL(do_trap_user)
+ do_ast
+ restore_registers 0
+ csrrw sp, sscratch, sp
+ sret
+END(cpu_trap_handler_user)
+
+ENTRY(syscall_return)
+ do_ast
+ restore_registers 0
+ csrrw sp, sscratch, sp
+ sret
+END(syscall_return)
+++ /dev/null
-/*
- * Copyright (c) 2020 Mengshi Li <mengshi.li.mars@gmail.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "assym.h"
-#include <machine/asm.h>
-#include <machine/trap.h>
-#include <machine/riscvreg.h>
-
-.macro save_registers el
- addi sp, sp, -(TRAPFRAME_SIZEOF)
-
- sd ra, (TF_RA)(sp)
-
-.if \el == 0 /* We came from userspace. */
- sd gp, (TF_GP)(sp)
-.option push
-.option norelax
- /* Load the kernel's global pointer */
- la gp, __global_pointer$
-.option pop
-
- /* Load our pcpu */
- sd tp, (TF_TP)(sp)
- ld tp, (TRAPFRAME_SIZEOF)(sp)
-.endif
-
- sd t0, (TF_T + 0 * 8)(sp)
- sd t1, (TF_T + 1 * 8)(sp)
- sd t2, (TF_T + 2 * 8)(sp)
- sd t3, (TF_T + 3 * 8)(sp)
- sd t4, (TF_T + 4 * 8)(sp)
- sd t5, (TF_T + 5 * 8)(sp)
- sd t6, (TF_T + 6 * 8)(sp)
-
- sd s0, (TF_S + 0 * 8)(sp)
- sd s1, (TF_S + 1 * 8)(sp)
- sd s2, (TF_S + 2 * 8)(sp)
- sd s3, (TF_S + 3 * 8)(sp)
- sd s4, (TF_S + 4 * 8)(sp)
- sd s5, (TF_S + 5 * 8)(sp)
- sd s6, (TF_S + 6 * 8)(sp)
- sd s7, (TF_S + 7 * 8)(sp)
- sd s8, (TF_S + 8 * 8)(sp)
- sd s9, (TF_S + 9 * 8)(sp)
- sd s10, (TF_S + 10 * 8)(sp)
- sd s11, (TF_S + 11 * 8)(sp)
-
- sd a0, (TF_A + 0 * 8)(sp)
- sd a1, (TF_A + 1 * 8)(sp)
- sd a2, (TF_A + 2 * 8)(sp)
- sd a3, (TF_A + 3 * 8)(sp)
- sd a4, (TF_A + 4 * 8)(sp)
- sd a5, (TF_A + 5 * 8)(sp)
- sd a6, (TF_A + 6 * 8)(sp)
- sd a7, (TF_A + 7 * 8)(sp)
-
-.if \el == 1
- /* Store kernel sp */
- li t1, TRAPFRAME_SIZEOF
- add t0, sp, t1
- sd t0, (TF_SP)(sp)
-.else
- /* Store user sp */
- csrr t0, sscratch
- sd t0, (TF_SP)(sp)
-.endif
- li t0, 0
- csrw sscratch, t0
- csrr t0, sepc
- sd t0, (TF_SEPC)(sp)
- csrr t0, sstatus
- sd t0, (TF_SSTATUS)(sp)
- csrr t0, stval
- sd t0, (TF_STVAL)(sp)
- csrr t0, scause
- sd t0, (TF_SCAUSE)(sp)
-.endm
-
-.macro restore_registers el
- ld t0, (TF_SSTATUS)(sp)
-.if \el == 0
- /* Ensure user interrupts will be enabled on eret */
- li t1, SSTATUS_SPIE
- or t0, t0, t1
-.else
- /*
- * Disable interrupts for supervisor mode exceptions.
- * For user mode exceptions we have already done this
- * in do_ast.
- */
- li t1, ~SSTATUS_SIE
- and t0, t0, t1
-.endif
- csrw sstatus, t0
-
- ld t0, (TF_SEPC)(sp)
- csrw sepc, t0
-
-.if \el == 0
- /* We go to userspace. Load user sp */
- ld t0, (TF_SP)(sp)
- csrw sscratch, t0
-
- /* Store our pcpu */
- sd tp, (TRAPFRAME_SIZEOF)(sp)
- ld tp, (TF_TP)(sp)
-
- /* And restore the user's global pointer */
- ld gp, (TF_GP)(sp)
-.endif
-
- ld ra, (TF_RA)(sp)
-
- ld t0, (TF_T + 0 * 8)(sp)
- ld t1, (TF_T + 1 * 8)(sp)
- ld t2, (TF_T + 2 * 8)(sp)
- ld t3, (TF_T + 3 * 8)(sp)
- ld t4, (TF_T + 4 * 8)(sp)
- ld t5, (TF_T + 5 * 8)(sp)
- ld t6, (TF_T + 6 * 8)(sp)
-
- ld s0, (TF_S + 0 * 8)(sp)
- ld s1, (TF_S + 1 * 8)(sp)
- ld s2, (TF_S + 2 * 8)(sp)
- ld s3, (TF_S + 3 * 8)(sp)
- ld s4, (TF_S + 4 * 8)(sp)
- ld s5, (TF_S + 5 * 8)(sp)
- ld s6, (TF_S + 6 * 8)(sp)
- ld s7, (TF_S + 7 * 8)(sp)
- ld s8, (TF_S + 8 * 8)(sp)
- ld s9, (TF_S + 9 * 8)(sp)
- ld s10, (TF_S + 10 * 8)(sp)
- ld s11, (TF_S + 11 * 8)(sp)
-
- ld a0, (TF_A + 0 * 8)(sp)
- ld a1, (TF_A + 1 * 8)(sp)
- ld a2, (TF_A + 2 * 8)(sp)
- ld a3, (TF_A + 3 * 8)(sp)
- ld a4, (TF_A + 4 * 8)(sp)
- ld a5, (TF_A + 5 * 8)(sp)
- ld a6, (TF_A + 6 * 8)(sp)
- ld a7, (TF_A + 7 * 8)(sp)
-
- addi sp, sp, (TRAPFRAME_SIZEOF)
-.endm
-
-.macro do_ast
- /* Disable interrupts */
- csrr a4, sstatus
-1:
- csrci sstatus, (SSTATUS_SIE)
-
- /* Check for astpending */
- ld a1, CI_CURPROC(tp)
- beqz a1, 2f
- lw a2, P_ASTPENDING(a1)
- beqz a2, 2f
-
- sw x0, P_ASTPENDING(a1)
-
- /* Restore interrupts */
- csrw sstatus, a4
-
- /* handle the ast */
- mv a0, sp
- la t0, _C_LABEL(ast)
- jalr t0
- j 1b
-2:
-.endm
-
-ENTRY(cpu_trap_handler)
- csrrw sp, sscratch, sp
- beqz sp, 1f
- /* User mode detected */
- j cpu_trap_handler_user
-1:
- /* Supervisor mode detected */
- csrrw sp, sscratch, sp
- j cpu_trap_handler_supervisor
-END(cpu_trap_handler)
-
-ENTRY(cpu_trap_handler_supervisor)
- save_registers 1
- mv a0, sp
- call _C_LABEL(do_trap_supervisor)
- restore_registers 1
- sret
-END(cpu_trap_handler_supervisor)
-
-ENTRY(cpu_trap_handler_user)
- save_registers 0
- mv a0, sp
- call _C_LABEL(do_trap_user)
- do_ast
- restore_registers 0
- csrrw sp, sscratch, sp
- sret
-END(cpu_trap_handler_user)
-
-ENTRY(syscall_return)
- do_ast
- restore_registers 0
- csrrw sp, sscratch, sp
- sret
-END(syscall_return)
--- /dev/null
+/*
+ * Copyright (c) 2020 Shivam Waghela <shivamwaghela@gmail.com>
+ * Copyright (c) 2020 Brian Bamsch <bbamsch@google.com>
+ * Copyright (c) 2020 Mengshi Li <mengshi.li.mars@gmail.com>
+ * Copyright (c) 2015 Dale Rahn <drahn@dalerahn.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/signalvar.h>
+#include <sys/siginfo.h>
+#include <sys/syscall.h>
+#include <sys/syscall_mi.h>
+
+#include <machine/riscvreg.h>
+#include <machine/syscall.h>
+#include <machine/db_machdep.h>
+
+/* Called from exception.S */
+void do_trap_supervisor(struct trapframe *);
+void do_trap_user(struct trapframe *);
+
+static void data_abort(struct trapframe *, int);
+
+static void
+dump_regs(struct trapframe *frame)
+{
+ int n;
+ int i;
+
+ n = (sizeof(frame->tf_t) / sizeof(frame->tf_t[0]));
+ for (i = 0; i < n; i++)
+ printf("t[%d] == 0x%016lx\n", i, frame->tf_t[i]);
+
+ n = (sizeof(frame->tf_s) / sizeof(frame->tf_s[0]));
+ for (i = 0; i < n; i++)
+ printf("s[%d] == 0x%016lx\n", i, frame->tf_s[i]);
+
+ n = (sizeof(frame->tf_a) / sizeof(frame->tf_a[0]));
+ for (i = 0; i < n; i++)
+ printf("a[%d] == 0x%016lx\n", i, frame->tf_a[i]);
+
+ printf("sepc == 0x%016lx\n", frame->tf_sepc);
+ printf("sstatus == 0x%016lx\n", frame->tf_sstatus);
+}
+
+void
+do_trap_supervisor(struct trapframe *frame)
+{
+ uint64_t exception;
+
+ /* Ensure we came from supervisor mode, interrupts disabled */
+ KASSERTMSG((csr_read(sstatus) & (SSTATUS_SPP | SSTATUS_SIE)) ==
+ SSTATUS_SPP, "Came from S mode with interrupts enabled");
+
+ if (frame->tf_scause & EXCP_INTR) {
+ /* Interrupt */
+ riscv_cpu_intr(frame);
+ return;
+ }
+
+ exception = (frame->tf_scause & EXCP_MASK);
+ switch(exception) {
+ case EXCP_FAULT_LOAD:
+ case EXCP_FAULT_STORE:
+ case EXCP_FAULT_FETCH:
+ case EXCP_STORE_PAGE_FAULT:
+ case EXCP_LOAD_PAGE_FAULT:
+ data_abort(frame, 0);
+ break;
+ case EXCP_BREAKPOINT:
+#ifdef DDB
+ // kdb_trap(exception, 0, frame);
+ db_trapper(frame->tf_sepc,0/*XXX*/, frame, exception);
+#else
+ dump_regs(frame);
+ panic("No debugger in kernel.\n");
+#endif
+ break;
+ case EXCP_ILLEGAL_INSTRUCTION:
+ dump_regs(frame);
+ panic("Illegal instruction at 0x%016lx\n", frame->tf_sepc);
+ break;
+ default:
+ dump_regs(frame);
+ panic("Unknown kernel exception %llx trap value %lx\n",
+ exception, frame->tf_stval);
+ }
+}
+
+
+void
+do_trap_user(struct trapframe *frame)
+{
+ uint64_t exception;
+ union sigval sv;
+ struct proc *p;
+ struct pcb *pcb;
+
+ p = curcpu()->ci_curproc;
+ p->p_addr->u_pcb.pcb_tf = frame;
+ pcb = curcpu()->ci_curpcb;
+
+ /* Ensure we came from usermode, interrupts disabled */
+ KASSERTMSG((csr_read(sstatus) & (SSTATUS_SPP | SSTATUS_SIE)) == 0,
+ "Came from U mode with interrupts enabled");
+
+ /* Save fpu context before (possibly) calling interrupt handler.
+ * Could end up context switching in interrupt handler.
+ */
+ fpu_save(p, frame);
+
+ exception = (frame->tf_scause & EXCP_MASK);
+ if (frame->tf_scause & EXCP_INTR) {
+ /* Interrupt */
+ riscv_cpu_intr(frame);
+ frame->tf_sstatus &= ~SSTATUS_FS_MASK;
+ if (pcb->pcb_fpcpu == curcpu() && curcpu()->ci_fpuproc == p) {
+ frame->tf_sstatus |= SSTATUS_FS_CLEAN;
+ }
+ return;
+ }
+
+ enable_interrupts(); //XXX allow preemption?
+
+#if 0 // XXX Debug logging
+ printf( "do_trap_user: curproc: %p, sepc: %lx, ra: %lx frame: %p\n",
+ curcpu()->ci_curproc, frame->tf_sepc, frame->tf_ra, frame);
+#endif
+
+ switch(exception) {
+ case EXCP_FAULT_LOAD:
+ case EXCP_FAULT_STORE:
+ case EXCP_FAULT_FETCH:
+ case EXCP_STORE_PAGE_FAULT:
+ case EXCP_LOAD_PAGE_FAULT:
+ case EXCP_INST_PAGE_FAULT:
+ data_abort(frame, 1);
+ break;
+ case EXCP_USER_ECALL:
+ frame->tf_sepc += 4; /* Next instruction */
+ svc_handler(frame);
+ break;
+ case EXCP_ILLEGAL_INSTRUCTION:
+
+ if ((frame->tf_sstatus & SSTATUS_FS_MASK) ==
+ SSTATUS_FS_OFF) {
+ if(fpu_valid_opcode(frame->tf_stval)) {
+
+ /* XXX do this here or should it be in the
+ * trap handler in the restore path?
+ */
+ fpu_load(p);
+
+ frame->tf_sstatus &= ~SSTATUS_FS_MASK;
+ break;
+ }
+ }
+ printf("ILL at %lx scause %lx stval %lx\n", frame->tf_sepc, 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",
+ exception, frame->tf_stval);
+ }
+ disable_interrupts(); /* XXX - ??? */
+ /* now that we will not context switch again,
+ * see if we should enable FPU
+ */
+ frame->tf_sstatus &= ~SSTATUS_FS_MASK;
+ if (pcb->pcb_fpcpu == curcpu() && curcpu()->ci_fpuproc == p) {
+ frame->tf_sstatus |= SSTATUS_FS_CLEAN;
+ //printf ("FPU enabled userland %p %p\n",
+ // pcb->pcb_fpcpu, curcpu()->ci_fpuproc);
+ }
+}
+
+static void
+data_abort(struct trapframe *frame, int usermode)
+{
+ struct vm_map *map;
+ uint64_t stval;
+ union sigval sv;
+ struct pcb *pcb;
+ vm_prot_t ftype;
+ vaddr_t va;
+ struct proc *p;
+ int error, sig, code, access_type;
+
+ 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();
+
+ 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;
+ }
+
+ ftype = VM_FAULT_INVALID; // should check for failed permissions.
+
+ if (usermode)
+ map = &p->p_vmspace->vm_map;
+ else 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, usermode))
+ goto done;
+
+ KERNEL_LOCK();
+ error = uvm_fault(map, va, ftype, access_type);
+ KERNEL_UNLOCK();
+
+ 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;
+ }
+ }
+
+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);
+}
+
+++ /dev/null
-/*
- * Copyright (c) 2020 Shivam Waghela <shivamwaghela@gmail.com>
- * Copyright (c) 2020 Brian Bamsch <bbamsch@google.com>
- * Copyright (c) 2020 Mengshi Li <mengshi.li.mars@gmail.com>
- * Copyright (c) 2015 Dale Rahn <drahn@dalerahn.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/proc.h>
-#include <sys/user.h>
-#include <sys/signalvar.h>
-#include <sys/siginfo.h>
-#include <sys/syscall.h>
-#include <sys/syscall_mi.h>
-
-#include <machine/riscvreg.h>
-#include <machine/syscall.h>
-#include <machine/db_machdep.h>
-
-/* Called from trap.S */
-void do_trap_supervisor(struct trapframe *);
-void do_trap_user(struct trapframe *);
-
-static void data_abort(struct trapframe *, int);
-
-static void
-dump_regs(struct trapframe *frame)
-{
- int n;
- int i;
-
- n = (sizeof(frame->tf_t) / sizeof(frame->tf_t[0]));
- for (i = 0; i < n; i++)
- printf("t[%d] == 0x%016lx\n", i, frame->tf_t[i]);
-
- n = (sizeof(frame->tf_s) / sizeof(frame->tf_s[0]));
- for (i = 0; i < n; i++)
- printf("s[%d] == 0x%016lx\n", i, frame->tf_s[i]);
-
- n = (sizeof(frame->tf_a) / sizeof(frame->tf_a[0]));
- for (i = 0; i < n; i++)
- printf("a[%d] == 0x%016lx\n", i, frame->tf_a[i]);
-
- printf("sepc == 0x%016lx\n", frame->tf_sepc);
- printf("sstatus == 0x%016lx\n", frame->tf_sstatus);
-}
-
-void
-do_trap_supervisor(struct trapframe *frame)
-{
- uint64_t exception;
-
- /* Ensure we came from supervisor mode, interrupts disabled */
- KASSERTMSG((csr_read(sstatus) & (SSTATUS_SPP | SSTATUS_SIE)) ==
- SSTATUS_SPP, "Came from S mode with interrupts enabled");
-
- if (frame->tf_scause & EXCP_INTR) {
- /* Interrupt */
- riscv_cpu_intr(frame);
- return;
- }
-
- exception = (frame->tf_scause & EXCP_MASK);
- switch(exception) {
- case EXCP_FAULT_LOAD:
- case EXCP_FAULT_STORE:
- case EXCP_FAULT_FETCH:
- case EXCP_STORE_PAGE_FAULT:
- case EXCP_LOAD_PAGE_FAULT:
- data_abort(frame, 0);
- break;
- case EXCP_BREAKPOINT:
-#ifdef DDB
- // kdb_trap(exception, 0, frame);
- db_trapper(frame->tf_sepc,0/*XXX*/, frame, exception);
-#else
- dump_regs(frame);
- panic("No debugger in kernel.\n");
-#endif
- break;
- case EXCP_ILLEGAL_INSTRUCTION:
- dump_regs(frame);
- panic("Illegal instruction at 0x%016lx\n", frame->tf_sepc);
- break;
- default:
- dump_regs(frame);
- panic("Unknown kernel exception %llx trap value %lx\n",
- exception, frame->tf_stval);
- }
-}
-
-
-void
-do_trap_user(struct trapframe *frame)
-{
- uint64_t exception;
- union sigval sv;
- struct proc *p;
- struct pcb *pcb;
-
- p = curcpu()->ci_curproc;
- p->p_addr->u_pcb.pcb_tf = frame;
- pcb = curcpu()->ci_curpcb;
-
- /* Ensure we came from usermode, interrupts disabled */
- KASSERTMSG((csr_read(sstatus) & (SSTATUS_SPP | SSTATUS_SIE)) == 0,
- "Came from U mode with interrupts enabled");
-
- /* Save fpu context before (possibly) calling interrupt handler.
- * Could end up context switching in interrupt handler.
- */
- fpu_save(p, frame);
-
- exception = (frame->tf_scause & EXCP_MASK);
- if (frame->tf_scause & EXCP_INTR) {
- /* Interrupt */
- riscv_cpu_intr(frame);
- frame->tf_sstatus &= ~SSTATUS_FS_MASK;
- if (pcb->pcb_fpcpu == curcpu() && curcpu()->ci_fpuproc == p) {
- frame->tf_sstatus |= SSTATUS_FS_CLEAN;
- }
- return;
- }
-
- enable_interrupts(); //XXX allow preemption?
-
-#if 0 // XXX Debug logging
- printf( "do_trap_user: curproc: %p, sepc: %lx, ra: %lx frame: %p\n",
- curcpu()->ci_curproc, frame->tf_sepc, frame->tf_ra, frame);
-#endif
-
- switch(exception) {
- case EXCP_FAULT_LOAD:
- case EXCP_FAULT_STORE:
- case EXCP_FAULT_FETCH:
- case EXCP_STORE_PAGE_FAULT:
- case EXCP_LOAD_PAGE_FAULT:
- case EXCP_INST_PAGE_FAULT:
- data_abort(frame, 1);
- break;
- case EXCP_USER_ECALL:
- frame->tf_sepc += 4; /* Next instruction */
- svc_handler(frame);
- break;
- case EXCP_ILLEGAL_INSTRUCTION:
-
- if ((frame->tf_sstatus & SSTATUS_FS_MASK) ==
- SSTATUS_FS_OFF) {
- if(fpu_valid_opcode(frame->tf_stval)) {
-
- /* XXX do this here or should it be in the
- * trap handler in the restore path?
- */
- fpu_load(p);
-
- frame->tf_sstatus &= ~SSTATUS_FS_MASK;
- break;
- }
- }
- printf("ILL at %lx scause %lx stval %lx\n", frame->tf_sepc, 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",
- exception, frame->tf_stval);
- }
- disable_interrupts(); /* XXX - ??? */
- /* now that we will not context switch again,
- * see if we should enable FPU
- */
- frame->tf_sstatus &= ~SSTATUS_FS_MASK;
- if (pcb->pcb_fpcpu == curcpu() && curcpu()->ci_fpuproc == p) {
- frame->tf_sstatus |= SSTATUS_FS_CLEAN;
- //printf ("FPU enabled userland %p %p\n",
- // pcb->pcb_fpcpu, curcpu()->ci_fpuproc);
- }
-}
-
-static void
-data_abort(struct trapframe *frame, int usermode)
-{
- struct vm_map *map;
- uint64_t stval;
- union sigval sv;
- struct pcb *pcb;
- vm_prot_t ftype;
- vaddr_t va;
- struct proc *p;
- int error, sig, code, access_type;
-
- 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();
-
- 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;
- }
-
- ftype = VM_FAULT_INVALID; // should check for failed permissions.
-
- if (usermode)
- map = &p->p_vmspace->vm_map;
- else 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, usermode))
- goto done;
-
- KERNEL_LOCK();
- error = uvm_fault(map, va, ftype, access_type);
- KERNEL_UNLOCK();
-
- 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;
- }
- }
-
-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);
-}
-