Module Name: src Committed By: skrll Date: Fri Oct 14 07:58:30 UTC 2022
Modified Files: src/sys/arch/riscv/conf: files.riscv src/sys/arch/riscv/riscv: locore.S Added Files: src/sys/arch/riscv/riscv: cpu_switch.S Log Message: Split out a bunch of functions from locore.S into cpu_switch.S NFC To generate a diff of this commit: cvs rdiff -u -r1.10 -r1.11 src/sys/arch/riscv/conf/files.riscv cvs rdiff -u -r0 -r1.1 src/sys/arch/riscv/riscv/cpu_switch.S cvs rdiff -u -r1.29 -r1.30 src/sys/arch/riscv/riscv/locore.S Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/riscv/conf/files.riscv diff -u src/sys/arch/riscv/conf/files.riscv:1.10 src/sys/arch/riscv/conf/files.riscv:1.11 --- src/sys/arch/riscv/conf/files.riscv:1.10 Tue Sep 27 08:18:21 2022 +++ src/sys/arch/riscv/conf/files.riscv Fri Oct 14 07:58:30 2022 @@ -1,4 +1,4 @@ -# $NetBSD: files.riscv,v 1.10 2022/09/27 08:18:21 skrll Exp $ +# $NetBSD: files.riscv,v 1.11 2022/10/14 07:58:30 skrll Exp $ # maxpartitions 16 @@ -21,6 +21,7 @@ file arch/riscv/riscv/bus_space_notimpl. file arch/riscv/riscv/clock_machdep.c file arch/riscv/riscv/core_machdep.c coredump file arch/riscv/riscv/cpu_subr.c +file arch/riscv/riscv/cpu_switch.S file arch/riscv/riscv/db_interface.c ddb file arch/riscv/riscv/db_disasm.c ddb file arch/riscv/riscv/db_machdep.c ddb | kgdb Index: src/sys/arch/riscv/riscv/locore.S diff -u src/sys/arch/riscv/riscv/locore.S:1.29 src/sys/arch/riscv/riscv/locore.S:1.30 --- src/sys/arch/riscv/riscv/locore.S:1.29 Fri Sep 30 06:23:59 2022 +++ src/sys/arch/riscv/riscv/locore.S Fri Oct 14 07:58:30 2022 @@ -1,4 +1,4 @@ -/* $NetBSD: locore.S,v 1.29 2022/09/30 06:23:59 skrll Exp $ */ +/* $NetBSD: locore.S,v 1.30 2022/10/14 07:58:30 skrll Exp $ */ /*- * Copyright (c) 2014, 2022 The NetBSD Foundation, Inc. @@ -566,396 +566,6 @@ l3_pte: mmutables_end: -// -// struct lwp *cpu_switchto(struct lwp *oldl, struct lwp *newl, bool returning); -// -ENTRY_NP(cpu_switchto) - addi sp, sp, -TF_LEN // allocate trapframe - - REG_S ra, TF_RA(sp) // save return address - REG_S s0, TF_S0(sp) // save callee saved address - REG_S s1, TF_S1(sp) // save callee saved address - REG_S s2, TF_S2(sp) // save callee saved address - REG_S s3, TF_S3(sp) // save callee saved address - REG_S s4, TF_S4(sp) // save callee saved address - REG_S s5, TF_S5(sp) // save callee saved address - REG_S s6, TF_S6(sp) // save callee saved address - REG_S s7, TF_S7(sp) // save callee saved address - REG_S s8, TF_S8(sp) // save callee saved address - REG_S s9, TF_S9(sp) // save callee saved address - REG_S s10, TF_S10(sp) // save callee saved address - REG_S s11, TF_S11(sp) // save callee saved address - csrr t4, sstatus // get status for intr state - REG_S t4, TF_SR(sp) // save it - - REG_S sp, L_MD_KTF(a0) // record trapframe pointer - - csrrci t0, sstatus, SR_SIE // # disable interrupts - - mv tp, a1 // # put the new lwp in thread pointer - - PTR_L t1, L_CPU(tp) // # get curcpu - PTR_S tp, CI_CURLWP(t1) // # update curcpu with the new curlwp - - REG_L sp, L_MD_KTF(tp) // # load its kernel stack pointer - REG_L t4, TF_SR(sp) // # fetch status register - csrw sstatus, t4 // # restore it (and interrupts?) - - REG_L s0, TF_S0(sp) // restore callee saved - REG_L s1, TF_S1(sp) // restore callee saved - REG_L s2, TF_S2(sp) // restore callee saved - REG_L s3, TF_S3(sp) // restore callee saved - REG_L s4, TF_S4(sp) // restore callee saved - REG_L s5, TF_S5(sp) // restore callee saved - REG_L s6, TF_S6(sp) // restore callee saved - REG_L s7, TF_S7(sp) // restore callee saved - REG_L s8, TF_S8(sp) // restore callee saved - REG_L s9, TF_S9(sp) // restore callee saved - REG_L s10, TF_S10(sp) // restore callee saved - REG_L s11, TF_S11(sp) // restore callee saved - - REG_L ra, TF_RA(sp) // restore return address - - addi sp, sp, TF_LEN // remove trapframe - - // a0 = oldl - // a1 = curcpu() - // tp = newl - - ret -END(cpu_switchto) - -ENTRY_NP(cpu_lwp_trampoline) - mv a1, tp // get new lwp - call _C_LABEL(lwp_startup) // call lwp startup - - mv a0, s1 // get saved arg - jalr s0 // call saved func - - // If the saved func returns, we are returning to user land. - j _C_LABEL(exception_userexit) -END(cpu_lwp_trampoline) - -ENTRY_NP(cpu_fast_switchto_cleanup) - INT_L t0, CI_MTX_COUNT(a1) // get mutex count - REG_L ra, CALLFRAME_RA(sp) // get return address - REG_L a0, CALLFRAME_S0(sp) // get pinned LWP - addi t0, t0, 1 // increment mutex count - INT_S t0, CI_MTX_COUNT(a1) // save it - addi sp, sp, CALLFRAME_SIZ // remove callframe -#if IPL_SCHED != IPL_HIGH - tail _C_LABEL(splhigh) // go back to IPL HIGH -#else - ret // just return -#endif -END(cpu_fast_switchto_cleanup) - -// -// void cpu_fast_switchto(struct lwp *, int s); -// -ENTRY_NP(cpu_fast_switchto) - addi sp, sp, -(TF_LEN + CALLFRAME_SIZ) - REG_S a0, (TF_LEN + CALLFRAME_S0)(sp) - REG_S ra, (TF_LEN + CALLFRAME_RA)(sp) - - PTR_LA t2, _C_LABEL(cpu_fast_switchto_cleanup) - - REG_S t2, TF_RA(sp) // return to someplace else - REG_S s0, TF_S0(sp) // save callee saved register - REG_S s1, TF_S1(sp) // save callee saved register - REG_S s2, TF_S2(sp) // save callee saved register - REG_S s3, TF_S3(sp) // save callee saved register - REG_S s4, TF_S4(sp) // save callee saved register - REG_S s5, TF_S5(sp) // save callee saved register - REG_S s6, TF_S6(sp) // save callee saved register - REG_S s7, TF_S7(sp) // save callee saved register - REG_S s8, TF_S8(sp) // save callee saved register - REG_S s9, TF_S9(sp) // save callee saved register - REG_S s10, TF_S10(sp) // save callee saved register - REG_S s11, TF_S11(sp) // save callee saved register - csrr t4, sstatus // get status register (for intr state) - REG_S t4, TF_SR(sp) // save it - - mv s0, tp // remember curlwp - mv s1, sp // remember kernel stack - - csrrci t0, sstatus, SR_SIE // disable interrupts - PTR_L t1, L_CPU(tp) // get curcpu() - - PTR_S sp, L_MD_KTF(tp) // save trapframe ptr in oldlwp - mv tp, a0 // set thread pointer to newlwp - PTR_S tp, CI_CURLWP(t1) // update curlwp - PTR_L sp, L_MD_KTF(tp) // switch to its stack - csrw sstatus, t0 // reenable interrupts - call _C_LABEL(softint_dispatch) - csrrci t0, sstatus, SR_SIE // disable interrupts - PTR_L t1, L_CPU(tp) // get curcpu() again - mv tp, s0 // return to pinned lwp - PTR_S tp, CI_CURLWP(t1) // restore curlwp - csrw sstatus, t0 // reenable interrupts - mv sp, s1 // restore stack pointer - - REG_L ra, (TF_RA + CALLFRAME_RA)(sp) // get return address - REG_L s0, TF_S0(sp) // restore register we used - REG_L s1, TF_S1(sp) // restore register we used - - addi sp, sp, TF_LEN+CALLFRAME_SIZ // drop trapframe/callframe - ret // return -END(cpu_fast_switchto) - -// RISCV only has a simple exception handler handles both synchronous traps -// and interrupts. -ENTRY_NP(cpu_exception_handler) - csrrw tp, sscratch, tp // swap scratch and thread pointer - beqz tp, .Lexception_kernel // tp == 0, already on kernel stack - // - // The exception happened while user code was executing. We need to - // get the pointer to the user trapframe from the LWP md area. Then we - // save t1 and tp so we have a register to work with and to get curlwp - // into tp. We also save the saved SP into the trapframe. - // Upon entry on an exception from user, sscratch will contain curlwp. - // - REG_S sp, L_MD_USP(tp) // save user stack pointer temporarily - PTR_L sp, L_MD_UTF(sp) // trapframe pointer loaded - REG_S t1, TF_T1(sp) // save t1 - REG_L t1, L_MD_USP(tp) // get user stack pointer - REG_S t1, TF_SP(sp) // save thread pointer in trapframe - csrrw t1, sscratch, zero // swap saved thread pointer with 0 - REG_L t1, TF_TP(sp) // save thread pointer in trapframe - li t1, 0 // indicate user exception - j .Lexception_common - - // - // The exception happened while we were already in the kernel. That - // means tp already has curlwp and sp has the kernel stack pointer so - // just need to restore it and then adjust it down for space for the - // trap frame. We save t1 so we can use it the original sp into the - // trapframe for use by the exception exiting code. - // -.Lexception_kernel: - csrrw tp, sscratch, zero // get back our thread pointer - addi sp, sp, -TF_LEN // allocate stack frame - REG_S t1, TF_T1(sp) // save t1 - addi t1, sp, TF_LEN - REG_S t1, TF_SP(sp) // save SP - li t1, 1 // indicate kernel exception - -.Lexception_common: - // Now we save all the temporary registers into the trapframe since - // they will most certainly be changed. - REG_S ra, TF_RA(sp) // save return address - REG_S gp, TF_GP(sp) // save gp - REG_S a0, TF_A0(sp) // save a0 - REG_S a1, TF_A1(sp) // save a1 - REG_S a2, TF_A2(sp) // save a2 - REG_S a3, TF_A3(sp) // save a3 - REG_S a4, TF_A4(sp) // save a4 - REG_S a5, TF_A5(sp) // save a5 - REG_S a6, TF_A6(sp) // save a6 - REG_S a7, TF_A7(sp) // save a7 - REG_S t0, TF_T0(sp) // save t0 - // t1 is already saved - REG_S t2, TF_T2(sp) // save t2 - REG_S t3, TF_T3(sp) // save t3 - REG_S t4, TF_T4(sp) // save t4 - REG_S t5, TF_T5(sp) // save t5 - REG_S t6, TF_T6(sp) // save t6 - - // Now we get the - mv a0, sp // trapframe pointer - csrr a1, sepc // get exception pc - csrr a2, sstatus // get status - csrr a3, scause // get cause - - REG_S a1, TF_PC(sp) - INT_S a2, TF_SR(sp) - INT_S a3, TF_CAUSE(sp) // save cause - - // Now we've saved the trapfame, the cause is still in a3. - - bltz a3, intr_handler // MSB is set if interrupt - - // stval is only relevant for non-interrupts - csrr a4, stval // get stval - REG_S a4, TF_TVAL(sp) - - beqz t1, trap_user // this was a user trap - // This was a kernel exception - call _C_LABEL(cpu_trap) // just call trap to handle it -exception_kernexit: - // If we got here, we are returning from a kernel exception (either a - // trap or interrupt). Simply return the volatile registers and the - // exception PC and status, load the saved SP from the trapframe, and - // return from the exception - csrrci zero, sstatus, SR_SIE // disable interrupts - - REG_L ra, TF_RA(sp) // restore return address - REG_L gp, TF_GP(sp) // restore gp - REG_L a0, TF_A0(sp) // restore a0 - REG_L a1, TF_A1(sp) // restore a1 - REG_L a2, TF_A2(sp) // restore a2 - REG_L a3, TF_A3(sp) // restore a3 - REG_L a4, TF_A4(sp) // restore a4 - REG_L a5, TF_A5(sp) // restore a5 - REG_L a6, TF_A6(sp) // restore a6 - REG_L a7, TF_A7(sp) // restore a7 - REG_L t2, TF_T2(sp) // restore t2 - REG_L t3, TF_T3(sp) // restore t3 - REG_L t4, TF_T4(sp) // restore t4 - REG_L t5, TF_T3(sp) // restore t5 - REG_L t6, TF_T4(sp) // restore t6 - - REG_L t0, TF_PC(sp) // fetch exception PC - REG_L t1, TF_SR(sp) // fetch status - - csrw sepc, t0 // restore exception PC - csrw sstatus, t1 // restore status - - REG_L t0, TF_T0(sp) // restore t0 - REG_L t1, TF_T1(sp) // restore t1 - REG_L sp, TF_SP(sp) // restore SP - sret // and we're done - -trap_user: - REG_S s0, TF_S0(sp) // only save from userland - REG_S s1, TF_S1(sp) // only save from userland - REG_S s2, TF_S2(sp) // only save from userland - REG_S s3, TF_S3(sp) // only save from userland - REG_S s4, TF_S4(sp) // only save from userland - REG_S s5, TF_S5(sp) // only save from userland - REG_S s6, TF_S6(sp) // only save from userland - REG_S s7, TF_S7(sp) // only save from userland - REG_S s8, TF_S8(sp) // only save from userland - REG_S s9, TF_S9(sp) // only save from userland - REG_S s10, TF_S10(sp) // only save from userland - REG_S s11, TF_S11(sp) // only save from userland - - csrsi sstatus, SR_SIE // reenable interrupts - - li t0, CAUSE_SYSCALL // let's see if this was a syscall - beq a3, t0, trap_syscall // yes it was - - call _C_LABEL(cpu_trap) // nope, just a regular trap -_C_LABEL(exception_userexit): - INT_L t0, L_MD_ASTPENDING(tp) // ast pending? - bnez t0, trap_doast // yes, handle it. - csrrci zero, sstatus, SR_SIE // disable interrupts - csrw sscratch, tp // show we are coming from userland - REG_L tp, TF_TP(sp) // only restore from userland - REG_L s0, TF_S0(sp) // only restore from userland - REG_L s1, TF_S1(sp) // only restore from userland - REG_L s2, TF_S2(sp) // only restore from userland - REG_L s3, TF_S3(sp) // only restore from userland - REG_L s4, TF_S4(sp) // only restore from userland - REG_L s5, TF_S5(sp) // only restore from userland - REG_L s6, TF_S6(sp) // only restore from userland - REG_L s7, TF_S7(sp) // only restore from userland - REG_L s8, TF_S8(sp) // only restore from userland - REG_L s9, TF_S9(sp) // only restore from userland - REG_L s10, TF_S10(sp) // only restore from userland - REG_L s11, TF_S11(sp) // only restore from userland - j exception_kernexit - -trap_syscall: - PTR_LA ra, exception_userexit - PTR_L t0, L_PROC(tp) // get proc struct - PTR_L t0, P_MD_SYSCALL(t0) // get syscall address from proc - jr t0 // and jump to it - -intr_usersave: - REG_S s0, TF_S0(sp) // only save from userland - REG_S s1, TF_S1(sp) // only save from userland - REG_S s2, TF_S2(sp) // only save from userland - REG_S s3, TF_S3(sp) // only save from userland - REG_S s4, TF_S4(sp) // only save from userland - REG_S s5, TF_S5(sp) // only save from userland - REG_S s6, TF_S6(sp) // only save from userland - REG_S s7, TF_S7(sp) // only save from userland - REG_S s8, TF_S8(sp) // only save from userland - REG_S s9, TF_S9(sp) // only save from userland - REG_S s10, TF_S10(sp) // only save from userland - REG_S s11, TF_S11(sp) // only save from userland - PTR_LA ra, exception_userexit -trap_doast: - mv a0, sp // only argument is trapframe - tail _C_LABEL(cpu_ast) - -intr_user: - call _C_LABEL(cpu_intr) // handle interrupt - INT_L t0, L_MD_ASTPENDING(tp) // get astpending - bnez t0, intr_usersave // if one is pending, deal with in - - csrw sscratch, tp // show we are coming from userland - REG_L tp, TF_TP(sp) // restore thread pointer - j exception_kernexit // do standard exception exit - -intr_handler: - beqz t1, intr_user - call _C_LABEL(cpu_intr) - j exception_kernexit -END(cpu_exception_handler) - -// int cpu_set_onfault(struct faultbuf *fb, register_t retval) -// -ENTRY_NP(cpu_set_onfault) - REG_S ra, FB_RA(a0) - REG_S s0, FB_S0(a0) - REG_S s1, FB_S1(a0) - REG_S s2, FB_S2(a0) - REG_S s3, FB_S3(a0) - REG_S s4, FB_S4(a0) - REG_S s5, FB_S5(a0) - REG_S s6, FB_S6(a0) - REG_S s7, FB_S7(a0) - REG_S s8, FB_S8(a0) - REG_S s9, FB_S9(a0) - REG_S s10, FB_S10(a0) - REG_S s11, FB_S11(a0) - REG_S sp, FB_SP(a0) - REG_S a1, FB_A0(a0) - PTR_S a0, L_MD_ONFAULT(tp) - li a0, 0 - ret -END(cpu_set_onfault) - -ENTRY_NP(setjmp) - REG_S ra, FB_RA(a0) - REG_S s0, FB_S0(a0) - REG_S s1, FB_S1(a0) - REG_S s2, FB_S2(a0) - REG_S s3, FB_S3(a0) - REG_S s4, FB_S4(a0) - REG_S s5, FB_S5(a0) - REG_S s6, FB_S6(a0) - REG_S s7, FB_S7(a0) - REG_S s8, FB_S8(a0) - REG_S s9, FB_S9(a0) - REG_S s10, FB_S10(a0) - REG_S s11, FB_S11(a0) - REG_S sp, FB_SP(a0) - li a0, 0 - ret -END(setjmp) - -ENTRY_NP(longjmp) - REG_L ra, FB_RA(a0) - REG_L s0, FB_S0(a0) - REG_L s1, FB_S1(a0) - REG_L s2, FB_S2(a0) - REG_L s3, FB_S3(a0) - REG_L s4, FB_S4(a0) - REG_L s5, FB_S5(a0) - REG_L s6, FB_S6(a0) - REG_L s7, FB_S7(a0) - REG_L s8, FB_S8(a0) - REG_L s9, FB_S9(a0) - REG_L s10, FB_S10(a0) - REG_L s11, FB_S11(a0) - REG_L sp, FB_SP(a0) - mv a0, a1 - ret -END(longjmp) - ENTRY_NP(cpu_Debugger) cpu_Debugger_insn: sbreak Added files: Index: src/sys/arch/riscv/riscv/cpu_switch.S diff -u /dev/null src/sys/arch/riscv/riscv/cpu_switch.S:1.1 --- /dev/null Fri Oct 14 07:58:30 2022 +++ src/sys/arch/riscv/riscv/cpu_switch.S Fri Oct 14 07:58:30 2022 @@ -0,0 +1,438 @@ +/* $NetBSD: cpu_switch.S,v 1.1 2022/10/14 07:58:30 skrll Exp $ */ + +/*- + * Copyright (c) 2014 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Thomas of 3am Software Foundry. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <machine/asm.h> +#include "assym.h" + +/* + * struct lwp * + * cpu_switchto(struct lwp *oldl, struct lwp *newl, bool returning); + */ +ENTRY_NP(cpu_switchto) + addi sp, sp, -TF_LEN // allocate trapframe + + REG_S ra, TF_RA(sp) // save return address + REG_S s0, TF_S0(sp) // save callee saved address + REG_S s1, TF_S1(sp) // save callee saved address + REG_S s2, TF_S2(sp) // save callee saved address + REG_S s3, TF_S3(sp) // save callee saved address + REG_S s4, TF_S4(sp) // save callee saved address + REG_S s5, TF_S5(sp) // save callee saved address + REG_S s6, TF_S6(sp) // save callee saved address + REG_S s7, TF_S7(sp) // save callee saved address + REG_S s8, TF_S8(sp) // save callee saved address + REG_S s9, TF_S9(sp) // save callee saved address + REG_S s10, TF_S10(sp) // save callee saved address + REG_S s11, TF_S11(sp) // save callee saved address + csrr t4, sstatus // get status for intr state + REG_S t4, TF_SR(sp) // save it + + REG_S sp, L_MD_KTF(a0) // record trapframe pointer + + csrrci t0, sstatus, SR_SIE // # disable interrupts + + mv tp, a1 // # put the new lwp in thread pointer + + PTR_L t1, L_CPU(tp) // # get curcpu + PTR_S tp, CI_CURLWP(t1) // # update curcpu with the new curlwp + + REG_L sp, L_MD_KTF(tp) // # load its kernel stack pointer + REG_L t4, TF_SR(sp) // # fetch status register + csrw sstatus, t4 // # restore it (and interrupts?) + + REG_L s0, TF_S0(sp) // restore callee saved + REG_L s1, TF_S1(sp) // restore callee saved + REG_L s2, TF_S2(sp) // restore callee saved + REG_L s3, TF_S3(sp) // restore callee saved + REG_L s4, TF_S4(sp) // restore callee saved + REG_L s5, TF_S5(sp) // restore callee saved + REG_L s6, TF_S6(sp) // restore callee saved + REG_L s7, TF_S7(sp) // restore callee saved + REG_L s8, TF_S8(sp) // restore callee saved + REG_L s9, TF_S9(sp) // restore callee saved + REG_L s10, TF_S10(sp) // restore callee saved + REG_L s11, TF_S11(sp) // restore callee saved + + REG_L ra, TF_RA(sp) // restore return address + + addi sp, sp, TF_LEN // remove trapframe + + // a0 = oldl + // a1 = curcpu() + // tp = newl + + ret +END(cpu_switchto) + + +ENTRY_NP(cpu_lwp_trampoline) + mv a1, tp // get new lwp + call _C_LABEL(lwp_startup) // call lwp startup + + mv a0, s1 // get saved arg + jalr s0 // call saved func + + // If the saved func returns, we are returning to user land. + j _C_LABEL(exception_userexit) +END(cpu_lwp_trampoline) + + +ENTRY_NP(cpu_fast_switchto_cleanup) +// PTR_L t0, L_CPU(tp) // Get curcpu() +// INT_L t1, CI_MTX_COUNT(t0) // get mutex count +// addi t1, t1, 1 // increment mutex count +// INT_S t1, CI_MTX_COUNT(t0) // save it + mv ra, a1 // Restore real RA +#if IPL_SCHED != IPL_HIGH + tail _C_LABEL(splhigh) // go back to IPL HIGH +#else + ret // just return +#endif +END(cpu_fast_switchto_cleanup) + + +/* + * void + * cpu_fast_switchto(struct lwp *, int s); + */ +ENTRY_NP(cpu_fast_switchto) + addi sp, sp, -(TF_LEN + CALLFRAME_SIZ) + REG_S a0, (TF_LEN + CALLFRAME_S0)(sp) + REG_S ra, (TF_LEN + CALLFRAME_RA)(sp) + + PTR_LA t2, _C_LABEL(cpu_fast_switchto_cleanup) + + REG_S t2, TF_RA(sp) // return to someplace else + REG_S s0, TF_S0(sp) // save callee saved register + REG_S s1, TF_S1(sp) // save callee saved register + REG_S s2, TF_S2(sp) // save callee saved register + REG_S s3, TF_S3(sp) // save callee saved register + REG_S s4, TF_S4(sp) // save callee saved register + REG_S s5, TF_S5(sp) // save callee saved register + REG_S s6, TF_S6(sp) // save callee saved register + REG_S s7, TF_S7(sp) // save callee saved register + REG_S s8, TF_S8(sp) // save callee saved register + REG_S s9, TF_S9(sp) // save callee saved register + REG_S s10, TF_S10(sp) // save callee saved register + REG_S s11, TF_S11(sp) // save callee saved register + csrr t4, sstatus // get status register (for intr state) + REG_S t4, TF_SR(sp) // save it + + mv s0, tp // remember curlwp + mv s1, sp // remember kernel stack + + csrrci t0, sstatus, SR_SIE // disable interrupts + PTR_L t1, L_CPU(tp) // get curcpu() + + PTR_S sp, L_MD_KTF(tp) // save trapframe ptr in oldlwp + mv tp, a0 // set thread pointer to newlwp + PTR_S tp, CI_CURLWP(t1) // update curlwp + PTR_L sp, L_MD_KTF(tp) // switch to its stack + csrw sstatus, t0 // reenable interrupts + call _C_LABEL(softint_dispatch) + csrrci t0, sstatus, SR_SIE // disable interrupts + PTR_L t1, L_CPU(tp) // get curcpu() again + mv tp, s0 // return to pinned lwp + PTR_S tp, CI_CURLWP(t1) // restore curlwp + csrw sstatus, t0 // reenable interrupts + mv sp, s1 // restore stack pointer + + REG_L ra, TF_RA(sp) // get return address + REG_L s0, TF_S0(sp) // restore register we used + REG_L s1, TF_S1(sp) // restore register we used + + REG_L a0, (TF_LEN + CALLFRAME_S0)(sp) // Pass the softlwp + REG_L a1, (TF_LEN + CALLFRAME_RA)(sp) // Pass the real RA + + addi sp, sp, TF_LEN+CALLFRAME_SIZ // drop trapframe/callframe + ret // return +END(cpu_fast_switchto) + + +/* + * RISC-V only has a simple exception handler handles both synchronous traps + * and interrupts. + */ +ENTRY_NP(cpu_exception_handler) + csrrw tp, sscratch, tp // swap scratch and thread pointer + beqz tp, .Lexception_kernel // tp == 0, already on kernel stack + // + // The exception happened while user code was executing. We need to + // get the pointer to the user trapframe from the LWP md area. Then we + // save t1 and tp so we have a register to work with and to get curlwp + // into tp. We also save the saved SP into the trapframe. + // Upon entry on an exception from user, sscratch will contain curlwp. + // + REG_S sp, L_MD_USP(tp) // save user stack pointer temporarily + PTR_L sp, L_MD_UTF(sp) // trapframe pointer loaded + REG_S t1, TF_T1(sp) // save t1 + REG_L t1, L_MD_USP(tp) // get user stack pointer + REG_S t1, TF_SP(sp) // save thread pointer in trapframe + csrrw t1, sscratch, zero // swap saved thread pointer with 0 + REG_L t1, TF_TP(sp) // save thread pointer in trapframe + li t1, 0 // indicate user exception + j .Lexception_common + + // + // The exception happened while we were already in the kernel. That + // means tp already has curlwp and sp has the kernel stack pointer so + // just need to restore it and then adjust it down for space for the + // trap frame. We save t1 so we can use it the original sp into the + // trapframe for use by the exception exiting code. + // +.Lexception_kernel: + csrrw tp, sscratch, zero // get back our thread pointer + addi sp, sp, -TF_LEN // allocate stack frame + REG_S t1, TF_T1(sp) // save t1 + addi t1, sp, TF_LEN + REG_S t1, TF_SP(sp) // save SP + li t1, 1 // indicate kernel exception + +.Lexception_common: + // Now we save all the temporary registers into the trapframe since + // they will most certainly be changed. + REG_S ra, TF_RA(sp) // save return address + REG_S gp, TF_GP(sp) // save gp + REG_S a0, TF_A0(sp) // save a0 + REG_S a1, TF_A1(sp) // save a1 + REG_S a2, TF_A2(sp) // save a2 + REG_S a3, TF_A3(sp) // save a3 + REG_S a4, TF_A4(sp) // save a4 + REG_S a5, TF_A5(sp) // save a5 + REG_S a6, TF_A6(sp) // save a6 + REG_S a7, TF_A7(sp) // save a7 + REG_S t0, TF_T0(sp) // save t0 + // t1 is already saved + REG_S t2, TF_T2(sp) // save t2 + REG_S t3, TF_T3(sp) // save t3 + REG_S t4, TF_T4(sp) // save t4 + REG_S t5, TF_T5(sp) // save t5 + REG_S t6, TF_T6(sp) // save t6 + + // Now we get the + mv a0, sp // trapframe pointer + csrr a1, sepc // get exception pc + csrr a2, sstatus // get status + csrr a3, scause // get cause + + REG_S a1, TF_PC(sp) + REG_S a2, TF_SR(sp) + REG_S a3, TF_CAUSE(sp) // save cause + + // Now we've saved the trapfame, the cause is still in a3. + + bltz a3, intr_handler // MSB is set if interrupt + + // stval is only relevant for non-interrupts + csrr a4, stval // get stval + REG_S a4, TF_TVAL(sp) + + beqz t1, trap_user // this was a user trap + // This was a kernel exception + call _C_LABEL(cpu_trap) // just call trap to handle it +exception_kernexit: + // If we got here, we are returning from a kernel exception (either a + // trap or interrupt). Simply return the volatile registers and the + // exception PC and status, load the saved SP from the trapframe, and + // return from the exception + csrrci zero, sstatus, SR_SIE // disable interrupts + + REG_L ra, TF_RA(sp) // restore return address + REG_L gp, TF_GP(sp) // restore gp + REG_L a0, TF_A0(sp) // restore a0 + REG_L a1, TF_A1(sp) // restore a1 + REG_L a2, TF_A2(sp) // restore a2 + REG_L a3, TF_A3(sp) // restore a3 + REG_L a4, TF_A4(sp) // restore a4 + REG_L a5, TF_A5(sp) // restore a5 + REG_L a6, TF_A6(sp) // restore a6 + REG_L a7, TF_A7(sp) // restore a7 + REG_L t2, TF_T2(sp) // restore t2 + REG_L t3, TF_T3(sp) // restore t3 + REG_L t4, TF_T4(sp) // restore t4 + REG_L t5, TF_T3(sp) // restore t5 + REG_L t6, TF_T4(sp) // restore t6 + + REG_L t0, TF_PC(sp) // fetch exception PC + REG_L t1, TF_SR(sp) // fetch status + + csrw sepc, t0 // restore exception PC + csrw sstatus, t1 // restore status + + REG_L t0, TF_T0(sp) // restore t0 + REG_L t1, TF_T1(sp) // restore t1 + REG_L sp, TF_SP(sp) // restore SP + sret // and we're done + +trap_user: + REG_S s0, TF_S0(sp) // only save from userland + REG_S s1, TF_S1(sp) // only save from userland + REG_S s2, TF_S2(sp) // only save from userland + REG_S s3, TF_S3(sp) // only save from userland + REG_S s4, TF_S4(sp) // only save from userland + REG_S s5, TF_S5(sp) // only save from userland + REG_S s6, TF_S6(sp) // only save from userland + REG_S s7, TF_S7(sp) // only save from userland + REG_S s8, TF_S8(sp) // only save from userland + REG_S s9, TF_S9(sp) // only save from userland + REG_S s10, TF_S10(sp) // only save from userland + REG_S s11, TF_S11(sp) // only save from userland + + csrsi sstatus, SR_SIE // reenable interrupts + + li t0, CAUSE_SYSCALL // let's see if this was a syscall + beq a3, t0, trap_syscall // yes it was + + call _C_LABEL(cpu_trap) // nope, just a regular trap +_C_LABEL(exception_userexit): + INT_L t0, L_MD_ASTPENDING(tp) // ast pending? + bnez t0, trap_doast // yes, handle it. + csrrci zero, sstatus, SR_SIE // disable interrupts + csrw sscratch, tp // show we are coming from userland + REG_L tp, TF_TP(sp) // only restore from userland + REG_L s0, TF_S0(sp) // only restore from userland + REG_L s1, TF_S1(sp) // only restore from userland + REG_L s2, TF_S2(sp) // only restore from userland + REG_L s3, TF_S3(sp) // only restore from userland + REG_L s4, TF_S4(sp) // only restore from userland + REG_L s5, TF_S5(sp) // only restore from userland + REG_L s6, TF_S6(sp) // only restore from userland + REG_L s7, TF_S7(sp) // only restore from userland + REG_L s8, TF_S8(sp) // only restore from userland + REG_L s9, TF_S9(sp) // only restore from userland + REG_L s10, TF_S10(sp) // only restore from userland + REG_L s11, TF_S11(sp) // only restore from userland + j exception_kernexit + +trap_syscall: + PTR_LA ra, exception_userexit + PTR_L t0, L_PROC(tp) // get proc struct + PTR_L t0, P_MD_SYSCALL(t0) // get syscall address from proc + jr t0 // and jump to it + +intr_usersave: + REG_S s0, TF_S0(sp) // only save from userland + REG_S s1, TF_S1(sp) // only save from userland + REG_S s2, TF_S2(sp) // only save from userland + REG_S s3, TF_S3(sp) // only save from userland + REG_S s4, TF_S4(sp) // only save from userland + REG_S s5, TF_S5(sp) // only save from userland + REG_S s6, TF_S6(sp) // only save from userland + REG_S s7, TF_S7(sp) // only save from userland + REG_S s8, TF_S8(sp) // only save from userland + REG_S s9, TF_S9(sp) // only save from userland + REG_S s10, TF_S10(sp) // only save from userland + REG_S s11, TF_S11(sp) // only save from userland + PTR_LA ra, exception_userexit +trap_doast: + mv a0, sp // only argument is trapframe + tail _C_LABEL(cpu_ast) + +intr_user: + call _C_LABEL(cpu_intr) // handle interrupt + INT_L t0, L_MD_ASTPENDING(tp) // get astpending + bnez t0, intr_usersave // if one is pending, deal with in + + csrw sscratch, tp // show we are coming from userland + REG_L tp, TF_TP(sp) // restore thread pointer + j exception_kernexit // do standard exception exit + +intr_handler: + beqz t1, intr_user + call _C_LABEL(cpu_intr) + j exception_kernexit +END(cpu_exception_handler) + + +/* + * int + * cpu_set_onfault(struct faultbuf *fb, register_t retval) + */ +ENTRY_NP(cpu_set_onfault) + REG_S ra, FB_RA(a0) + REG_S s0, FB_S0(a0) + REG_S s1, FB_S1(a0) + REG_S s2, FB_S2(a0) + REG_S s3, FB_S3(a0) + REG_S s4, FB_S4(a0) + REG_S s5, FB_S5(a0) + REG_S s6, FB_S6(a0) + REG_S s7, FB_S7(a0) + REG_S s8, FB_S8(a0) + REG_S s9, FB_S9(a0) + REG_S s10, FB_S10(a0) + REG_S s11, FB_S11(a0) + REG_S sp, FB_SP(a0) + REG_S a1, FB_A0(a0) + PTR_S a0, L_MD_ONFAULT(tp) + li a0, 0 + ret +END(cpu_set_onfault) + + +ENTRY_NP(setjmp) + REG_S ra, FB_RA(a0) + REG_S s0, FB_S0(a0) + REG_S s1, FB_S1(a0) + REG_S s2, FB_S2(a0) + REG_S s3, FB_S3(a0) + REG_S s4, FB_S4(a0) + REG_S s5, FB_S5(a0) + REG_S s6, FB_S6(a0) + REG_S s7, FB_S7(a0) + REG_S s8, FB_S8(a0) + REG_S s9, FB_S9(a0) + REG_S s10, FB_S10(a0) + REG_S s11, FB_S11(a0) + REG_S sp, FB_SP(a0) + li a0, 0 + ret +END(setjmp) + + +ENTRY_NP(longjmp) + REG_L ra, FB_RA(a0) + REG_L s0, FB_S0(a0) + REG_L s1, FB_S1(a0) + REG_L s2, FB_S2(a0) + REG_L s3, FB_S3(a0) + REG_L s4, FB_S4(a0) + REG_L s5, FB_S5(a0) + REG_L s6, FB_S6(a0) + REG_L s7, FB_S7(a0) + REG_L s8, FB_S8(a0) + REG_L s9, FB_S9(a0) + REG_L s10, FB_S10(a0) + REG_L s11, FB_S11(a0) + REG_L sp, FB_SP(a0) + mv a0, a1 + ret +END(longjmp)