ax-cpu 0.10.0

Privileged instruction and structure abstractions for various CPU architectures
Documentation
/*
 * 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