Skip to main content

kvm/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4#![expect(missing_docs)]
5#![cfg(target_os = "linux")]
6// UNSAFETY: Calling KVM APIs and IOCTLs and dealing with the raw pointers
7// necessary for doing so.
8#![expect(unsafe_code)]
9
10pub use kvm_bindings::kvm_ioeventfd_flag_nr_datamatch;
11pub use kvm_bindings::kvm_ioeventfd_flag_nr_deassign;
12pub use kvm_bindings::*;
13use pal::unix::pthread::*;
14use parking_lot::RwLock;
15use std::fs::File;
16use std::io;
17use std::marker::PhantomData;
18use std::os::unix::prelude::*;
19use std::sync::Once;
20use std::sync::atomic::AtomicU8;
21use std::sync::atomic::AtomicUsize;
22use std::sync::atomic::Ordering;
23use thiserror::Error;
24
25mod ioctl {
26    #[cfg(target_arch = "aarch64")]
27    use super::KvmArmRmiPopulate;
28    use kvm_bindings::*;
29    #[cfg(target_arch = "x86_64")]
30    use nix::errno::Errno;
31    use nix::ioctl_read;
32    use nix::ioctl_readwrite;
33    use nix::ioctl_readwrite_bad;
34    use nix::ioctl_write_int_bad;
35    use nix::ioctl_write_ptr;
36    use nix::request_code_none;
37    use nix::request_code_readwrite;
38    use std::mem::size_of;
39
40    const KVMIO: u8 = 0xae;
41
42    ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x1));
43    ioctl_write_int_bad!(kvm_check_extension, request_code_none!(KVMIO, 0x03));
44    ioctl_write_int_bad!(kvm_get_vcpu_mmap_size, request_code_none!(KVMIO, 0x04));
45    #[cfg(target_arch = "x86_64")]
46    ioctl_readwrite!(kvm_get_supported_cpuid, KVMIO, 0x05, kvm_cpuid2);
47    #[cfg(target_arch = "x86_64")]
48    ioctl_readwrite!(kvm_get_supported_hv_cpuid, KVMIO, 0xc1, kvm_cpuid2);
49    ioctl_write_int_bad!(kvm_create_vcpu, request_code_none!(KVMIO, 0x41));
50    ioctl_write_ptr!(
51        kvm_set_user_memory_region,
52        KVMIO,
53        0x46,
54        kvm_userspace_memory_region
55    );
56    ioctl_write_ptr!(
57        kvm_set_user_memory_region2,
58        KVMIO,
59        0x49,
60        kvm_userspace_memory_region2
61    );
62    ioctl_write_ptr!(kvm_irq_line, KVMIO, 0x61, kvm_irq_level);
63    ioctl_write_ptr!(kvm_set_gsi_routing, KVMIO, 0x6a, kvm_irq_routing);
64    ioctl_write_ptr!(kvm_irqfd, KVMIO, 0x76, kvm_irqfd);
65    ioctl_write_int_bad!(kvm_set_boot_cpu_id, request_code_none!(KVMIO, 0x78));
66    ioctl_write_ptr!(kvm_set_clock, KVMIO, 0x7b, kvm_clock_data);
67    ioctl_read!(kvm_get_clock, KVMIO, 0x7c, kvm_clock_data);
68    ioctl_write_int_bad!(kvm_run, request_code_none!(KVMIO, 0x80));
69    // Is *NOT* defined for arm64
70    #[cfg(not(target_arch = "aarch64"))]
71    ioctl_read!(kvm_get_regs, KVMIO, 0x81, kvm_regs);
72    // Is *NOT* defined for arm64
73    #[cfg(not(target_arch = "aarch64"))]
74    ioctl_write_ptr!(kvm_set_regs, KVMIO, 0x82, kvm_regs);
75    ioctl_read!(kvm_get_sregs, KVMIO, 0x83, kvm_sregs);
76    ioctl_write_ptr!(kvm_set_sregs, KVMIO, 0x84, kvm_sregs);
77    ioctl_readwrite!(kvm_translation, KVMIO, 0x85, kvm_translation);
78    ioctl_write_ptr!(kvm_interrupt, KVMIO, 0x86, kvm_interrupt);
79    #[cfg(target_arch = "x86_64")]
80    ioctl_readwrite!(kvm_get_msrs, KVMIO, 0x88, kvm_msrs);
81    #[cfg(target_arch = "x86_64")]
82    ioctl_write_ptr!(kvm_set_msrs, KVMIO, 0x89, kvm_msrs);
83    ioctl_write_ptr!(kvm_set_signal_mask, KVMIO, 0x8b, kvm_signal_mask);
84    ioctl_read!(kvm_get_fpu, KVMIO, 0x8c, kvm_fpu);
85    ioctl_write_ptr!(kvm_set_fpu, KVMIO, 0x8d, kvm_fpu);
86    #[cfg(target_arch = "x86_64")]
87    ioctl_read!(kvm_get_lapic, KVMIO, 0x8e, kvm_lapic_state);
88    #[cfg(target_arch = "x86_64")]
89    ioctl_write_ptr!(kvm_set_lapic, KVMIO, 0x8f, kvm_lapic_state);
90    #[cfg(target_arch = "x86_64")]
91    ioctl_write_ptr!(kvm_set_cpuid2, KVMIO, 0x90, kvm_cpuid2);
92    ioctl_read!(kvm_get_mp_state, KVMIO, 0x98, kvm_mp_state);
93    ioctl_write_ptr!(kvm_set_mp_state, KVMIO, 0x99, kvm_mp_state);
94    ioctl_read!(kvm_get_vcpu_events, KVMIO, 0x9f, kvm_vcpu_events);
95    ioctl_write_ptr!(kvm_set_vcpu_events, KVMIO, 0xa0, kvm_vcpu_events);
96    #[cfg(target_arch = "x86_64")]
97    ioctl_read!(kvm_get_debugregs, KVMIO, 0xa1, kvm_debugregs);
98    #[cfg(target_arch = "x86_64")]
99    ioctl_write_ptr!(kvm_set_debugregs, KVMIO, 0xa2, kvm_debugregs);
100    ioctl_write_ptr!(kvm_enable_cap, KVMIO, 0xa3, kvm_enable_cap);
101    #[cfg(target_arch = "x86_64")]
102    ioctl_read!(kvm_get_xsave, KVMIO, 0xa4, kvm_xsave);
103    #[cfg(target_arch = "x86_64")]
104    ioctl_write_ptr!(kvm_set_xsave, KVMIO, 0xa5, kvm_xsave);
105    ioctl_write_ptr!(kvm_signal_msi, KVMIO, 0xa5, kvm_msi);
106    #[cfg(target_arch = "x86_64")]
107    ioctl_read!(kvm_get_xcrs, KVMIO, 0xa6, kvm_xcrs);
108    #[cfg(target_arch = "x86_64")]
109    ioctl_write_ptr!(kvm_set_xcrs, KVMIO, 0xa7, kvm_xcrs);
110    ioctl_write_ptr!(kvm_get_reg, KVMIO, 0xab, kvm_one_reg);
111    ioctl_write_ptr!(kvm_set_reg, KVMIO, 0xac, kvm_one_reg);
112    #[cfg(target_arch = "aarch64")]
113    ioctl_write_ptr!(kvm_arm_vcpu_init, KVMIO, 0xae, kvm_vcpu_init);
114    #[cfg(target_arch = "aarch64")]
115    ioctl_read!(kvm_arm_preferred_target, KVMIO, 0xaf, kvm_vcpu_init);
116    ioctl_write_ptr!(kvm_ioeventfd, KVMIO, 0x79, kvm_ioeventfd);
117    ioctl_write_ptr!(kvm_set_guest_debug, KVMIO, 0x9b, kvm_guest_debug);
118    #[cfg(target_arch = "x86_64")]
119    ioctl_write_ptr!(kvm_x86_setup_mce, KVMIO, 0x9c, u64);
120    #[cfg(target_arch = "x86_64")]
121    ioctl_read!(kvm_x86_get_mce_cap_supported, KVMIO, 0x9d, u64);
122    ioctl_write_ptr!(
123        kvm_set_memory_attributes,
124        KVMIO,
125        0xd2,
126        kvm_memory_attributes
127    );
128    ioctl_readwrite!(kvm_create_device, KVMIO, 0xe0, kvm_create_device);
129    ioctl_write_ptr!(kvm_set_device_attr, KVMIO, 0xe1, kvm_device_attr);
130    #[cfg(target_arch = "x86_64")]
131    ioctl_write_ptr!(kvm_get_device_attr, KVMIO, 0xe2, kvm_device_attr);
132    ioctl_readwrite!(kvm_create_guest_memfd, KVMIO, 0xd4, kvm_create_guest_memfd);
133    #[cfg(target_arch = "aarch64")]
134    ioctl_readwrite_bad!(
135        kvm_arm_rmi_populate,
136        request_code_readwrite!(KVMIO, 0xd7, size_of::<KvmArmRmiPopulate>()),
137        KvmArmRmiPopulate
138    );
139    #[cfg(target_arch = "x86_64")]
140    ioctl_readwrite_bad!(
141        kvm_memory_encrypt_op,
142        request_code_readwrite!(KVMIO, 0xba, size_of::<libc::c_ulong>()),
143        kvm_sev_cmd
144    );
145    #[cfg(target_arch = "x86_64")]
146    /// # Safety
147    ///
148    /// `fd` must refer to a valid KVM VM file descriptor.
149    pub unsafe fn kvm_memory_encrypt_op_supported(fd: libc::c_int) -> nix::Result<()> {
150        // SAFETY: Calling the KVM_MEMORY_ENCRYPT_OP ioctl with a null argument is
151        // the documented availability probe for SEV support.
152        match unsafe {
153            libc::ioctl(
154                fd,
155                request_code_readwrite!(KVMIO, 0xba, size_of::<libc::c_ulong>()),
156                std::ptr::null_mut::<libc::c_void>(),
157            )
158        } {
159            0 => Ok(()),
160            _ => Err(Errno::last()),
161        }
162    }
163}
164
165#[cfg(target_arch = "x86_64")]
166const KVM_CAP_VM_TYPES_UAPI: u32 = 235;
167#[cfg(target_arch = "x86_64")]
168const KVM_CAP_EXIT_HYPERCALL_UAPI: u32 = 201;
169#[cfg(target_arch = "x86_64")]
170pub const KVM_HC_MAP_GPA_RANGE_UAPI: u64 = 12;
171#[cfg(target_arch = "x86_64")]
172pub const KVM_MAP_GPA_RANGE_ENCRYPTED_UAPI: u64 = 1 << 4;
173#[cfg(target_arch = "x86_64")]
174pub const KVM_MAP_GPA_RANGE_DECRYPTED_UAPI: u64 = 0 << 4;
175#[cfg(target_arch = "x86_64")]
176const KVM_X86_SNP_VM_UAPI: libc::c_int = 4;
177
178pub const KVM_MEMORY_EXIT_FLAG_PRIVATE_UAPI: u64 = 1 << 3;
179
180#[cfg(target_arch = "aarch64")]
181pub const KVM_CAP_ARM_RMI_UAPI: u32 = 249;
182#[cfg(target_arch = "aarch64")]
183pub const KVM_ARM_RMI_POPULATE_FLAGS_MEASURE_UAPI: u32 = 1 << 0;
184#[cfg(target_arch = "aarch64")]
185const KVM_VM_TYPE_ARM_IPA_SIZE_MASK_UAPI: u64 = 0xff;
186#[cfg(target_arch = "aarch64")]
187const KVM_VM_TYPE_ARM_REALM_UAPI: u64 = 1 << 30;
188
189#[cfg(target_arch = "x86_64")]
190pub const KVM_SEV_SNP_PAGE_TYPE_NORMAL_UAPI: u8 = KVM_SEV_SNP_PAGE_TYPE_NORMAL as u8;
191#[cfg(target_arch = "x86_64")]
192pub const KVM_SEV_SNP_PAGE_TYPE_ZERO_UAPI: u8 = KVM_SEV_SNP_PAGE_TYPE_ZERO as u8;
193#[cfg(target_arch = "x86_64")]
194pub const KVM_SEV_SNP_PAGE_TYPE_UNMEASURED_UAPI: u8 = KVM_SEV_SNP_PAGE_TYPE_UNMEASURED as u8;
195#[cfg(target_arch = "x86_64")]
196pub const KVM_SEV_SNP_PAGE_TYPE_SECRETS_UAPI: u8 = KVM_SEV_SNP_PAGE_TYPE_SECRETS as u8;
197#[cfg(target_arch = "x86_64")]
198pub const KVM_SEV_SNP_PAGE_TYPE_CPUID_UAPI: u8 = KVM_SEV_SNP_PAGE_TYPE_CPUID as u8;
199
200#[derive(Debug, Copy, Clone, Eq, PartialEq)]
201pub enum VmType {
202    Default,
203    #[cfg(target_arch = "x86_64")]
204    Snp,
205    #[cfg(target_arch = "aarch64")]
206    Realm {
207        ipa_bits: u8,
208    },
209}
210
211#[cfg(target_arch = "x86_64")]
212#[derive(Debug, Copy, Clone, Eq, PartialEq)]
213pub enum SevSnpPageType {
214    Normal,
215    Zero,
216    Unmeasured,
217    Secrets,
218    Cpuid,
219}
220
221#[cfg(target_arch = "x86_64")]
222impl SevSnpPageType {
223    pub const fn as_uapi(self) -> u8 {
224        match self {
225            SevSnpPageType::Normal => KVM_SEV_SNP_PAGE_TYPE_NORMAL_UAPI,
226            SevSnpPageType::Zero => KVM_SEV_SNP_PAGE_TYPE_ZERO_UAPI,
227            SevSnpPageType::Unmeasured => KVM_SEV_SNP_PAGE_TYPE_UNMEASURED_UAPI,
228            SevSnpPageType::Secrets => KVM_SEV_SNP_PAGE_TYPE_SECRETS_UAPI,
229            SevSnpPageType::Cpuid => KVM_SEV_SNP_PAGE_TYPE_CPUID_UAPI,
230        }
231    }
232}
233
234#[cfg(target_arch = "aarch64")]
235#[repr(C)]
236#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
237pub struct KvmArmRmiPopulate {
238    pub base: u64,
239    pub size: u64,
240    pub source_uaddr: u64,
241    pub flags: u32,
242    pub reserved: u32,
243}
244
245#[derive(Error, Debug)]
246pub enum Error {
247    #[error("failed to open /dev/kvm")]
248    OpenKvm(#[source] io::Error),
249    #[error("SignalMsi")]
250    SignalMsi(#[source] nix::Error),
251    #[error("SetMemoryRegion")]
252    SetMemoryRegion(#[source] nix::Error),
253    #[error("SetMemoryAttributes")]
254    SetMemoryAttributes(#[source] nix::Error),
255    #[error("CreateGuestMemfd")]
256    CreateGuestMemfd(#[source] nix::Error),
257    #[error("CreateVm")]
258    CreateVm(#[source] nix::Error),
259    #[cfg(target_arch = "aarch64")]
260    #[error("ArmRmiPopulate")]
261    ArmRmiPopulate(#[source] nix::Error),
262    #[error("missing KVM capability: {0}")]
263    MissingCapability(&'static str),
264    #[error("unsupported KVM VM type: {0:?}")]
265    UnsupportedVmType(VmType),
266    #[cfg(target_arch = "x86_64")]
267    #[error("MemoryEncryptOp({command}, firmware_error={firmware_error:#x})")]
268    MemoryEncryptOp {
269        command: &'static str,
270        firmware_error: u32,
271        #[source]
272        source: nix::Error,
273    },
274    #[error("EnableCap({0})")]
275    EnableCap(&'static str, #[source] nix::Error),
276    #[error("CreateVCpu")]
277    CreateVCpu(#[source] nix::Error),
278    #[error("GetRegs")]
279    GetRegs(#[source] nix::Error),
280    #[error("GetSRegs")]
281    GetSRegs(#[source] nix::Error),
282    #[error("SetRegs")]
283    SetRegs(#[source] nix::Error),
284    #[error("SetSRegs")]
285    SetSRegs(#[source] nix::Error),
286    #[error("Run")]
287    Run(#[source] nix::Error),
288    #[error("RunMemoryFault(flags={flags:#x}, gpa={gpa:#x}, size={size:#x})")]
289    RunMemoryFault {
290        flags: u64,
291        gpa: u64,
292        size: u64,
293        #[source]
294        source: nix::Error,
295    },
296    #[error("GetVCpuMmapSize")]
297    GetVCpuMmapSize(#[source] nix::Error),
298    #[error("MmapVCpu")]
299    MmapVCpu(#[source] io::Error),
300    #[error("SetFpu")]
301    SetFpu(#[source] nix::Error),
302    #[error("GetSupportedCpuid")]
303    GetSupportedCpuid(#[source] nix::Error),
304    #[error("SetCpuid")]
305    SetCpuid(#[source] nix::Error),
306    #[error("Interrupt")]
307    Interrupt(#[source] nix::Error),
308    #[error("GetLApic")]
309    GetLApic(#[source] nix::Error),
310    #[error("SetLApic")]
311    SetLApic(#[source] nix::Error),
312    #[error("GetXsave")]
313    GetXsave(#[source] nix::Error),
314    #[error("SetXsave")]
315    SetXsave(#[source] nix::Error),
316    #[error("GetDebugRegs")]
317    GetDebugRegs(#[source] nix::Error),
318    #[error("SetDebugRegs")]
319    SetDebugRegs(#[source] nix::Error),
320    #[error("GetXcrs")]
321    GetXcrs(#[source] nix::Error),
322    #[error("SetXcrs")]
323    SetXcrs(#[source] nix::Error),
324    #[error("xsave is not enabled")]
325    XsaveNotEnabled,
326    #[error("SetGsiRouting")]
327    SetGsiRouting(#[source] nix::Error),
328    #[error("IrqLine")]
329    IrqLine(#[source] nix::Error),
330    #[error("GetMsrs")]
331    GetMsrs(#[source] nix::Error),
332    #[error("SetMsrs")]
333    SetMsrs(#[source] nix::Error),
334    #[error(
335        "MSR access only processed {completed} of {requested} entries (first failed MSR: {failed_msr:#x}, write={write})"
336    )]
337    IncompleteMsrs {
338        write: bool,
339        completed: usize,
340        requested: usize,
341        failed_msr: u32,
342    },
343    #[error("SetupMce")]
344    SetupMce(#[source] nix::Error),
345    #[error("GetMceCapSupported")]
346    GetMceCapSupported(#[source] nix::Error),
347    #[error("GetMpState")]
348    GetMpState(#[source] nix::Error),
349    #[error("SetMpState")]
350    SetMpState(#[source] nix::Error),
351    #[error("GetVcpuEvents")]
352    GetVcpuEvents(#[source] nix::Error),
353    #[error("SetVcpuEvents")]
354    SetVcpuEvents(#[source] nix::Error),
355    #[error("TranslateGva")]
356    TranslateGva(#[source] nix::Error),
357    #[error("unknown exit {0:#x}")]
358    UnknownExit(u32),
359    #[error("unknown Hyper-V exit {0:#x}")]
360    UnknownHvExit(u32),
361    #[error("ioeventfd")]
362    IoEventFd(#[source] nix::Error),
363    #[error("irqfd")]
364    IrqFd(#[source] nix::Error),
365    #[error("failed to set BSP")]
366    SetBsp(#[source] nix::Error),
367    #[error("CreateDevice")]
368    CreateDevice(#[source] nix::Error),
369    #[error("SetDeviceAttr")]
370    SetDeviceAttr(#[source] nix::Error),
371    #[error("GetDeviceAttr")]
372    GetDeviceAttr(#[source] nix::Error),
373    #[error("CheckExtension")]
374    CheckExtension(#[source] nix::Error),
375    #[error("GetClock")]
376    GetClock(#[source] nix::Error),
377    #[error("SetClock")]
378    SetClock(#[source] nix::Error),
379}
380
381type Result<T, E = Error> = std::result::Result<T, E>;
382
383#[derive(Debug)]
384struct Vp {
385    vcpu: File,
386    run_data: VpPtr,
387    thread: RwLock<Option<Pthread>>,
388    _phantom: PhantomData<kvm_run>,
389}
390
391/// Send+Sync wrapper around the mapped kvm_run pointer.
392#[derive(Debug)]
393struct VpPtr {
394    ptr: *mut kvm_run,
395    len: usize,
396}
397
398// SAFETY: this type contains a pointer to mapped data. By itself this is
399// Send+Sync since it's just a raw pointer value with no methods, but in context
400// it must be carefully accessed only by one thread at a time. This is mediated
401// by `Vp`.
402unsafe impl Send for VpPtr {}
403// SAFETY: see above comment
404unsafe impl Sync for VpPtr {}
405
406/// An open file to `/dev/kvm`.
407#[derive(Debug)]
408pub struct Kvm(File);
409
410impl Kvm {
411    /// Opens `/dev/kvm`.
412    pub fn new() -> Result<Self> {
413        let kvm = std::fs::OpenOptions::new()
414            .read(true)
415            .write(true)
416            .open("/dev/kvm")
417            .map_err(Error::OpenKvm)?;
418
419        Ok(Self(kvm))
420    }
421
422    /// Returns the CPUID values that are supported by the hypervisor.
423    #[cfg(target_arch = "x86_64")]
424    pub fn supported_cpuid(&self) -> Result<Vec<kvm_cpuid_entry2>> {
425        const MAX_CPUID_ENTRIES: usize = 256;
426        let mut supported_cpuid = Cpuid {
427            cpuid: kvm_cpuid2 {
428                nent: MAX_CPUID_ENTRIES as u32,
429                ..Default::default()
430            },
431            entries: [Default::default(); MAX_CPUID_ENTRIES],
432        };
433
434        // TODO: We are not checking for KVM_CAP_EXT_CPUID first.
435        // SAFETY: We have allocated an array for the ioctl to write to and correctly specified its size in nent.
436        unsafe {
437            ioctl::kvm_get_supported_cpuid(self.as_fd().as_raw_fd(), &mut supported_cpuid.cpuid)
438                .map_err(Error::GetSupportedCpuid)?;
439        }
440
441        Ok(supported_cpuid.entries[..supported_cpuid.cpuid.nent as usize].to_vec())
442    }
443
444    /// Returns the set of `IA32_MCG_CAP` capability bits that KVM supports
445    /// setting via [`Processor::setup_mce`] on this host (e.g. `MCG_CMCI_P`,
446    /// `MCG_LMCE_P` on Intel).
447    #[cfg(target_arch = "x86_64")]
448    pub fn supported_mce_cap(&self) -> Result<u64> {
449        let mut cap: u64 = 0;
450        // SAFETY: passing a valid pointer to a u64 for the ioctl to fill in.
451        unsafe {
452            ioctl::kvm_x86_get_mce_cap_supported(self.as_fd().as_raw_fd(), &mut cap)
453                .map_err(Error::GetMceCapSupported)?;
454        }
455        Ok(cap)
456    }
457
458    /// Returns the VMSA feature bits supported by KVM for SEV guests.
459    #[cfg(target_arch = "x86_64")]
460    pub fn supported_sev_vmsa_features(&self) -> Result<u64> {
461        let mut value = 0u64;
462        let attr = kvm_device_attr {
463            group: KVM_X86_GRP_SEV,
464            attr: u64::from(KVM_X86_SEV_VMSA_FEATURES),
465            addr: std::ptr::from_mut(&mut value) as u64,
466            flags: 0,
467        };
468        // SAFETY: `attr.addr` points to `value` for the duration of the ioctl.
469        unsafe {
470            ioctl::kvm_get_device_attr(self.as_fd().as_raw_fd(), &attr)
471                .map_err(Error::GetDeviceAttr)?;
472        }
473        Ok(value)
474    }
475
476    /// Returns the Hyper-V CPUID values that KVM supports for guest
477    /// enlightenments, including nested virtualization features.
478    #[cfg(target_arch = "x86_64")]
479    pub fn supported_hv_cpuid(&self) -> Result<Vec<kvm_cpuid_entry2>> {
480        const MAX_CPUID_ENTRIES: usize = 256;
481        let mut supported_cpuid = Cpuid {
482            cpuid: kvm_cpuid2 {
483                nent: MAX_CPUID_ENTRIES as u32,
484                ..Default::default()
485            },
486            entries: [Default::default(); MAX_CPUID_ENTRIES],
487        };
488
489        // SAFETY: We have allocated an array for the ioctl to write to and correctly specified its size in nent.
490        unsafe {
491            ioctl::kvm_get_supported_hv_cpuid(self.as_fd().as_raw_fd(), &mut supported_cpuid.cpuid)
492                .map_err(Error::GetSupportedCpuid)?;
493        }
494
495        Ok(supported_cpuid.entries[..supported_cpuid.cpuid.nent as usize].to_vec())
496    }
497
498    pub fn check_extension(&self, extension: u32) -> nix::Result<libc::c_int> {
499        // SAFETY: Calling IOCTL as documented, with no special requirements.
500        unsafe { ioctl::kvm_check_extension(self.as_fd().as_raw_fd(), extension as i32) }
501    }
502
503    pub fn new_vm(&self, vm_type: VmType) -> Result<Partition> {
504        let raw_vm_type = self.raw_vm_type(vm_type)?;
505        self.new_vm_with_type(raw_vm_type)
506    }
507
508    fn raw_vm_type(&self, vm_type: VmType) -> Result<libc::c_int> {
509        match vm_type {
510            VmType::Default => Ok(self.default_vm_type()),
511            #[cfg(target_arch = "x86_64")]
512            VmType::Snp => {
513                let supported_vm_types =
514                    self.check_extension(KVM_CAP_VM_TYPES_UAPI)
515                        .map_err(Error::CheckExtension)? as u64;
516                let raw_vm_type = KVM_X86_SNP_VM_UAPI;
517                let vm_type_bit = 1_u64
518                    .checked_shl(raw_vm_type as u32)
519                    .ok_or(Error::UnsupportedVmType(vm_type))?;
520                if supported_vm_types & vm_type_bit == 0 {
521                    return Err(Error::UnsupportedVmType(vm_type));
522                }
523                Ok(raw_vm_type)
524            }
525            #[cfg(target_arch = "aarch64")]
526            VmType::Realm { ipa_bits } => Ok((KVM_VM_TYPE_ARM_REALM_UAPI
527                | ((ipa_bits as u64) & KVM_VM_TYPE_ARM_IPA_SIZE_MASK_UAPI))
528                as libc::c_int),
529        }
530    }
531
532    fn default_vm_type(&self) -> libc::c_int {
533        // On ARM, can request memory isolation which we don't use.
534        // For that, include the `KVM_VM_TYPE_ARM_PROTECTED` flag.
535        // Use 0 as the fallback machine type, which implies 40bit
536        // IPA on ARM64, and on x86_64 is the only option.
537        #[cfg(target_arch = "aarch64")]
538        {
539            self.check_extension(KVM_CAP_ARM_VM_IPA_SIZE).unwrap_or(0)
540        }
541        #[cfg(not(target_arch = "aarch64"))]
542        {
543            0
544        }
545    }
546
547    fn new_vm_with_type(&self, vm_type: libc::c_int) -> Result<Partition> {
548        // SAFETY: Calling IOCTL as documented, with no special requirements.
549        let vm = unsafe {
550            let fd =
551                ioctl::kvm_create_vm(self.as_fd().as_raw_fd(), vm_type).map_err(Error::CreateVm)?;
552            File::from_raw_fd(fd)
553        };
554
555        // TODO: We are not checking KVM_CAP_ENABLE_CAP_VM first.
556        // TODO: We are not calling KVM_CHECK_EXTENSION first.
557        // SAFETY: Calling IOCTLs as documented, with no special requirements.
558        #[cfg(target_arch = "x86_64")]
559        unsafe {
560            // Disable quirks to make KVM behave more architecturally correct.
561            // TODO: Investigate using KVM_CAP_DISABLE_QUIRKS2 instead.
562            ioctl::kvm_enable_cap(
563                vm.as_raw_fd(),
564                &kvm_enable_cap {
565                    cap: KVM_CAP_DISABLE_QUIRKS,
566                    args: [KVM_X86_QUIRK_LINT0_REENABLED.into(), 0, 0, 0],
567                    ..Default::default()
568                },
569            )
570            .map_err(|err| Error::EnableCap("disable_quirks", err))?;
571        }
572
573        // SAFETY: Calling IOCTL as documented, with no special requirements.
574        let mmap_size = unsafe {
575            ioctl::kvm_get_vcpu_mmap_size(self.as_fd().as_raw_fd(), 0)
576                .map_err(Error::GetVCpuMmapSize)? as usize
577        };
578
579        Ok(Partition {
580            vm,
581            vps: Vec::new(),
582            mmap_size,
583        })
584    }
585}
586
587impl AsFd for Kvm {
588    fn as_fd(&self) -> BorrowedFd<'_> {
589        self.0.as_fd()
590    }
591}
592
593impl From<File> for Kvm {
594    fn from(fd: File) -> Self {
595        Self(fd)
596    }
597}
598
599impl From<Kvm> for File {
600    fn from(kvm: Kvm) -> Self {
601        kvm.0
602    }
603}
604
605#[repr(C)]
606#[cfg(target_arch = "x86_64")]
607struct Cpuid {
608    cpuid: kvm_cpuid2,
609    entries: [kvm_cpuid_entry2; 256],
610}
611
612#[derive(Debug)]
613pub struct Partition {
614    vm: File,
615    vps: Vec<Option<Vp>>,
616    mmap_size: usize,
617}
618
619impl Partition {
620    #[cfg(target_arch = "x86_64")]
621    pub fn check_sev_snp_launch_extensions(&self) -> Result<()> {
622        // SAFETY: This is the documented KVM_MEMORY_ENCRYPT_OP availability
623        // probe, and does not pass any userspace data pointer to KVM.
624        unsafe { ioctl::kvm_memory_encrypt_op_supported(self.vm.as_raw_fd()) }.map_err(|err| {
625            Error::MemoryEncryptOp {
626                command: "KVM_MEMORY_ENCRYPT_OP(NULL)",
627                firmware_error: 0,
628                source: err,
629            }
630        })
631    }
632
633    #[cfg(target_arch = "x86_64")]
634    pub fn enable_hypercall_exits(&self, hypercall_mask: u64) -> Result<()> {
635        // SAFETY: Calling IOCTL as documented, with no special requirements.
636        unsafe {
637            ioctl::kvm_enable_cap(
638                self.vm.as_raw_fd(),
639                &kvm_enable_cap {
640                    cap: KVM_CAP_EXIT_HYPERCALL_UAPI,
641                    args: [hypercall_mask, 0, 0, 0],
642                    ..Default::default()
643                },
644            )
645            .map_err(|err| Error::EnableCap("exit_hypercall", err))?;
646        }
647        Ok(())
648    }
649
650    pub fn check_extension(&self, extension: u32) -> nix::Result<libc::c_int> {
651        // SAFETY: Calling IOCTL as documented, with no special requirements.
652        unsafe { ioctl::kvm_check_extension(self.vm.as_raw_fd(), extension as i32) }
653    }
654
655    #[cfg(target_arch = "aarch64")]
656    pub fn arm_rmi_populate(&self, populate: &mut KvmArmRmiPopulate) -> Result<()> {
657        // SAFETY: `populate` points to a valid KVM_ARM_RMI_POPULATE argument for
658        // the duration of the ioctl. KVM may update it to report partial progress.
659        unsafe { ioctl::kvm_arm_rmi_populate(self.vm.as_raw_fd(), populate) }
660            .map_err(Error::ArmRmiPopulate)?;
661        Ok(())
662    }
663
664    #[cfg(target_arch = "x86_64")]
665    pub fn sev_snp_init(&self, sev: BorrowedFd<'_>, vmsa_features: u64) -> Result<()> {
666        let mut init = kvm_sev_init {
667            vmsa_features,
668            ..Default::default()
669        };
670        let mut command = kvm_sev_cmd {
671            id: sev_cmd_id_KVM_SEV_INIT2,
672            data: std::ptr::from_mut(&mut init) as u64,
673            sev_fd: sev.as_raw_fd() as u32,
674            ..Default::default()
675        };
676
677        // SAFETY: `command` and its data pointer refer to stack-allocated C ABI
678        // structs that remain valid for the duration of the ioctl.
679        unsafe {
680            ioctl::kvm_memory_encrypt_op(self.vm.as_raw_fd(), &mut command).map_err(|err| {
681                Error::MemoryEncryptOp {
682                    command: "KVM_SEV_INIT2",
683                    firmware_error: command.error,
684                    source: err,
685                }
686            })?;
687        }
688        Ok(())
689    }
690
691    #[cfg(target_arch = "x86_64")]
692    fn sev_snp_cmd<T>(
693        &self,
694        sev: BorrowedFd<'_>,
695        command_name: &'static str,
696        command_id: sev_cmd_id,
697        data: &mut T,
698    ) -> Result<()> {
699        let mut command = kvm_sev_cmd {
700            id: command_id,
701            data: std::ptr::from_mut(data) as u64,
702            sev_fd: sev.as_raw_fd() as u32,
703            ..Default::default()
704        };
705
706        loop {
707            // SAFETY: `command` and its data pointer refer to stack-allocated C ABI
708            // structs that remain valid for the duration of the ioctl.
709            match unsafe { ioctl::kvm_memory_encrypt_op(self.vm.as_raw_fd(), &mut command) } {
710                Ok(_) => break,
711                Err(nix::errno::Errno::EAGAIN) => {}
712                Err(err) => {
713                    return Err(Error::MemoryEncryptOp {
714                        command: command_name,
715                        firmware_error: command.error,
716                        source: err,
717                    });
718                }
719            }
720        }
721        Ok(())
722    }
723
724    #[cfg(target_arch = "x86_64")]
725    pub fn sev_snp_launch_start(
726        &self,
727        sev: BorrowedFd<'_>,
728        data: &mut kvm_sev_snp_launch_start,
729    ) -> Result<()> {
730        self.sev_snp_cmd(
731            sev,
732            "KVM_SEV_SNP_LAUNCH_START",
733            sev_cmd_id_KVM_SEV_SNP_LAUNCH_START,
734            data,
735        )
736    }
737
738    #[cfg(target_arch = "x86_64")]
739    pub fn sev_snp_launch_update(
740        &self,
741        sev: BorrowedFd<'_>,
742        gfn_start: u64,
743        uaddr: u64,
744        len: u64,
745        page_type: SevSnpPageType,
746    ) -> Result<()> {
747        let mut update = kvm_sev_snp_launch_update {
748            gfn_start,
749            uaddr,
750            len,
751            type_: page_type.as_uapi(),
752            ..Default::default()
753        };
754
755        while update.len != 0 {
756            self.sev_snp_cmd(
757                sev,
758                "KVM_SEV_SNP_LAUNCH_UPDATE",
759                sev_cmd_id_KVM_SEV_SNP_LAUNCH_UPDATE,
760                &mut update,
761            )?;
762        }
763        Ok(())
764    }
765
766    #[cfg(target_arch = "x86_64")]
767    pub fn sev_snp_launch_finish(
768        &self,
769        sev: BorrowedFd<'_>,
770        data: &mut kvm_sev_snp_launch_finish,
771    ) -> Result<()> {
772        self.sev_snp_cmd(
773            sev,
774            "KVM_SEV_SNP_LAUNCH_FINISH",
775            sev_cmd_id_KVM_SEV_SNP_LAUNCH_FINISH,
776            data,
777        )
778    }
779
780    pub fn enable_split_irqchip(&self, lines: u32) -> Result<()> {
781        // TODO: We are not checking KVM_CAP_ENABLE_CAP_VM first.
782        // TODO: We are not calling KVM_CHECK_EXTENSION first.
783        // SAFETY: Calling IOCTL as documented, with no special requirements.
784        unsafe {
785            ioctl::kvm_enable_cap(
786                self.vm.as_raw_fd(),
787                &kvm_enable_cap {
788                    cap: KVM_CAP_SPLIT_IRQCHIP,
789                    args: [lines.into(), 0, 0, 0],
790                    ..Default::default()
791                },
792            )
793            .map_err(|err| Error::EnableCap("split_irqchip", err))?;
794        }
795        Ok(())
796    }
797
798    /// Enable X2APIC IDs in interrupt and LAPIC APIs.
799    #[cfg(target_arch = "x86_64")]
800    pub fn enable_x2apic_api(&self) -> Result<()> {
801        let flags = KVM_X2APIC_API_USE_32BIT_IDS;
802        // SAFETY: Calling IOCTL as documented, with no special requirements.
803        unsafe {
804            ioctl::kvm_enable_cap(
805                self.vm.as_raw_fd(),
806                &kvm_enable_cap {
807                    cap: KVM_CAP_X2APIC_API,
808                    args: [flags.into(), 0, 0, 0],
809                    ..Default::default()
810                },
811            )
812            .map_err(|err| Error::EnableCap("x2apic_api", err))?;
813        }
814        Ok(())
815    }
816
817    pub fn enable_unknown_msr_exits(&self) -> Result<()> {
818        // SAFETY: Calling IOCTL as documented, with no special requirements.
819        // TODO: We are not checking KVM_CAP_ENABLE_CAP_VM first.
820        unsafe {
821            ioctl::kvm_enable_cap(
822                self.vm.as_raw_fd(),
823                &kvm_enable_cap {
824                    cap: KVM_CAP_X86_USER_SPACE_MSR,
825                    args: [KVM_MSR_EXIT_REASON_UNKNOWN.into(), 0, 0, 0],
826                    ..Default::default()
827                },
828            )
829            .map_err(|err| Error::EnableCap("user_space_msr", err))?;
830        }
831        Ok(())
832    }
833
834    /// Set the VCPU index of the BSP. This must be called before any VCPUs are
835    /// created.
836    #[cfg(target_arch = "x86_64")]
837    pub fn set_bsp(&mut self, vcpu_idx: u32) -> Result<()> {
838        // SAFETY: Calling IOCTL as documented, with no special requirements.
839        unsafe {
840            ioctl::kvm_set_boot_cpu_id(self.vm.as_raw_fd(), vcpu_idx as i32)
841                .map_err(Error::SetBsp)?;
842        }
843
844        Ok(())
845    }
846
847    pub fn add_vp(&mut self, vcpu_idx: u32) -> Result<()> {
848        // TODO: We are not checking KVM_CAP_NR_VCPUS or KVM_CAP_MAX_VCPUS first.
849        // SAFETY: Calling IOCTL as documented, with no special requirements.
850        let vcpu = unsafe {
851            let fd = ioctl::kvm_create_vcpu(self.vm.as_raw_fd(), vcpu_idx as i32)
852                .map_err(Error::CreateVCpu)?;
853            File::from_raw_fd(fd)
854        };
855
856        // SAFETY: Calling mmap with a null pointer is valid, and vcpu is guaranteed to have a valid fd.
857        let ptr = unsafe {
858            let ptr = libc::mmap(
859                std::ptr::null_mut(),
860                self.mmap_size,
861                libc::PROT_READ | libc::PROT_WRITE,
862                libc::MAP_SHARED,
863                vcpu.as_raw_fd(),
864                0,
865            );
866            if ptr == libc::MAP_FAILED {
867                return Err(Error::MmapVCpu(io::Error::last_os_error()));
868            }
869            ptr
870        };
871
872        #[cfg(target_arch = "aarch64")]
873        {
874            // Can request additional features like so:
875            let mut kvi = kvm_vcpu_init::default();
876            kvi.features[0] |= 1 << KVM_ARM_VCPU_PSCI_0_2;
877
878            if vcpu_idx > 0 {
879                kvi.features[0] |= 1 << KVM_ARM_VCPU_POWER_OFF;
880            }
881
882            let mut pref_target = kvm_vcpu_init::default();
883            // SAFETY: Calling IOCTL as documented, with no special requirements.
884            unsafe {
885                ioctl::kvm_arm_preferred_target(self.vm.as_raw_fd(), &mut pref_target)
886                    .map_err(Error::CreateVCpu)?
887            };
888
889            kvi.target = pref_target.target;
890            // SAFETY: Calling IOCTL as documented, with no special requirements.
891            unsafe { ioctl::kvm_arm_vcpu_init(vcpu.as_raw_fd(), &kvi).map_err(Error::CreateVCpu)? };
892        }
893
894        let vp = Vp {
895            vcpu,
896            run_data: VpPtr {
897                ptr: ptr.cast(),
898                len: self.mmap_size,
899            },
900            thread: RwLock::new(None),
901            _phantom: PhantomData,
902        };
903        if self.vps.len() <= vcpu_idx as usize {
904            self.vps.resize_with(vcpu_idx as usize + 1, || None);
905        }
906        assert!(self.vps[vcpu_idx as usize].replace(vp).is_none());
907
908        Ok(())
909    }
910
911    pub fn vp(&self, index: u32) -> Processor<'_> {
912        Processor(self, index)
913    }
914
915    pub fn request_msi(&self, msi: &kvm_msi) -> Result<()> {
916        // TODO: We are not checking KVM_CAP_SIGNAL_MSI first.
917        // SAFETY: Calling IOCTL as documented, with no special requirements.
918        unsafe {
919            ioctl::kvm_signal_msi(self.vm.as_raw_fd(), msi).map_err(Error::SignalMsi)?;
920        }
921        Ok(())
922    }
923
924    /// Sets or clears a userspace memory slot.
925    ///
926    /// # Safety
927    ///
928    /// If `size` is nonzero, `data..data + size` must be a valid userspace
929    /// mapping for KVM to access until the slot is changed or cleared. The
930    /// caller must also ensure that `addr` and `size` satisfy KVM's memory-slot
931    /// alignment and range requirements.
932    pub unsafe fn set_user_memory_region(
933        &self,
934        slot: u32,
935        data: *mut u8,
936        size: usize,
937        addr: u64,
938        readonly: bool,
939    ) -> Result<()> {
940        let region = kvm_userspace_memory_region {
941            slot,
942            flags: if readonly { KVM_MEM_READONLY } else { 0 },
943            guest_phys_addr: addr,
944            memory_size: size as u64,
945            userspace_addr: data as usize as u64,
946        };
947        // SAFETY: the caller guarantees that any non-empty userspace range
948        // remains valid for KVM while the slot references it.
949        unsafe {
950            ioctl::kvm_set_user_memory_region(self.vm.as_raw_fd(), &region)
951                .map_err(Error::SetMemoryRegion)?;
952        }
953        Ok(())
954    }
955
956    /// Sets or clears a userspace memory slot with optional guestmemfd backing.
957    ///
958    /// # Safety
959    ///
960    /// If `size` is nonzero, `data..data + size` must be a valid userspace
961    /// mapping for KVM to access until the slot is changed or cleared. The
962    /// caller must ensure that `addr`, `size`, and any `guestmemfd` offset
963    /// satisfy KVM's memory-slot alignment and range requirements. If
964    /// `guest_memfd` is supplied, the file must remain open and valid for as
965    /// long as KVM may reference the slot.
966    pub unsafe fn set_user_memory_region2(
967        &self,
968        slot: u32,
969        data: *mut u8,
970        size: usize,
971        addr: u64,
972        readonly: bool,
973        guest_memfd: Option<(&File, u64)>,
974    ) -> Result<()> {
975        let (guest_memfd, guest_memfd_offset, guest_memfd_flag) = guest_memfd
976            .map(|(file, offset)| (file.as_raw_fd() as u32, offset, KVM_MEM_GUEST_MEMFD))
977            .unwrap_or((0, 0, 0));
978        let region = kvm_userspace_memory_region2 {
979            slot,
980            flags: if readonly { KVM_MEM_READONLY } else { 0 } | guest_memfd_flag,
981            guest_phys_addr: addr,
982            memory_size: size as u64,
983            userspace_addr: data as usize as u64,
984            guest_memfd_offset,
985            guest_memfd,
986            ..Default::default()
987        };
988        // SAFETY: the caller guarantees that any non-empty userspace range and
989        // optional guestmemfd backing remain valid for KVM while the slot
990        // references them.
991        unsafe {
992            ioctl::kvm_set_user_memory_region2(self.vm.as_raw_fd(), &region)
993                .map_err(Error::SetMemoryRegion)?;
994        }
995        Ok(())
996    }
997
998    pub fn create_guest_memfd(&self, size: u64) -> Result<File> {
999        let mut guest_memfd = kvm_create_guest_memfd {
1000            size,
1001            ..Default::default()
1002        };
1003        // SAFETY: `guest_memfd` is a valid C ABI struct for KVM to read.
1004        let fd = unsafe {
1005            ioctl::kvm_create_guest_memfd(self.vm.as_raw_fd(), &mut guest_memfd)
1006                .map_err(Error::CreateGuestMemfd)?
1007        };
1008        // SAFETY: On success, KVM returns a new owned file descriptor.
1009        Ok(unsafe { File::from_raw_fd(fd) })
1010    }
1011
1012    pub fn set_memory_attributes(&self, addr: u64, size: u64, attributes: u64) -> Result<()> {
1013        let attr = kvm_memory_attributes {
1014            address: addr,
1015            size,
1016            attributes,
1017            ..Default::default()
1018        };
1019        // SAFETY: `attr` is a valid C ABI struct for KVM to read.
1020        unsafe {
1021            ioctl::kvm_set_memory_attributes(self.vm.as_raw_fd(), &attr)
1022                .map_err(Error::SetMemoryAttributes)?;
1023        }
1024        Ok(())
1025    }
1026
1027    pub fn set_gsi_routes(&self, routes: &[(u32, RoutingEntry)]) -> Result<()> {
1028        const MAX_ROUTES: usize = 2048;
1029        assert!(routes.len() <= MAX_ROUTES);
1030
1031        #[repr(C)]
1032        struct Routes {
1033            header: kvm_irq_routing,
1034            entries: [kvm_irq_routing_entry; MAX_ROUTES],
1035        }
1036
1037        let mut kvm_routes = Routes {
1038            header: Default::default(),
1039            entries: [Default::default(); MAX_ROUTES],
1040        };
1041        for (i, route) in routes.iter().enumerate() {
1042            let (type_, flags, u) = match route.1 {
1043                RoutingEntry::Msi {
1044                    address_lo,
1045                    address_hi,
1046                    data,
1047                    devid,
1048                } => {
1049                    let (flags, anon) = if let Some(devid) = devid {
1050                        (
1051                            KVM_MSI_VALID_DEVID,
1052                            kvm_irq_routing_msi__bindgen_ty_1 { devid },
1053                        )
1054                    } else {
1055                        (0, Default::default())
1056                    };
1057                    (
1058                        KVM_IRQ_ROUTING_MSI,
1059                        flags,
1060                        kvm_irq_routing_entry__bindgen_ty_1 {
1061                            msi: kvm_irq_routing_msi {
1062                                address_lo,
1063                                address_hi,
1064                                data,
1065                                __bindgen_anon_1: anon,
1066                            },
1067                        },
1068                    )
1069                }
1070                RoutingEntry::HvSint { vp, sint } => (
1071                    KVM_IRQ_ROUTING_HV_SINT,
1072                    0,
1073                    kvm_irq_routing_entry__bindgen_ty_1 {
1074                        hv_sint: kvm_irq_routing_hv_sint {
1075                            vcpu: vp,
1076                            sint: sint.into(),
1077                        },
1078                    },
1079                ),
1080                RoutingEntry::Irqchip { pin } => (
1081                    KVM_IRQ_ROUTING_IRQCHIP,
1082                    0,
1083                    kvm_irq_routing_entry__bindgen_ty_1 {
1084                        irqchip: kvm_irq_routing_irqchip { pin, irqchip: 0 },
1085                    },
1086                ),
1087            };
1088            kvm_routes.entries[i] = kvm_irq_routing_entry {
1089                gsi: route.0,
1090                type_,
1091                flags,
1092                pad: 0,
1093                u,
1094            };
1095            kvm_routes.header.nr += 1;
1096        }
1097
1098        // TODO: We are not checking KVM_CAP_IRQ_ROUTING first.
1099        // SAFETY: Our Routes type puts the entries array immediately after the header in memory, as required.
1100        unsafe {
1101            ioctl::kvm_set_gsi_routing(self.vm.as_raw_fd(), &kvm_routes.header)
1102                .map_err(Error::SetGsiRouting)?;
1103        }
1104        Ok(())
1105    }
1106
1107    pub fn irqfd(&self, gsi: u32, event: RawFd, assign: bool) -> Result<()> {
1108        // TODO: We are not checking KVM_CAP_IRQFD first.
1109        // SAFETY: Calling IOCTL as documented, with no special requirements.
1110        unsafe {
1111            ioctl::kvm_irqfd(
1112                self.vm.as_raw_fd(),
1113                &kvm_irqfd {
1114                    fd: event as u32,
1115                    gsi,
1116                    flags: if assign { 0 } else { KVM_IRQFD_FLAG_DEASSIGN },
1117                    resamplefd: 0,
1118                    pad: [0; 16],
1119                },
1120            )
1121            .map_err(Error::IrqFd)
1122            .map(drop)
1123        }
1124    }
1125
1126    pub fn irq_line(&self, gsi: u32, level: bool) -> Result<()> {
1127        // TODO: We are not checking KVM_CAP_IRQCHIP first.
1128        // SAFETY: Calling IOCTL as documented, with no special requirements.
1129        unsafe {
1130            ioctl::kvm_irq_line(
1131                self.vm.as_raw_fd(),
1132                &kvm_irq_level {
1133                    __bindgen_anon_1: kvm_irq_level__bindgen_ty_1 { irq: gsi },
1134                    level: level.into(),
1135                },
1136            )
1137            .map_err(Error::IrqLine)?;
1138        }
1139        Ok(())
1140    }
1141
1142    pub fn ioeventfd(
1143        &self,
1144        datamatch: u64,
1145        addr: u64,
1146        len: u32,
1147        fd: i32,
1148        flags: u32,
1149    ) -> Result<()> {
1150        // TODO: We are not checking KVM_CAP_IOEVENTFD first.
1151        // SAFETY: Calling IOCTL as documented, with no special requirements.
1152        unsafe {
1153            ioctl::kvm_ioeventfd(
1154                self.vm.as_raw_fd(),
1155                &kvm_ioeventfd {
1156                    datamatch,
1157                    addr,
1158                    len,
1159                    fd,
1160                    flags,
1161                    ..Default::default()
1162                },
1163            )
1164            .map_err(Error::IoEventFd)?;
1165        };
1166        Ok(())
1167    }
1168
1169    pub fn create_device(&self, ty: u32, flags: u32) -> nix::Result<Device> {
1170        // SAFETY: Calling IOCTL as documented, with no special requirements.
1171        // The reference: https://www.kernel.org/doc/html/latest/virt/kvm/api.html#kvm-create-device.
1172        // The kernel checks on the input parameters and returns the appropriate
1173        // error code.
1174        unsafe {
1175            let mut device = kvm_create_device {
1176                type_: ty,
1177                fd: 0,
1178                flags,
1179            };
1180            ioctl::kvm_create_device(self.vm.as_raw_fd(), &mut device)?;
1181            Ok(Device(File::from_raw_fd(device.fd as i32)))
1182        }
1183    }
1184
1185    /// Tests whether a device type can be created without actually creating it.
1186    ///
1187    /// Uses `KVM_CREATE_DEVICE_TEST` to probe support. Unlike
1188    /// [`create_device`](Self::create_device), this does not wrap any fd.
1189    pub fn test_create_device(&self, ty: u32) -> nix::Result<()> {
1190        // SAFETY: With KVM_CREATE_DEVICE_TEST the kernel only checks
1191        // whether the device type is supported and does not populate
1192        // `device.fd`.
1193        unsafe {
1194            let mut device = kvm_create_device {
1195                type_: ty,
1196                fd: 0,
1197                flags: KVM_CREATE_DEVICE_TEST,
1198            };
1199            ioctl::kvm_create_device(self.vm.as_raw_fd(), &mut device)?;
1200        }
1201        Ok(())
1202    }
1203
1204    /// Gets the current kvmclock value.
1205    pub fn get_clock_ns(&self) -> Result<kvm_clock_data> {
1206        let mut clock = kvm_clock_data::default();
1207        // SAFETY: Calling IOCTL as documented, with no special requirements.
1208        unsafe {
1209            ioctl::kvm_get_clock(self.vm.as_raw_fd(), &mut clock).map_err(Error::GetClock)?;
1210        }
1211        Ok(clock)
1212    }
1213
1214    /// Sets the current kvmclock value.
1215    pub fn set_clock_ns(&self, clock_ns: u64) -> Result<()> {
1216        let clock = kvm_clock_data {
1217            clock: clock_ns,
1218            ..Default::default()
1219        };
1220        // SAFETY: Calling IOCTL as documented, with no special requirements.
1221        unsafe {
1222            ioctl::kvm_set_clock(self.vm.as_raw_fd(), &clock).map_err(Error::SetClock)?;
1223        }
1224        Ok(())
1225    }
1226}
1227
1228/// An in-kernel emulated device.
1229pub struct Device(File);
1230
1231impl Device {
1232    /// # Safety
1233    ///
1234    /// `addr` must point to the appropriate input for the attribute being
1235    /// set.
1236    pub unsafe fn set_device_attr<T>(
1237        &self,
1238        group: u32,
1239        attr: u32,
1240        addr: &T,
1241        flags: u32,
1242    ) -> nix::Result<()> {
1243        // SAFETY: caller guaranteed.
1244        unsafe {
1245            ioctl::kvm_set_device_attr(
1246                self.0.as_raw_fd(),
1247                &kvm_device_attr {
1248                    group,
1249                    attr: attr as u64,
1250                    addr: std::ptr::from_ref(addr) as u64,
1251                    flags,
1252                },
1253            )?;
1254        }
1255        Ok(())
1256    }
1257}
1258
1259#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1260pub enum RoutingEntry {
1261    Irqchip {
1262        pin: u32,
1263    },
1264    Msi {
1265        address_lo: u32,
1266        address_hi: u32,
1267        data: u32,
1268        devid: Option<u32>,
1269    },
1270    HvSint {
1271        vp: u32,
1272        sint: u8,
1273    },
1274}
1275
1276pub struct Processor<'a>(&'a Partition, u32);
1277
1278impl<'a> Processor<'a> {
1279    pub fn enable_synic(&self) -> Result<()> {
1280        // TODO: We are not checking KVM_CAP_ENABLE_CAP_VM first.
1281        // TODO: We are not calling KVM_CHECK_EXTENSION first.
1282        // SAFETY: Calling IOCTL as documented, with no special requirements.
1283        unsafe {
1284            ioctl::kvm_enable_cap(
1285                self.get().vcpu.as_raw_fd(),
1286                &kvm_enable_cap {
1287                    cap: KVM_CAP_HYPERV_SYNIC2,
1288                    ..Default::default()
1289                },
1290            )
1291            .map_err(|err| Error::EnableCap("hyperv_synic2", err))?;
1292        }
1293        Ok(())
1294    }
1295
1296    #[cfg(target_arch = "x86_64")]
1297    pub fn set_cpuid(&self, entries: &[kvm_cpuid_entry2]) -> Result<()> {
1298        const MAX_CPUID_ENTRIES: usize = 256;
1299        assert!(entries.len() <= MAX_CPUID_ENTRIES);
1300
1301        let mut cpuid: Cpuid = Cpuid {
1302            cpuid: Default::default(),
1303            entries: [Default::default(); MAX_CPUID_ENTRIES],
1304        };
1305        for (i, e) in entries.iter().enumerate() {
1306            cpuid.entries[i] = *e;
1307            cpuid.cpuid.nent += 1;
1308        }
1309
1310        // SAFETY: Our Cpuid type puts the entries array immediately after the header in memory, as required.
1311        unsafe {
1312            ioctl::kvm_set_cpuid2(self.get().vcpu.as_raw_fd(), &cpuid.cpuid)
1313                .map_err(Error::SetCpuid)?;
1314        }
1315        Ok(())
1316    }
1317
1318    fn get(&self) -> &'a Vp {
1319        self.0.vps[self.1 as usize].as_ref().expect("vp exists")
1320    }
1321
1322    /// Forces an exit to be returned from the next call to [`VpRunner::run`].
1323    ///
1324    /// Note that this does nothing if a [`VpRunner`] does not currently exist
1325    /// for this VP, or if this is called from the same thread as the runner.
1326    pub fn force_exit(&self) {
1327        let vp = self.get();
1328        let thread = vp.thread.read();
1329        if let Some(thread) = *thread {
1330            if thread != Pthread::current() {
1331                thread
1332                    .signal(libc::SIGRTMIN())
1333                    .expect("thread cancel signal failed");
1334            }
1335        }
1336    }
1337
1338    pub fn interrupt(&self, vector: u32) -> Result<()> {
1339        // SAFETY: Calling IOCTL as documented, with no special requirements.
1340        unsafe {
1341            ioctl::kvm_interrupt(self.get().vcpu.as_raw_fd(), &kvm_interrupt { irq: vector })
1342                .map_err(Error::Interrupt)?;
1343        };
1344        Ok(())
1345    }
1346
1347    /// Very not structured way of setting the register. Could enjoy using an enum.
1348    pub fn set_reg64(&self, reg_id: u64, value: u64) -> Result<()> {
1349        let reg = kvm_one_reg {
1350            id: reg_id,
1351            addr: std::ptr::from_ref(&value) as u64,
1352        };
1353        // SAFETY: Calling IOCTL as documented, with no special requirements.
1354        unsafe {
1355            ioctl::kvm_set_reg(self.get().vcpu.as_raw_fd(), &reg).map_err(Error::SetRegs)?;
1356        }
1357        Ok(())
1358    }
1359
1360    #[cfg(not(target_arch = "aarch64"))]
1361    pub fn set_regs(&self, regs: &kvm_regs) -> Result<()> {
1362        // This IOCTL does not work on arm64.
1363        // SAFETY: Calling IOCTL as documented, with no special requirements.
1364        unsafe {
1365            ioctl::kvm_set_regs(self.get().vcpu.as_raw_fd(), regs).map_err(Error::SetRegs)?;
1366        }
1367        Ok(())
1368    }
1369
1370    #[cfg(not(target_arch = "aarch64"))]
1371    pub fn set_sregs(&self, sregs: &kvm_sregs) -> Result<()> {
1372        // This IOCTL does not work on arm64.
1373        // SAFETY: Calling IOCTL as documented, with no special requirements.
1374        unsafe {
1375            ioctl::kvm_set_sregs(self.get().vcpu.as_raw_fd(), sregs).map_err(Error::SetRegs)?;
1376        }
1377        Ok(())
1378    }
1379
1380    /// Very not structured way of getting the register. Could enjoy using an enum.
1381    pub fn get_reg64(&self, reg_id: u64) -> Result<u64> {
1382        let mut value: u64 = 0;
1383        let reg = kvm_one_reg {
1384            id: reg_id,
1385            addr: std::ptr::from_mut(&mut value) as u64,
1386        };
1387        // SAFETY: Calling IOCTL as documented, with no special requirements.
1388        unsafe {
1389            ioctl::kvm_get_reg(self.get().vcpu.as_raw_fd(), &reg).map_err(Error::GetRegs)?;
1390        }
1391
1392        Ok(value)
1393    }
1394
1395    #[cfg(not(target_arch = "aarch64"))]
1396    pub fn get_regs(&self) -> Result<kvm_regs> {
1397        let mut regs = Default::default();
1398        // This IOCTL does not work on arm64.
1399        // SAFETY: Calling IOCTL as documented, with no special requirements.
1400        unsafe {
1401            ioctl::kvm_get_regs(self.get().vcpu.as_raw_fd(), &mut regs).map_err(Error::GetRegs)?;
1402        }
1403        Ok(regs)
1404    }
1405
1406    #[cfg(not(target_arch = "aarch64"))]
1407    pub fn get_sregs(&self) -> Result<kvm_sregs> {
1408        let mut sregs = Default::default();
1409        // This IOCTL does not work on arm64.
1410        // SAFETY: Calling IOCTL as documented, with no special requirements.
1411        unsafe {
1412            ioctl::kvm_get_sregs(self.get().vcpu.as_raw_fd(), &mut sregs)
1413                .map_err(Error::GetSRegs)?;
1414        }
1415        Ok(sregs)
1416    }
1417
1418    #[cfg(target_arch = "x86_64")]
1419    pub fn get_msrs(&self, msrs: &[u32], values: &mut [u64]) -> Result<()> {
1420        const MAX_MSR_ENTRIES: usize = 256;
1421        assert_eq!(msrs.len(), values.len());
1422        assert!(msrs.len() <= MAX_MSR_ENTRIES);
1423
1424        #[repr(C)]
1425        struct Msrs {
1426            header: kvm_msrs,
1427            entries: [kvm_msr_entry; MAX_MSR_ENTRIES],
1428        }
1429        let mut input = Msrs {
1430            header: kvm_msrs {
1431                nmsrs: msrs.len() as u32,
1432                ..Default::default()
1433            },
1434            entries: [Default::default(); MAX_MSR_ENTRIES],
1435        };
1436        for (i, msr) in msrs.iter().enumerate() {
1437            input.entries[i] = kvm_msr_entry {
1438                index: *msr,
1439                reserved: 0,
1440                data: 0,
1441            };
1442        }
1443
1444        // SAFETY: Our Msrs type puts the entries array immediately after the header in memory, as required.
1445        let completed = unsafe {
1446            ioctl::kvm_get_msrs(self.get().vcpu.as_raw_fd(), &mut input.header)
1447                .map_err(Error::GetMsrs)?
1448        } as usize;
1449        assert!(completed <= msrs.len());
1450        if completed < msrs.len() {
1451            return Err(Error::IncompleteMsrs {
1452                requested: msrs.len(),
1453                completed,
1454                failed_msr: msrs.get(completed).copied().unwrap(),
1455                write: false,
1456            });
1457        }
1458        for (v, e) in values.iter_mut().zip(&input.entries) {
1459            *v = e.data;
1460        }
1461        Ok(())
1462    }
1463
1464    #[cfg(target_arch = "x86_64")]
1465    pub fn set_msrs(&self, msrs: &[(u32, u64)]) -> Result<()> {
1466        const MAX_MSR_ENTRIES: usize = 256;
1467        assert!(msrs.len() <= MAX_MSR_ENTRIES);
1468
1469        #[repr(C)]
1470        struct Msrs {
1471            header: kvm_msrs,
1472            entries: [kvm_msr_entry; MAX_MSR_ENTRIES],
1473        }
1474        let mut input = Msrs {
1475            header: kvm_msrs {
1476                nmsrs: msrs.len() as u32,
1477                ..Default::default()
1478            },
1479            entries: [Default::default(); MAX_MSR_ENTRIES],
1480        };
1481        for (i, msr) in msrs.iter().enumerate() {
1482            input.entries[i] = kvm_msr_entry {
1483                index: msr.0,
1484                reserved: 0,
1485                data: msr.1,
1486            };
1487        }
1488
1489        // SAFETY: Our Msrs type puts the entries array immediately after the header in memory, as required.
1490        let completed = unsafe {
1491            ioctl::kvm_set_msrs(self.get().vcpu.as_raw_fd(), &input.header)
1492                .map_err(Error::SetMsrs)?
1493        } as usize;
1494        assert!(completed <= msrs.len());
1495        if completed < msrs.len() {
1496            return Err(Error::IncompleteMsrs {
1497                requested: msrs.len(),
1498                completed,
1499                failed_msr: msrs.get(completed).copied().unwrap().0,
1500                write: true,
1501            });
1502        }
1503        Ok(())
1504    }
1505
1506    /// Configures the vCPU's machine-check capability register
1507    /// (`IA32_MCG_CAP`) via `KVM_X86_SETUP_MCE`.
1508    ///
1509    /// `mcg_cap` should only contain capability bits reported as supported by
1510    /// [`Kvm::supported_mce_cap`] (plus the bank count in the low byte);
1511    /// otherwise KVM returns `EINVAL`.
1512    #[cfg(target_arch = "x86_64")]
1513    pub fn setup_mce(&self, mcg_cap: u64) -> Result<()> {
1514        // SAFETY: passing a valid pointer to a u64 for the ioctl to read.
1515        unsafe {
1516            ioctl::kvm_x86_setup_mce(self.get().vcpu.as_raw_fd(), &mcg_cap)
1517                .map_err(Error::SetupMce)?;
1518        }
1519        Ok(())
1520    }
1521
1522    #[cfg(target_arch = "x86_64")]
1523    pub fn get_lapic(&self, state: &mut [u8; 1024]) -> Result<()> {
1524        assert_eq!(size_of_val(state), size_of::<kvm_lapic_state>());
1525
1526        // TODO: We are not checking KVM_CAP_IRQCHIP first.
1527        // SAFETY: We have verified that our output buffer is the correct size.
1528        unsafe {
1529            ioctl::kvm_get_lapic(self.get().vcpu.as_raw_fd(), state.as_mut_ptr().cast())
1530                .map_err(Error::GetLApic)?;
1531        }
1532        Ok(())
1533    }
1534
1535    #[cfg(target_arch = "x86_64")]
1536    pub fn set_lapic(&self, state: &[u8; 1024]) -> Result<()> {
1537        assert_eq!(size_of_val(state), size_of::<kvm_lapic_state>());
1538
1539        // TODO: We are not checking KVM_CAP_IRQCHIP first.
1540        // SAFETY: We have verified that our input buffer is the correct size.
1541        unsafe {
1542            ioctl::kvm_set_lapic(self.get().vcpu.as_raw_fd(), state.as_ptr().cast())
1543                .map_err(Error::SetLApic)?;
1544        }
1545        Ok(())
1546    }
1547
1548    #[cfg(target_arch = "x86_64")]
1549    pub fn get_xsave(&self, state: &mut [u8; 4096]) -> Result<()> {
1550        assert_eq!(size_of_val(state), size_of::<kvm_xsave>());
1551
1552        // TODO: We are not checking KVM_CAP_XSAVE2 first.
1553        // SAFETY: We have verified that our output buffer is the correct size.
1554        unsafe {
1555            ioctl::kvm_get_xsave(self.get().vcpu.as_raw_fd(), state.as_mut_ptr().cast())
1556                .map_err(Error::GetXsave)?;
1557        }
1558        Ok(())
1559    }
1560
1561    #[cfg(target_arch = "x86_64")]
1562    pub fn set_xsave(&self, state: &[u8; 4096]) -> Result<()> {
1563        assert_eq!(size_of_val(state), size_of::<kvm_xsave>());
1564
1565        // TODO: We are not checking KVM_CAP_XSAVE2 first.
1566        // SAFETY: We have verified that our input buffer is the correct size.
1567        unsafe {
1568            ioctl::kvm_set_xsave(self.get().vcpu.as_raw_fd(), state.as_ptr().cast())
1569                .map_err(Error::SetXsave)?;
1570        }
1571        Ok(())
1572    }
1573
1574    #[cfg(target_arch = "x86_64")]
1575    pub fn set_debug_regs(&self, regs: &DebugRegisters) -> Result<()> {
1576        let data = kvm_debugregs {
1577            db: regs.db,
1578            dr6: regs.dr6,
1579            dr7: regs.dr7,
1580            flags: 0,
1581            reserved: [0; 9],
1582        };
1583
1584        // TODO: We are not checking KVM_CAP_DEBUGREGS first.
1585        // SAFETY: Calling IOCTL as documented, with no special requirements.
1586        unsafe {
1587            ioctl::kvm_set_debugregs(self.get().vcpu.as_raw_fd(), &data)
1588                .map_err(Error::SetDebugRegs)?;
1589        }
1590        Ok(())
1591    }
1592
1593    #[cfg(target_arch = "x86_64")]
1594    pub fn get_debug_regs(&self) -> Result<DebugRegisters> {
1595        let mut data = Default::default();
1596
1597        // TODO: We are not checking KVM_CAP_DEBUGREGS first.
1598        // SAFETY: Calling IOCTL as documented, with no special requirements.
1599        unsafe {
1600            ioctl::kvm_get_debugregs(self.get().vcpu.as_raw_fd(), &mut data)
1601                .map_err(Error::GetDebugRegs)?;
1602        }
1603
1604        Ok(DebugRegisters {
1605            db: data.db,
1606            dr6: data.dr6,
1607            dr7: data.dr7,
1608        })
1609    }
1610
1611    #[cfg(target_arch = "x86_64")]
1612    pub fn set_xcr0(&self, value: u64) -> Result<()> {
1613        let mut data = kvm_xcrs {
1614            nr_xcrs: 1,
1615            ..Default::default()
1616        };
1617        data.xcrs[0] = kvm_xcr {
1618            xcr: 0,
1619            reserved: 0,
1620            value,
1621        };
1622
1623        // TODO: We are not checking KVM_CAP_XCRS first.
1624        // SAFETY: Calling IOCTL as documented, with no special requirements.
1625        unsafe {
1626            ioctl::kvm_set_xcrs(self.get().vcpu.as_raw_fd(), &data).map_err(Error::GetXcrs)?;
1627        }
1628        Ok(())
1629    }
1630
1631    #[cfg(target_arch = "x86_64")]
1632    pub fn get_xcr0(&self) -> Result<u64> {
1633        let mut data = Default::default();
1634
1635        // TODO: We are not checking KVM_CAP_XCRS first.
1636        // SAFETY: Calling IOCTL as documented, with no special requirements.
1637        unsafe {
1638            ioctl::kvm_get_xcrs(self.get().vcpu.as_raw_fd(), &mut data).map_err(Error::SetXcrs)?;
1639        }
1640
1641        if data.nr_xcrs < 1 {
1642            return Err(Error::XsaveNotEnabled);
1643        }
1644        assert_eq!(data.nr_xcrs, 1);
1645        assert_eq!(data.xcrs[0].xcr, 0);
1646        Ok(data.xcrs[0].value)
1647    }
1648
1649    pub fn set_mp_state(&self, state: u32) -> Result<()> {
1650        let state = kvm_mp_state { mp_state: state };
1651        // TODO: We are not checking KVM_CAP_MP_STATE first.
1652        // SAFETY: Calling IOCTL as documented, with no special requirements.
1653        unsafe {
1654            ioctl::kvm_set_mp_state(self.get().vcpu.as_raw_fd(), &state)
1655                .map_err(Error::SetMpState)?;
1656        }
1657        Ok(())
1658    }
1659
1660    pub fn get_mp_state(&self) -> Result<u32> {
1661        let mut state = Default::default();
1662        // TODO: We are not checking KVM_CAP_MP_STATE first.
1663        // SAFETY: Calling IOCTL as documented, with no special requirements.
1664        unsafe {
1665            ioctl::kvm_get_mp_state(self.get().vcpu.as_raw_fd(), &mut state)
1666                .map_err(Error::GetMpState)?;
1667        }
1668        Ok(state.mp_state)
1669    }
1670
1671    pub fn set_vcpu_events(&self, events: &kvm_vcpu_events) -> Result<()> {
1672        // TODO: We are not checking KVM_CAP_VCPU_EVENTS first.
1673        // SAFETY: Calling IOCTL as documented, with no special requirements.
1674        unsafe {
1675            ioctl::kvm_set_vcpu_events(self.get().vcpu.as_raw_fd(), events)
1676                .map_err(Error::SetVcpuEvents)?;
1677        }
1678        Ok(())
1679    }
1680
1681    pub fn get_vcpu_events(&self) -> Result<kvm_vcpu_events> {
1682        let mut events = Default::default();
1683        // TODO: We are not checking KVM_CAP_VCPU_EVENTS first.
1684        // SAFETY: Calling IOCTL as documented, with no special requirements.
1685        unsafe {
1686            ioctl::kvm_get_vcpu_events(self.get().vcpu.as_raw_fd(), &mut events)
1687                .map_err(Error::GetVcpuEvents)?;
1688        }
1689        Ok(events)
1690    }
1691
1692    pub fn translate_gva(&self, gva: u64) -> Result<kvm_translation> {
1693        let mut translation = kvm_translation {
1694            linear_address: gva,
1695            ..Default::default()
1696        };
1697
1698        // SAFETY: Calling IOCTL as documented, with no special requirements.
1699        unsafe {
1700            ioctl::kvm_translation(self.get().vcpu.as_raw_fd(), &mut translation)
1701                .map_err(Error::TranslateGva)?;
1702        }
1703
1704        Ok(translation)
1705    }
1706
1707    /// Sets the guest debugging state: `control` bits `KVM_GUESTDBG_*`, `db`
1708    /// containing DR0 through DR3, and `dr7`.
1709    #[cfg(target_arch = "x86_64")]
1710    pub fn set_guest_debug(&self, control: u32, db: [u64; 4], dr7: u64) -> Result<()> {
1711        // N.B. Debug registers 4 through 6 are not used by KVM in this path.
1712        let debug = kvm_guest_debug {
1713            control,
1714            pad: 0,
1715            arch: kvm_guest_debug_arch {
1716                debugreg: [db[0], db[1], db[2], db[3], 0, 0, 0, dr7],
1717            },
1718        };
1719
1720        // TODO: We are not checking KVM_CAP_SET_GUEST_DEBUG first.
1721        // SAFETY: Calling IOCTL as documented, with no special requirements.
1722        unsafe {
1723            ioctl::kvm_set_guest_debug(self.get().vcpu.as_raw_fd(), &debug)
1724                .map_err(Error::GetRegs)?;
1725        }
1726        Ok(())
1727    }
1728
1729    /// # Safety
1730    ///
1731    /// `addr` must point to the appropriate input for the attribute being
1732    /// set.
1733    pub unsafe fn set_device_attr<T>(
1734        &self,
1735        group: u32,
1736        attr: u32,
1737        addr: &T,
1738        flags: u32,
1739    ) -> nix::Result<libc::c_int> {
1740        // SAFETY: caller guaranteed.
1741        unsafe {
1742            ioctl::kvm_set_device_attr(
1743                self.get().vcpu.as_raw_fd(),
1744                &kvm_device_attr {
1745                    group,
1746                    attr: attr as u64,
1747                    addr: std::ptr::from_ref(addr) as u64,
1748                    flags,
1749                },
1750            )
1751        }
1752    }
1753
1754    pub fn runner(&self) -> VpRunner<'a> {
1755        // Ensure this thread is uniquely running the VP, and store the thread
1756        // ID to support cancellation.
1757        assert!(
1758            self.get()
1759                .thread
1760                .write()
1761                .replace(Pthread::current())
1762                .is_none()
1763        );
1764
1765        VpRunner {
1766            partition: self.0,
1767            idx: self.1,
1768            _not_send_sync: PhantomData,
1769        }
1770    }
1771}
1772
1773pub struct VpRunner<'a> {
1774    partition: &'a Partition,
1775    idx: u32,
1776    // This type stores the current thread in `partition` and removes it in
1777    // `drop`, so don't allow sending or sharing this.
1778    _not_send_sync: PhantomData<*const u8>,
1779}
1780
1781impl Drop for VpRunner<'_> {
1782    fn drop(&mut self) {
1783        // The thread is no longer in use.
1784        let thread = self.get().thread.write().take();
1785        assert_eq!(thread, Some(Pthread::current()));
1786    }
1787}
1788
1789impl<'a> VpRunner<'a> {
1790    fn get(&self) -> &'a Vp {
1791        self.partition.vp(self.idx).get()
1792    }
1793
1794    fn run_data(&mut self) -> &mut kvm_run {
1795        let vp = self.get();
1796        // SAFETY: there are no other references to this data right
1797        // now since this thread is uniquely processing the VP, and
1798        // the VP is not running (so the kernel is not mutating the
1799        // structure either).
1800        unsafe { &mut *vp.run_data.ptr }
1801    }
1802
1803    #[cfg_attr(target_arch = "aarch64", expect(dead_code))]
1804    fn run_data_slice(&mut self) -> &mut [u8] {
1805        let vp = self.get();
1806        // SAFETY: there are no other references to this data right
1807        // now since this thread is uniquely processing the VP, and
1808        // the VP is not running (so the kernel is not mutating the
1809        // structure either).
1810        unsafe { std::slice::from_raw_parts_mut(vp.run_data.ptr.cast::<u8>(), vp.run_data.len) }
1811    }
1812
1813    /// Issues an IOCTL to run the VP.
1814    fn run_vp_once(&mut self) -> Result<bool> {
1815        CURRENT_KVM_RUN.with(|r| {
1816            let vp = self.get();
1817
1818            // Clear immediate_exit before giving up exclusive ownership of the
1819            // kvm_run structure.
1820            self.run_data().immediate_exit = 0;
1821
1822            // Swap the kvm_run structure pointer in so the signal handler can set
1823            // immediate_exit if the signal arrives just before the kvm_run ioctl.
1824            match r.swap(vp.run_data.ptr as usize, Ordering::Relaxed) {
1825                NO_KVM_RUN => {}
1826                CANCEL_KVM_RUN => {
1827                    // A cancel request signal arrived before the swap. Set
1828                    // immediate_exit so that any pending exit gets completed,
1829                    // and then the IOCTL returns before actually running the
1830                    // VP.
1831                    //
1832                    // The kvm_run structure is now aliased, so don't call
1833                    // `run_data()` to get it.
1834                    //
1835                    // SAFETY: the signal thread that might access the structure
1836                    // will also use `set_immediate_exit`.
1837                    unsafe { set_immediate_exit(vp.run_data.ptr) };
1838                }
1839                state => unreachable!("unexpected state {:#x}", state),
1840            }
1841
1842            // SAFETY: Calling IOCTL as documented, with no special requirements.
1843            let result = unsafe { ioctl::kvm_run(vp.vcpu.as_raw_fd(), 0) };
1844            CURRENT_KVM_RUN.with(|r| r.store(NO_KVM_RUN, Ordering::Relaxed));
1845            match result {
1846                Ok(_) => Ok(true),
1847                Err(err) => match err {
1848                    nix::errno::Errno::EINTR | nix::errno::Errno::EAGAIN => Ok(false),
1849                    _ if self.run_data().exit_reason == KVM_EXIT_MEMORY_FAULT => {
1850                        // SAFETY: KVM reported KVM_EXIT_MEMORY_FAULT, so this is the active union field.
1851                        let memory_fault = unsafe { self.run_data().__bindgen_anon_1.memory_fault };
1852                        Err(Error::RunMemoryFault {
1853                            flags: memory_fault.flags,
1854                            gpa: memory_fault.gpa,
1855                            size: memory_fault.size,
1856                            source: err,
1857                        })
1858                    }
1859                    _ => Err(Error::Run(err)),
1860                },
1861            }
1862        })
1863    }
1864
1865    /// Completes the current exit without running the VP further.
1866    ///
1867    /// This may generate more exits.
1868    pub fn complete_exit(&mut self) -> Result<Exit<'_>, Error> {
1869        CURRENT_KVM_RUN.with(|run| run.store(CANCEL_KVM_RUN, Ordering::Relaxed));
1870        self.run()
1871    }
1872
1873    /// Continues running the VP.
1874    ///
1875    /// Runs until an exit occurs or interrupted by a signal or a call to
1876    /// [`Processor::force_exit`].
1877    pub fn run(&mut self) -> Result<Exit<'_>, Error> {
1878        if !self.run_vp_once()? {
1879            return Ok(Exit::Interrupted);
1880        }
1881
1882        let exit = match self.run_data().exit_reason {
1883            #[cfg(target_arch = "x86_64")]
1884            KVM_EXIT_DEBUG => {
1885                // SAFETY: no other references to this data.
1886                let debug = unsafe { &self.run_data().__bindgen_anon_1.debug };
1887
1888                Exit::Debug {
1889                    exception: debug.arch.exception,
1890                    pc: debug.arch.pc,
1891                    dr6: debug.arch.dr6,
1892                    dr7: debug.arch.dr7,
1893                }
1894            }
1895            #[cfg(target_arch = "x86_64")]
1896            KVM_EXIT_IO => {
1897                // SAFETY: this is the active union field.
1898                let io = unsafe { self.run_data().__bindgen_anon_1.io };
1899
1900                let offset = io.data_offset as usize;
1901                let data = &mut self.run_data_slice()
1902                    [offset..offset + io.size as usize * io.count as usize];
1903                if io.direction == KVM_EXIT_IO_IN as u8 {
1904                    Exit::IoIn {
1905                        port: io.port,
1906                        size: io.size,
1907                        data,
1908                    }
1909                } else {
1910                    Exit::IoOut {
1911                        port: io.port,
1912                        size: io.size,
1913                        data,
1914                    }
1915                }
1916            }
1917            #[cfg(target_arch = "x86_64")]
1918            KVM_EXIT_IRQ_WINDOW_OPEN => {
1919                let rdata = self.run_data();
1920                assert!(rdata.ready_for_interrupt_injection != 0);
1921                rdata.request_interrupt_window = 0;
1922                Exit::InterruptWindow
1923            }
1924            KVM_EXIT_MMIO => {
1925                // SAFETY: this is the active union field.
1926                let mmio = unsafe { &mut self.run_data().__bindgen_anon_1.mmio };
1927                if mmio.is_write != 0 {
1928                    Exit::MmioWrite {
1929                        address: mmio.phys_addr,
1930                        data: &mmio.data[0..mmio.len as usize],
1931                    }
1932                } else {
1933                    mmio.data = [0; 8];
1934                    Exit::MmioRead {
1935                        address: mmio.phys_addr,
1936                        data: &mut mmio.data[0..mmio.len as usize],
1937                    }
1938                }
1939            }
1940            KVM_EXIT_SHUTDOWN => Exit::Shutdown,
1941            #[cfg(target_arch = "x86_64")]
1942            KVM_EXIT_HYPERV => {
1943                // SAFETY: this is the active union field.
1944                let hyperv = unsafe { &mut self.run_data().__bindgen_anon_1.hyperv };
1945                match hyperv.type_ {
1946                    KVM_EXIT_HYPERV_HCALL => {
1947                        // SAFETY: this is the active union field.
1948                        let hcall = unsafe { &mut hyperv.u.hcall };
1949                        Exit::HvHypercall {
1950                            input: hcall.input,
1951                            result: &mut hcall.result,
1952                            params: hcall.params,
1953                        }
1954                    }
1955                    KVM_EXIT_HYPERV_SYNIC => {
1956                        // SAFETY: this is the active union field.
1957                        let synic = unsafe { &hyperv.u.synic };
1958                        Exit::SynicUpdate {
1959                            msr: synic.msr,
1960                            control: synic.control,
1961                            siefp: synic.evt_page,
1962                            simp: synic.msg_page,
1963                        }
1964                    }
1965                    _ => return Err(Error::UnknownHvExit(hyperv.type_)),
1966                }
1967            }
1968            #[cfg(target_arch = "x86_64")]
1969            KVM_EXIT_IOAPIC_EOI => {
1970                // SAFETY: this is the active union field.
1971                let eoi = unsafe { &mut self.run_data().__bindgen_anon_1.eoi };
1972
1973                Exit::Eoi { irq: eoi.vector }
1974            }
1975            KVM_EXIT_FAIL_ENTRY => {
1976                // SAFETY: this is the active union field.
1977                let fail_entry = unsafe { &self.run_data().__bindgen_anon_1.fail_entry };
1978                Exit::FailEntry {
1979                    hardware_entry_failure_reason: fail_entry.hardware_entry_failure_reason,
1980                }
1981            }
1982            KVM_EXIT_INTERNAL_ERROR => {
1983                // SAFETY: this is the active union field.
1984                let internal = unsafe { &self.run_data().__bindgen_anon_1.internal };
1985                if internal.suberror == KVM_INTERNAL_ERROR_EMULATION {
1986                    // FUTURE: update bindings and get the instruction bytes when they are present.
1987                    Exit::EmulationFailure {
1988                        instruction_bytes: &[],
1989                    }
1990                } else {
1991                    Exit::InternalError {
1992                        error: internal.suberror,
1993                        data: &internal.data[..internal.ndata as usize],
1994                    }
1995                }
1996            }
1997            #[cfg(target_arch = "x86_64")]
1998            KVM_EXIT_HYPERCALL => {
1999                // SAFETY: this is the active union field.
2000                let hypercall = unsafe { &mut self.run_data().__bindgen_anon_1.hypercall };
2001                Exit::Hypercall {
2002                    nr: hypercall.nr,
2003                    args: hypercall.args,
2004                    result: &mut hypercall.ret,
2005                    // SAFETY: this is the active field for KVM_EXIT_HYPERCALL.
2006                    flags: unsafe { hypercall.__bindgen_anon_1.flags },
2007                }
2008            }
2009            #[cfg(target_arch = "x86_64")]
2010            KVM_EXIT_X86_WRMSR => {
2011                // SAFETY: this is the active union field.
2012                let msr = unsafe { &mut self.run_data().__bindgen_anon_1.msr };
2013                msr.error = 0;
2014                Exit::MsrWrite {
2015                    index: msr.index,
2016                    data: msr.data,
2017                    error: &mut msr.error,
2018                }
2019            }
2020            #[cfg(target_arch = "x86_64")]
2021            KVM_EXIT_X86_RDMSR => {
2022                // SAFETY: this is the active union field.
2023                let msr = unsafe { &mut self.run_data().__bindgen_anon_1.msr };
2024                msr.data = 0;
2025                msr.error = 0;
2026                Exit::MsrRead {
2027                    index: msr.index,
2028                    data: &mut msr.data,
2029                    error: &mut msr.error,
2030                }
2031            }
2032            KVM_EXIT_SYSTEM_EVENT => {
2033                // SAFETY: this is the active union field.
2034                let system_event = unsafe { &self.run_data().__bindgen_anon_1.system_event };
2035                Exit::SystemEvent {
2036                    event_type: system_event.type_,
2037                    // SAFETY: accessing the flags field of the union.
2038                    event_flags: unsafe { system_event.__bindgen_anon_1.flags },
2039                }
2040            }
2041            exit_reason => return Err(Error::UnknownExit(exit_reason)),
2042        };
2043        Ok(exit)
2044    }
2045
2046    /// Request an exit when the interrupt window opens.
2047    ///
2048    /// Returns true if the window is already open (in which case the request is
2049    /// not registered).
2050    #[must_use]
2051    pub fn check_or_request_interrupt_window(&mut self) -> bool {
2052        let rdata = self.run_data();
2053        if rdata.ready_for_interrupt_injection != 0 {
2054            true
2055        } else {
2056            rdata.request_interrupt_window = 1;
2057            false
2058        }
2059    }
2060
2061    /// Injects an extint interrupt.
2062    ///
2063    /// Caller must ensure that either it has received a
2064    /// [`Exit::InterruptWindow`] exit, or that
2065    /// [`Self::check_or_request_interrupt_window`] has returned `true`.
2066    pub fn inject_extint_interrupt(&mut self, vector: u8) -> Result<()> {
2067        self.partition.vp(self.idx).interrupt(vector.into())?;
2068        // Remember that there is a pending extint interrupt. KVM will update
2069        // this field again after the VP runs.
2070        self.run_data().ready_for_interrupt_injection = 0;
2071        Ok(())
2072    }
2073}
2074
2075#[derive(Debug)]
2076pub enum Exit<'a> {
2077    Interrupted,
2078    #[cfg(target_arch = "x86_64")]
2079    InterruptWindow,
2080    #[cfg(target_arch = "x86_64")]
2081    IoIn {
2082        port: u16,
2083        size: u8,
2084        data: &'a mut [u8],
2085    },
2086    #[cfg(target_arch = "x86_64")]
2087    IoOut {
2088        port: u16,
2089        size: u8,
2090        data: &'a [u8],
2091    },
2092    MmioRead {
2093        address: u64,
2094        data: &'a mut [u8],
2095    },
2096    MmioWrite {
2097        address: u64,
2098        data: &'a [u8],
2099    },
2100    #[cfg(target_arch = "x86_64")]
2101    Hypercall {
2102        nr: u64,
2103        args: [u64; 6],
2104        result: &'a mut u64,
2105        flags: u64,
2106    },
2107    #[cfg(target_arch = "x86_64")]
2108    MsrRead {
2109        index: u32,
2110        data: &'a mut u64,
2111        error: &'a mut u8,
2112    },
2113    #[cfg(target_arch = "x86_64")]
2114    MsrWrite {
2115        index: u32,
2116        data: u64,
2117        error: &'a mut u8,
2118    },
2119    Shutdown,
2120    FailEntry {
2121        hardware_entry_failure_reason: u64,
2122    },
2123    InternalError {
2124        error: u32,
2125        data: &'a [u64],
2126    },
2127    EmulationFailure {
2128        instruction_bytes: &'a [u8],
2129    },
2130    #[cfg(target_arch = "x86_64")]
2131    SynicUpdate {
2132        msr: u32,
2133        control: u64,
2134        siefp: u64,
2135        simp: u64,
2136    },
2137    #[cfg(target_arch = "x86_64")]
2138    HvHypercall {
2139        input: u64,
2140        result: &'a mut u64,
2141        params: [u64; 2],
2142    },
2143    #[cfg(target_arch = "x86_64")]
2144    Debug {
2145        exception: u32,
2146        pc: u64,
2147        dr6: u64,
2148        dr7: u64,
2149    },
2150    #[cfg(target_arch = "x86_64")]
2151    Eoi {
2152        irq: u8,
2153    },
2154    SystemEvent {
2155        event_type: u32,
2156        event_flags: u64,
2157    },
2158}
2159
2160/// Set up a signal used to cause KVM run_vp to return.
2161pub fn init() {
2162    static SIGNAL_HANDLER_INIT: Once = Once::new();
2163    SIGNAL_HANDLER_INIT.call_once(|| {
2164        let handler = || {
2165            CURRENT_KVM_RUN.with(|run| {
2166                // This interrupts the other code that accesses CURRENT_KVM_RUN, so a
2167                // compare_exchange is not necessary.
2168                let rdata = run.load(Ordering::Relaxed);
2169                match rdata {
2170                    NO_KVM_RUN => run.store(CANCEL_KVM_RUN, Ordering::Relaxed),
2171                    CANCEL_KVM_RUN => {}
2172                    _ => {
2173                        // SAFETY: other concurrent accesses to the structure are via
2174                        // `set_immediate_exit` or via atomic accesses in the kernel.
2175                        unsafe { set_immediate_exit(rdata as *mut kvm_run) };
2176                    }
2177                }
2178            })
2179        };
2180        // Ensure the thread local is initialized.
2181        CURRENT_KVM_RUN.with(|value| {
2182            std::hint::black_box(value);
2183        });
2184        // SAFETY: The signal handler does not perform any actions that are forbidden
2185        // for signal handlers to perform, as it only performs thread-local and atomic
2186        // reads and writes. We are guaranteed to not interrupt thread local initialization
2187        // as we have ensured it is initialized above.
2188        unsafe {
2189            signal_hook::low_level::register(libc::SIGRTMIN(), handler).unwrap();
2190        }
2191    });
2192}
2193
2194const NO_KVM_RUN: usize = 0;
2195const CANCEL_KVM_RUN: usize = 1;
2196
2197thread_local! {
2198    static CURRENT_KVM_RUN: AtomicUsize = const { AtomicUsize::new(NO_KVM_RUN) };
2199}
2200
2201/// Sets `rdata.immediate_exit` to 1 without constructing a mutable reference.
2202///
2203/// This can be used when the kvm_run is aliased by the kernel or by other
2204/// threads that might call this function.
2205#[expect(clippy::missing_safety_doc)]
2206unsafe fn set_immediate_exit(rdata: *mut kvm_run) {
2207    // SAFETY: rdata may be aliased by the kernel right now, so it's
2208    // not safe to construct a mutable reference to it. Use an
2209    // atomic store to carefully write without requiring a mutable
2210    // reference.
2211    unsafe {
2212        (*(std::ptr::addr_of!((*rdata).immediate_exit).cast::<AtomicU8>()))
2213            .store(1, Ordering::Relaxed);
2214    }
2215}
2216
2217pub struct DebugRegisters {
2218    /// DR0-3.
2219    pub db: [u64; 4],
2220    pub dr6: u64,
2221    pub dr7: u64,
2222}
2223
2224#[cfg(all(test, target_arch = "x86_64"))]
2225mod tests {
2226    use super::*;
2227
2228    #[test]
2229    fn sev_snp_page_type_values_match_kvm_uapi() {
2230        assert_eq!(SevSnpPageType::Normal.as_uapi(), 1);
2231        assert_eq!(SevSnpPageType::Zero.as_uapi(), 3);
2232        assert_eq!(SevSnpPageType::Unmeasured.as_uapi(), 4);
2233        assert_eq!(SevSnpPageType::Secrets.as_uapi(), 5);
2234        assert_eq!(SevSnpPageType::Cpuid.as_uapi(), 6);
2235    }
2236
2237    #[test]
2238    fn sev_snp_launch_update_uses_expected_zero_page_shape() {
2239        let update = kvm_sev_snp_launch_update {
2240            gfn_start: 0x1234,
2241            uaddr: 0,
2242            len: 0x2000,
2243            type_: SevSnpPageType::Zero.as_uapi(),
2244            ..Default::default()
2245        };
2246
2247        assert_eq!(update.gfn_start, 0x1234);
2248        assert_eq!(update.uaddr, 0);
2249        assert_eq!(update.len, 0x2000);
2250        assert_eq!(update.type_, KVM_SEV_SNP_PAGE_TYPE_ZERO_UAPI);
2251        assert_eq!(update.flags, 0);
2252    }
2253}