diff --git a/hypervisor/arch/riscv/intr.S b/hypervisor/arch/riscv/intr.S index 31daa57ce..7b87ed5b9 100644 --- a/hypervisor/arch/riscv/intr.S +++ b/hypervisor/arch/riscv/intr.S @@ -10,18 +10,143 @@ #include #include +.macro cpu_ctx_save + /* General purpose registers. */ + sd sp, CPU_REGS_OFFSET_SP(t0) + sd ra, CPU_REGS_OFFSET_RA(t0) + sd gp, CPU_REGS_OFFSET_GP(t0) + sd tp, CPU_REGS_OFFSET_TP(t0) + sd t1, CPU_REGS_OFFSET_T1(t0) + sd t2, CPU_REGS_OFFSET_T2(t0) + sd s0, CPU_REGS_OFFSET_S0(t0) + sd s1, CPU_REGS_OFFSET_S1(t0) + sd a0, CPU_REGS_OFFSET_A0(t0) + sd a1, CPU_REGS_OFFSET_A1(t0) + sd a2, CPU_REGS_OFFSET_A2(t0) + sd a3, CPU_REGS_OFFSET_A3(t0) + sd a4, CPU_REGS_OFFSET_A4(t0) + sd a5, CPU_REGS_OFFSET_A5(t0) + sd a6, CPU_REGS_OFFSET_A6(t0) + sd a7, CPU_REGS_OFFSET_A7(t0) + sd s2, CPU_REGS_OFFSET_S2(t0) + sd s3, CPU_REGS_OFFSET_S3(t0) + sd s4, CPU_REGS_OFFSET_S4(t0) + sd s5, CPU_REGS_OFFSET_S5(t0) + sd s6, CPU_REGS_OFFSET_S6(t0) + sd s7, CPU_REGS_OFFSET_S7(t0) + sd s8, CPU_REGS_OFFSET_S8(t0) + sd s9, CPU_REGS_OFFSET_S9(t0) + sd s10, CPU_REGS_OFFSET_S10(t0) + sd s11, CPU_REGS_OFFSET_S11(t0) + sd t3, CPU_REGS_OFFSET_T3(t0) + sd t4, CPU_REGS_OFFSET_T4(t0) + sd t5, CPU_REGS_OFFSET_T5(t0) + sd t6, CPU_REGS_OFFSET_T6(t0) + + /* Control and Status Registers (CSRs). */ + csrr t1, sstatus + sd t1, CPU_REGS_OFFSET_STATUS(t0) + csrr t2, scause + sd t2, CPU_REGS_OFFSET_CAUSE(t0) + csrr t3, stval + sd t3, CPU_REGS_OFFSET_TVAL(t0) + csrr t4, sscratch + sd t4, CPU_REGS_OFFSET_T0(t0) + csrr t5, sepc + sd t5, CPU_REGS_OFFSET_EPC(t0) +.endm + +.macro cpu_ctx_restore + /* Control and Status Registers (CSRs). */ + ld t1, CPU_REGS_OFFSET_EPC(t0) + csrw sepc, t1 + ld t2, CPU_REGS_OFFSET_STATUS(t0) + csrw sstatus, t2 + + /* General purpose registers. */ + ld sp, CPU_REGS_OFFSET_SP(t0) + ld ra, CPU_REGS_OFFSET_RA(t0) + ld gp, CPU_REGS_OFFSET_GP(t0) + ld tp, CPU_REGS_OFFSET_TP(t0) + ld t1, CPU_REGS_OFFSET_T1(t0) + ld t2, CPU_REGS_OFFSET_T2(t0) + ld s0, CPU_REGS_OFFSET_S0(t0) + ld s1, CPU_REGS_OFFSET_S1(t0) + ld a0, CPU_REGS_OFFSET_A0(t0) + ld a1, CPU_REGS_OFFSET_A1(t0) + ld a2, CPU_REGS_OFFSET_A2(t0) + ld a3, CPU_REGS_OFFSET_A3(t0) + ld a4, CPU_REGS_OFFSET_A4(t0) + ld a5, CPU_REGS_OFFSET_A5(t0) + ld a6, CPU_REGS_OFFSET_A6(t0) + ld a7, CPU_REGS_OFFSET_A7(t0) + ld s2, CPU_REGS_OFFSET_S2(t0) + ld s3, CPU_REGS_OFFSET_S3(t0) + ld s4, CPU_REGS_OFFSET_S4(t0) + ld s5, CPU_REGS_OFFSET_S5(t0) + ld s6, CPU_REGS_OFFSET_S6(t0) + ld s7, CPU_REGS_OFFSET_S7(t0) + ld s8, CPU_REGS_OFFSET_S8(t0) + ld s9, CPU_REGS_OFFSET_S9(t0) + ld s10, CPU_REGS_OFFSET_S10(t0) + ld s11, CPU_REGS_OFFSET_S11(t0) + ld t3, CPU_REGS_OFFSET_T3(t0) + ld t4, CPU_REGS_OFFSET_T4(t0) + ld t5, CPU_REGS_OFFSET_T5(t0) + ld t6, CPU_REGS_OFFSET_T6(t0) + ld t0, CPU_REGS_OFFSET_T0(t0) +.endm + +.macro cpu_host_state_load + ld sp, CPU_REGS_OFFSET_EXC_SP(t0) + ld tp, CPU_REGS_OFFSET_HOST_TP(t0) + ld gp, CPU_REGS_OFFSET_HOST_GP(t0) +.endm + +.macro cpu_host_state_save + sd sp, CPU_REGS_OFFSET_EXC_SP(t0) + sd tp, CPU_REGS_OFFSET_HOST_TP(t0) + sd gp, CPU_REGS_OFFSET_HOST_GP(t0) +.endm + .text .balign 4 .globl strap_handler strap_handler: - /** Save CPU registers (`struct cpu_regs` within `struct intr_excp_ctx`) to stack. */ - cpu_ctx_save + /* + * sscratch == 0: trap comes from hs-mode + * sscratch != 0: trap comes from v-mode, and sscratch points to struct acrn_vcpu_arch + */ + csrrw t0, sscratch, t0 + bnez t0, vcpu_exit_trap - /** Pass sp in a0, as the argument to dispatch_trap(). */ - mv a0, sp + addi sp, sp, -CPU_REGS_OFFSET_LAST + mv t0, sp + cpu_ctx_save + csrw sscratch, zero + + /** Pass t0 in a0, as the argument to dispatch_trap(). */ + mv a0, t0 call dispatch_trap - /** Restore CPU registers (`struct cpu_regs` within `struct intr_excp_ctx`) from stack. */ + mv t0, sp + cpu_ctx_restore + addi sp, sp, CPU_REGS_OFFSET_LAST + sret + +vcpu_exit_trap: + cpu_ctx_save + cpu_host_state_load + csrw sscratch, zero + + /* t0 points to struct acrn_vcpu_arch */ + mv a0, t0 + call dispatch_vcpu_trap + + .globl vcpu_exit_return +vcpu_exit_return: + csrr t0, sscratch + cpu_host_state_save cpu_ctx_restore sret diff --git a/hypervisor/arch/riscv/irq.c b/hypervisor/arch/riscv/irq.c index df88c0d6a..56ee25ca8 100644 --- a/hypervisor/arch/riscv/irq.c +++ b/hypervisor/arch/riscv/irq.c @@ -296,6 +296,12 @@ void arch_init_interrupt(__unused uint16_t pcpu_id) */ cpu_csr_write(CSR_STVEC, (addr | TRAP_VECTOR_MODE_DIRECT)); cpu_csr_write(CSR_SIE, (IP_IE_SSI | IP_IE_STI | IP_IE_SEI)); + + /* sscratch holds the value used by save/restore routine. + * sscratch == 0: save/restore to per-cpu stack (hs-mode trap handling) + * sscratch != 0: save/restore to vcpu struct (v-mode trap handling) + */ + cpu_csr_write(CSR_SSCRATCH, 0ULL); } bool riscv_is_valid_acrn_irq(uint32_t irq) diff --git a/hypervisor/include/arch/riscv/asm/cpu.h b/hypervisor/include/arch/riscv/asm/cpu.h index d3cfbdb21..c05bc5e66 100644 --- a/hypervisor/include/arch/riscv/asm/cpu.h +++ b/hypervisor/include/arch/riscv/asm/cpu.h @@ -63,6 +63,12 @@ struct cpu_regs { uint64_t cause; uint64_t tval; uint64_t scratch; + uint64_t hstatus; + + /* Host context. Used only in v-mode traps. */ + uint64_t host_tp; + uint64_t host_gp; + uint64_t exc_sp; }; /* stack_frame is linked with the sequence of stack operation in arch_switch_to() */ @@ -181,108 +187,6 @@ static inline void clac(void) {} #else /* ASSEMBLER */ #include -/* The following symbols must remain consistent: - * - CPU_REGS_OFFSET_* macros in `include/arch/riscv/asm/offset.h` - * - struct cpu_regs - * - cpu_ctx_save/cpu_ctx_restore macros used in assembly - */ -.macro cpu_ctx_save - addi sp, sp, -CPU_REGS_OFFSET_LAST - - /* General purpose registers. */ - /* Save sp first to avoid corrupting the stack frame */ - sd sp, CPU_REGS_OFFSET_SP(sp) - sd ra, CPU_REGS_OFFSET_RA(sp) - sd gp, CPU_REGS_OFFSET_GP(sp) - sd tp, CPU_REGS_OFFSET_TP(sp) - sd t0, CPU_REGS_OFFSET_T0(sp) - sd t1, CPU_REGS_OFFSET_T1(sp) - sd t2, CPU_REGS_OFFSET_T2(sp) - sd s0, CPU_REGS_OFFSET_S0(sp) - sd s1, CPU_REGS_OFFSET_S1(sp) - sd a0, CPU_REGS_OFFSET_A0(sp) - sd a1, CPU_REGS_OFFSET_A1(sp) - sd a2, CPU_REGS_OFFSET_A2(sp) - sd a3, CPU_REGS_OFFSET_A3(sp) - sd a4, CPU_REGS_OFFSET_A4(sp) - sd a5, CPU_REGS_OFFSET_A5(sp) - sd a6, CPU_REGS_OFFSET_A6(sp) - sd a7, CPU_REGS_OFFSET_A7(sp) - sd s2, CPU_REGS_OFFSET_S2(sp) - sd s3, CPU_REGS_OFFSET_S3(sp) - sd s4, CPU_REGS_OFFSET_S4(sp) - sd s5, CPU_REGS_OFFSET_S5(sp) - sd s6, CPU_REGS_OFFSET_S6(sp) - sd s7, CPU_REGS_OFFSET_S7(sp) - sd s8, CPU_REGS_OFFSET_S8(sp) - sd s9, CPU_REGS_OFFSET_S9(sp) - sd s10, CPU_REGS_OFFSET_S10(sp) - sd s11, CPU_REGS_OFFSET_S11(sp) - sd t3, CPU_REGS_OFFSET_T3(sp) - sd t4, CPU_REGS_OFFSET_T4(sp) - sd t5, CPU_REGS_OFFSET_T5(sp) - sd t6, CPU_REGS_OFFSET_T6(sp) - - /* Control and Status Registers (CSRs). */ - csrr t0, sepc - sd t0, CPU_REGS_OFFSET_EPC(sp) - csrr t1, sstatus - sd t1, CPU_REGS_OFFSET_STATUS(sp) - csrr t2, scause - sd t2, CPU_REGS_OFFSET_CAUSE(sp) - csrr t3, stval - sd t3, CPU_REGS_OFFSET_TVAL(sp) - csrr t4, sscratch - sd t4, CPU_REGS_OFFSET_SCRATCH(sp) -.endm - -.macro cpu_ctx_restore - /* Control and Status Registers (CSRs). */ - ld t0, CPU_REGS_OFFSET_EPC(sp) - csrw sepc, t0 - ld t1, CPU_REGS_OFFSET_STATUS(sp) - csrw sstatus, t1 - /* Restoring scause/stval is unnecessary and will be skipped. */ - ld t4, CPU_REGS_OFFSET_SCRATCH(sp) - csrw sscratch, t4 - - /* General purpose registers. */ - ld ra, CPU_REGS_OFFSET_RA(sp) - ld gp, CPU_REGS_OFFSET_GP(sp) - ld tp, CPU_REGS_OFFSET_TP(sp) - ld t0, CPU_REGS_OFFSET_T0(sp) - ld t1, CPU_REGS_OFFSET_T1(sp) - ld t2, CPU_REGS_OFFSET_T2(sp) - ld s0, CPU_REGS_OFFSET_S0(sp) - ld s1, CPU_REGS_OFFSET_S1(sp) - ld a0, CPU_REGS_OFFSET_A0(sp) - ld a1, CPU_REGS_OFFSET_A1(sp) - ld a2, CPU_REGS_OFFSET_A2(sp) - ld a3, CPU_REGS_OFFSET_A3(sp) - ld a4, CPU_REGS_OFFSET_A4(sp) - ld a5, CPU_REGS_OFFSET_A5(sp) - ld a6, CPU_REGS_OFFSET_A6(sp) - ld a7, CPU_REGS_OFFSET_A7(sp) - ld s2, CPU_REGS_OFFSET_S2(sp) - ld s3, CPU_REGS_OFFSET_S3(sp) - ld s4, CPU_REGS_OFFSET_S4(sp) - ld s5, CPU_REGS_OFFSET_S5(sp) - ld s6, CPU_REGS_OFFSET_S6(sp) - ld s7, CPU_REGS_OFFSET_S7(sp) - ld s8, CPU_REGS_OFFSET_S8(sp) - ld s9, CPU_REGS_OFFSET_S9(sp) - ld s10, CPU_REGS_OFFSET_S10(sp) - ld s11, CPU_REGS_OFFSET_S11(sp) - ld t3, CPU_REGS_OFFSET_T3(sp) - ld t4, CPU_REGS_OFFSET_T4(sp) - ld t5, CPU_REGS_OFFSET_T5(sp) - ld t6, CPU_REGS_OFFSET_T6(sp) - /* Restore sp last to avoid corrupting the stack frame */ - ld sp, CPU_REGS_OFFSET_SP(sp) - - addi sp, sp, CPU_REGS_OFFSET_LAST -.endm - #endif /* ASSEMBLER */ #endif /* RISCV_CPU_H */ diff --git a/hypervisor/include/arch/riscv/asm/offset.h b/hypervisor/include/arch/riscv/asm/offset.h index ab199133a..eae0ffd91 100644 --- a/hypervisor/include/arch/riscv/asm/offset.h +++ b/hypervisor/include/arch/riscv/asm/offset.h @@ -55,8 +55,12 @@ #define CPU_REGS_OFFSET_CAUSE 0x110 #define CPU_REGS_OFFSET_TVAL 0x118 #define CPU_REGS_OFFSET_SCRATCH 0x120 +#define CPU_REGS_OFFSET_HSTATUS 0x128 +#define CPU_REGS_OFFSET_HOST_TP 0x130 +#define CPU_REGS_OFFSET_HOST_GP 0x138 +#define CPU_REGS_OFFSET_EXC_SP 0x140 /* Total context area size (struct cpu_regs). */ -#define CPU_REGS_OFFSET_LAST (CPU_REGS_OFFSET_SCRATCH + 8) +#define CPU_REGS_OFFSET_LAST (CPU_REGS_OFFSET_EXC_SP + 8) #endif /* RISCV_OFFSET_H */