@@ -158,6 +158,8 @@ pub enum VcpuExit<'a> {
158158 X86Rdmsr ( ReadMsrExit < ' a > ) ,
159159 /// Corresponds to KVM_EXIT_X86_WRMSR.
160160 X86Wrmsr ( WriteMsrExit < ' a > ) ,
161+ /// Corresponds to KVM_EXIT_X86_BUS_LOCK.
162+ X86BusLock ,
161163 /// Corresponds to an exit reason that is unknown from the current version
162164 /// of the kvm-ioctls crate. Let the consumer decide about what to do with
163165 /// it.
@@ -1544,6 +1546,7 @@ impl VcpuFd {
15441546 Ok ( VcpuExit :: IoapicEoi ( eoi. vector ) )
15451547 }
15461548 KVM_EXIT_HYPERV => Ok ( VcpuExit :: Hyperv ) ,
1549+ KVM_EXIT_X86_BUS_LOCK => Ok ( VcpuExit :: X86BusLock ) ,
15471550 r => Ok ( VcpuExit :: Unsupported ( r) ) ,
15481551 }
15491552 } else {
@@ -1848,6 +1851,18 @@ impl VcpuFd {
18481851 0 => Ok ( ( ) ) ,
18491852 _ => Err ( errno:: Error :: last ( ) ) ,
18501853 }
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
18511866 }
18521867}
18531868
@@ -3075,4 +3090,39 @@ mod tests {
30753090 e => panic ! ( "Unexpected exit: {:?}" , e) ,
30763091 }
30773092 }
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+ }
30783128}
0 commit comments