diff options
Diffstat (limited to 'library/stdarch/crates/core_arch/src/x86/xsave.rs')
-rw-r--r-- | library/stdarch/crates/core_arch/src/x86/xsave.rs | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/library/stdarch/crates/core_arch/src/x86/xsave.rs b/library/stdarch/crates/core_arch/src/x86/xsave.rs new file mode 100644 index 000000000..30f807e44 --- /dev/null +++ b/library/stdarch/crates/core_arch/src/x86/xsave.rs @@ -0,0 +1,282 @@ +//! `i586`'s `xsave` and `xsaveopt` target feature intrinsics +#![allow(clippy::module_name_repetitions)] + +#[cfg(test)] +use stdarch_test::assert_instr; + +#[allow(improper_ctypes)] +extern "C" { + #[link_name = "llvm.x86.xsave"] + fn xsave(p: *mut u8, hi: u32, lo: u32); + #[link_name = "llvm.x86.xrstor"] + fn xrstor(p: *const u8, hi: u32, lo: u32); + #[link_name = "llvm.x86.xsetbv"] + fn xsetbv(v: u32, hi: u32, lo: u32); + #[link_name = "llvm.x86.xgetbv"] + fn xgetbv(v: u32) -> i64; + #[link_name = "llvm.x86.xsaveopt"] + fn xsaveopt(p: *mut u8, hi: u32, lo: u32); + #[link_name = "llvm.x86.xsavec"] + fn xsavec(p: *mut u8, hi: u32, lo: u32); + #[link_name = "llvm.x86.xsaves"] + fn xsaves(p: *mut u8, hi: u32, lo: u32); + #[link_name = "llvm.x86.xrstors"] + fn xrstors(p: *const u8, hi: u32, lo: u32); +} + +/// Performs a full or partial save of the enabled processor states to memory at +/// `mem_addr`. +/// +/// State is saved based on bits `[62:0]` in `save_mask` and XCR0. +/// `mem_addr` must be aligned on a 64-byte boundary. +/// +/// The format of the XSAVE area is detailed in Section 13.4, “XSAVE Area,” of +/// Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 1. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_xsave) +#[inline] +#[target_feature(enable = "xsave")] +#[cfg_attr(test, assert_instr(xsave))] +#[stable(feature = "simd_x86", since = "1.27.0")] +pub unsafe fn _xsave(mem_addr: *mut u8, save_mask: u64) { + xsave(mem_addr, (save_mask >> 32) as u32, save_mask as u32); +} + +/// Performs a full or partial restore of the enabled processor states using +/// the state information stored in memory at `mem_addr`. +/// +/// State is restored based on bits `[62:0]` in `rs_mask`, `XCR0`, and +/// `mem_addr.HEADER.XSTATE_BV`. `mem_addr` must be aligned on a 64-byte +/// boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_xrstor) +#[inline] +#[target_feature(enable = "xsave")] +#[cfg_attr(test, assert_instr(xrstor))] +#[stable(feature = "simd_x86", since = "1.27.0")] +pub unsafe fn _xrstor(mem_addr: *const u8, rs_mask: u64) { + xrstor(mem_addr, (rs_mask >> 32) as u32, rs_mask as u32); +} + +/// `XFEATURE_ENABLED_MASK` for `XCR` +/// +/// This intrinsic maps to `XSETBV` instruction. +#[stable(feature = "simd_x86", since = "1.27.0")] +pub const _XCR_XFEATURE_ENABLED_MASK: u32 = 0; + +/// Copies 64-bits from `val` to the extended control register (`XCR`) specified +/// by `a`. +/// +/// Currently only `XFEATURE_ENABLED_MASK` `XCR` is supported. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_xsetbv) +#[inline] +#[target_feature(enable = "xsave")] +#[cfg_attr(test, assert_instr(xsetbv))] +#[stable(feature = "simd_x86", since = "1.27.0")] +pub unsafe fn _xsetbv(a: u32, val: u64) { + xsetbv(a, (val >> 32) as u32, val as u32); +} + +/// Reads the contents of the extended control register `XCR` +/// specified in `xcr_no`. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_xgetbv) +#[inline] +#[target_feature(enable = "xsave")] +#[cfg_attr(test, assert_instr(xgetbv))] +#[stable(feature = "simd_x86", since = "1.27.0")] +pub unsafe fn _xgetbv(xcr_no: u32) -> u64 { + xgetbv(xcr_no) as u64 +} + +/// Performs a full or partial save of the enabled processor states to memory at +/// `mem_addr`. +/// +/// State is saved based on bits `[62:0]` in `save_mask` and `XCR0`. +/// `mem_addr` must be aligned on a 64-byte boundary. The hardware may optimize +/// the manner in which data is saved. The performance of this instruction will +/// be equal to or better than using the `XSAVE` instruction. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_xsaveopt) +#[inline] +#[target_feature(enable = "xsave,xsaveopt")] +#[cfg_attr(test, assert_instr(xsaveopt))] +#[stable(feature = "simd_x86", since = "1.27.0")] +pub unsafe fn _xsaveopt(mem_addr: *mut u8, save_mask: u64) { + xsaveopt(mem_addr, (save_mask >> 32) as u32, save_mask as u32); +} + +/// Performs a full or partial save of the enabled processor states to memory +/// at `mem_addr`. +/// +/// `xsavec` differs from `xsave` in that it uses compaction and that it may +/// use init optimization. State is saved based on bits `[62:0]` in `save_mask` +/// and `XCR0`. `mem_addr` must be aligned on a 64-byte boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_xsavec) +#[inline] +#[target_feature(enable = "xsave,xsavec")] +#[cfg_attr(test, assert_instr(xsavec))] +#[stable(feature = "simd_x86", since = "1.27.0")] +pub unsafe fn _xsavec(mem_addr: *mut u8, save_mask: u64) { + xsavec(mem_addr, (save_mask >> 32) as u32, save_mask as u32); +} + +/// Performs a full or partial save of the enabled processor states to memory at +/// `mem_addr` +/// +/// `xsaves` differs from xsave in that it can save state components +/// corresponding to bits set in `IA32_XSS` `MSR` and that it may use the +/// modified optimization. State is saved based on bits `[62:0]` in `save_mask` +/// and `XCR0`. `mem_addr` must be aligned on a 64-byte boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_xsaves) +#[inline] +#[target_feature(enable = "xsave,xsaves")] +#[cfg_attr(test, assert_instr(xsaves))] +#[stable(feature = "simd_x86", since = "1.27.0")] +pub unsafe fn _xsaves(mem_addr: *mut u8, save_mask: u64) { + xsaves(mem_addr, (save_mask >> 32) as u32, save_mask as u32); +} + +/// Performs a full or partial restore of the enabled processor states using the +/// state information stored in memory at `mem_addr`. +/// +/// `xrstors` differs from `xrstor` in that it can restore state components +/// corresponding to bits set in the `IA32_XSS` `MSR`; `xrstors` cannot restore +/// from an `xsave` area in which the extended region is in the standard form. +/// State is restored based on bits `[62:0]` in `rs_mask`, `XCR0`, and +/// `mem_addr.HEADER.XSTATE_BV`. `mem_addr` must be aligned on a 64-byte +/// boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_xrstors) +#[inline] +#[target_feature(enable = "xsave,xsaves")] +#[cfg_attr(test, assert_instr(xrstors))] +#[stable(feature = "simd_x86", since = "1.27.0")] +pub unsafe fn _xrstors(mem_addr: *const u8, rs_mask: u64) { + xrstors(mem_addr, (rs_mask >> 32) as u32, rs_mask as u32); +} + +#[cfg(test)] +mod tests { + use std::{fmt, prelude::v1::*}; + + use crate::core_arch::x86::*; + use stdarch_test::simd_test; + + #[repr(align(64))] + struct XsaveArea { + // max size for 256-bit registers is 800 bytes: + // see https://software.intel.com/en-us/node/682996 + // max size for 512-bit registers is 2560 bytes: + // FIXME: add source + data: [u8; 2560], + } + + impl XsaveArea { + fn new() -> XsaveArea { + XsaveArea { data: [0; 2560] } + } + fn ptr(&mut self) -> *mut u8 { + &mut self.data[0] as *mut _ as *mut u8 + } + } + + impl PartialEq<XsaveArea> for XsaveArea { + fn eq(&self, other: &XsaveArea) -> bool { + for i in 0..self.data.len() { + if self.data[i] != other.data[i] { + return false; + } + } + true + } + } + + impl fmt::Debug for XsaveArea { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[")?; + for i in 0..self.data.len() { + write!(f, "{}", self.data[i])?; + if i != self.data.len() - 1 { + write!(f, ", ")?; + } + } + write!(f, "]") + } + } + + // FIXME: https://github.com/rust-lang/stdarch/issues/209 + /* + #[simd_test(enable = "xsave")] + unsafe fn xsave() { + let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers + let mut a = XsaveArea::new(); + let mut b = XsaveArea::new(); + + _xsave(a.ptr(), m); + _xrstor(a.ptr(), m); + _xsave(b.ptr(), m); + assert_eq!(a, b); + } + */ + + #[simd_test(enable = "xsave")] + unsafe fn xgetbv_xsetbv() { + let xcr_n: u32 = _XCR_XFEATURE_ENABLED_MASK; + + let xcr: u64 = _xgetbv(xcr_n); + // FIXME: XSETBV is a privileged instruction we should only test this + // when running in privileged mode: + // + // _xsetbv(xcr_n, xcr); + let xcr_cpy: u64 = _xgetbv(xcr_n); + assert_eq!(xcr, xcr_cpy); + } + + // FIXME: https://github.com/rust-lang/stdarch/issues/209 + /* + #[simd_test(enable = "xsave,xsaveopt")] + unsafe fn xsaveopt() { + let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers + let mut a = XsaveArea::new(); + let mut b = XsaveArea::new(); + + _xsaveopt(a.ptr(), m); + _xrstor(a.ptr(), m); + _xsaveopt(b.ptr(), m); + assert_eq!(a, b); + } + */ + + // FIXME: this looks like a bug in Intel's SDE: + #[cfg(not(stdarch_intel_sde))] + #[simd_test(enable = "xsave,xsavec")] + unsafe fn xsavec() { + let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers + let mut a = XsaveArea::new(); + let mut b = XsaveArea::new(); + + _xsavec(a.ptr(), m); + _xrstor(a.ptr(), m); + _xsavec(b.ptr(), m); + assert_eq!(a, b); + } + + // FIXME: https://github.com/rust-lang/stdarch/issues/209 + /* + #[simd_test(enable = "xsave,xsaves")] + unsafe fn xsaves() { + let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers + let mut a = XsaveArea::new(); + let mut b = XsaveArea::new(); + + _xsaves(a.ptr(), m); + _xrstors(a.ptr(), m); + _xsaves(b.ptr(), m); + assert_eq!(a, b); + } + */ +} |