8
8
use std:: cell:: Cell ;
9
9
use std:: sync:: atomic:: { fence, Ordering } ;
10
10
use std:: sync:: mpsc:: { channel, Receiver , Sender , TryRecvError } ;
11
- #[ cfg( test) ]
12
- use std:: sync:: Mutex ;
13
11
use std:: sync:: { Arc , Barrier } ;
14
12
use std:: { fmt, io, thread} ;
15
13
@@ -104,10 +102,6 @@ pub struct Vcpu {
104
102
response_receiver : Option < Receiver < VcpuResponse > > ,
105
103
/// The transmitting end of the responses channel owned by the vcpu side.
106
104
response_sender : Sender < VcpuResponse > ,
107
-
108
- /// Exit reason used to test run_emulation function.
109
- #[ cfg( test) ]
110
- test_vcpu_exit_reason : Mutex < Option < Result < VcpuExit < ' static > , errno:: Error > > > ,
111
105
}
112
106
113
107
impl Vcpu {
@@ -218,8 +212,6 @@ impl Vcpu {
218
212
response_sender,
219
213
kvm_vcpu,
220
214
fd,
221
- #[ cfg( test) ]
222
- test_vcpu_exit_reason : Mutex :: new ( None ) ,
223
215
} )
224
216
}
225
217
@@ -449,15 +441,6 @@ impl Vcpu {
449
441
StateMachine :: finish ( )
450
442
}
451
443
452
- #[ cfg( not( test) ) ]
453
- /// Calls `KVM_RUN` with this [`Vcpu`]'s underlying file descriptor.
454
- ///
455
- /// Blocks until a `VM_EXIT` is received, in which case this function returns a [`VcpuExit`]
456
- /// containing the reason.
457
- pub fn emulate ( & self ) -> Result < VcpuExit , errno:: Error > {
458
- self . fd . run ( )
459
- }
460
-
461
444
/// Runs the vCPU in KVM context and handles the kvm exit reason.
462
445
///
463
446
/// Returns error or enum specifying whether emulation was handled or interrupted.
@@ -467,18 +450,36 @@ impl Vcpu {
467
450
self . fd . set_kvm_immediate_exit ( 0 ) ;
468
451
return Ok ( VcpuEmulation :: Interrupted ) ;
469
452
}
470
- match self . emulate ( ) {
453
+
454
+ match self . fd . run ( ) {
455
+ Err ( ref err) if err. errno ( ) == libc:: EINTR => {
456
+ self . fd . set_kvm_immediate_exit ( 0 ) ;
457
+ // Notify that this KVM_RUN was interrupted.
458
+ Ok ( VcpuEmulation :: Interrupted )
459
+ }
460
+ emulation_result => self . kvm_vcpu . handle_kvm_exit ( emulation_result) ,
461
+ }
462
+ }
463
+ }
464
+
465
+ impl KvmVcpu {
466
+ /// Handle the return value of a call to [`VcpuFd::run`] and update our emulation accordingly
467
+ pub fn handle_kvm_exit (
468
+ & mut self ,
469
+ emulation_result : Result < VcpuExit , errno:: Error > ,
470
+ ) -> Result < VcpuEmulation , VcpuError > {
471
+ match emulation_result {
471
472
Ok ( run) => match run {
472
473
VcpuExit :: MmioRead ( addr, data) => {
473
- if let Some ( mmio_bus) = & self . kvm_vcpu . mmio_bus {
474
+ if let Some ( mmio_bus) = & self . mmio_bus {
474
475
let _metric = METRICS . vcpu . exit_mmio_read_agg . record_latency_metrics ( ) ;
475
476
mmio_bus. read ( addr, data) ;
476
477
METRICS . vcpu . exit_mmio_read . inc ( ) ;
477
478
}
478
479
Ok ( VcpuEmulation :: Handled )
479
480
}
480
481
VcpuExit :: MmioWrite ( addr, data) => {
481
- if let Some ( mmio_bus) = & self . kvm_vcpu . mmio_bus {
482
+ if let Some ( mmio_bus) = & self . mmio_bus {
482
483
let _metric = METRICS . vcpu . exit_mmio_write_agg . record_latency_metrics ( ) ;
483
484
mmio_bus. write ( addr, data) ;
484
485
METRICS . vcpu . exit_mmio_write . inc ( ) ;
@@ -538,36 +539,27 @@ impl Vcpu {
538
539
} ,
539
540
arch_specific_reason => {
540
541
// run specific architecture emulation.
541
- self . kvm_vcpu . run_arch_emulation ( arch_specific_reason)
542
+ self . run_arch_emulation ( arch_specific_reason)
542
543
}
543
544
} ,
544
545
// The unwrap on raw_os_error can only fail if we have a logic
545
546
// error in our code in which case it is better to panic.
546
- Err ( ref err) => {
547
- match err. errno ( ) {
548
- libc:: EAGAIN => Ok ( VcpuEmulation :: Handled ) ,
549
- libc:: EINTR => {
550
- self . fd . set_kvm_immediate_exit ( 0 ) ;
551
- // Notify that this KVM_RUN was interrupted.
552
- Ok ( VcpuEmulation :: Interrupted )
553
- }
554
- libc:: ENOSYS => {
555
- METRICS . vcpu . failures . inc ( ) ;
556
- error ! (
557
- "Received ENOSYS error because KVM failed to emulate an instruction."
558
- ) ;
559
- Err ( VcpuError :: FaultyKvmExit (
560
- "Received ENOSYS error because KVM failed to emulate an instruction."
561
- . to_string ( ) ,
562
- ) )
563
- }
564
- _ => {
565
- METRICS . vcpu . failures . inc ( ) ;
566
- error ! ( "Failure during vcpu run: {}" , err) ;
567
- Err ( VcpuError :: FaultyKvmExit ( format ! ( "{}" , err) ) )
568
- }
547
+ Err ( ref err) => match err. errno ( ) {
548
+ libc:: EAGAIN => Ok ( VcpuEmulation :: Handled ) ,
549
+ libc:: ENOSYS => {
550
+ METRICS . vcpu . failures . inc ( ) ;
551
+ error ! ( "Received ENOSYS error because KVM failed to emulate an instruction." ) ;
552
+ Err ( VcpuError :: FaultyKvmExit (
553
+ "Received ENOSYS error because KVM failed to emulate an instruction."
554
+ . to_string ( ) ,
555
+ ) )
569
556
}
570
- }
557
+ _ => {
558
+ METRICS . vcpu . failures . inc ( ) ;
559
+ error ! ( "Failure during vcpu run: {}" , err) ;
560
+ Err ( VcpuError :: FaultyKvmExit ( format ! ( "{}" , err) ) )
561
+ }
562
+ } ,
571
563
}
572
564
}
573
565
}
@@ -730,29 +722,16 @@ pub mod tests {
730
722
use crate :: vstate:: vm:: Vm ;
731
723
use crate :: RECV_TIMEOUT_SEC ;
732
724
733
- impl Vcpu {
734
- pub fn emulate ( & self ) -> Result < VcpuExit , errno:: Error > {
735
- self . test_vcpu_exit_reason
736
- . lock ( )
737
- . unwrap ( )
738
- . take ( )
739
- . unwrap_or_else ( || Err ( errno:: Error :: new ( libc:: SIGILL ) ) )
740
- }
741
- }
742
-
743
725
#[ test]
744
- fn test_run_emulation ( ) {
726
+ fn test_handle_kvm_exit ( ) {
745
727
let ( _vm, mut vcpu, _vm_mem) = setup_vcpu ( 0x1000 ) ;
746
- vcpu. test_vcpu_exit_reason = Mutex :: new ( Some ( Ok ( VcpuExit :: Hlt ) ) ) ;
747
- let res = vcpu. run_emulation ( ) ;
728
+ let res = vcpu. kvm_vcpu . handle_kvm_exit ( Ok ( VcpuExit :: Hlt ) ) ;
748
729
assert_eq ! ( res. unwrap( ) , VcpuEmulation :: Stopped ) ;
749
730
750
- * ( vcpu. test_vcpu_exit_reason . lock ( ) . unwrap ( ) ) = Some ( Ok ( VcpuExit :: Shutdown ) ) ;
751
- let res = vcpu. run_emulation ( ) ;
731
+ let res = vcpu. kvm_vcpu . handle_kvm_exit ( Ok ( VcpuExit :: Shutdown ) ) ;
752
732
assert_eq ! ( res. unwrap( ) , VcpuEmulation :: Stopped ) ;
753
733
754
- * ( vcpu. test_vcpu_exit_reason . lock ( ) . unwrap ( ) ) = Some ( Ok ( VcpuExit :: FailEntry ( 0 , 0 ) ) ) ;
755
- let res = vcpu. run_emulation ( ) ;
734
+ let res = vcpu. kvm_vcpu . handle_kvm_exit ( Ok ( VcpuExit :: FailEntry ( 0 , 0 ) ) ) ;
756
735
assert_eq ! (
757
736
format!( "{:?}" , res. unwrap_err( ) ) ,
758
737
format!(
@@ -761,8 +740,7 @@ pub mod tests {
761
740
)
762
741
) ;
763
742
764
- * ( vcpu. test_vcpu_exit_reason . lock ( ) . unwrap ( ) ) = Some ( Ok ( VcpuExit :: InternalError ) ) ;
765
- let res = vcpu. run_emulation ( ) ;
743
+ let res = vcpu. kvm_vcpu . handle_kvm_exit ( Ok ( VcpuExit :: InternalError ) ) ;
766
744
assert_eq ! (
767
745
format!( "{:?}" , res. unwrap_err( ) ) ,
768
746
format!(
@@ -771,16 +749,19 @@ pub mod tests {
771
749
)
772
750
) ;
773
751
774
- * ( vcpu. test_vcpu_exit_reason . lock ( ) . unwrap ( ) ) = Some ( Ok ( VcpuExit :: SystemEvent ( 2 , & [ ] ) ) ) ;
775
- let res = vcpu. run_emulation ( ) ;
752
+ let res = vcpu
753
+ . kvm_vcpu
754
+ . handle_kvm_exit ( Ok ( VcpuExit :: SystemEvent ( 2 , & [ ] ) ) ) ;
776
755
assert_eq ! ( res. unwrap( ) , VcpuEmulation :: Stopped ) ;
777
756
778
- * ( vcpu. test_vcpu_exit_reason . lock ( ) . unwrap ( ) ) = Some ( Ok ( VcpuExit :: SystemEvent ( 1 , & [ ] ) ) ) ;
779
- let res = vcpu. run_emulation ( ) ;
757
+ let res = vcpu
758
+ . kvm_vcpu
759
+ . handle_kvm_exit ( Ok ( VcpuExit :: SystemEvent ( 1 , & [ ] ) ) ) ;
780
760
assert_eq ! ( res. unwrap( ) , VcpuEmulation :: Stopped ) ;
781
761
782
- * ( vcpu. test_vcpu_exit_reason . lock ( ) . unwrap ( ) ) = Some ( Ok ( VcpuExit :: SystemEvent ( 3 , & [ ] ) ) ) ;
783
- let res = vcpu. run_emulation ( ) ;
762
+ let res = vcpu
763
+ . kvm_vcpu
764
+ . handle_kvm_exit ( Ok ( VcpuExit :: SystemEvent ( 3 , & [ ] ) ) ) ;
784
765
assert_eq ! (
785
766
format!( "{:?}" , res. unwrap_err( ) ) ,
786
767
format!(
@@ -790,19 +771,20 @@ pub mod tests {
790
771
) ;
791
772
792
773
// Check what happens with an unhandled exit reason.
793
- * ( vcpu. test_vcpu_exit_reason . lock ( ) . unwrap ( ) ) = Some ( Ok ( VcpuExit :: Unknown ) ) ;
794
- let res = vcpu. run_emulation ( ) ;
774
+ let res = vcpu. kvm_vcpu . handle_kvm_exit ( Ok ( VcpuExit :: Unknown ) ) ;
795
775
assert_eq ! (
796
776
res. unwrap_err( ) . to_string( ) ,
797
777
"Unexpected kvm exit received: Unknown" . to_string( )
798
778
) ;
799
779
800
- * ( vcpu. test_vcpu_exit_reason . lock ( ) . unwrap ( ) ) = Some ( Err ( errno:: Error :: new ( libc:: EAGAIN ) ) ) ;
801
- let res = vcpu. run_emulation ( ) ;
780
+ let res = vcpu
781
+ . kvm_vcpu
782
+ . handle_kvm_exit ( Err ( errno:: Error :: new ( libc:: EAGAIN ) ) ) ;
802
783
assert_eq ! ( res. unwrap( ) , VcpuEmulation :: Handled ) ;
803
784
804
- * ( vcpu. test_vcpu_exit_reason . lock ( ) . unwrap ( ) ) = Some ( Err ( errno:: Error :: new ( libc:: ENOSYS ) ) ) ;
805
- let res = vcpu. run_emulation ( ) ;
785
+ let res = vcpu
786
+ . kvm_vcpu
787
+ . handle_kvm_exit ( Err ( errno:: Error :: new ( libc:: ENOSYS ) ) ) ;
806
788
assert_eq ! (
807
789
format!( "{:?}" , res. unwrap_err( ) ) ,
808
790
format!(
@@ -814,12 +796,9 @@ pub mod tests {
814
796
)
815
797
) ;
816
798
817
- * ( vcpu. test_vcpu_exit_reason . lock ( ) . unwrap ( ) ) = Some ( Err ( errno:: Error :: new ( libc:: EINTR ) ) ) ;
818
- let res = vcpu. run_emulation ( ) ;
819
- assert_eq ! ( res. unwrap( ) , VcpuEmulation :: Interrupted ) ;
820
-
821
- * ( vcpu. test_vcpu_exit_reason . lock ( ) . unwrap ( ) ) = Some ( Err ( errno:: Error :: new ( libc:: EINVAL ) ) ) ;
822
- let res = vcpu. run_emulation ( ) ;
799
+ let res = vcpu
800
+ . kvm_vcpu
801
+ . handle_kvm_exit ( Err ( errno:: Error :: new ( libc:: EINVAL ) ) ) ;
823
802
assert_eq ! (
824
803
format!( "{:?}" , res. unwrap_err( ) ) ,
825
804
format!(
@@ -833,20 +812,15 @@ pub mod tests {
833
812
bus. insert ( dummy, 0x10 , 0x10 ) . unwrap ( ) ;
834
813
vcpu. set_mmio_bus ( bus) ;
835
814
let addr = 0x10 ;
836
- static mut DATA : [ u8 ; 4 ] = [ 0 , 0 , 0 , 0 ] ;
837
815
838
- unsafe {
839
- * ( vcpu. test_vcpu_exit_reason . lock ( ) . unwrap ( ) ) =
840
- Some ( Ok ( VcpuExit :: MmioRead ( addr, & mut DATA ) ) ) ;
841
- }
842
- let res = vcpu. run_emulation ( ) ;
816
+ let res = vcpu
817
+ . kvm_vcpu
818
+ . handle_kvm_exit ( Ok ( VcpuExit :: MmioRead ( addr, & mut [ 0 , 0 , 0 , 0 ] ) ) ) ;
843
819
assert_eq ! ( res. unwrap( ) , VcpuEmulation :: Handled ) ;
844
820
845
- unsafe {
846
- * ( vcpu. test_vcpu_exit_reason . lock ( ) . unwrap ( ) ) =
847
- Some ( Ok ( VcpuExit :: MmioWrite ( addr, & DATA ) ) ) ;
848
- }
849
- let res = vcpu. run_emulation ( ) ;
821
+ let res = vcpu
822
+ . kvm_vcpu
823
+ . handle_kvm_exit ( Ok ( VcpuExit :: MmioWrite ( addr, & [ 0 , 0 , 0 , 0 ] ) ) ) ;
850
824
assert_eq ! ( res. unwrap( ) , VcpuEmulation :: Handled ) ;
851
825
}
852
826
@@ -1083,7 +1057,6 @@ pub mod tests {
1083
1057
1084
1058
vcpu. fd . set_kvm_immediate_exit ( 1 ) ;
1085
1059
// Set a dummy value to be returned by the emulate call
1086
- * ( vcpu. test_vcpu_exit_reason . lock ( ) . unwrap ( ) ) = Some ( Ok ( VcpuExit :: Shutdown ) ) ;
1087
1060
let result = vcpu. run_emulation ( ) . expect ( "Failed to run emulation" ) ;
1088
1061
assert_eq ! (
1089
1062
result,
0 commit comments