diff --git a/mshv-bindings/src/hvcall.rs b/mshv-bindings/src/hvcall.rs index 00c3d33..f169e3f 100644 --- a/mshv-bindings/src/hvcall.rs +++ b/mshv-bindings/src/hvcall.rs @@ -47,6 +47,7 @@ pub struct RepInput { size: usize, rep_count: usize, } + impl RepInput { /// Create a RepInput for a rep hypercall /// diff --git a/mshv-bindings/src/x86_64/regs.rs b/mshv-bindings/src/x86_64/regs.rs index 6ba5dd8..e8a1c90 100644 --- a/mshv-bindings/src/x86_64/regs.rs +++ b/mshv-bindings/src/x86_64/regs.rs @@ -389,6 +389,7 @@ pub struct VcpuEvents { pub pending_event0: [u8; 16usize], pub pending_event1: [u8; 16usize], } + #[repr(C)] #[derive(Debug, Default, Copy, Clone, Eq, PartialEq, AsBytes, FromBytes, FromZeroes)] #[cfg_attr(feature = "with-serde", derive(Deserialize, Serialize))] @@ -408,6 +409,7 @@ pub struct hv_cpuid_entry { pub edx: __u32, pub padding: [__u32; 3usize], } + #[repr(C)] #[derive(Debug, Default)] #[cfg_attr(feature = "with-serde", derive(Deserialize, Serialize))] @@ -496,6 +498,7 @@ impl Drop for Buffer { pub struct LapicState { pub regs: [::std::os::raw::c_char; 1024usize], } + impl Default for LapicState { fn default() -> Self { unsafe { ::std::mem::zeroed() } @@ -674,6 +677,7 @@ pub struct SuspendRegisters { pub explicit_register: u64, pub intercept_register: u64, } + #[repr(C)] #[derive(Debug, Default, Copy, Clone, Eq, PartialEq, AsBytes, FromBytes, FromZeroes)] #[cfg_attr(feature = "with-serde", derive(Deserialize, Serialize))] diff --git a/mshv-bindings/src/x86_64/serializers.rs b/mshv-bindings/src/x86_64/serializers.rs index 4979e32..9988a8b 100644 --- a/mshv-bindings/src/x86_64/serializers.rs +++ b/mshv-bindings/src/x86_64/serializers.rs @@ -96,6 +96,7 @@ mod tests { .zip(d_state.regs.iter()) .all(|(a, b)| a == b)); } + #[test] fn test_xsave_serialization_deserialization() { let mut xsave = XSave { diff --git a/mshv-bindings/src/x86_64/unmarshal.rs b/mshv-bindings/src/x86_64/unmarshal.rs index 35f25c4..ca468b7 100644 --- a/mshv-bindings/src/x86_64/unmarshal.rs +++ b/mshv-bindings/src/x86_64/unmarshal.rs @@ -20,6 +20,7 @@ impl hv_message { unsafe { std::ptr::read_unaligned(std::ptr::addr_of!(self.u.payload) as *const _) }; Ok(ret) } + #[inline] pub fn to_memory_info(&self) -> Result { if self.header.message_type != hv_message_type_HVMSG_GPA_INTERCEPT @@ -35,6 +36,7 @@ impl hv_message { unsafe { std::ptr::read_unaligned(std::ptr::addr_of!(self.u.payload) as *const _) }; Ok(ret) } + #[inline] pub fn to_gpa_attribute_info(&self) -> Result { if self.header.message_type != hv_message_type_HVMSG_GPA_ATTRIBUTE_INTERCEPT { @@ -47,6 +49,7 @@ impl hv_message { unsafe { std::ptr::read_unaligned(std::ptr::addr_of!(self.u.payload) as *const _) }; Ok(ret) } + #[inline] pub fn to_ioport_info(&self) -> Result { if self.header.message_type != hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT { @@ -59,6 +62,7 @@ impl hv_message { unsafe { std::ptr::read_unaligned(std::ptr::addr_of!(self.u.payload) as *const _) }; Ok(ret) } + #[inline] pub fn to_msr_info(&self) -> Result { if self.header.message_type != hv_message_type_HVMSG_X64_MSR_INTERCEPT { @@ -71,6 +75,7 @@ impl hv_message { unsafe { std::ptr::read_unaligned(std::ptr::addr_of!(self.u.payload) as *const _) }; Ok(ret) } + #[inline] pub fn to_exception_info(&self) -> Result { if self.header.message_type != hv_message_type_HVMSG_X64_EXCEPTION_INTERCEPT { @@ -83,6 +88,7 @@ impl hv_message { unsafe { std::ptr::read_unaligned(std::ptr::addr_of!(self.u.payload) as *const _) }; Ok(ret) } + #[inline] pub fn to_invalid_vp_register_info(&self) -> Result { if self.header.message_type != hv_message_type_HVMSG_INVALID_VP_REGISTER_VALUE { @@ -95,6 +101,7 @@ impl hv_message { unsafe { std::ptr::read_unaligned(std::ptr::addr_of!(self.u.payload) as *const _) }; Ok(ret) } + #[inline] pub fn to_unrecoverable_exception_info( &self, @@ -109,6 +116,7 @@ impl hv_message { unsafe { std::ptr::read_unaligned(std::ptr::addr_of!(self.u.payload) as *const _) }; Ok(ret) } + #[inline] pub fn to_interruption_deliverable_info( &self, @@ -123,6 +131,7 @@ impl hv_message { unsafe { std::ptr::read_unaligned(std::ptr::addr_of!(self.u.payload) as *const _) }; Ok(ret) } + #[inline] pub fn to_apic_eoi_info(&self) -> Result { if self.header.message_type != hv_message_type_HVMSG_X64_APIC_EOI { @@ -135,6 +144,7 @@ impl hv_message { unsafe { std::ptr::read_unaligned(std::ptr::addr_of!(self.u.payload) as *const _) }; Ok(ret) } + #[inline] pub fn to_hypercall_intercept_info(&self) -> Result { if self.header.message_type != hv_message_type_HVMSG_HYPERCALL_INTERCEPT { @@ -147,6 +157,7 @@ impl hv_message { unsafe { std::ptr::read_unaligned(std::ptr::addr_of!(self.u.payload) as *const _) }; Ok(ret) } + #[inline] pub fn to_sint_deliverable_info(&self) -> Result { if self.header.message_type != hv_message_type_HVMSG_SYNIC_SINT_DELIVERABLE { @@ -159,6 +170,7 @@ impl hv_message { unsafe { std::ptr::read_unaligned(std::ptr::addr_of!(self.u.payload) as *const _) }; Ok(ret) } + #[inline] pub fn to_vmg_intercept_info(&self) -> Result { if self.header.message_type != hv_message_type_HVMSG_X64_SEV_VMGEXIT_INTERCEPT { diff --git a/mshv-ioctls/src/ioctls/mod.rs b/mshv-ioctls/src/ioctls/mod.rs index fab0129..c2cfdc0 100644 --- a/mshv-ioctls/src/ioctls/mod.rs +++ b/mshv-ioctls/src/ioctls/mod.rs @@ -57,6 +57,7 @@ impl MshvError { } error.into() } + /// Convert to error code. Analogous to errno::Error::errno() pub fn errno(self) -> i32 { errno::Error::from(self).errno() @@ -130,6 +131,7 @@ mod tests { assert!(mshv_err == mshv_err_check); } } + #[test] fn test_errno_from_mshv_root_hvcall() { let args = mshv_root_hvcall { diff --git a/mshv-ioctls/src/ioctls/system.rs b/mshv-ioctls/src/ioctls/system.rs index 8977b93..f77a540 100644 --- a/mshv-ioctls/src/ioctls/system.rs +++ b/mshv-ioctls/src/ioctls/system.rs @@ -25,8 +25,8 @@ pub struct MshvPartitionBuilder { mshv_partition: mshv_create_partition, } +/// Synthetic processor features #[derive(Debug)] -/// pub enum SyntheticProcessorFeature { /// Report a hypervisor is present. HypervisorPresent, @@ -226,6 +226,7 @@ impl MshvPartitionBuilder { } self } + /// Builds the partition pub fn build(&self) -> mshv_create_partition { self.mshv_partition @@ -242,6 +243,7 @@ impl Mshv { let ret = unsafe { Self::new_with_fd_number(fd) }; Ok(ret) } + /// Creates a new Mshv object assuming `fd` represents an existing open file descriptor /// associated with `/dev/mshv`. /// @@ -408,6 +410,7 @@ impl Mshv { .unwrap()) } } + #[allow(dead_code)] #[cfg(test)] mod tests { @@ -421,6 +424,7 @@ mod tests { let vm = hv.create_vm(); assert!(vm.is_ok()); } + #[test] #[ignore] fn test_create_vm_with_default_config() { @@ -429,6 +433,7 @@ mod tests { let vm = hv.create_vm_with_config(&pr); assert!(vm.is_ok()); } + #[test] fn test_get_msr_index_list() { let hv = Mshv::new().unwrap(); diff --git a/mshv-ioctls/src/ioctls/vcpu.rs b/mshv-ioctls/src/ioctls/vcpu.rs index eb9ba32..98e83e6 100644 --- a/mshv-ioctls/src/ioctls/vcpu.rs +++ b/mshv-ioctls/src/ioctls/vcpu.rs @@ -1331,6 +1331,7 @@ mod tests { assert!(g_sregs.apic_base == s_sregs.apic_base); assert!(g_sregs.efer == s_sregs.efer); } + #[test] fn test_set_get_standardregisters() { let hv = Mshv::new().unwrap(); @@ -1345,6 +1346,7 @@ mod tests { assert!(g_regs.rcx == s_regs.rcx); assert!(g_regs.rdx == s_regs.rdx); } + #[test] fn test_set_get_debug_gisters() { let hv = Mshv::new().unwrap(); @@ -1361,6 +1363,7 @@ mod tests { assert!(g_regs.dr6 == s_regs.dr6); assert!(g_regs.dr7 == s_regs.dr7); } + #[cfg(target_arch = "x86_64")] #[test] fn test_set_get_fpu() { @@ -1389,6 +1392,7 @@ mod tests { assert!(g_regs.last_dp == s_regs.last_dp); assert!(g_regs.mxcsr == s_regs.mxcsr); } + #[cfg(target_arch = "x86_64")] #[test] fn test_run_code() { @@ -1537,6 +1541,7 @@ mod tests { vm.unmap_user_memory(mem_region).unwrap(); unsafe { libc::munmap(load_addr as *mut c_void, mem_size) }; } + #[test] fn test_set_get_msrs() { let hv = Mshv::new().unwrap(); @@ -1573,6 +1578,7 @@ mod tests { assert!(g_regs.as_slice()[0].data == s_regs.as_slice()[0].data); assert!(g_regs.as_slice()[1].data == s_regs.as_slice()[1].data); } + #[test] fn test_set_get_vcpu_events() { let hv = Mshv::new().unwrap(); @@ -1590,6 +1596,7 @@ mod tests { assert!(g_regs.pending_event1[i] == s_regs.pending_event1[i]); } } + #[test] fn test_set_get_xcrs() { let hv = Mshv::new().unwrap(); @@ -1601,6 +1608,7 @@ mod tests { let g_regs = vcpu.get_xcrs().unwrap(); assert!(g_regs.xcr0 == s_regs.xcr0); } + #[test] fn test_set_get_lapic() { let hv = Mshv::new().unwrap(); @@ -1614,6 +1622,7 @@ mod tests { assert!(state.regs[i] == g_state.regs[i]); } } + #[test] fn test_set_registers_64() { let hv = Mshv::new().unwrap(); @@ -1643,6 +1652,7 @@ mod tests { assert!(get_regs[1].value.reg64 == 0x2); } } + #[test] fn test_get_set_xsave() { let hv = Mshv::new().unwrap(); @@ -1653,6 +1663,7 @@ mod tests { vcpu.set_xsave(&state).unwrap(); } + #[test] fn test_get_suspend_regs() { let hv = Mshv::new().unwrap(); @@ -1664,6 +1675,7 @@ mod tests { assert!(regs.explicit_register == 0x1); assert!(regs.intercept_register == 0x0); } + #[test] fn test_set_get_misc_regs() { let hv = Mshv::new().unwrap(); @@ -1675,6 +1687,7 @@ mod tests { let g_regs = vcpu.get_misc_regs().unwrap(); assert!(g_regs.hypercall == s_regs.hypercall); } + #[test] fn test_get_cpuid_values() { let hv = Mshv::new().unwrap(); diff --git a/mshv-ioctls/src/ioctls/vm.rs b/mshv-ioctls/src/ioctls/vm.rs index e87117c..b7c7662 100644 --- a/mshv-ioctls/src/ioctls/vm.rs +++ b/mshv-ioctls/src/ioctls/vm.rs @@ -85,6 +85,7 @@ pub struct InterruptRequest { /// True means CPU is in long mode pub long_mode: bool, } + /// Wrapper over Mshv VM ioctls. #[derive(Debug)] pub struct VmFd { @@ -109,6 +110,7 @@ impl VmFd { Err(errno::Error::last().into()) } } + /// Modify host visibility for a range of GPA pub fn modify_gpa_host_access( &self, @@ -123,6 +125,7 @@ impl VmFd { Err(errno::Error::last().into()) } } + /// Import the isolated pages pub fn import_isolated_pages( &self, @@ -136,6 +139,7 @@ impl VmFd { Err(errno::Error::last().into()) } } + /// Mark completion of importing the isoalted pages pub fn complete_isolated_import(&self, data: &mshv_complete_isolated_import) -> Result<()> { // SAFETY: IOCTL with correct types @@ -146,6 +150,7 @@ impl VmFd { Err(errno::Error::last().into()) } } + /// Issue PSP request from guest side pub fn psp_issue_guest_request(&self, data: &mshv_issue_psp_guest_request) -> Result<()> { // SAFETY: IOCTL with correct types @@ -156,6 +161,7 @@ impl VmFd { Err(errno::Error::last().into()) } } + /// Create AP threads for SEV-SNP guest pub fn sev_snp_ap_create(&self, data: &mshv_sev_snp_ap_create) -> Result<()> { // SAFETY: IOCTL with correct types @@ -166,6 +172,7 @@ impl VmFd { Err(errno::Error::last().into()) } } + /// Creates/modifies a guest physical memory. pub fn map_user_memory(&self, user_memory_region: mshv_user_mem_region) -> Result<()> { // SAFETY: IOCTL with correct types @@ -176,6 +183,7 @@ impl VmFd { Err(errno::Error::last().into()) } } + /// Unmap a guest physical memory. pub fn unmap_user_memory(&self, user_memory_region: mshv_user_mem_region) -> Result<()> { // SAFETY: IOCTL with correct types @@ -186,6 +194,7 @@ impl VmFd { Err(errno::Error::last().into()) } } + /// Creates a new MSHV vCPU file descriptor pub fn create_vcpu(&self, id: u8) -> Result { let vp_arg = mshv_create_vp { @@ -204,6 +213,7 @@ impl VmFd { Ok(new_vcpu(id as u32, vcpu)) } + /// Inject an interrupt into the guest.. pub fn request_virtual_interrupt(&self, request: &InterruptRequest) -> Result<()> { let mut control_flags: u32 = 0; @@ -233,6 +243,7 @@ impl VmFd { Err(errno::Error::last().into()) } } + /// /// signal_event_direct: Send a sint signal event to the vp. pub fn signal_event_direct(&self, vp: u32, sint: u8, flag: u16) -> Result { @@ -251,6 +262,7 @@ impl VmFd { Err(errno::Error::last().into()) } } + /// /// post_message_direct: Post a message to the vp using a given sint. pub fn post_message_direct(&self, vp: u32, sint: u8, msg: &[u8]) -> Result<()> { @@ -269,6 +281,7 @@ impl VmFd { Err(errno::Error::last().into()) } } + /// /// register_deliverabilty_notifications: Register for a notification when /// hypervisor is ready to process more post_message_direct(s). @@ -292,6 +305,7 @@ impl VmFd { Err(errno::Error::last().into()) } } + /// irqfd: Passes in an eventfd which is to be used for injecting /// interrupts from userland. fn irqfd(&self, fd: RawFd, resamplefd: RawFd, gsi: u32, flags: u32) -> Result<()> { @@ -310,6 +324,7 @@ impl VmFd { Err(errno::Error::last().into()) } } + /// Registers an event that will, when signaled, trigger the `gsi` IRQ. /// /// # Arguments @@ -334,6 +349,7 @@ impl VmFd { pub fn register_irqfd(&self, fd: &EventFd, gsi: u32) -> Result<()> { self.irqfd(fd.as_raw_fd(), 0, gsi, 0) } + /// Registers an event that will, when signaled, assert the `gsi` IRQ. /// If the irqchip is resampled by the guest, the IRQ is de-asserted, /// and `resamplefd` is notified. @@ -373,6 +389,7 @@ impl VmFd { MSHV_IRQFD_FLAG_RESAMPLE, ) } + /// Unregisters an event that will, when signaled, trigger the `gsi` IRQ. /// /// # Arguments @@ -472,6 +489,7 @@ impl VmFd { Err(errno::Error::last().into()) } } + /// Registers an event to be signaled whenever a certain address is written to. /// /// # Arguments @@ -505,6 +523,7 @@ impl VmFd { ) -> Result<()> { self.ioeventfd(fd, addr, datamatch, 0) } + /// Unregisters an event from a certain address it has been previously registered to. /// /// # Arguments @@ -558,6 +577,7 @@ impl VmFd { Err(errno::Error::last().into()) } } + /// Sets a partion property pub fn set_partition_property(&self, code: u32, value: u64) -> Result<()> { let property: mshv_partition_property = mshv_partition_property { @@ -572,6 +592,7 @@ impl VmFd { Err(errno::Error::last().into()) } } + /// Generic hvcall version of set_partition_property pub fn hvcall_set_partition_property(&self, code: u32, value: u64) -> Result<()> { let input = hv_input_set_partition_property { @@ -582,6 +603,7 @@ impl VmFd { let mut args = make_args!(HVCALL_SET_PARTITION_PROPERTY, input); self.hvcall(&mut args) } + /// Enable dirty page tracking by hypervisor /// Flags: /// bit 1: Enabled @@ -593,6 +615,7 @@ impl VmFd { flag, ) } + /// Disable dirty page tracking by hypervisor /// Prerequisite: It is required to set the dirty bits if cleared /// previously, otherwise this hypercall will be failed. @@ -606,6 +629,7 @@ impl VmFd { flag, ) } + /// Get page access state /// The data provides each page's access state whether it is dirty or accessed /// Prerequisite: Need to enable page_acess_tracking @@ -645,6 +669,7 @@ impl VmFd { Err(errno::Error::last().into()) } } + /// Gets the bitmap of pages dirtied since the last call of this function /// /// Flags: @@ -702,6 +727,7 @@ impl VmFd { } Ok(bitmap) } + /// Create an in-kernel device /// /// See the documentation for `MSHV_CREATE_DEVICE`. @@ -770,6 +796,7 @@ mod tests { vm.unmap_user_memory(mem).unwrap(); } + #[test] fn test_create_vcpu() { let hv = Mshv::new().unwrap(); @@ -777,6 +804,7 @@ mod tests { let vcpu = vm.create_vcpu(0); assert!(vcpu.is_ok()); } + #[test] fn test_assert_virtual_interrupt() { /* TODO better test with some code */ @@ -796,6 +824,7 @@ mod tests { }; vm.request_virtual_interrupt(&cfg).unwrap(); } + #[test] fn test_install_intercept() { let hv = Mshv::new().unwrap(); @@ -807,6 +836,7 @@ mod tests { }; assert!(vm.install_intercept(intercept_args).is_ok()); } + #[test] fn test_get_property() { let hv = Mshv::new().unwrap(); @@ -845,6 +875,7 @@ mod tests { .into() ); } + #[test] fn test_set_property() { let hv = Mshv::new().unwrap(); @@ -872,6 +903,7 @@ mod tests { let fault_ret = vm.get_partition_property(code).unwrap(); assert!(fault_ret == fault); } + #[test] fn test_set_partition_property_invalid() { let hv = Mshv::new().unwrap(); @@ -891,6 +923,7 @@ mod tests { }; assert!(res_1.err().unwrap() == mshv_err_check); } + #[test] fn test_irqfd() { use libc::EFD_NONBLOCK; @@ -900,6 +933,7 @@ mod tests { vm.register_irqfd(&efd, 30).unwrap(); vm.unregister_irqfd(&efd, 30).unwrap(); } + #[test] fn test_ioeventfd() { let efd = EventFd::new(0).unwrap(); @@ -909,6 +943,7 @@ mod tests { vm.register_ioevent(&efd, &addr, NoDatamatch).unwrap(); vm.unregister_ioevent(&efd, &addr, NoDatamatch).unwrap(); } + #[test] fn test_set_msi_routing() { let hv = Mshv::new().unwrap(); @@ -916,6 +951,7 @@ mod tests { let msi_routing = mshv_msi_routing::default(); assert!(vm.set_msi_routing(&msi_routing).is_ok()); } + #[test] fn test_get_gpa_access_states() { let hv = Mshv::new().unwrap(); @@ -949,6 +985,7 @@ mod tests { vm.unmap_user_memory(mem_region).unwrap(); unsafe { libc::munmap(load_addr as *mut c_void, mem_size) }; } + #[test] #[ignore] fn test_signal_event_direct() { @@ -959,6 +996,7 @@ mod tests { let _vcpu = vm.create_vcpu(0).unwrap(); vm.signal_event_direct(0, 0, 1).unwrap(); } + #[test] #[ignore] fn test_post_message_direct() { @@ -970,6 +1008,7 @@ mod tests { let hv_message: [u8; mem::size_of::()] = [0; mem::size_of::()]; vm.post_message_direct(0, 0, &hv_message).unwrap(); } + #[test] fn test_register_deliverabilty_notifications() { let hv = Mshv::new().unwrap();