@@ -14,7 +14,7 @@ use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};
1414use std:: thread;
1515
1616use super :: TimestampUs ;
17- use super :: FC_EXIT_CODE_GENERIC_ERROR ;
17+ use super :: { FC_EXIT_CODE_GENERIC_ERROR , FC_EXIT_CODE_OK } ;
1818#[ cfg( target_arch = "aarch64" ) ]
1919use arch:: aarch64:: gic:: GICDevice ;
2020#[ cfg( target_arch = "x86_64" ) ]
@@ -926,11 +926,11 @@ impl Vcpu {
926926 }
927927 VcpuExit :: Hlt => {
928928 info ! ( "Received KVM_EXIT_HLT signal" ) ;
929- Err ( Error :: VcpuUnhandledKvmExit )
929+ Ok ( VcpuEmulation :: Stopped )
930930 }
931931 VcpuExit :: Shutdown => {
932932 info ! ( "Received KVM_EXIT_SHUTDOWN signal" ) ;
933- Err ( Error :: VcpuUnhandledKvmExit )
933+ Ok ( VcpuEmulation :: Stopped )
934934 }
935935 // Documentation specifies that below kvm exits are considered
936936 // errors.
@@ -1002,6 +1002,14 @@ impl Vcpu {
10021002 Ok ( VcpuEmulation :: Handled ) => ( ) ,
10031003 // Emulation was interrupted, check external events.
10041004 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 ) ,
10051013 // Emulation errors lead to vCPU exit.
10061014 Err ( _) => return self . exit ( FC_EXIT_CODE_GENERIC_ERROR ) ,
10071015 }
@@ -1167,6 +1175,7 @@ impl VcpuHandle {
11671175enum VcpuEmulation {
11681176 Handled ,
11691177 Interrupted ,
1178+ Stopped ,
11701179}
11711180
11721181#[ cfg( test) ]
0 commit comments