@@ -158,6 +158,8 @@ pub enum VcpuExit<'a> {
158
158
X86Rdmsr ( ReadMsrExit < ' a > ) ,
159
159
/// Corresponds to KVM_EXIT_X86_WRMSR.
160
160
X86Wrmsr ( WriteMsrExit < ' a > ) ,
161
+ /// Corresponds to KVM_EXIT_X86_BUS_LOCK.
162
+ X86BusLock ,
161
163
/// Corresponds to an exit reason that is unknown from the current version
162
164
/// of the kvm-ioctls crate. Let the consumer decide about what to do with
163
165
/// it.
@@ -1544,6 +1546,7 @@ impl VcpuFd {
1544
1546
Ok ( VcpuExit :: IoapicEoi ( eoi. vector ) )
1545
1547
}
1546
1548
KVM_EXIT_HYPERV => Ok ( VcpuExit :: Hyperv ) ,
1549
+ KVM_EXIT_X86_BUS_LOCK => Ok ( VcpuExit :: X86BusLock ) ,
1547
1550
r => Ok ( VcpuExit :: Unsupported ( r) ) ,
1548
1551
}
1549
1552
} else {
@@ -1848,6 +1851,18 @@ impl VcpuFd {
1848
1851
0 => Ok ( ( ) ) ,
1849
1852
_ => Err ( errno:: Error :: last ( ) ) ,
1850
1853
}
1854
+
1855
+ /// If [`Cap::X86BusLockExit`](crate::Cap::X86BusLockExit) was enabled,
1856
+ /// checks whether a bus lock was detected on the last VM exit. This may
1857
+ /// return `true` even if the corresponding exit was not
1858
+ /// [`VcpuExit::X86BusLock`], as a different VM exit may have preempted
1859
+ /// it.
1860
+ ///
1861
+ /// See the API documentation for `KVM_CAP_X86_BUS_LOCK_EXIT`.
1862
+ #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
1863
+ pub fn bus_lock_detected ( & self ) -> bool {
1864
+ let kvm_run = self . kvm_run_ptr . as_ref ( ) ;
1865
+ kvm_run. flags as u32 & KVM_RUN_X86_BUS_LOCK != 0
1851
1866
}
1852
1867
}
1853
1868
@@ -3075,4 +3090,39 @@ mod tests {
3075
3090
e => panic ! ( "Unexpected exit: {:?}" , e) ,
3076
3091
}
3077
3092
}
3093
+
3094
+ #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
3095
+ #[ test]
3096
+ fn test_enable_bus_lock_detection ( ) {
3097
+ let kvm = Kvm :: new ( ) . unwrap ( ) ;
3098
+ let vm = kvm. create_vm ( ) . unwrap ( ) ;
3099
+ if !vm. check_extension ( Cap :: X86BusLockExit ) {
3100
+ return ;
3101
+ }
3102
+ let args = KVM_BUS_LOCK_DETECTION_EXIT ;
3103
+ let cap = kvm_enable_cap {
3104
+ cap : Cap :: X86BusLockExit as u32 ,
3105
+ args : [ args as u64 , 0 , 0 , 0 ] ,
3106
+ ..Default :: default ( )
3107
+ } ;
3108
+ vm. enable_cap ( & cap) . unwrap ( ) ;
3109
+ }
3110
+
3111
+ #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
3112
+ #[ test]
3113
+ fn test_enable_bus_lock_detection_invalid ( ) {
3114
+ let kvm = Kvm :: new ( ) . unwrap ( ) ;
3115
+ let vm = kvm. create_vm ( ) . unwrap ( ) ;
3116
+ if !vm. check_extension ( Cap :: X86BusLockExit ) {
3117
+ return ;
3118
+ }
3119
+ // These flags should be mutually exclusive
3120
+ let args = KVM_BUS_LOCK_DETECTION_OFF | KVM_BUS_LOCK_DETECTION_EXIT ;
3121
+ let cap = kvm_enable_cap {
3122
+ cap : Cap :: X86BusLockExit as u32 ,
3123
+ args : [ args as u64 , 0 , 0 , 0 ] ,
3124
+ ..Default :: default ( )
3125
+ } ;
3126
+ vm. enable_cap ( & cap) . unwrap_err ( ) ;
3127
+ }
3078
3128
}
0 commit comments