@@ -13,7 +13,10 @@ use std::os::unix::io::{AsRawFd, RawFd};
1313use crate :: ioctls:: { KvmRunWrapper , Result } ;
1414use crate :: kvm_ioctls:: * ;
1515#[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
16- use kvm_bindings:: { CpuId , Msrs , KVM_MAX_CPUID_ENTRIES } ;
16+ use kvm_bindings:: {
17+ CpuId , Msrs , KVM_MAX_CPUID_ENTRIES , KVM_MSR_EXIT_REASON_FILTER , KVM_MSR_EXIT_REASON_INVAL ,
18+ KVM_MSR_EXIT_REASON_UNKNOWN ,
19+ } ;
1720use vmm_sys_util:: errno;
1821use vmm_sys_util:: ioctl:: { ioctl, ioctl_with_mut_ref, ioctl_with_ref} ;
1922#[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
@@ -25,6 +28,55 @@ pub fn reg_size(reg_id: u64) -> usize {
2528 2_usize . pow ( ( ( reg_id & KVM_REG_SIZE_MASK ) >> KVM_REG_SIZE_SHIFT ) as u32 )
2629}
2730
31+ /// Information about a [`VcpuExit`] triggered by an MSR read (`KVM_EXIT_X86_RDMSR`).
32+ #[ derive( Debug ) ]
33+ pub struct ReadMsrExit < ' a > {
34+ /// Must be set to 1 by the the user if the read access should fail. This
35+ /// will inject a #GP fault into the guest when the VCPU is executed
36+ /// again.
37+ pub error : & ' a mut u8 ,
38+ /// The reason for this exit.
39+ pub reason : MsrExitReason ,
40+ /// The MSR the guest wants to read.
41+ pub index : u32 ,
42+ /// The data to be supplied by the user as the MSR Contents to the guest.
43+ pub data : & ' a mut u64 ,
44+ }
45+
46+ /// Information about a [`VcpuExit`] triggered by an MSR write (`KVM_EXIT_X86_WRMSR`).
47+ #[ derive( Debug ) ]
48+ pub struct WriteMsrExit < ' a > {
49+ /// Must be set to 1 by the the user if the write access should fail. This
50+ /// will inject a #GP fault into the guest when the VCPU is executed
51+ /// again.
52+ pub error : & ' a mut u8 ,
53+ /// The reason for this exit.
54+ pub reason : MsrExitReason ,
55+ /// The MSR the guest wants to write.
56+ pub index : u32 ,
57+ /// The data the guest wants to write into the MSR.
58+ pub data : u64 ,
59+ }
60+
61+ bitflags:: bitflags! {
62+ /// The reason for a [`VcpuExit::X86Rdmsr`] or[`VcpuExit::X86Wrmsr`]. This
63+ /// is also used when enabling
64+ /// [`Cap::X86UserSpaceMsr`](crate::Cap::X86UserSpaceMsr) to specify which
65+ /// reasons should be forwarded to the user via those exits.
66+ #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
67+ pub struct MsrExitReason : u32 {
68+ /// Corresponds to [`KVM_MSR_EXIT_REASON_UNKNOWN`]. The exit was
69+ /// triggered by an access to an MSR that is unknown to KVM.
70+ const Unknown = KVM_MSR_EXIT_REASON_UNKNOWN ;
71+ /// Corresponds to [`KVM_MSR_EXIT_REASON_INVAL`]. The exit was
72+ /// triggered by an access to an invalid MSR or to reserved bits.
73+ const Inval = KVM_MSR_EXIT_REASON_INVAL ;
74+ /// Corresponds to [`KVM_MSR_EXIT_REASON_FILTER`]. The exit was
75+ /// triggered by an access to a filtered MSR.
76+ const Filter = KVM_MSR_EXIT_REASON_FILTER ;
77+ }
78+ }
79+
2880/// Reasons for vCPU exits.
2981///
3082/// The exit reasons are mapped to the `KVM_EXIT_*` defines in the
@@ -102,6 +154,10 @@ pub enum VcpuExit<'a> {
102154 IoapicEoi ( u8 /* vector */ ) ,
103155 /// Corresponds to KVM_EXIT_HYPERV.
104156 Hyperv ,
157+ /// Corresponds to KVM_EXIT_X86_RDMSR.
158+ X86Rdmsr ( ReadMsrExit < ' a > ) ,
159+ /// Corresponds to KVM_EXIT_X86_WRMSR.
160+ X86Wrmsr ( WriteMsrExit < ' a > ) ,
105161 /// Corresponds to an exit reason that is unknown from the current version
106162 /// of the kvm-ioctls crate. Let the consumer decide about what to do with
107163 /// it.
@@ -1422,6 +1478,30 @@ impl VcpuFd {
14221478 Ok ( VcpuExit :: MmioRead ( addr, data_slice) )
14231479 }
14241480 }
1481+ KVM_EXIT_X86_RDMSR => {
1482+ // SAFETY: Safe because the exit_reason (which comes from the kernel) told us
1483+ // which union field to use.
1484+ let msr = unsafe { & mut run. __bindgen_anon_1 . msr } ;
1485+ let exit = ReadMsrExit {
1486+ error : & mut msr. error ,
1487+ reason : MsrExitReason :: from_bits_truncate ( msr. reason ) ,
1488+ index : msr. index ,
1489+ data : & mut msr. data ,
1490+ } ;
1491+ Ok ( VcpuExit :: X86Rdmsr ( exit) )
1492+ }
1493+ KVM_EXIT_X86_WRMSR => {
1494+ // SAFETY: Safe because the exit_reason (which comes from the kernel) told us
1495+ // which union field to use.
1496+ let msr = unsafe { & mut run. __bindgen_anon_1 . msr } ;
1497+ let exit = WriteMsrExit {
1498+ error : & mut msr. error ,
1499+ reason : MsrExitReason :: from_bits_truncate ( msr. reason ) ,
1500+ index : msr. index ,
1501+ data : msr. data ,
1502+ } ;
1503+ Ok ( VcpuExit :: X86Wrmsr ( exit) )
1504+ }
14251505 KVM_EXIT_IRQ_WINDOW_OPEN => Ok ( VcpuExit :: IrqWindowOpen ) ,
14261506 KVM_EXIT_SHUTDOWN => Ok ( VcpuExit :: Shutdown ) ,
14271507 KVM_EXIT_FAIL_ENTRY => {
0 commit comments