From 5422ffd02ddad37654177f7941aa52b313bbc96d Mon Sep 17 00:00:00 2001 From: luojia65 Date: Fri, 31 Dec 2021 18:00:53 +0800 Subject: [PATCH 1/6] riscv: more instruction intrinsics todo: wait before supervisor extension in rustc risc-v target is available (e.g. when we're developing kernel modules or kernels themselves, S extension is enabled) sinval.vma instructions FENCE.I instruction --- crates/core_arch/src/riscv/mod.rs | 137 +++++++++++++++++++++++++++++- 1 file changed, 136 insertions(+), 1 deletion(-) diff --git a/crates/core_arch/src/riscv/mod.rs b/crates/core_arch/src/riscv/mod.rs index b93c35fc4f..11abf4ed2f 100644 --- a/crates/core_arch/src/riscv/mod.rs +++ b/crates/core_arch/src/riscv/mod.rs @@ -1,10 +1,145 @@ //! RISC-V intrinsics +use crate::arch::asm; + /// Generates the `PAUSE` instruction /// /// The PAUSE instruction is a HINT that indicates the current hart's rate of instruction retirement /// should be temporarily reduced or paused. The duration of its effect must be bounded and may be zero. #[inline] pub fn pause() { - unsafe { crate::arch::asm!(".word 0x0100000F", options(nomem, nostack)) } + unsafe { asm!(".insn i 0x0F, 0, x0, x0, 0x010", options(nomem, nostack)) } +} + +/// Generates the `NOP` instruction +/// +/// The NOP instruction does not change any architecturally visible state, except for +/// advancing the `pc` and incrementing any applicable performance counters. +#[inline] +pub fn nop() { + unsafe { asm!("nop") } +} + +/// Generates the `WFI` instruction +/// +/// The WFI instruction provides a hint to the implementation that the current hart can be stalled +/// until an interrupt might need servicing. This instruction is a hint, +/// and a legal implementation is to simply implement WFI as a NOP. +#[inline] +pub unsafe fn wfi() { + asm!("wfi") +} + +/// Generates the `FENCE.I` instruction +/// +/// A FENCE.I instruction ensures that a subsequent instruction fetch on a RISC-V hart will see +/// any previous data stores already visible to the same RISC-V hart. +/// +/// FENCE.I does not ensure that other RISC-V harts' instruction fetches will observe the +/// local hart's stores in a multiprocessor system. +#[inline] +pub unsafe fn fence_i() { + asm!("fence.i") +} + +/// Generates the `SFENCE.VMA` instruction for given virtual address and address space +/// +/// The fence orders only reads and writes made to leaf page table entries corresponding to +/// the virtual address in parameter `vaddr`, for the address space identified by integer parameter +/// `asid`. Accesses to global mappings are not ordered. The fence also invalidates all +/// address-translation cache entries that contain leaf page table entries corresponding to the +/// virtual address in parameter `vaddr` and that match the address space identified by integer +/// parameter `asid`, except for entries containing global mappings. +#[inline] +pub unsafe fn sfence_vma(vaddr: usize, asid: usize) { + asm!("sfence.vma {}, {}", in(reg) vaddr, in(reg) asid) +} + +/// Generates the `SFENCE.VMA` instruction for given virtual address +/// +/// The fence orders only reads and writes made to leaf page table entries corresponding to +/// the virtual address in parameter `vaddr`, for all address spaces. +/// The fence also invalidates all address-translation cache entries that contain leaf page +/// table entries corresponding to the virtual address in parameter `vaddr`, for all address spaces. +#[inline] +pub unsafe fn sfence_vma_vaddr(vaddr: usize) { + asm!("sfence.vma {}, x0", in(reg) vaddr) +} + +/// Generates the `SFENCE.VMA` instruction for given address space +/// +/// The fence orders all reads and writes made to any level of the page tables, +/// but only for the address space identified by integer parameter `asid`. +/// +/// Accesses to global mappings are not ordered. The fence also invalidates all +/// address-translation cache entries matching the address space identified by integer +/// parameter `asid`, except for entries containing global mappings. +#[inline] +pub unsafe fn sfence_vma_asid(asid: usize) { + asm!("sfence.vma x0, {}", in(reg) asid) +} + +/// Generates the `SFENCE.VMA` instruction for all address spaces and virtual addresses +/// +/// The fence orders all reads and writes made to any level of the page +/// tables, for all address spaces. The fence also invalidates all address-translation cache entries, +/// for all address spaces. +#[inline] +pub unsafe fn sfence_vma_all() { + asm!("sfence.vma") +} + +/// Generates the `SINVAL.VMA` instruction for given virtual address and address space +/// +/// This instruction invalidates any address-translation cache entries that an +/// `SFENCE.VMA` instruction with the same values of `vaddr` and `asid` would invalidate. +#[inline] +pub unsafe fn sinval_vma(vaddr: usize, asid: usize) { + // asm!("sinval.vma {}, {}", in(reg) vaddr, in(reg) asid) + asm!(".insn r 0x73, 0, 0x0B, x0, {}, {}", in(reg) vaddr, in(reg) asid) +} + +/// Generates the `SINVAL.VMA` instruction for given virtual address +/// +/// This instruction invalidates any address-translation cache entries that an +/// `SFENCE.VMA` instruction with the same values of `vaddr` and `asid` would invalidate. +#[inline] +pub unsafe fn sinval_vma_vaddr(vaddr: usize) { + asm!(".insn r 0x73, 0, 0x0B, x0, {}, x0", in(reg) vaddr) +} + +/// Generates the `SINVAL.VMA` instruction for given address space +/// +/// This instruction invalidates any address-translation cache entries that an +/// `SFENCE.VMA` instruction with the same values of `vaddr` and `asid` would invalidate. +#[inline] +pub unsafe fn sinval_vma_asid(asid: usize) { + asm!(".insn r 0x73, 0, 0x0B, x0, x0, {}", in(reg) asid) +} + +/// Generates the `SINVAL.VMA` instruction for all address spaces and virtual addresses +/// +/// This instruction invalidates any address-translation cache entries that an +/// `SFENCE.VMA` instruction with the same values of `vaddr` and `asid` would invalidate. +#[inline] +pub unsafe fn sinval_vma_all() { + asm!(".insn r 0x73, 0, 0x0B, x0, x0, x0") +} + +/// Generates the `SFENCE.W.INVAL` instruction +/// +/// This instruction guarantees that any previous stores already visible to the current RISC-V hart +/// are ordered before subsequent `SINVAL.VMA` instructions executed by the same hart. +#[inline] +pub unsafe fn sfence_w_inval() { + asm!(".insn i 0x73, 0, x0, x0, 0x180") +} + +/// Generates the `SFENCE.INVAL.IR` instruction +/// +/// This instruction guarantees that any previous SINVAL.VMA instructions executed by the current hart +/// are ordered before subsequent implicit references by that hart to the memory-management data structures. +#[inline] +pub unsafe fn sfence_inval_ir() { + asm!(".insn i 0x73, 0, x0, x0, 0x181") } From 2a84e9aaea79de3eba9d7a05d6c224efe7de5c8a Mon Sep 17 00:00:00 2001 From: luojia65 Date: Sat, 1 Jan 2022 14:40:36 +0800 Subject: [PATCH 2/6] riscv: hypervisor load and store instructions adds `riscv64` module --- crates/core_arch/src/mod.rs | 15 +++ crates/core_arch/src/riscv/mod.rs | 164 ++++++++++++++++++++++++++++ crates/core_arch/src/riscv64/mod.rs | 55 ++++++++++ 3 files changed, 234 insertions(+) create mode 100644 crates/core_arch/src/riscv64/mod.rs diff --git a/crates/core_arch/src/mod.rs b/crates/core_arch/src/mod.rs index ec28bd62c4..decf692343 100644 --- a/crates/core_arch/src/mod.rs +++ b/crates/core_arch/src/mod.rs @@ -66,6 +66,17 @@ pub mod arch { pub use crate::core_arch::riscv::*; } + /// Platform-specific intrinsics for the `riscv64` platform. + /// + /// See the [module documentation](../index.html) for more details. + #[cfg(any(target_arch = "riscv64", doc))] + #[doc(cfg(any(target_arch = "riscv64")))] + #[unstable(feature = "stdsimd", issue = "27731")] + pub mod riscv64 { + pub use crate::core_arch::riscv::*; + pub use crate::core_arch::riscv64::*; + } + /// Platform-specific intrinsics for the `wasm32` platform. /// /// This module provides intrinsics specific to the WebAssembly @@ -266,6 +277,10 @@ mod arm; #[doc(cfg(any(target_arch = "riscv32", target_arch = "riscv64")))] mod riscv; +#[cfg(any(target_arch = "riscv64", doc))] +#[doc(cfg(any(target_arch = "riscv64")))] +mod riscv64; + #[cfg(any(target_family = "wasm", doc))] #[doc(cfg(target_family = "wasm"))] mod wasm32; diff --git a/crates/core_arch/src/riscv/mod.rs b/crates/core_arch/src/riscv/mod.rs index 11abf4ed2f..68a0275507 100644 --- a/crates/core_arch/src/riscv/mod.rs +++ b/crates/core_arch/src/riscv/mod.rs @@ -143,3 +143,167 @@ pub unsafe fn sfence_w_inval() { pub unsafe fn sfence_inval_ir() { asm!(".insn i 0x73, 0, x0, x0, 0x181") } + +/// Loads memory from hypervisor by signed byte integer +/// +/// This instruction performs an explicit memory access as though `V=1`; +/// i.e., with the address translation and protection, and the endianness, that apply to memory +/// accesses in either VS-mode or VU-mode. +/// +/// # Unsafety +/// +/// This function accesses the virtual supervisor or user via a `HLV.B` instruction which is effectively +/// an unreference to any memory address, thus is wrapped into an unsafe function. +#[inline] +pub unsafe fn hlv_b(src: *const i8) -> i8 { + let value: i8; + asm!(".insn i 0x73, 0x4, {}, {}, 0x600", out(reg) value, in(reg) src); + value +} + +/// Loads memory from hypervisor by unsigned byte integer +/// +/// This instruction performs an explicit memory access as though `V=1`; +/// i.e., with the address translation and protection, and the endianness, that apply to memory +/// accesses in either VS-mode or VU-mode. +/// +/// # Unsafety +/// +/// This function accesses the virtual supervisor or user via a `HLV.BU` instruction which is effectively +/// an unreference to any memory address, thus is wrapped into an unsafe function. +#[inline] +pub unsafe fn hlv_bu(src: *const u8) -> u8 { + let value: u8; + asm!(".insn i 0x73, 0x4, {}, {}, 0x601", out(reg) value, in(reg) src); + value +} + +/// Loads memory from hypervisor by signed half integer +/// +/// This instruction performs an explicit memory access as though `V=1`; +/// i.e., with the address translation and protection, and the endianness, that apply to memory +/// accesses in either VS-mode or VU-mode. +/// +/// # Unsafety +/// +/// This function accesses the virtual supervisor or user via a `HLV.H` instruction which is effectively +/// an unreference to any memory address, thus is wrapped into an unsafe function. +#[inline] +pub unsafe fn hlv_h(src: *const i16) -> i16 { + let value: i16; + asm!(".insn i 0x73, 0x4, {}, {}, 0x640", out(reg) value, in(reg) src); + value +} + +/// Loads memory from hypervisor by unsigned half integer +/// +/// This instruction performs an explicit memory access as though `V=1`; +/// i.e., with the address translation and protection, and the endianness, that apply to memory +/// accesses in either VS-mode or VU-mode. +/// +/// # Unsafety +/// +/// This function accesses the virtual supervisor or user via a `HLV.HU` instruction which is effectively +/// an unreference to any memory address, thus is wrapped into an unsafe function. +#[inline] +pub unsafe fn hlv_hu(src: *const u16) -> u16 { + let value: u16; + asm!(".insn i 0x73, 0x4, {}, {}, 0x641", out(reg) value, in(reg) src); + value +} + +/// Accesses instruction from hypervisor by unsigned half integer +/// +/// This instruction performs an explicit memory access as though `V=1`; +/// the memory being read must be executable in both stages of address translation, +/// but read permission is not required. +/// +/// # Unsafety +/// +/// This function accesses the virtual supervisor or user via a `HLVX.HU` instruction which is effectively +/// an unreference to any memory address, thus is wrapped into an unsafe function. +#[inline] +pub unsafe fn hlvx_hu(src: *const u16) -> u16 { + let insn: u16; + asm!(".insn i 0x73, 0x4, {}, {}, 0x643", out(reg) insn, in(reg) src); + insn +} + +/// Loads memory from hypervisor by signed word integer +/// +/// This instruction performs an explicit memory access as though `V=1`; +/// i.e., with the address translation and protection, and the endianness, that apply to memory +/// accesses in either VS-mode or VU-mode. +/// +/// # Unsafety +/// +/// This function accesses the virtual supervisor or user via a `HLV.W` instruction which is effectively +/// an unreference to any memory address, thus is wrapped into an unsafe function. +#[inline] +pub unsafe fn hlv_w(src: *const i32) -> i32 { + let value: i32; + asm!(".insn i 0x73, 0x4, {}, {}, 0x680", out(reg) value, in(reg) src); + value +} + +/// Accesses instruction from hypervisor by unsigned word integer +/// +/// This instruction performs an explicit memory access as though `V=1`; +/// the memory being read must be executable in both stages of address translation, +/// but read permission is not required. +/// +/// # Unsafety +/// +/// This function accesses the virtual supervisor or user via a `HLVX.WU` instruction which is effectively +/// an unreference to any memory address, thus is wrapped into an unsafe function. +#[inline] +pub unsafe fn hlvx_wu(src: *const u32) -> u32 { + let insn: u32; + asm!(".insn i 0x73, 0x4, {}, {}, 0x683", out(reg) insn, in(reg) src); + insn +} + +/// Stores memory from hypervisor by byte integer +/// +/// This instruction performs an explicit memory access as though `V=1`; +/// i.e., with the address translation and protection, and the endianness, that apply to memory +/// accesses in either VS-mode or VU-mode. +/// +/// # Unsafety +/// +/// This function accesses the virtual supervisor or user via a `HSV.B` instruction which is effectively +/// an unreference to any memory address, thus is wrapped into an unsafe function. +#[inline] +pub unsafe fn hsv_b(dst: *mut i8, src: i8) { + asm!(".insn r 0x73, 0x4, 0x31, x0, {}, {}", in(reg) dst, in(reg) src); +} + +/// Stores memory from hypervisor by half integer +/// +/// This instruction performs an explicit memory access as though `V=1`; +/// i.e., with the address translation and protection, and the endianness, that apply to memory +/// accesses in either VS-mode or VU-mode. +/// +/// # Unsafety +/// +/// This function accesses the virtual supervisor or user via a `HSV.H` instruction which is effectively +/// an unreference to any memory address, thus is wrapped into an unsafe function. +#[inline] +pub unsafe fn hsv_h(dst: *mut i16, src: i16) { + asm!(".insn r 0x73, 0x4, 0x33, x0, {}, {}", in(reg) dst, in(reg) src); +} + +/// Stores memory from hypervisor by word integer +/// +/// This instruction performs an explicit memory access as though `V=1`; +/// i.e., with the address translation and protection, and the endianness, that apply to memory +/// accesses in either VS-mode or VU-mode. +/// +/// # Unsafety +/// +/// This function accesses the virtual supervisor or user via a `HSV.W` instruction which is effectively +/// an unreference to any memory address, thus is wrapped into an unsafe function. +#[inline] +pub unsafe fn hsv_w(dst: *mut i32, src: i32) { + asm!(".insn r 0x73, 0x4, 0x35, x0, {}, {}", in(reg) dst, in(reg) src); +} diff --git a/crates/core_arch/src/riscv64/mod.rs b/crates/core_arch/src/riscv64/mod.rs new file mode 100644 index 0000000000..846e6e38bd --- /dev/null +++ b/crates/core_arch/src/riscv64/mod.rs @@ -0,0 +1,55 @@ +//! RISC-V RV64 specific intrinsics +use crate::arch::asm; + +/// Loads memory from hypervisor by unsigned word integer +/// +/// This instruction performs an explicit memory access as though `V=1`; +/// i.e., with the address translation and protection, and the endianness, that apply to memory +/// accesses in either VS-mode or VU-mode. +/// +/// This operation is not available under RV32 base instruction set. +/// +/// # Unsafety +/// +/// This function accesses the virtual supervisor or user via a `HLV.WU` instruction which is effectively +/// an unreference to any memory address, thus is wrapped into an unsafe function. +#[inline] +pub unsafe fn hlv_wu(src: *const u32) -> u32 { + let value: u32; + asm!(".insn i 0x73, 0x4, {}, {}, 0x681", out(reg) value, in(reg) src); + value +} + +/// Loads memory from hypervisor by unsigned double integer +/// +/// This instruction performs an explicit memory access as though `V=1`; +/// i.e., with the address translation and protection, and the endianness, that apply to memory +/// accesses in either VS-mode or VU-mode. +/// +/// This operation is not available under RV32 base instruction set. +/// +/// # Unsafety +/// +/// This function accesses the virtual supervisor or user via a `HLV.D` instruction which is effectively +/// an unreference to any memory address, thus is wrapped into an unsafe function. +#[inline] +pub unsafe fn hlv_d(src: *const i64) -> i64 { + let value: i64; + asm!(".insn i 0x73, 0x4, {}, {}, 0x6C0", out(reg) value, in(reg) src); + value +} + +/// Stores memory from hypervisor by double integer +/// +/// This instruction performs an explicit memory access as though `V=1`; +/// i.e., with the address translation and protection, and the endianness, that apply to memory +/// accesses in either VS-mode or VU-mode. +/// +/// # Unsafety +/// +/// This function accesses the virtual supervisor or user via a `HSV.D` instruction which is effectively +/// an unreference to any memory address, thus is wrapped into an unsafe function. +#[inline] +pub unsafe fn hsv_d(dst: *mut i64, src: i64) { + asm!(".insn r 0x73, 0x4, 0x37, x0, {}, {}", in(reg) dst, in(reg) src); +} From 0c00e44ce79ef1015e6b519ffd3e46b3804b9641 Mon Sep 17 00:00:00 2001 From: luojia65 Date: Sat, 1 Jan 2022 15:54:20 +0800 Subject: [PATCH 3/6] riscv: hypervisor extension fences --- crates/core_arch/src/riscv/mod.rs | 208 ++++++++++++++++++++++++++++-- 1 file changed, 200 insertions(+), 8 deletions(-) diff --git a/crates/core_arch/src/riscv/mod.rs b/crates/core_arch/src/riscv/mod.rs index 68a0275507..72bb1dd385 100644 --- a/crates/core_arch/src/riscv/mod.rs +++ b/crates/core_arch/src/riscv/mod.rs @@ -42,7 +42,7 @@ pub unsafe fn fence_i() { asm!("fence.i") } -/// Generates the `SFENCE.VMA` instruction for given virtual address and address space +/// Supervisor memory management fence for given virtual address and address space /// /// The fence orders only reads and writes made to leaf page table entries corresponding to /// the virtual address in parameter `vaddr`, for the address space identified by integer parameter @@ -55,7 +55,7 @@ pub unsafe fn sfence_vma(vaddr: usize, asid: usize) { asm!("sfence.vma {}, {}", in(reg) vaddr, in(reg) asid) } -/// Generates the `SFENCE.VMA` instruction for given virtual address +/// Supervisor memory management fence for given virtual address /// /// The fence orders only reads and writes made to leaf page table entries corresponding to /// the virtual address in parameter `vaddr`, for all address spaces. @@ -66,7 +66,7 @@ pub unsafe fn sfence_vma_vaddr(vaddr: usize) { asm!("sfence.vma {}, x0", in(reg) vaddr) } -/// Generates the `SFENCE.VMA` instruction for given address space +/// Supervisor memory management fence for given address space /// /// The fence orders all reads and writes made to any level of the page tables, /// but only for the address space identified by integer parameter `asid`. @@ -79,7 +79,7 @@ pub unsafe fn sfence_vma_asid(asid: usize) { asm!("sfence.vma x0, {}", in(reg) asid) } -/// Generates the `SFENCE.VMA` instruction for all address spaces and virtual addresses +/// Supervisor memory management fence for all address spaces and virtual addresses /// /// The fence orders all reads and writes made to any level of the page /// tables, for all address spaces. The fence also invalidates all address-translation cache entries, @@ -89,7 +89,7 @@ pub unsafe fn sfence_vma_all() { asm!("sfence.vma") } -/// Generates the `SINVAL.VMA` instruction for given virtual address and address space +/// Invalidate supervisor translation cache for given virtual address and address space /// /// This instruction invalidates any address-translation cache entries that an /// `SFENCE.VMA` instruction with the same values of `vaddr` and `asid` would invalidate. @@ -99,7 +99,7 @@ pub unsafe fn sinval_vma(vaddr: usize, asid: usize) { asm!(".insn r 0x73, 0, 0x0B, x0, {}, {}", in(reg) vaddr, in(reg) asid) } -/// Generates the `SINVAL.VMA` instruction for given virtual address +/// Invalidate supervisor translation cache for given virtual address /// /// This instruction invalidates any address-translation cache entries that an /// `SFENCE.VMA` instruction with the same values of `vaddr` and `asid` would invalidate. @@ -108,7 +108,7 @@ pub unsafe fn sinval_vma_vaddr(vaddr: usize) { asm!(".insn r 0x73, 0, 0x0B, x0, {}, x0", in(reg) vaddr) } -/// Generates the `SINVAL.VMA` instruction for given address space +/// Invalidate supervisor translation cache for given address space /// /// This instruction invalidates any address-translation cache entries that an /// `SFENCE.VMA` instruction with the same values of `vaddr` and `asid` would invalidate. @@ -117,7 +117,7 @@ pub unsafe fn sinval_vma_asid(asid: usize) { asm!(".insn r 0x73, 0, 0x0B, x0, x0, {}", in(reg) asid) } -/// Generates the `SINVAL.VMA` instruction for all address spaces and virtual addresses +/// Invalidate supervisor translation cache for all address spaces and virtual addresses /// /// This instruction invalidates any address-translation cache entries that an /// `SFENCE.VMA` instruction with the same values of `vaddr` and `asid` would invalidate. @@ -132,6 +132,7 @@ pub unsafe fn sinval_vma_all() { /// are ordered before subsequent `SINVAL.VMA` instructions executed by the same hart. #[inline] pub unsafe fn sfence_w_inval() { + // asm!("sfence.w.inval") asm!(".insn i 0x73, 0, x0, x0, 0x180") } @@ -141,6 +142,7 @@ pub unsafe fn sfence_w_inval() { /// are ordered before subsequent implicit references by that hart to the memory-management data structures. #[inline] pub unsafe fn sfence_inval_ir() { + // asm!("sfence.inval.ir") asm!(".insn i 0x73, 0, x0, x0, 0x181") } @@ -307,3 +309,193 @@ pub unsafe fn hsv_h(dst: *mut i16, src: i16) { pub unsafe fn hsv_w(dst: *mut i32, src: i32) { asm!(".insn r 0x73, 0x4, 0x35, x0, {}, {}", in(reg) dst, in(reg) src); } + +/// Hypervisor memory management fence for given guest virtual address and guest address space +/// +/// Guarantees that any previous stores already visible to the current hart are ordered before all +/// implicit reads by that hart done for VS-stage address translation for instructions that: +/// - are subsequent to the `HFENCE.VVMA`, and +/// - execute when `hgatp.VMID` has the same setting as it did when `HFENCE.VVMA` executed. +/// +/// This fence specifies a single guest virtual address, and a single guest address-space identifier. +#[inline] +pub unsafe fn hfence_vvma(vaddr: usize, asid: usize) { + // asm!("hfence.vvma {}, {}", in(reg) vaddr, in(reg) asid) + asm!(".insn r 0x73, 0, 0x11, x0, {}, {}", in(reg) vaddr, in(reg) asid) +} + +/// Hypervisor memory management fence for given guest virtual address +/// +/// Guarantees that any previous stores already visible to the current hart are ordered before all +/// implicit reads by that hart done for VS-stage address translation for instructions that: +/// - are subsequent to the `HFENCE.VVMA`, and +/// - execute when `hgatp.VMID` has the same setting as it did when `HFENCE.VVMA` executed. +/// +/// This fence specifies a single guest virtual address. +#[inline] +pub unsafe fn hfence_vvma_vaddr(vaddr: usize) { + asm!(".insn r 0x73, 0, 0x11, x0, {}, x0", in(reg) vaddr) +} + +/// Hypervisor memory management fence for given guest address space +/// +/// Guarantees that any previous stores already visible to the current hart are ordered before all +/// implicit reads by that hart done for VS-stage address translation for instructions that: +/// - are subsequent to the `HFENCE.VVMA`, and +/// - execute when `hgatp.VMID` has the same setting as it did when `HFENCE.VVMA` executed. +/// +/// This fence specifies a single guest address-space identifier. +#[inline] +pub unsafe fn hfence_vvma_asid(asid: usize) { + asm!(".insn r 0x73, 0, 0x11, x0, x0, {}", in(reg) asid) +} + +/// Hypervisor memory management fence for all guest address spaces and guest virtual addresses +/// +/// Guarantees that any previous stores already visible to the current hart are ordered before all +/// implicit reads by that hart done for VS-stage address translation for instructions that: +/// - are subsequent to the `HFENCE.VVMA`, and +/// - execute when `hgatp.VMID` has the same setting as it did when `HFENCE.VVMA` executed. +/// +/// This fence applies to any guest address spaces and guest virtual addresses. +#[inline] +pub unsafe fn hfence_vvma_all() { + asm!(".insn r 0x73, 0, 0x11, x0, x0, x0") +} + +/// Hypervisor memory management fence for guest physical address and virtual machine +/// +/// Guarantees that any previous stores already visible to the current hart are ordered before all implicit reads +/// by that hart done for G-stage address translation for instructions that follow the HFENCE.GVMA. +/// +/// This fence specifies a single guest physical address, **shifted right by 2 bits**, and a single virtual machine +/// by virtual machine identifier (VMID). +#[inline] +pub unsafe fn hfence_gvma(gaddr: usize, vmid: usize) { + // asm!("hfence.gvma {}, {}", in(reg) gaddr, in(reg) vmid) + asm!(".insn r 0x73, 0, 0x31, x0, {}, {}", in(reg) gaddr, in(reg) vmid) +} + +/// Hypervisor memory management fence for guest physical address +/// +/// Guarantees that any previous stores already visible to the current hart are ordered before all implicit reads +/// by that hart done for G-stage address translation for instructions that follow the HFENCE.GVMA. +/// +/// This fence specifies a single guest physical address; **the physical address should be shifted right by 2 bits**. +#[inline] +pub unsafe fn hfence_gvma_gaddr(gaddr: usize) { + asm!(".insn r 0x73, 0, 0x31, x0, {}, x0", in(reg) gaddr) +} + +/// Hypervisor memory management fence for given virtual machine +/// +/// Guarantees that any previous stores already visible to the current hart are ordered before all implicit reads +/// by that hart done for G-stage address translation for instructions that follow the HFENCE.GVMA. +/// +/// This fence specifies a single virtual machine by virtual machine identifier (VMID). +#[inline] +pub unsafe fn hfence_gvma_vmid(vmid: usize) { + asm!(".insn r 0x73, 0, 0x31, x0, x0, {}", in(reg) vmid) +} + +/// Hypervisor memory management fence for all virtual machines and guest physical addresses +/// +/// Guarantees that any previous stores already visible to the current hart are ordered before all implicit reads +/// by that hart done for G-stage address translation for instructions that follow the HFENCE.GVMA. +/// +/// This fence specifies all guest physical addresses and all virtual machines. +#[inline] +pub unsafe fn hfence_gvma_all() { + asm!(".insn r 0x73, 0, 0x31, x0, x0, x0") +} + +/// Invalidate hypervisor translation cache for given guest virtual address and guest address space +/// +/// This instruction invalidates any address-translation cache entries that an +/// `HFENCE.VVMA` instruction with the same values of `vaddr` and `asid` would invalidate. +/// +/// This fence specifies a single guest virtual address, and a single guest address-space identifier. +#[inline] +pub unsafe fn hinval_vvma(vaddr: usize, asid: usize) { + // asm!("hinval.vvma {}, {}", in(reg) vaddr, in(reg) asid) + asm!(".insn r 0x73, 0, 0x13, x0, {}, {}", in(reg) vaddr, in(reg) asid) +} + +/// Invalidate hypervisor translation cache for given guest virtual address +/// +/// This instruction invalidates any address-translation cache entries that an +/// `HFENCE.VVMA` instruction with the same values of `vaddr` and `asid` would invalidate. +/// +/// This fence specifies a single guest virtual address. +#[inline] +pub unsafe fn hinval_vvma_vaddr(vaddr: usize) { + asm!(".insn r 0x73, 0, 0x13, x0, {}, x0", in(reg) vaddr) +} + +/// Invalidate hypervisor translation cache for given guest address space +/// +/// This instruction invalidates any address-translation cache entries that an +/// `HFENCE.VVMA` instruction with the same values of `vaddr` and `asid` would invalidate. +/// +/// This fence specifies a single guest address-space identifier. +#[inline] +pub unsafe fn hinval_vvma_asid(asid: usize) { + asm!(".insn r 0x73, 0, 0x13, x0, x0, {}", in(reg) asid) +} + +/// Invalidate hypervisor translation cache for all guest address spaces and guest virtual addresses +/// +/// This instruction invalidates any address-translation cache entries that an +/// `HFENCE.VVMA` instruction with the same values of `vaddr` and `asid` would invalidate. +/// +/// This fence applies to any guest address spaces and guest virtual addresses. +#[inline] +pub unsafe fn hinval_vvma_all() { + asm!(".insn r 0x73, 0, 0x13, x0, x0, x0") +} + +/// Invalidate hypervisor translation cache for guest physical address and virtual machine +/// +/// This instruction invalidates any address-translation cache entries that an +/// `HFENCE.GVMA` instruction with the same values of `gaddr` and `vmid` would invalidate. +/// +/// This fence specifies a single guest physical address, **shifted right by 2 bits**, and a single virtual machine +/// by virtual machine identifier (VMID). +#[inline] +pub unsafe fn hinval_gvma(gaddr: usize, vmid: usize) { + // asm!("hinval.gvma {}, {}", in(reg) gaddr, in(reg) vmid) + asm!(".insn r 0x73, 0, 0x33, x0, {}, {}", in(reg) gaddr, in(reg) vmid) +} + +/// Invalidate hypervisor translation cache for guest physical address +/// +/// This instruction invalidates any address-translation cache entries that an +/// `HFENCE.GVMA` instruction with the same values of `gaddr` and `vmid` would invalidate. +/// +/// This fence specifies a single guest physical address; **the physical address should be shifted right by 2 bits**. +#[inline] +pub unsafe fn hinval_gvma_gaddr(gaddr: usize) { + asm!(".insn r 0x73, 0, 0x33, x0, {}, x0", in(reg) gaddr) +} + +/// Invalidate hypervisor translation cache for given virtual machine +/// +/// This instruction invalidates any address-translation cache entries that an +/// `HFENCE.GVMA` instruction with the same values of `gaddr` and `vmid` would invalidate. +/// +/// This fence specifies a single virtual machine by virtual machine identifier (VMID). +#[inline] +pub unsafe fn hinval_gvma_vmid(vmid: usize) { + asm!(".insn r 0x73, 0, 0x33, x0, x0, {}", in(reg) vmid) +} + +/// Invalidate hypervisor translation cache for all virtual machines and guest physical addresses +/// +/// This instruction invalidates any address-translation cache entries that an +/// `HFENCE.GVMA` instruction with the same values of `gaddr` and `vmid` would invalidate. +/// +/// This fence specifies all guest physical addresses and all virtual machines. +#[inline] +pub unsafe fn hinval_gvma_all() { + asm!(".insn r 0x73, 0, 0x33, x0, x0, x0") +} From ebe01418dc5db1871b96458cb9355e0430aef884 Mon Sep 17 00:00:00 2001 From: luojia65 Date: Sat, 1 Jan 2022 15:59:16 +0800 Subject: [PATCH 4/6] riscv: adjust documents for virtual memory instructions modify core arch docs --- crates/core_arch/src/core_arch_docs.md | 2 + crates/core_arch/src/riscv/mod.rs | 80 ++++++++++---------------- crates/core_arch/src/riscv64/mod.rs | 24 +++----- 3 files changed, 41 insertions(+), 65 deletions(-) diff --git a/crates/core_arch/src/core_arch_docs.md b/crates/core_arch/src/core_arch_docs.md index be0f98c843..da41747800 100644 --- a/crates/core_arch/src/core_arch_docs.md +++ b/crates/core_arch/src/core_arch_docs.md @@ -186,6 +186,7 @@ others at: * [`arm`] * [`aarch64`] * [`riscv`] +* [`riscv64`] * [`mips`] * [`mips64`] * [`powerpc`] @@ -198,6 +199,7 @@ others at: [`arm`]: arm/index.html [`aarch64`]: aarch64/index.html [`riscv`]: riscv/index.html +[`riscv64`]: riscv64/index.html [`mips`]: mips/index.html [`mips64`]: mips64/index.html [`powerpc`]: powerpc/index.html diff --git a/crates/core_arch/src/riscv/mod.rs b/crates/core_arch/src/riscv/mod.rs index 72bb1dd385..ee9b721f26 100644 --- a/crates/core_arch/src/riscv/mod.rs +++ b/crates/core_arch/src/riscv/mod.rs @@ -146,16 +146,14 @@ pub unsafe fn sfence_inval_ir() { asm!(".insn i 0x73, 0, x0, x0, 0x181") } -/// Loads memory from hypervisor by signed byte integer +/// Loads virtual machine memory by signed byte integer /// /// This instruction performs an explicit memory access as though `V=1`; /// i.e., with the address translation and protection, and the endianness, that apply to memory /// accesses in either VS-mode or VU-mode. /// -/// # Unsafety -/// -/// This function accesses the virtual supervisor or user via a `HLV.B` instruction which is effectively -/// an unreference to any memory address, thus is wrapped into an unsafe function. +/// This function is unsafe for it accesses the virtual supervisor or user via a `HLV.B` +/// instruction which is effectively an unreference to any memory address. #[inline] pub unsafe fn hlv_b(src: *const i8) -> i8 { let value: i8; @@ -163,16 +161,14 @@ pub unsafe fn hlv_b(src: *const i8) -> i8 { value } -/// Loads memory from hypervisor by unsigned byte integer +/// Loads virtual machine memory by unsigned byte integer /// /// This instruction performs an explicit memory access as though `V=1`; /// i.e., with the address translation and protection, and the endianness, that apply to memory /// accesses in either VS-mode or VU-mode. /// -/// # Unsafety -/// -/// This function accesses the virtual supervisor or user via a `HLV.BU` instruction which is effectively -/// an unreference to any memory address, thus is wrapped into an unsafe function. +/// This function is unsafe for it accesses the virtual supervisor or user via a `HLV.BU` +/// instruction which is effectively an unreference to any memory address. #[inline] pub unsafe fn hlv_bu(src: *const u8) -> u8 { let value: u8; @@ -180,16 +176,14 @@ pub unsafe fn hlv_bu(src: *const u8) -> u8 { value } -/// Loads memory from hypervisor by signed half integer +/// Loads virtual machine memory by signed half integer /// /// This instruction performs an explicit memory access as though `V=1`; /// i.e., with the address translation and protection, and the endianness, that apply to memory /// accesses in either VS-mode or VU-mode. /// -/// # Unsafety -/// -/// This function accesses the virtual supervisor or user via a `HLV.H` instruction which is effectively -/// an unreference to any memory address, thus is wrapped into an unsafe function. +/// This function is unsafe for it accesses the virtual supervisor or user via a `HLV.H` +/// instruction which is effectively an unreference to any memory address. #[inline] pub unsafe fn hlv_h(src: *const i16) -> i16 { let value: i16; @@ -197,16 +191,14 @@ pub unsafe fn hlv_h(src: *const i16) -> i16 { value } -/// Loads memory from hypervisor by unsigned half integer +/// Loads virtual machine memory by unsigned half integer /// /// This instruction performs an explicit memory access as though `V=1`; /// i.e., with the address translation and protection, and the endianness, that apply to memory /// accesses in either VS-mode or VU-mode. /// -/// # Unsafety -/// -/// This function accesses the virtual supervisor or user via a `HLV.HU` instruction which is effectively -/// an unreference to any memory address, thus is wrapped into an unsafe function. +/// This function is unsafe for it accesses the virtual supervisor or user via a `HLV.HU` +/// instruction which is effectively an unreference to any memory address. #[inline] pub unsafe fn hlv_hu(src: *const u16) -> u16 { let value: u16; @@ -214,16 +206,14 @@ pub unsafe fn hlv_hu(src: *const u16) -> u16 { value } -/// Accesses instruction from hypervisor by unsigned half integer +/// Accesses virtual machine instruction by unsigned half integer /// /// This instruction performs an explicit memory access as though `V=1`; /// the memory being read must be executable in both stages of address translation, /// but read permission is not required. /// -/// # Unsafety -/// -/// This function accesses the virtual supervisor or user via a `HLVX.HU` instruction which is effectively -/// an unreference to any memory address, thus is wrapped into an unsafe function. +/// This function is unsafe for it accesses the virtual supervisor or user via a `HLVX.HU` +/// instruction which is effectively an unreference to any memory address. #[inline] pub unsafe fn hlvx_hu(src: *const u16) -> u16 { let insn: u16; @@ -231,16 +221,14 @@ pub unsafe fn hlvx_hu(src: *const u16) -> u16 { insn } -/// Loads memory from hypervisor by signed word integer +/// Loads virtual machine memory by signed word integer /// /// This instruction performs an explicit memory access as though `V=1`; /// i.e., with the address translation and protection, and the endianness, that apply to memory /// accesses in either VS-mode or VU-mode. /// -/// # Unsafety -/// -/// This function accesses the virtual supervisor or user via a `HLV.W` instruction which is effectively -/// an unreference to any memory address, thus is wrapped into an unsafe function. +/// This function is unsafe for it accesses the virtual supervisor or user via a `HLV.W` +/// instruction which is effectively an unreference to any memory address. #[inline] pub unsafe fn hlv_w(src: *const i32) -> i32 { let value: i32; @@ -248,16 +236,14 @@ pub unsafe fn hlv_w(src: *const i32) -> i32 { value } -/// Accesses instruction from hypervisor by unsigned word integer +/// Accesses virtual machine instruction by unsigned word integer /// /// This instruction performs an explicit memory access as though `V=1`; /// the memory being read must be executable in both stages of address translation, /// but read permission is not required. /// -/// # Unsafety -/// -/// This function accesses the virtual supervisor or user via a `HLVX.WU` instruction which is effectively -/// an unreference to any memory address, thus is wrapped into an unsafe function. +/// This function is unsafe for it accesses the virtual supervisor or user via a `HLVX.WU` +/// instruction which is effectively an unreference to any memory address. #[inline] pub unsafe fn hlvx_wu(src: *const u32) -> u32 { let insn: u32; @@ -265,46 +251,40 @@ pub unsafe fn hlvx_wu(src: *const u32) -> u32 { insn } -/// Stores memory from hypervisor by byte integer +/// Stores virtual machine memory by byte integer /// /// This instruction performs an explicit memory access as though `V=1`; /// i.e., with the address translation and protection, and the endianness, that apply to memory /// accesses in either VS-mode or VU-mode. /// -/// # Unsafety -/// -/// This function accesses the virtual supervisor or user via a `HSV.B` instruction which is effectively -/// an unreference to any memory address, thus is wrapped into an unsafe function. +/// This function is unsafe for it accesses the virtual supervisor or user via a `HSV.B` +/// instruction which is effectively an unreference to any memory address. #[inline] pub unsafe fn hsv_b(dst: *mut i8, src: i8) { asm!(".insn r 0x73, 0x4, 0x31, x0, {}, {}", in(reg) dst, in(reg) src); } -/// Stores memory from hypervisor by half integer +/// Stores virtual machine memory by half integer /// /// This instruction performs an explicit memory access as though `V=1`; /// i.e., with the address translation and protection, and the endianness, that apply to memory /// accesses in either VS-mode or VU-mode. /// -/// # Unsafety -/// -/// This function accesses the virtual supervisor or user via a `HSV.H` instruction which is effectively -/// an unreference to any memory address, thus is wrapped into an unsafe function. +/// This function is unsafe for it accesses the virtual supervisor or user via a `HSV.H` +/// instruction which is effectively an unreference to any memory address. #[inline] pub unsafe fn hsv_h(dst: *mut i16, src: i16) { asm!(".insn r 0x73, 0x4, 0x33, x0, {}, {}", in(reg) dst, in(reg) src); } -/// Stores memory from hypervisor by word integer +/// Stores virtual machine memory by word integer /// /// This instruction performs an explicit memory access as though `V=1`; /// i.e., with the address translation and protection, and the endianness, that apply to memory /// accesses in either VS-mode or VU-mode. /// -/// # Unsafety -/// -/// This function accesses the virtual supervisor or user via a `HSV.W` instruction which is effectively -/// an unreference to any memory address, thus is wrapped into an unsafe function. +/// This function is unsafe for it accesses the virtual supervisor or user via a `HSV.W` +/// instruction which is effectively an unreference to any memory address. #[inline] pub unsafe fn hsv_w(dst: *mut i32, src: i32) { asm!(".insn r 0x73, 0x4, 0x35, x0, {}, {}", in(reg) dst, in(reg) src); diff --git a/crates/core_arch/src/riscv64/mod.rs b/crates/core_arch/src/riscv64/mod.rs index 846e6e38bd..6df3425e64 100644 --- a/crates/core_arch/src/riscv64/mod.rs +++ b/crates/core_arch/src/riscv64/mod.rs @@ -1,7 +1,7 @@ //! RISC-V RV64 specific intrinsics use crate::arch::asm; -/// Loads memory from hypervisor by unsigned word integer +/// Loads virtual machine memory by unsigned word integer /// /// This instruction performs an explicit memory access as though `V=1`; /// i.e., with the address translation and protection, and the endianness, that apply to memory @@ -9,10 +9,8 @@ use crate::arch::asm; /// /// This operation is not available under RV32 base instruction set. /// -/// # Unsafety -/// -/// This function accesses the virtual supervisor or user via a `HLV.WU` instruction which is effectively -/// an unreference to any memory address, thus is wrapped into an unsafe function. +/// This function is unsafe for it accesses the virtual supervisor or user via a `HLV.WU` +/// instruction which is effectively an unreference to any memory address. #[inline] pub unsafe fn hlv_wu(src: *const u32) -> u32 { let value: u32; @@ -20,7 +18,7 @@ pub unsafe fn hlv_wu(src: *const u32) -> u32 { value } -/// Loads memory from hypervisor by unsigned double integer +/// Loads virtual machine memory by unsigned double integer /// /// This instruction performs an explicit memory access as though `V=1`; /// i.e., with the address translation and protection, and the endianness, that apply to memory @@ -28,10 +26,8 @@ pub unsafe fn hlv_wu(src: *const u32) -> u32 { /// /// This operation is not available under RV32 base instruction set. /// -/// # Unsafety -/// -/// This function accesses the virtual supervisor or user via a `HLV.D` instruction which is effectively -/// an unreference to any memory address, thus is wrapped into an unsafe function. +/// This function is unsafe for it accesses the virtual supervisor or user via a `HLV.D` +/// instruction which is effectively an unreference to any memory address. #[inline] pub unsafe fn hlv_d(src: *const i64) -> i64 { let value: i64; @@ -39,16 +35,14 @@ pub unsafe fn hlv_d(src: *const i64) -> i64 { value } -/// Stores memory from hypervisor by double integer +/// Stores virtual machine memory by double integer /// /// This instruction performs an explicit memory access as though `V=1`; /// i.e., with the address translation and protection, and the endianness, that apply to memory /// accesses in either VS-mode or VU-mode. /// -/// # Unsafety -/// -/// This function accesses the virtual supervisor or user via a `HSV.D` instruction which is effectively -/// an unreference to any memory address, thus is wrapped into an unsafe function. +/// This function is unsafe for it accesses the virtual supervisor or user via a `HSV.D` +/// instruction which is effectively an unreference to any memory address. #[inline] pub unsafe fn hsv_d(dst: *mut i64, src: i64) { asm!(".insn r 0x73, 0x4, 0x37, x0, {}, {}", in(reg) dst, in(reg) src); From d69b77601ee8ca58995995962b69cdda6258d619 Mon Sep 17 00:00:00 2001 From: luojia65 Date: Tue, 4 Jan 2022 13:50:04 +0800 Subject: [PATCH 5/6] riscv: use name `riscv32` for 32-bit RISC-V architecture rename internal riscv32 module to riscv_shared --- crates/core_arch/src/core_arch_docs.md | 4 ++-- crates/core_arch/src/mod.rs | 17 ++++++++++------- .../src/{riscv => riscv_shared}/mod.rs | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) rename crates/core_arch/src/{riscv => riscv_shared}/mod.rs (99%) diff --git a/crates/core_arch/src/core_arch_docs.md b/crates/core_arch/src/core_arch_docs.md index da41747800..58b7eda9a8 100644 --- a/crates/core_arch/src/core_arch_docs.md +++ b/crates/core_arch/src/core_arch_docs.md @@ -185,7 +185,7 @@ others at: * [`x86_64`] * [`arm`] * [`aarch64`] -* [`riscv`] +* [`riscv32`] * [`riscv64`] * [`mips`] * [`mips64`] @@ -198,7 +198,7 @@ others at: [`x86_64`]: x86_64/index.html [`arm`]: arm/index.html [`aarch64`]: aarch64/index.html -[`riscv`]: riscv/index.html +[`riscv32`]: riscv32/index.html [`riscv64`]: riscv64/index.html [`mips`]: mips/index.html [`mips64`]: mips64/index.html diff --git a/crates/core_arch/src/mod.rs b/crates/core_arch/src/mod.rs index decf692343..20751eeec5 100644 --- a/crates/core_arch/src/mod.rs +++ b/crates/core_arch/src/mod.rs @@ -56,14 +56,14 @@ pub mod arch { pub use crate::core_arch::aarch64::*; } - /// Platform-specific intrinsics for the `riscv` platform. + /// Platform-specific intrinsics for the `riscv32` platform. /// /// See the [module documentation](../index.html) for more details. - #[cfg(any(target_arch = "riscv32", target_arch = "riscv64", doc))] - #[doc(cfg(any(target_arch = "riscv32", target_arch = "riscv64")))] + #[cfg(any(target_arch = "riscv32", doc))] + #[doc(cfg(any(target_arch = "riscv32")))] #[unstable(feature = "stdsimd", issue = "27731")] - pub mod riscv { - pub use crate::core_arch::riscv::*; + pub mod riscv32 { + pub use crate::core_arch::riscv_shared::*; } /// Platform-specific intrinsics for the `riscv64` platform. @@ -73,8 +73,11 @@ pub mod arch { #[doc(cfg(any(target_arch = "riscv64")))] #[unstable(feature = "stdsimd", issue = "27731")] pub mod riscv64 { - pub use crate::core_arch::riscv::*; pub use crate::core_arch::riscv64::*; + // RISC-V RV64 supports all RV32 instructions as well in current specifications (2022-01-05). + // Module `riscv_shared` includes instructions available under all RISC-V platforms, + // i.e. RISC-V RV32 instructions. + pub use crate::core_arch::riscv_shared::*; } /// Platform-specific intrinsics for the `wasm32` platform. @@ -275,7 +278,7 @@ mod arm; #[cfg(any(target_arch = "riscv32", target_arch = "riscv64", doc))] #[doc(cfg(any(target_arch = "riscv32", target_arch = "riscv64")))] -mod riscv; +mod riscv_shared; #[cfg(any(target_arch = "riscv64", doc))] #[doc(cfg(any(target_arch = "riscv64")))] diff --git a/crates/core_arch/src/riscv/mod.rs b/crates/core_arch/src/riscv_shared/mod.rs similarity index 99% rename from crates/core_arch/src/riscv/mod.rs rename to crates/core_arch/src/riscv_shared/mod.rs index ee9b721f26..6226d446ee 100644 --- a/crates/core_arch/src/riscv/mod.rs +++ b/crates/core_arch/src/riscv_shared/mod.rs @@ -1,4 +1,4 @@ -//! RISC-V intrinsics +//! Shared RISC-V intrinsics use crate::arch::asm; From 682558b75c6ee95511aebdb6fdb71a6892c09866 Mon Sep 17 00:00:00 2001 From: luojia65 Date: Wed, 5 Jan 2022 13:58:12 +0800 Subject: [PATCH 6/6] riscv: set correct options for asm macro uses --- crates/core_arch/src/riscv64/mod.rs | 6 +- crates/core_arch/src/riscv_shared/mod.rs | 90 ++++++++++++------------ 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/crates/core_arch/src/riscv64/mod.rs b/crates/core_arch/src/riscv64/mod.rs index 6df3425e64..24aae78325 100644 --- a/crates/core_arch/src/riscv64/mod.rs +++ b/crates/core_arch/src/riscv64/mod.rs @@ -14,7 +14,7 @@ use crate::arch::asm; #[inline] pub unsafe fn hlv_wu(src: *const u32) -> u32 { let value: u32; - asm!(".insn i 0x73, 0x4, {}, {}, 0x681", out(reg) value, in(reg) src); + asm!(".insn i 0x73, 0x4, {}, {}, 0x681", out(reg) value, in(reg) src, options(readonly, nostack)); value } @@ -31,7 +31,7 @@ pub unsafe fn hlv_wu(src: *const u32) -> u32 { #[inline] pub unsafe fn hlv_d(src: *const i64) -> i64 { let value: i64; - asm!(".insn i 0x73, 0x4, {}, {}, 0x6C0", out(reg) value, in(reg) src); + asm!(".insn i 0x73, 0x4, {}, {}, 0x6C0", out(reg) value, in(reg) src, options(readonly, nostack)); value } @@ -45,5 +45,5 @@ pub unsafe fn hlv_d(src: *const i64) -> i64 { /// instruction which is effectively an unreference to any memory address. #[inline] pub unsafe fn hsv_d(dst: *mut i64, src: i64) { - asm!(".insn r 0x73, 0x4, 0x37, x0, {}, {}", in(reg) dst, in(reg) src); + asm!(".insn r 0x73, 0x4, 0x37, x0, {}, {}", in(reg) dst, in(reg) src, options(nostack)); } diff --git a/crates/core_arch/src/riscv_shared/mod.rs b/crates/core_arch/src/riscv_shared/mod.rs index 6226d446ee..a2c9cb2436 100644 --- a/crates/core_arch/src/riscv_shared/mod.rs +++ b/crates/core_arch/src/riscv_shared/mod.rs @@ -17,7 +17,7 @@ pub fn pause() { /// advancing the `pc` and incrementing any applicable performance counters. #[inline] pub fn nop() { - unsafe { asm!("nop") } + unsafe { asm!("nop", options(nomem, nostack)) } } /// Generates the `WFI` instruction @@ -27,7 +27,7 @@ pub fn nop() { /// and a legal implementation is to simply implement WFI as a NOP. #[inline] pub unsafe fn wfi() { - asm!("wfi") + asm!("wfi", options(nomem, nostack)) } /// Generates the `FENCE.I` instruction @@ -39,7 +39,7 @@ pub unsafe fn wfi() { /// local hart's stores in a multiprocessor system. #[inline] pub unsafe fn fence_i() { - asm!("fence.i") + asm!("fence.i", options(nostack)) } /// Supervisor memory management fence for given virtual address and address space @@ -52,7 +52,7 @@ pub unsafe fn fence_i() { /// parameter `asid`, except for entries containing global mappings. #[inline] pub unsafe fn sfence_vma(vaddr: usize, asid: usize) { - asm!("sfence.vma {}, {}", in(reg) vaddr, in(reg) asid) + asm!("sfence.vma {}, {}", in(reg) vaddr, in(reg) asid, options(nostack)) } /// Supervisor memory management fence for given virtual address @@ -63,7 +63,7 @@ pub unsafe fn sfence_vma(vaddr: usize, asid: usize) { /// table entries corresponding to the virtual address in parameter `vaddr`, for all address spaces. #[inline] pub unsafe fn sfence_vma_vaddr(vaddr: usize) { - asm!("sfence.vma {}, x0", in(reg) vaddr) + asm!("sfence.vma {}, x0", in(reg) vaddr, options(nostack)) } /// Supervisor memory management fence for given address space @@ -76,7 +76,7 @@ pub unsafe fn sfence_vma_vaddr(vaddr: usize) { /// parameter `asid`, except for entries containing global mappings. #[inline] pub unsafe fn sfence_vma_asid(asid: usize) { - asm!("sfence.vma x0, {}", in(reg) asid) + asm!("sfence.vma x0, {}", in(reg) asid, options(nostack)) } /// Supervisor memory management fence for all address spaces and virtual addresses @@ -86,7 +86,7 @@ pub unsafe fn sfence_vma_asid(asid: usize) { /// for all address spaces. #[inline] pub unsafe fn sfence_vma_all() { - asm!("sfence.vma") + asm!("sfence.vma", options(nostack)) } /// Invalidate supervisor translation cache for given virtual address and address space @@ -95,8 +95,8 @@ pub unsafe fn sfence_vma_all() { /// `SFENCE.VMA` instruction with the same values of `vaddr` and `asid` would invalidate. #[inline] pub unsafe fn sinval_vma(vaddr: usize, asid: usize) { - // asm!("sinval.vma {}, {}", in(reg) vaddr, in(reg) asid) - asm!(".insn r 0x73, 0, 0x0B, x0, {}, {}", in(reg) vaddr, in(reg) asid) + // asm!("sinval.vma {}, {}", in(reg) vaddr, in(reg) asid, options(nostack)) + asm!(".insn r 0x73, 0, 0x0B, x0, {}, {}", in(reg) vaddr, in(reg) asid, options(nostack)) } /// Invalidate supervisor translation cache for given virtual address @@ -105,7 +105,7 @@ pub unsafe fn sinval_vma(vaddr: usize, asid: usize) { /// `SFENCE.VMA` instruction with the same values of `vaddr` and `asid` would invalidate. #[inline] pub unsafe fn sinval_vma_vaddr(vaddr: usize) { - asm!(".insn r 0x73, 0, 0x0B, x0, {}, x0", in(reg) vaddr) + asm!(".insn r 0x73, 0, 0x0B, x0, {}, x0", in(reg) vaddr, options(nostack)) } /// Invalidate supervisor translation cache for given address space @@ -114,7 +114,7 @@ pub unsafe fn sinval_vma_vaddr(vaddr: usize) { /// `SFENCE.VMA` instruction with the same values of `vaddr` and `asid` would invalidate. #[inline] pub unsafe fn sinval_vma_asid(asid: usize) { - asm!(".insn r 0x73, 0, 0x0B, x0, x0, {}", in(reg) asid) + asm!(".insn r 0x73, 0, 0x0B, x0, x0, {}", in(reg) asid, options(nostack)) } /// Invalidate supervisor translation cache for all address spaces and virtual addresses @@ -123,7 +123,7 @@ pub unsafe fn sinval_vma_asid(asid: usize) { /// `SFENCE.VMA` instruction with the same values of `vaddr` and `asid` would invalidate. #[inline] pub unsafe fn sinval_vma_all() { - asm!(".insn r 0x73, 0, 0x0B, x0, x0, x0") + asm!(".insn r 0x73, 0, 0x0B, x0, x0, x0", options(nostack)) } /// Generates the `SFENCE.W.INVAL` instruction @@ -132,8 +132,8 @@ pub unsafe fn sinval_vma_all() { /// are ordered before subsequent `SINVAL.VMA` instructions executed by the same hart. #[inline] pub unsafe fn sfence_w_inval() { - // asm!("sfence.w.inval") - asm!(".insn i 0x73, 0, x0, x0, 0x180") + // asm!("sfence.w.inval", options(nostack)) + asm!(".insn i 0x73, 0, x0, x0, 0x180", options(nostack)) } /// Generates the `SFENCE.INVAL.IR` instruction @@ -142,8 +142,8 @@ pub unsafe fn sfence_w_inval() { /// are ordered before subsequent implicit references by that hart to the memory-management data structures. #[inline] pub unsafe fn sfence_inval_ir() { - // asm!("sfence.inval.ir") - asm!(".insn i 0x73, 0, x0, x0, 0x181") + // asm!("sfence.inval.ir", options(nostack)) + asm!(".insn i 0x73, 0, x0, x0, 0x181", options(nostack)) } /// Loads virtual machine memory by signed byte integer @@ -157,7 +157,7 @@ pub unsafe fn sfence_inval_ir() { #[inline] pub unsafe fn hlv_b(src: *const i8) -> i8 { let value: i8; - asm!(".insn i 0x73, 0x4, {}, {}, 0x600", out(reg) value, in(reg) src); + asm!(".insn i 0x73, 0x4, {}, {}, 0x600", out(reg) value, in(reg) src, options(readonly, nostack)); value } @@ -172,7 +172,7 @@ pub unsafe fn hlv_b(src: *const i8) -> i8 { #[inline] pub unsafe fn hlv_bu(src: *const u8) -> u8 { let value: u8; - asm!(".insn i 0x73, 0x4, {}, {}, 0x601", out(reg) value, in(reg) src); + asm!(".insn i 0x73, 0x4, {}, {}, 0x601", out(reg) value, in(reg) src, options(readonly, nostack)); value } @@ -187,7 +187,7 @@ pub unsafe fn hlv_bu(src: *const u8) -> u8 { #[inline] pub unsafe fn hlv_h(src: *const i16) -> i16 { let value: i16; - asm!(".insn i 0x73, 0x4, {}, {}, 0x640", out(reg) value, in(reg) src); + asm!(".insn i 0x73, 0x4, {}, {}, 0x640", out(reg) value, in(reg) src, options(readonly, nostack)); value } @@ -202,7 +202,7 @@ pub unsafe fn hlv_h(src: *const i16) -> i16 { #[inline] pub unsafe fn hlv_hu(src: *const u16) -> u16 { let value: u16; - asm!(".insn i 0x73, 0x4, {}, {}, 0x641", out(reg) value, in(reg) src); + asm!(".insn i 0x73, 0x4, {}, {}, 0x641", out(reg) value, in(reg) src, options(readonly, nostack)); value } @@ -217,7 +217,7 @@ pub unsafe fn hlv_hu(src: *const u16) -> u16 { #[inline] pub unsafe fn hlvx_hu(src: *const u16) -> u16 { let insn: u16; - asm!(".insn i 0x73, 0x4, {}, {}, 0x643", out(reg) insn, in(reg) src); + asm!(".insn i 0x73, 0x4, {}, {}, 0x643", out(reg) insn, in(reg) src, options(readonly, nostack)); insn } @@ -232,7 +232,7 @@ pub unsafe fn hlvx_hu(src: *const u16) -> u16 { #[inline] pub unsafe fn hlv_w(src: *const i32) -> i32 { let value: i32; - asm!(".insn i 0x73, 0x4, {}, {}, 0x680", out(reg) value, in(reg) src); + asm!(".insn i 0x73, 0x4, {}, {}, 0x680", out(reg) value, in(reg) src, options(readonly, nostack)); value } @@ -247,7 +247,7 @@ pub unsafe fn hlv_w(src: *const i32) -> i32 { #[inline] pub unsafe fn hlvx_wu(src: *const u32) -> u32 { let insn: u32; - asm!(".insn i 0x73, 0x4, {}, {}, 0x683", out(reg) insn, in(reg) src); + asm!(".insn i 0x73, 0x4, {}, {}, 0x683", out(reg) insn, in(reg) src, options(readonly, nostack)); insn } @@ -261,7 +261,7 @@ pub unsafe fn hlvx_wu(src: *const u32) -> u32 { /// instruction which is effectively an unreference to any memory address. #[inline] pub unsafe fn hsv_b(dst: *mut i8, src: i8) { - asm!(".insn r 0x73, 0x4, 0x31, x0, {}, {}", in(reg) dst, in(reg) src); + asm!(".insn r 0x73, 0x4, 0x31, x0, {}, {}", in(reg) dst, in(reg) src, options(nostack)); } /// Stores virtual machine memory by half integer @@ -274,7 +274,7 @@ pub unsafe fn hsv_b(dst: *mut i8, src: i8) { /// instruction which is effectively an unreference to any memory address. #[inline] pub unsafe fn hsv_h(dst: *mut i16, src: i16) { - asm!(".insn r 0x73, 0x4, 0x33, x0, {}, {}", in(reg) dst, in(reg) src); + asm!(".insn r 0x73, 0x4, 0x33, x0, {}, {}", in(reg) dst, in(reg) src, options(nostack)); } /// Stores virtual machine memory by word integer @@ -287,7 +287,7 @@ pub unsafe fn hsv_h(dst: *mut i16, src: i16) { /// instruction which is effectively an unreference to any memory address. #[inline] pub unsafe fn hsv_w(dst: *mut i32, src: i32) { - asm!(".insn r 0x73, 0x4, 0x35, x0, {}, {}", in(reg) dst, in(reg) src); + asm!(".insn r 0x73, 0x4, 0x35, x0, {}, {}", in(reg) dst, in(reg) src, options(nostack)); } /// Hypervisor memory management fence for given guest virtual address and guest address space @@ -301,7 +301,7 @@ pub unsafe fn hsv_w(dst: *mut i32, src: i32) { #[inline] pub unsafe fn hfence_vvma(vaddr: usize, asid: usize) { // asm!("hfence.vvma {}, {}", in(reg) vaddr, in(reg) asid) - asm!(".insn r 0x73, 0, 0x11, x0, {}, {}", in(reg) vaddr, in(reg) asid) + asm!(".insn r 0x73, 0, 0x11, x0, {}, {}", in(reg) vaddr, in(reg) asid, options(nostack)) } /// Hypervisor memory management fence for given guest virtual address @@ -314,7 +314,7 @@ pub unsafe fn hfence_vvma(vaddr: usize, asid: usize) { /// This fence specifies a single guest virtual address. #[inline] pub unsafe fn hfence_vvma_vaddr(vaddr: usize) { - asm!(".insn r 0x73, 0, 0x11, x0, {}, x0", in(reg) vaddr) + asm!(".insn r 0x73, 0, 0x11, x0, {}, x0", in(reg) vaddr, options(nostack)) } /// Hypervisor memory management fence for given guest address space @@ -327,7 +327,7 @@ pub unsafe fn hfence_vvma_vaddr(vaddr: usize) { /// This fence specifies a single guest address-space identifier. #[inline] pub unsafe fn hfence_vvma_asid(asid: usize) { - asm!(".insn r 0x73, 0, 0x11, x0, x0, {}", in(reg) asid) + asm!(".insn r 0x73, 0, 0x11, x0, x0, {}", in(reg) asid, options(nostack)) } /// Hypervisor memory management fence for all guest address spaces and guest virtual addresses @@ -340,7 +340,7 @@ pub unsafe fn hfence_vvma_asid(asid: usize) { /// This fence applies to any guest address spaces and guest virtual addresses. #[inline] pub unsafe fn hfence_vvma_all() { - asm!(".insn r 0x73, 0, 0x11, x0, x0, x0") + asm!(".insn r 0x73, 0, 0x11, x0, x0, x0", options(nostack)) } /// Hypervisor memory management fence for guest physical address and virtual machine @@ -352,8 +352,8 @@ pub unsafe fn hfence_vvma_all() { /// by virtual machine identifier (VMID). #[inline] pub unsafe fn hfence_gvma(gaddr: usize, vmid: usize) { - // asm!("hfence.gvma {}, {}", in(reg) gaddr, in(reg) vmid) - asm!(".insn r 0x73, 0, 0x31, x0, {}, {}", in(reg) gaddr, in(reg) vmid) + // asm!("hfence.gvma {}, {}", in(reg) gaddr, in(reg) vmid, options(nostack)) + asm!(".insn r 0x73, 0, 0x31, x0, {}, {}", in(reg) gaddr, in(reg) vmid, options(nostack)) } /// Hypervisor memory management fence for guest physical address @@ -364,7 +364,7 @@ pub unsafe fn hfence_gvma(gaddr: usize, vmid: usize) { /// This fence specifies a single guest physical address; **the physical address should be shifted right by 2 bits**. #[inline] pub unsafe fn hfence_gvma_gaddr(gaddr: usize) { - asm!(".insn r 0x73, 0, 0x31, x0, {}, x0", in(reg) gaddr) + asm!(".insn r 0x73, 0, 0x31, x0, {}, x0", in(reg) gaddr, options(nostack)) } /// Hypervisor memory management fence for given virtual machine @@ -375,7 +375,7 @@ pub unsafe fn hfence_gvma_gaddr(gaddr: usize) { /// This fence specifies a single virtual machine by virtual machine identifier (VMID). #[inline] pub unsafe fn hfence_gvma_vmid(vmid: usize) { - asm!(".insn r 0x73, 0, 0x31, x0, x0, {}", in(reg) vmid) + asm!(".insn r 0x73, 0, 0x31, x0, x0, {}", in(reg) vmid, options(nostack)) } /// Hypervisor memory management fence for all virtual machines and guest physical addresses @@ -386,7 +386,7 @@ pub unsafe fn hfence_gvma_vmid(vmid: usize) { /// This fence specifies all guest physical addresses and all virtual machines. #[inline] pub unsafe fn hfence_gvma_all() { - asm!(".insn r 0x73, 0, 0x31, x0, x0, x0") + asm!(".insn r 0x73, 0, 0x31, x0, x0, x0", options(nostack)) } /// Invalidate hypervisor translation cache for given guest virtual address and guest address space @@ -397,8 +397,8 @@ pub unsafe fn hfence_gvma_all() { /// This fence specifies a single guest virtual address, and a single guest address-space identifier. #[inline] pub unsafe fn hinval_vvma(vaddr: usize, asid: usize) { - // asm!("hinval.vvma {}, {}", in(reg) vaddr, in(reg) asid) - asm!(".insn r 0x73, 0, 0x13, x0, {}, {}", in(reg) vaddr, in(reg) asid) + // asm!("hinval.vvma {}, {}", in(reg) vaddr, in(reg) asid, options(nostack)) + asm!(".insn r 0x73, 0, 0x13, x0, {}, {}", in(reg) vaddr, in(reg) asid, options(nostack)) } /// Invalidate hypervisor translation cache for given guest virtual address @@ -409,7 +409,7 @@ pub unsafe fn hinval_vvma(vaddr: usize, asid: usize) { /// This fence specifies a single guest virtual address. #[inline] pub unsafe fn hinval_vvma_vaddr(vaddr: usize) { - asm!(".insn r 0x73, 0, 0x13, x0, {}, x0", in(reg) vaddr) + asm!(".insn r 0x73, 0, 0x13, x0, {}, x0", in(reg) vaddr, options(nostack)) } /// Invalidate hypervisor translation cache for given guest address space @@ -420,7 +420,7 @@ pub unsafe fn hinval_vvma_vaddr(vaddr: usize) { /// This fence specifies a single guest address-space identifier. #[inline] pub unsafe fn hinval_vvma_asid(asid: usize) { - asm!(".insn r 0x73, 0, 0x13, x0, x0, {}", in(reg) asid) + asm!(".insn r 0x73, 0, 0x13, x0, x0, {}", in(reg) asid, options(nostack)) } /// Invalidate hypervisor translation cache for all guest address spaces and guest virtual addresses @@ -431,7 +431,7 @@ pub unsafe fn hinval_vvma_asid(asid: usize) { /// This fence applies to any guest address spaces and guest virtual addresses. #[inline] pub unsafe fn hinval_vvma_all() { - asm!(".insn r 0x73, 0, 0x13, x0, x0, x0") + asm!(".insn r 0x73, 0, 0x13, x0, x0, x0", options(nostack)) } /// Invalidate hypervisor translation cache for guest physical address and virtual machine @@ -443,8 +443,8 @@ pub unsafe fn hinval_vvma_all() { /// by virtual machine identifier (VMID). #[inline] pub unsafe fn hinval_gvma(gaddr: usize, vmid: usize) { - // asm!("hinval.gvma {}, {}", in(reg) gaddr, in(reg) vmid) - asm!(".insn r 0x73, 0, 0x33, x0, {}, {}", in(reg) gaddr, in(reg) vmid) + // asm!("hinval.gvma {}, {}", in(reg) gaddr, in(reg) vmid, options(nostack)) + asm!(".insn r 0x73, 0, 0x33, x0, {}, {}", in(reg) gaddr, in(reg) vmid, options(nostack)) } /// Invalidate hypervisor translation cache for guest physical address @@ -455,7 +455,7 @@ pub unsafe fn hinval_gvma(gaddr: usize, vmid: usize) { /// This fence specifies a single guest physical address; **the physical address should be shifted right by 2 bits**. #[inline] pub unsafe fn hinval_gvma_gaddr(gaddr: usize) { - asm!(".insn r 0x73, 0, 0x33, x0, {}, x0", in(reg) gaddr) + asm!(".insn r 0x73, 0, 0x33, x0, {}, x0", in(reg) gaddr, options(nostack)) } /// Invalidate hypervisor translation cache for given virtual machine @@ -466,7 +466,7 @@ pub unsafe fn hinval_gvma_gaddr(gaddr: usize) { /// This fence specifies a single virtual machine by virtual machine identifier (VMID). #[inline] pub unsafe fn hinval_gvma_vmid(vmid: usize) { - asm!(".insn r 0x73, 0, 0x33, x0, x0, {}", in(reg) vmid) + asm!(".insn r 0x73, 0, 0x33, x0, x0, {}", in(reg) vmid, options(nostack)) } /// Invalidate hypervisor translation cache for all virtual machines and guest physical addresses @@ -477,5 +477,5 @@ pub unsafe fn hinval_gvma_vmid(vmid: usize) { /// This fence specifies all guest physical addresses and all virtual machines. #[inline] pub unsafe fn hinval_gvma_all() { - asm!(".insn r 0x73, 0, 0x33, x0, x0, x0") + asm!(".insn r 0x73, 0, 0x33, x0, x0, x0", options(nostack)) }