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