linux-kvm 0.7.0

Safe API to the Linux KVM API.
Documentation
//! Raw data types for use with various KVM `ioctl` requests.

use linux_unsafe::ulong;

/// The layout of the shared memory region used to communicate with the
/// `KVM_RUN` ioctl request, which is `mmap`ed from the VCPU's file descriptor.
#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
#[repr(C)]
pub struct kvm_run {
    pub request_interrupt_window: u8,
    pub immediate_exit: u8,
    pub padding1: [u8; 6],
    pub exit_reason: u32,
    pub ready_for_interrupt_injection: u8,
    pub if_flag: u8,
    pub flags: u16,
    pub cr8: u64,
    pub apic_base: u64,

    #[cfg(target_arch = "s390x")]
    pub psw_mask: u64,
    #[cfg(target_arch = "s390x")]
    pub psw_addr: u64,

    pub exit_details: ExitDetails,
}

impl core::fmt::Debug for kvm_run {
    #[inline(never)]
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        let mut ds = f.debug_struct("kvm_run");
        ds.field("request_interrupt_window", &self.request_interrupt_window)
            .field("immediate_exit", &self.immediate_exit)
            .field("padding1", &self.padding1)
            .field("exit_reason", &self.exit_reason)
            .field(
                "ready_for_interrupt_injection",
                &self.ready_for_interrupt_injection,
            )
            .field("if_flag", &self.if_flag)
            .field("flags", &self.flags)
            .field("cr8", &self.cr8)
            .field("apic_base", &self.apic_base);

        #[cfg(target_arch = "s390x")]
        {
            ds.field("psw_mask", &self.psw_mask)
                .field("psw_addr", &self.psw_addr);
        }

        #[cfg(not(feature = "nightly"))]
        ds.field("exit_details", &self.exit_details);
        // more useful debug info when DebugStruct.field_with is available
        #[cfg(feature = "nightly")]
        ds.field_with(
            "exit_details",
            #[inline(never)]
            |f| {
                let mut ds = f.debug_struct("ExitDetails");
                // The following is technically unsound because all of the fields
                // are pub and so it's possible to construct a value where
                // exit_reason disagrees with exit_details, but all of the variants
                // are just plain data without any implicit padding and with
                // field types where all bit patterns are valid, so this should
                // be okay in practice and makes this debug output far more useful.
                match self.exit_reason {
                    0 => ds.field("hw", unsafe { &self.exit_details.hw }).finish(),
                    1 => ds
                        .field("exception", unsafe { &self.exit_details.ex })
                        .finish(),
                    2 => ds.field("io", unsafe { &self.exit_details.io }).finish(),
                    4 => ds
                        .field("debug", unsafe { &self.exit_details.debug })
                        .finish(),
                    6 => ds
                        .field("mmio", unsafe { &self.exit_details.mmio })
                        .finish(),
                    9 => ds
                        .field("fail_entry", unsafe { &self.exit_details.fail_entry })
                        .finish(),
                    24 => ds
                        .field("system_event", unsafe { &self.exit_details.system_event })
                        .finish(),
                    35 => ds
                        .field("riscv_sbi", unsafe { &self.exit_details.riscv_sbi })
                        .finish(),
                    36 => ds
                        .field("riscv_csr", unsafe { &self.exit_details.riscv_csr })
                        .finish(),
                    37 => ds
                        .field("notify", unsafe { &self.exit_details.notify })
                        .finish(),
                    39 => ds
                        .field("memory_fault", unsafe { &self.exit_details.memory_fault })
                        .finish(),
                    _ => ds.finish_non_exhaustive(),
                }
            },
        );
        ds.finish()
    }
}

#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct kvm_userspace_memory_region {
    pub slot: u32,
    pub flags: u32,
    pub guest_phys_addr: u64,
    pub memory_size: u64,    // in bytes
    pub userspace_addr: u64, // start of the userspace allocated memory
}

