@@ -14,7 +14,7 @@ use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};
14
14
use std:: thread;
15
15
16
16
use super :: TimestampUs ;
17
- use super :: FC_EXIT_CODE_GENERIC_ERROR ;
17
+ use super :: { FC_EXIT_CODE_GENERIC_ERROR , FC_EXIT_CODE_OK } ;
18
18
#[ cfg( target_arch = "aarch64" ) ]
19
19
use arch:: aarch64:: gic:: GICDevice ;
20
20
#[ cfg( target_arch = "x86_64" ) ]
@@ -926,11 +926,11 @@ impl Vcpu {
926
926
}
927
927
VcpuExit :: Hlt => {
928
928
info ! ( "Received KVM_EXIT_HLT signal" ) ;
929
- Err ( Error :: VcpuUnhandledKvmExit )
929
+ Ok ( VcpuEmulation :: Stopped )
930
930
}
931
931
VcpuExit :: Shutdown => {
932
932
info ! ( "Received KVM_EXIT_SHUTDOWN signal" ) ;
933
- Err ( Error :: VcpuUnhandledKvmExit )
933
+ Ok ( VcpuEmulation :: Stopped )
934
934
}
935
935
// Documentation specifies that below kvm exits are considered
936
936
// errors.
@@ -1002,6 +1002,14 @@ impl Vcpu {
1002
1002
Ok ( VcpuEmulation :: Handled ) => ( ) ,
1003
1003
// Emulation was interrupted, check external events.
1004
1004
Ok ( VcpuEmulation :: Interrupted ) => break ,
1005
+ // If the guest was rebooted or halted:
1006
+ // - vCPU0 will always exit out of `KVM_RUN` with KVM_EXIT_SHUTDOWN or
1007
+ // KVM_EXIT_HLT.
1008
+ // - the other vCPUs won't ever exit out of `KVM_RUN`, but they won't consume CPU.
1009
+ // Moreover if we allow the vCPU0 thread to finish execution, this might generate a
1010
+ // seccomp failure because musl calls `sigprocmask` as part of `pthread_exit`.
1011
+ // So we pause vCPU0 and send a signal to the emulation thread to stop the VMM.
1012
+ Ok ( VcpuEmulation :: Stopped ) => return self . exit ( FC_EXIT_CODE_OK ) ,
1005
1013
// Emulation errors lead to vCPU exit.
1006
1014
Err ( _) => return self . exit ( FC_EXIT_CODE_GENERIC_ERROR ) ,
1007
1015
}
@@ -1167,6 +1175,7 @@ impl VcpuHandle {
1167
1175
enum VcpuEmulation {
1168
1176
Handled ,
1169
1177
Interrupted ,
1178
+ Stopped ,
1170
1179
}
1171
1180
1172
1181
#[ cfg( test) ]
0 commit comments