@@ -397,42 +397,53 @@ impl HypervLinuxDriver {
397
397
398
398
Self :: setup_initial_sregs ( & mut vcpu_fd, pml4_ptr. absolute ( ) ?) ?;
399
399
400
- Ok ( Self {
400
+ let interrupt_handle = Arc :: new ( LinuxInterruptHandle {
401
+ running : AtomicU64 :: new ( 0 ) ,
402
+ cancel_requested : AtomicBool :: new ( false ) ,
403
+ #[ cfg( gdb) ]
404
+ debug_interrupt : AtomicBool :: new ( false ) ,
405
+ #[ cfg( all(
406
+ target_arch = "x86_64" ,
407
+ target_vendor = "unknown" ,
408
+ target_os = "linux" ,
409
+ target_env = "musl"
410
+ ) ) ]
411
+ tid : AtomicU64 :: new ( unsafe { libc:: pthread_self ( ) as u64 } ) ,
412
+ #[ cfg( not( all(
413
+ target_arch = "x86_64" ,
414
+ target_vendor = "unknown" ,
415
+ target_os = "linux" ,
416
+ target_env = "musl"
417
+ ) ) ) ]
418
+ tid : AtomicU64 :: new ( unsafe { libc:: pthread_self ( ) } ) ,
419
+ retry_delay : config. get_interrupt_retry_delay ( ) ,
420
+ sig_rt_min_offset : config. get_interrupt_vcpu_sigrtmin_offset ( ) ,
421
+ dropped : AtomicBool :: new ( false ) ,
422
+ } ) ;
423
+
424
+ #[ allow( unused_mut) ]
425
+ let mut hv = Self {
401
426
_mshv : mshv,
402
427
vm_fd,
403
428
vcpu_fd,
404
429
mem_regions,
405
430
entrypoint : entrypoint_ptr. absolute ( ) ?,
406
431
orig_rsp : rsp_ptr,
407
- interrupt_handle : Arc :: new ( LinuxInterruptHandle {
408
- running : AtomicU64 :: new ( 0 ) ,
409
- cancel_requested : AtomicBool :: new ( false ) ,
410
- #[ cfg( all(
411
- target_arch = "x86_64" ,
412
- target_vendor = "unknown" ,
413
- target_os = "linux" ,
414
- target_env = "musl"
415
- ) ) ]
416
- tid : AtomicU64 :: new ( unsafe { libc:: pthread_self ( ) as u64 } ) ,
417
- #[ cfg( not( all(
418
- target_arch = "x86_64" ,
419
- target_vendor = "unknown" ,
420
- target_os = "linux" ,
421
- target_env = "musl"
422
- ) ) ) ]
423
- tid : AtomicU64 :: new ( unsafe { libc:: pthread_self ( ) } ) ,
424
- retry_delay : config. get_interrupt_retry_delay ( ) ,
425
- sig_rt_min_offset : config. get_interrupt_vcpu_sigrtmin_offset ( ) ,
426
- dropped : AtomicBool :: new ( false ) ,
427
- } ) ,
428
-
432
+ interrupt_handle : interrupt_handle. clone ( ) ,
429
433
#[ cfg( gdb) ]
430
434
debug,
431
435
#[ cfg( gdb) ]
432
436
gdb_conn,
433
437
#[ cfg( crashdump) ]
434
438
rt_cfg,
435
- } )
439
+ } ;
440
+
441
+ // Send the interrupt handle to the GDB thread if debugging is enabled
442
+ // This is used to allow the GDB thread to stop the vCPU
443
+ #[ cfg( gdb) ]
444
+ hv. send_dbg_msg ( DebugResponse :: InterruptHandle ( interrupt_handle) ) ?;
445
+
446
+ Ok ( hv)
436
447
}
437
448
438
449
#[ instrument( err( Debug ) , skip_all, parent = Span :: current( ) , level = "Trace" ) ]
@@ -634,6 +645,14 @@ impl Hypervisor for HypervLinuxDriver {
634
645
e
635
646
)
636
647
} ) ?;
648
+ #[ cfg( not( gdb) ) ]
649
+ let debug_interrupt = false ;
650
+ #[ cfg( gdb) ]
651
+ let debug_interrupt = self
652
+ . interrupt_handle
653
+ . debug_interrupt
654
+ . load ( Ordering :: Relaxed ) ;
655
+
637
656
// Don't run the vcpu if `cancel_requested` is true
638
657
//
639
658
// Note: if a `InterruptHandle::kill()` called while this thread is **here**
@@ -642,6 +661,7 @@ impl Hypervisor for HypervLinuxDriver {
642
661
. interrupt_handle
643
662
. cancel_requested
644
663
. load ( Ordering :: Relaxed )
664
+ || debug_interrupt
645
665
{
646
666
Err ( MshvError :: Errno ( vmm_sys_util:: errno:: Error :: new (
647
667
libc:: EINTR ,
@@ -667,6 +687,11 @@ impl Hypervisor for HypervLinuxDriver {
667
687
. interrupt_handle
668
688
. cancel_requested
669
689
. load ( Ordering :: Relaxed ) ;
690
+ #[ cfg( gdb) ]
691
+ let debug_interrupt = self
692
+ . interrupt_handle
693
+ . debug_interrupt
694
+ . load ( Ordering :: Relaxed ) ;
670
695
// Note: if a `InterruptHandle::kill()` called while this thread is **here**
671
696
// Then `cancel_requested` will be set to true again, which will cancel the **next vcpu run**.
672
697
// Additionally signals will be sent to this thread until `running` is set to false.
@@ -754,27 +779,23 @@ impl Hypervisor for HypervLinuxDriver {
754
779
Err ( e) => match e. errno ( ) {
755
780
// we send a signal to the thread to cancel execution this results in EINTR being returned by KVM so we return Cancelled
756
781
libc:: EINTR => {
757
- // If cancellation was not requested for this specific vm, the vcpu was interrupted because of stale signal
758
- // that was meant to be delivered to a previous/other vcpu on this same thread, so let's ignore it
782
+ // If cancellation was not requested for this specific vm, the vcpu was interrupted because of debug interrupt or
783
+ // a stale signal that meant to be delivered to a previous/other vcpu on this same thread, so let's ignore it
759
784
if cancel_requested {
760
785
self . interrupt_handle
761
786
. cancel_requested
762
787
. store ( false , Ordering :: Relaxed ) ;
763
788
HyperlightExit :: Cancelled ( )
764
789
} else {
765
- // In case of the gdb feature, if no cancellation was requested,
766
- // and the debugging is enabled it means the vCPU was stopped because
767
- // of an interrupt coming from the debugger thread
768
790
#[ cfg( gdb) ]
769
- if self . debug . is_some ( ) {
791
+ if debug_interrupt {
792
+ self . interrupt_handle
793
+ . debug_interrupt
794
+ . store ( false , Ordering :: Relaxed ) ;
795
+
770
796
// If the vCPU was stopped because of an interrupt, we need to
771
797
// return a special exit reason so that the gdb thread can handle it
772
798
// and resume execution
773
- // NOTE: There is a chance that the vCPU was stopped because of a stale
774
- // signal that was meant to be delivered to a previous/other vCPU on this
775
- // same thread, however, we cannot distinguish between the two cases, so
776
- // we assume that the vCPU was stopped because of an interrupt.
777
- // This is fine, because the debugger will be notified about an interrupt
778
799
HyperlightExit :: Debug ( VcpuStopReason :: Interrupt )
779
800
} else {
780
801
HyperlightExit :: Retry ( )
0 commit comments