@@ -16,7 +16,7 @@ use std::{fmt, io, thread};
16
16
use kvm_bindings:: { KVM_SYSTEM_EVENT_RESET , KVM_SYSTEM_EVENT_SHUTDOWN } ;
17
17
use kvm_ioctls:: VcpuExit ;
18
18
use libc:: { c_int, c_void, siginfo_t} ;
19
- use log:: { error, info} ;
19
+ use log:: { error, info, warn } ;
20
20
use seccompiler:: { BpfProgram , BpfProgramRef } ;
21
21
use utils:: errno;
22
22
use utils:: eventfd:: EventFd ;
@@ -341,6 +341,13 @@ impl Vcpu {
341
341
match self . event_receiver . recv ( ) {
342
342
// Paused ---- Resume ----> Running
343
343
Ok ( VcpuEvent :: Resume ) => {
344
+ if self . kvm_vcpu . fd . get_kvm_run ( ) . immediate_exit == 1u8 {
345
+ warn ! (
346
+ "Received a VcpuEvent::Resume message with immediate_exit enabled. \
347
+ immediate_exit was disabled before proceeding"
348
+ ) ;
349
+ self . kvm_vcpu . fd . set_kvm_immediate_exit ( 0 ) ;
350
+ }
344
351
// Nothing special to do.
345
352
self . response_sender
346
353
. send ( VcpuResponse :: Resumed )
@@ -445,7 +452,12 @@ impl Vcpu {
445
452
/// Runs the vCPU in KVM context and handles the kvm exit reason.
446
453
///
447
454
/// Returns error or enum specifying whether emulation was handled or interrupted.
448
- pub fn run_emulation ( & self ) -> Result < VcpuEmulation , VcpuError > {
455
+ pub fn run_emulation ( & mut self ) -> Result < VcpuEmulation , VcpuError > {
456
+ if self . kvm_vcpu . fd . get_kvm_run ( ) . immediate_exit == 1u8 {
457
+ warn ! ( "Requested a vCPU run with immediate_exit enabled. The operation was skipped" ) ;
458
+ self . kvm_vcpu . fd . set_kvm_immediate_exit ( 0 ) ;
459
+ return Ok ( VcpuEmulation :: Interrupted ) ;
460
+ }
449
461
match self . emulate ( ) {
450
462
Ok ( run) => match run {
451
463
VcpuExit :: MmioRead ( addr, data) => {
@@ -1059,6 +1071,32 @@ pub mod tests {
1059
1071
) ;
1060
1072
}
1061
1073
1074
+ #[ test]
1075
+ fn test_immediate_exit_shortcircuits_execution ( ) {
1076
+ let ( _vm, mut vcpu, _) = setup_vcpu ( 0x1000 ) ;
1077
+
1078
+ vcpu. kvm_vcpu . fd . set_kvm_immediate_exit ( 1 ) ;
1079
+ // Set a dummy value to be returned by the emulate call
1080
+ * ( vcpu. test_vcpu_exit_reason . lock ( ) . unwrap ( ) ) = Some ( Ok ( VcpuExit :: Shutdown ) ) ;
1081
+ let result = vcpu. run_emulation ( ) . expect ( "Failed to run emulation" ) ;
1082
+ assert_eq ! (
1083
+ result,
1084
+ VcpuEmulation :: Interrupted ,
1085
+ "The Immediate Exit short-circuit should have prevented the execution of emulate"
1086
+ ) ;
1087
+
1088
+ let event_sender = vcpu. event_sender . take ( ) . expect ( "vCPU already started" ) ;
1089
+ let _ = event_sender. send ( VcpuEvent :: Resume ) ;
1090
+ vcpu. kvm_vcpu . fd . set_kvm_immediate_exit ( 1 ) ;
1091
+ // paused is expected to coerce immediate_exit to 0 when receiving a VcpuEvent::Resume
1092
+ let _ = vcpu. paused ( ) ;
1093
+ assert_eq ! (
1094
+ 0 ,
1095
+ vcpu. kvm_vcpu. fd. get_kvm_run( ) . immediate_exit,
1096
+ "Immediate Exit should have been disabled by sending Resume to a paused VM"
1097
+ )
1098
+ }
1099
+
1062
1100
#[ test]
1063
1101
fn test_vcpu_pause_resume ( ) {
1064
1102
let ( vcpu_handle, vcpu_exit_evt) = vcpu_configured_for_boot ( ) ;
0 commit comments