#[cfg(target_arch = "x86_64")]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct kvm_regs {
    pub rax: u64,
    pub rbx: u64,
    pub rcx: u64,
    pub rdx: u64,
    pub rsi: u64,
    pub rdi: u64,
    pub rsp: u64,
    pub rbp: u64,
    pub r8: u64,
    pub r9: u64,
    pub r10: u64,
    pub r11: u64,
    pub r12: u64,
    pub r13: u64,
    pub r14: u64,
    pub r15: u64,
    pub rip: u64,
    pub rflags: u64,
}

#[cfg(target_arch = "aarch64")]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct kvm_regs {
    pub regs: aarch64_user_pt_regs,
    pub sp_el1: u64,
    pub elr_el1: u64,
    pub spsr: [u64; 5],
    pub fp_regs: aarch64_user_fpsimd_state,
}

#[cfg(target_arch = "aarch64")]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct aarch64_user_pt_regs {
    pub regs: [u64; 31],
    pub sp: u64,
    pub pc: u64,
    pub pstate: u64,
}

#[cfg(target_arch = "aarch64")]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct aarch64_user_fpsimd_state {
    pub vregs: [u128; 32],
    pub fpsr: u32,
    pub fpcr: u32,
    pub __reserved: [u32; 2],
}

#[cfg(target_arch = "riscv64")]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct kvm_regs {
    // The RISC-V port does not support getting/setting
    // all registers together. It only supports individual
    // register accesses using the GET_ONE_REG/SET_ONE_REG operations.
}

#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct kvm_one_reg {
    pub id: u64,
    pub addr: u64,
}

#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct kvm_debug_exit_arch {
    // TODO: Use conditional compilation to vary this by target architecture,
    // for those that actually use this.
}

/// Used for the `exit_details` field of [`kvm_run`].
#[derive(Clone, Copy)]
#[repr(C)]
pub union ExitDetails {
    pub hw: ExitUnknown,
    pub fail_entry: ExitFailEntry,
    pub ex: ExitException,
    pub io: ExitIo,
    pub debug: ExitDebug,
    pub mmio: ExitMmio,
    pub system_event: ExitSystemEvent,
    pub riscv_sbi: ExitRiscvSbi,
    pub riscv_csr: ExitRiscvCsr,
    pub notify: ExitNotify,
    pub memory_fault: ExitMemoryFault,
    // TODO: The rest of these
    pub padding: [linux_unsafe::char; 256],
}

impl core::fmt::Debug for ExitDetails {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        f.debug_struct("ExitDetails").finish_non_exhaustive()
    }
}

#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct ExitUnknown {
    pub hardware_exit_reason: u64,
}

#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct ExitFailEntry {
    pub hardware_entry_failure_reason: u64,
    pub cpu: u32,
}

#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct ExitException {
    pub exception: u32,
    pub error_code: u32,
}

#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct ExitIo {
    pub direction: u8,
    pub size: u8,
    pub port: u16,
    pub count: u32,
    pub data_offset: u64,
}

#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct ExitDebug {
    pub arch: kvm_debug_exit_arch,
}

#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct ExitMmio {
    pub phys_addr: u64,
    pub data: [u8; 8],
    pub len: u32,
    pub is_write: u8,
}

#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct ExitSystemEvent {
    pub type_: u32,
    pub ndata: u32,
    pub data: [u64; 16],
}

#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct ExitRiscvSbi {
    pub extension_id: ulong,
    pub function_id: ulong,
    pub args: [ulong; 6],
    pub ret: [ulong; 2],
}

#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct ExitRiscvCsr {
    pub csr_num: ulong,
    pub new_value: ulong,
    pub write_mask: ulong,
    pub ret_value: ulong,
}

#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct ExitNotify {
    pub flags: u32,
}

#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct ExitMemoryFault {
    pub flags: u32,
    pub gpa: u32,
    pub size: u32,
}