/*
* Restore the CPU-owned host anchor and task-owned host TLS immediately after
* the guest register image is durable. No host per-CPU or Rust access is safe
* before all three values are live again.
*/
.macro RESTORE_HOST_ANCHORS
ld t1, ({hyp_sscratch})(a0)
csrw sscratch, t1
ld gp, ({hyp_gp})(a0)
ld tp, ({hyp_tp})(a0)
.endm
/// Enter the guest given in `Vcpu` from `a0`
.section .text
.global __ax_cpu_riscv_run_guest
.hidden __ax_cpu_riscv_run_guest
.type __ax_cpu_riscv_run_guest, @function
__ax_cpu_riscv_run_guest:
/* Save hypervisor state */
/* Save hypervisor GPRs (except T0-T6 and a0, which is GuestInfo and stashed in sscratch) */
sd ra, ({hyp_ra})(a0)
sd gp, ({hyp_gp})(a0)
sd tp, ({hyp_tp})(a0)
sd s0, ({hyp_s0})(a0)
sd s1, ({hyp_s1})(a0)
sd a1, ({hyp_a1})(a0)
sd a2, ({hyp_a2})(a0)
sd a3, ({hyp_a3})(a0)
sd a4, ({hyp_a4})(a0)
sd a5, ({hyp_a5})(a0)
sd a6, ({hyp_a6})(a0)
sd a7, ({hyp_a7})(a0)
sd s2, ({hyp_s2})(a0)
sd s3, ({hyp_s3})(a0)
sd s4, ({hyp_s4})(a0)
sd s5, ({hyp_s5})(a0)
sd s6, ({hyp_s6})(a0)
sd s7, ({hyp_s7})(a0)
sd s8, ({hyp_s8})(a0)
sd s9, ({hyp_s9})(a0)
sd s10, ({hyp_s10})(a0)
sd s11, ({hyp_s11})(a0)
sd sp, ({hyp_sp})(a0)
/* Save host FP before exposing the guest bank; preserve exact host FS. */
csrr t1, sstatus
sd t1, ({hyp_sstatus})(a0)
li t1, 0x6000
csrs sstatus, t1
addi t0, a0, {host_fp}
PUSH_FLOAT_REGS t0
frcsr t1
sd t1, {fcsr}(t0)
addi t0, a0, {guest_fp}
POP_FLOAT_REGS t0
ld t1, {fcsr}(t0)
fscsr t1
/* Install the guest's saved execution status. */
ld t1, ({guest_sstatus})(a0)
csrw sstatus, t1
ld t1, ({guest_hstatus})(a0)
csrrw t1, hstatus, t1
sd t1, ({hyp_hstatus})(a0)
ld t1, ({guest_scounteren})(a0)
csrrw t1, scounteren, t1
sd t1, ({hyp_scounteren})(a0)
ld t1, ({guest_sepc})(a0)
csrw sepc, t1
/* Set stvec so that hypervisor resumes after the sret when the guest exits. */
la t1, __ax_cpu_riscv_guest_exit
csrrw t1, stvec, t1
sd t1, ({hyp_stvec})(a0)
/* Save sscratch and replace with pointer to GuestInfo. */
csrrw t1, sscratch, a0
sd t1, ({hyp_sscratch})(a0)
/* Restore the gprs from this GuestInfo */
ld ra, ({guest_ra})(a0)
ld gp, ({guest_gp})(a0)
ld tp, ({guest_tp})(a0)
ld s0, ({guest_s0})(a0)
ld s1, ({guest_s1})(a0)
ld a1, ({guest_a1})(a0)
ld a2, ({guest_a2})(a0)
ld a3, ({guest_a3})(a0)
ld a4, ({guest_a4})(a0)
ld a5, ({guest_a5})(a0)
ld a6, ({guest_a6})(a0)
ld a7, ({guest_a7})(a0)
ld s2, ({guest_s2})(a0)
ld s3, ({guest_s3})(a0)
ld s4, ({guest_s4})(a0)
ld s5, ({guest_s5})(a0)
ld s6, ({guest_s6})(a0)
ld s7, ({guest_s7})(a0)
ld s8, ({guest_s8})(a0)
ld s9, ({guest_s9})(a0)
ld s10, ({guest_s10})(a0)
ld s11, ({guest_s11})(a0)
ld t0, ({guest_t0})(a0)
ld t1, ({guest_t1})(a0)
ld t2, ({guest_t2})(a0)
ld t3, ({guest_t3})(a0)
ld t4, ({guest_t4})(a0)
ld t5, ({guest_t5})(a0)
ld t6, ({guest_t6})(a0)
ld sp, ({guest_sp})(a0)
ld a0, ({guest_a0})(a0)
sret
.align 2
__ax_cpu_riscv_guest_exit:
/* Pull GuestInfo out of sscratch, swapping with guest's a0 */
csrrw a0, sscratch, a0
/* Save guest GPRs. */
sd ra, ({guest_ra})(a0)
sd gp, ({guest_gp})(a0)
sd tp, ({guest_tp})(a0)
sd s0, ({guest_s0})(a0)
sd s1, ({guest_s1})(a0)
sd a1, ({guest_a1})(a0)
sd a2, ({guest_a2})(a0)
sd a3, ({guest_a3})(a0)
sd a4, ({guest_a4})(a0)
sd a5, ({guest_a5})(a0)
sd a6, ({guest_a6})(a0)
sd a7, ({guest_a7})(a0)
sd s2, ({guest_s2})(a0)
sd s3, ({guest_s3})(a0)
sd s4, ({guest_s4})(a0)
sd s5, ({guest_s5})(a0)
sd s6, ({guest_s6})(a0)
sd s7, ({guest_s7})(a0)
sd s8, ({guest_s8})(a0)
sd s9, ({guest_s9})(a0)
sd s10, ({guest_s10})(a0)
sd s11, ({guest_s11})(a0)
sd t0, ({guest_t0})(a0)
sd t1, ({guest_t1})(a0)
sd t2, ({guest_t2})(a0)
sd t3, ({guest_t3})(a0)
sd t4, ({guest_t4})(a0)
sd t5, ({guest_t5})(a0)
sd t6, ({guest_t6})(a0)
sd sp, ({guest_sp})(a0)
/* Save Guest a0 after recovering from sscratch. */
csrr t0, sscratch
sd t0, ({guest_a0})(a0)
RESTORE_HOST_ANCHORS
/* Make the exit durable before restoring the host's trap environment. */
csrr t1, scause
sd t1, {trap_scause}(a0)
csrr t1, stval
sd t1, {trap_stval}(a0)
csrr t1, htval
sd t1, {trap_htval}(a0)
csrr t1, htinst
sd t1, {trap_htinst}(a0)
csrr t1, sstatus
sd t1, ({guest_sstatus})(a0)
/* Both FP banks use the CPU's shared save/restore fragments. */
li t1, 0x6000
csrs sstatus, t1
addi t0, a0, {guest_fp}
PUSH_FLOAT_REGS t0
frcsr t1
sd t1, {fcsr}(t0)
addi t0, a0, {host_fp}
POP_FLOAT_REGS t0
ld t1, {fcsr}(t0)
fscsr t1
/* Restore host status only after the FP bank is complete. */
ld t1, ({hyp_sstatus})(a0)
csrw sstatus, t1
ld t1, ({hyp_hstatus})(a0)
csrrw t1, hstatus, t1
sd t1, ({guest_hstatus})(a0)
ld t1, ({hyp_scounteren})(a0)
csrrw t1, scounteren, t1
sd t1, ({guest_scounteren})(a0)
ld t1, ({hyp_stvec})(a0)
csrw stvec, t1
/* Save guest EPC. */
csrr t1, sepc
sd t1, ({guest_sepc})(a0)
sd t1, {trap_pc}(a0)
/* Restore hypervisor GPRs. */
ld ra, ({hyp_ra})(a0)
ld s0, ({hyp_s0})(a0)
ld s1, ({hyp_s1})(a0)
ld a1, ({hyp_a1})(a0)
ld a2, ({hyp_a2})(a0)
ld a3, ({hyp_a3})(a0)
ld a4, ({hyp_a4})(a0)
ld a5, ({hyp_a5})(a0)
ld a6, ({hyp_a6})(a0)
ld a7, ({hyp_a7})(a0)
ld s2, ({hyp_s2})(a0)
ld s3, ({hyp_s3})(a0)
ld s4, ({hyp_s4})(a0)
ld s5, ({hyp_s5})(a0)
ld s6, ({hyp_s6})(a0)
ld s7, ({hyp_s7})(a0)
ld s8, ({hyp_s8})(a0)
ld s9, ({hyp_s9})(a0)
ld s10, ({hyp_s10})(a0)
ld s11, ({hyp_s11})(a0)
ld sp, ({hyp_sp})(a0)
ret