x86/bits64/
vmx.rs

1//! Virtualize processor hardware for multiple software environments using Virtual Machine Extensions.
2
3use crate::bits64::rflags::{self, RFlags};
4use crate::vmx::{Result, VmFail};
5use core::arch::asm;
6
7/// Helper used to extract VMX-specific Result in accordance with
8/// conventions described in Intel SDM, Volume 3C, Section 30.2.
9// We inline this to provide an obstruction-free path from this function's
10// call site to the moment where `rflags::read()` reads RFLAGS. Otherwise it's
11// possible for RFLAGS register to be clobbered by a function prologue,
12// see https://github.com/gz/rust-x86/pull/50.
13#[inline(always)]
14fn vmx_capture_status() -> Result<()> {
15    let flags = rflags::read();
16
17    if flags.contains(RFlags::FLAGS_ZF) {
18        Err(VmFail::VmFailValid)
19    } else if flags.contains(RFlags::FLAGS_CF) {
20        Err(VmFail::VmFailInvalid)
21    } else {
22        Ok(())
23    }
24}
25
26/// Enable VMX operation.
27///
28/// `addr` specifies a 4KB-aligned physical address of VMXON region initialized
29/// in accordance with Intel SDM, Volume 3C, Section 24.11.5.
30///
31/// # Safety
32/// Needs CPL 0.
33pub unsafe fn vmxon(addr: u64) -> Result<()> {
34    asm!("vmxon ({0})", in(reg) &addr, options(att_syntax));
35    vmx_capture_status()
36}
37
38/// Disable VMX operation.
39///
40/// # Safety
41/// Needs CPL 0.
42pub unsafe fn vmxoff() -> Result<()> {
43    asm!("vmxoff");
44    vmx_capture_status()
45}
46
47/// Clear VMCS.
48///
49/// Ensures that VMCS data maintained on the processor is copied to the VMCS region
50/// located at 4KB-aligned physical address `addr` and initializes some parts of it.
51///
52/// # Safety
53/// Needs CPL 0.
54pub unsafe fn vmclear(addr: u64) -> Result<()> {
55    asm!("vmclear ({0})", in(reg) &addr, options(att_syntax));
56    vmx_capture_status()
57}
58
59/// Load current VMCS pointer.
60///
61/// Marks the current-VMCS pointer valid and loads it with the physical address `addr`.
62///
63/// # Safety
64/// Needs CPL 0.
65pub unsafe fn vmptrld(addr: u64) -> Result<()> {
66    asm!("vmptrld ({0})", in(reg) &addr, options(att_syntax));
67    vmx_capture_status()
68}
69
70/// Return current VMCS pointer.
71///
72/// # Safety
73/// Needs CPL 0.
74pub unsafe fn vmptrst() -> Result<u64> {
75    let value: u64 = 0;
76    asm!("vmptrst ({0})", in(reg) &value, options(att_syntax));
77    vmx_capture_status().and(Ok(value))
78}
79
80/// Read a specified field from a VMCS.
81///
82/// # Safety
83/// Needs CPL 0.
84pub unsafe fn vmread(field: u32) -> Result<u64> {
85    let field: u64 = field.into();
86    let value: u64;
87    asm!("vmread {0}, {1}", in(reg) field, out(reg) value, options(att_syntax));
88    vmx_capture_status().and(Ok(value))
89}
90
91/// Write to a specified field in a VMCS.
92///
93/// # Safety
94/// Needs CPL 0.
95pub unsafe fn vmwrite(field: u32, value: u64) -> Result<()> {
96    let field: u64 = field.into();
97    asm!("vmwrite {1}, {0}", in(reg) field, in(reg) value, options(att_syntax));
98    vmx_capture_status()
99}
100
101/// Launch virtual machine.
102///
103/// # Safety
104/// Needs CPL 0.
105#[inline(always)]
106pub unsafe fn vmlaunch() -> Result<()> {
107    asm!("vmlaunch");
108    vmx_capture_status()
109}
110
111/// Resume virtual machine.
112///
113/// # Safety
114/// Needs CPL 0.
115#[inline(always)]
116pub unsafe fn vmresume() -> Result<()> {
117    asm!("vmresume");
118    vmx_capture_status()
119}