kvm_bindings/x86_64/
nested.rs

1//! Higher-level abstractions for working with nested state.
2//!
3//! Getting and setting the nested KVM state is helpful if nested virtualization
4//! is used and the state needs to be serialized, e.g., for live-migration or
5//! state save/resume. See [`KvmNestedStateBuffer`].
6
7use crate::KVM_STATE_NESTED_SVM_VMCB_SIZE;
8use crate::{KVM_STATE_NESTED_VMX_VMCS_SIZE, kvm_nested_state__bindgen_ty_1};
9use core::mem;
10
11/// Non-zero variant of the bindgen data union.
12///
13/// Please note that on SVM, this type wastes one page as the VMX state is
14/// larger.
15#[derive(Clone, Copy)]
16#[cfg_attr(feature = "serde", derive(zerocopy::Immutable, zerocopy::FromBytes))]
17#[repr(C)]
18pub union kvm_nested_state__data {
19    pub vmx: kvm_vmx_nested_state_data,
20    pub svm: kvm_svm_nested_state_data,
21}
22
23impl Default for kvm_nested_state__data {
24    fn default() -> Self {
25        // SAFETY: Every bit pattern is valid.
26        unsafe { mem::zeroed() }
27    }
28}
29
30#[derive(Clone, Copy)]
31#[cfg_attr(
32    feature = "serde",
33    derive(zerocopy::IntoBytes, zerocopy::Immutable, zerocopy::FromBytes)
34)]
35#[repr(C)]
36pub struct kvm_vmx_nested_state_data {
37    pub vmcs12: [u8; KVM_STATE_NESTED_VMX_VMCS_SIZE as usize],
38    pub shadow_vmcs12: [u8; KVM_STATE_NESTED_VMX_VMCS_SIZE as usize],
39}
40
41#[derive(Clone, Copy)]
42#[cfg_attr(
43    feature = "serde",
44    derive(zerocopy::IntoBytes, zerocopy::Immutable, zerocopy::FromBytes)
45)]
46#[repr(C)]
47pub struct kvm_svm_nested_state_data {
48    pub vmcb12: [u8; KVM_STATE_NESTED_SVM_VMCB_SIZE as usize],
49}
50
51/// A stack-allocated buffer for nested KVM state including the mandatory
52/// header with meta-information.
53///
54/// KVM uses a dynamically sized buffer structure (with a header reporting the
55/// size of the buffer/state). This helper type makes working with
56/// `get_nested_state()` and `set_nested_state`() significantly more convenient
57/// at the cost of a slightly higher memory footprint in some cases.
58///
59/// # Type Size
60///
61/// On Intel VMX, the actual state requires `128 + 8192 == 8320` bytes, on
62/// AMD SVM, the actual state requires `128 + 4096 == 4224` bytes. This type
63/// doesn't make a differentiation and unifies the required memory. By
64/// sacrificing a few more bytes on VMX, this type is generally convenient to
65/// use.
66#[derive(Clone, Copy)]
67#[cfg_attr(
68    feature = "serde",
69    derive(zerocopy::IntoBytes, zerocopy::Immutable, zerocopy::FromBytes)
70)]
71#[repr(C)]
72#[non_exhaustive] // Prevent constructor bypass in public API.
73pub struct KvmNestedStateBuffer {
74    pub flags: u16,
75    pub format: u16,
76    pub size: u32,
77    pub hdr: kvm_nested_state__bindgen_ty_1,
78    pub data: kvm_nested_state__data,
79}
80
81impl KvmNestedStateBuffer {
82    /// Creates a new empty buffer, ready for nested state to be stored in by KVM.
83    ///
84    /// The `size` property will report the size of the buffer to KVM.
85    pub fn empty() -> Self {
86        // SAFETY: Every bit pattern is valid.
87        let mut this: KvmNestedStateBuffer = unsafe { mem::zeroed() };
88        // This way, KVM knows the size of the buffer to store state into.
89        // See: https://elixir.bootlin.com/linux/v6.12/source/arch/x86/kvm/x86.c#L6193
90        this.size = size_of::<Self>() as u32;
91        this
92    }
93}
94
95impl Default for KvmNestedStateBuffer {
96    fn default() -> Self {
97        Self::empty()
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104
105    use crate::kvm_nested_state as kvm_nested_state_raw_binding;
106
107    #[test]
108    fn test_layout() {
109        assert_eq!(
110            align_of::<kvm_nested_state_raw_binding>(),
111            align_of::<KvmNestedStateBuffer>()
112        );
113        assert!(size_of::<KvmNestedStateBuffer>() > size_of::<kvm_nested_state_raw_binding>());
114        // When this fails/changes, we should re-evaluate the overall types and API
115        assert_eq!(size_of::<KvmNestedStateBuffer>(), 8320);
116    }
117}