@@ -18,14 +18,17 @@ use core::ffi::c_void;
18
18
use std:: fmt;
19
19
use std:: fmt:: { Debug , Formatter } ;
20
20
use std:: string:: String ;
21
+ use std:: sync:: atomic:: { AtomicBool , Ordering } ;
22
+ use std:: sync:: Arc ;
21
23
22
24
use hyperlight_common:: mem:: PAGE_SIZE_USIZE ;
23
25
use log:: LevelFilter ;
24
26
use tracing:: { instrument, Span } ;
25
27
use windows:: Win32 :: System :: Hypervisor :: {
26
- WHvX64RegisterCr0 , WHvX64RegisterCr3 , WHvX64RegisterCr4 , WHvX64RegisterCs , WHvX64RegisterEfer ,
27
- WHV_MEMORY_ACCESS_TYPE , WHV_PARTITION_HANDLE , WHV_REGISTER_VALUE , WHV_RUN_VP_EXIT_CONTEXT ,
28
- WHV_RUN_VP_EXIT_REASON , WHV_X64_SEGMENT_REGISTER , WHV_X64_SEGMENT_REGISTER_0 ,
28
+ WHvCancelRunVirtualProcessor , WHvX64RegisterCr0 , WHvX64RegisterCr3 , WHvX64RegisterCr4 ,
29
+ WHvX64RegisterCs , WHvX64RegisterEfer , WHV_MEMORY_ACCESS_TYPE , WHV_PARTITION_HANDLE ,
30
+ WHV_REGISTER_VALUE , WHV_RUN_VP_EXIT_CONTEXT , WHV_RUN_VP_EXIT_REASON , WHV_X64_SEGMENT_REGISTER ,
31
+ WHV_X64_SEGMENT_REGISTER_0 ,
29
32
} ;
30
33
31
34
use super :: fpu:: { FP_TAG_WORD_DEFAULT , MXCSR_DEFAULT } ;
@@ -37,11 +40,11 @@ use super::surrogate_process_manager::*;
37
40
use super :: windows_hypervisor_platform:: { VMPartition , VMProcessor } ;
38
41
use super :: wrappers:: { HandleWrapper , WHvFPURegisters } ;
39
42
use super :: {
40
- HyperlightExit , Hypervisor , VirtualCPU , CR0_AM , CR0_ET , CR0_MP , CR0_NE , CR0_PE , CR0_PG , CR0_WP ,
41
- CR4_OSFXSR , CR4_OSXMMEXCPT , CR4_PAE , EFER_LMA , EFER_LME , EFER_NX , EFER_SCE ,
43
+ HyperlightExit , Hypervisor , InterruptHandle , VirtualCPU , CR0_AM , CR0_ET , CR0_MP , CR0_NE ,
44
+ CR0_PE , CR0_PG , CR0_WP , CR4_OSFXSR , CR4_OSXMMEXCPT , CR4_PAE , EFER_LMA , EFER_LME , EFER_NX ,
45
+ EFER_SCE ,
42
46
} ;
43
47
use crate :: hypervisor:: fpu:: FP_CONTROL_WORD_DEFAULT ;
44
- use crate :: hypervisor:: hypervisor_handler:: HypervisorHandler ;
45
48
use crate :: hypervisor:: wrappers:: WHvGeneralRegisters ;
46
49
use crate :: mem:: memory_region:: { MemoryRegion , MemoryRegionFlags } ;
47
50
use crate :: mem:: ptr:: { GuestPtr , RawPtr } ;
@@ -56,6 +59,7 @@ pub(crate) struct HypervWindowsDriver {
56
59
entrypoint : u64 ,
57
60
orig_rsp : GuestPtr ,
58
61
mem_regions : Vec < MemoryRegion > ,
62
+ interrupt_handle : Arc < WindowsInterruptHandle > ,
59
63
}
60
64
/* This does not automatically impl Send/Sync because the host
61
65
* address of the shared memory region is a raw pointer, which are
@@ -90,6 +94,7 @@ impl HypervWindowsDriver {
90
94
91
95
let mut proc = VMProcessor :: new ( partition) ?;
92
96
Self :: setup_initial_sregs ( & mut proc, pml4_address) ?;
97
+ let partition_handle = proc. get_partition_hdl ( ) ;
93
98
94
99
// subtract 2 pages for the guard pages, since when we copy memory to and from surrogate process,
95
100
// we don't want to copy the guard pages themselves (that would cause access violation)
@@ -102,6 +107,11 @@ impl HypervWindowsDriver {
102
107
entrypoint,
103
108
orig_rsp : GuestPtr :: try_from ( RawPtr :: from ( rsp) ) ?,
104
109
mem_regions,
110
+ interrupt_handle : Arc :: new ( WindowsInterruptHandle {
111
+ running : AtomicBool :: new ( false ) ,
112
+ partition_handle,
113
+ dropped : AtomicBool :: new ( false ) ,
114
+ } ) ,
105
115
} )
106
116
}
107
117
@@ -151,11 +161,6 @@ impl HypervWindowsDriver {
151
161
error. push_str ( & format ! ( "Registers: \n {:#?}" , self . processor. get_regs( ) ?) ) ;
152
162
Ok ( error)
153
163
}
154
-
155
- #[ instrument( skip_all, parent = Span :: current( ) , level = "Trace" ) ]
156
- pub ( crate ) fn get_partition_hdl ( & self ) -> WHV_PARTITION_HANDLE {
157
- self . processor . get_partition_hdl ( )
158
- }
159
164
}
160
165
161
166
impl Debug for HypervWindowsDriver {
@@ -307,7 +312,6 @@ impl Hypervisor for HypervWindowsDriver {
307
312
page_size : u32 ,
308
313
outb_hdl : OutBHandlerWrapper ,
309
314
mem_access_hdl : MemAccessHandlerWrapper ,
310
- hv_handler : Option < HypervisorHandler > ,
311
315
max_guest_log_level : Option < LevelFilter > ,
312
316
#[ cfg( gdb) ] dbg_mem_access_hdl : DbgMemAccessHandlerWrapper ,
313
317
) -> Result < ( ) > {
@@ -333,7 +337,6 @@ impl Hypervisor for HypervWindowsDriver {
333
337
334
338
VirtualCPU :: run (
335
339
self . as_mut_hypervisor ( ) ,
336
- hv_handler,
337
340
outb_hdl,
338
341
mem_access_hdl,
339
342
#[ cfg( gdb) ]
@@ -349,7 +352,6 @@ impl Hypervisor for HypervWindowsDriver {
349
352
dispatch_func_addr : RawPtr ,
350
353
outb_hdl : OutBHandlerWrapper ,
351
354
mem_access_hdl : MemAccessHandlerWrapper ,
352
- hv_handler : Option < HypervisorHandler > ,
353
355
#[ cfg( gdb) ] dbg_mem_access_hdl : DbgMemAccessHandlerWrapper ,
354
356
) -> Result < ( ) > {
355
357
// Reset general purpose registers, then set RIP and RSP
@@ -371,7 +373,6 @@ impl Hypervisor for HypervWindowsDriver {
371
373
372
374
VirtualCPU :: run (
373
375
self . as_mut_hypervisor ( ) ,
374
- hv_handler,
375
376
outb_hdl,
376
377
mem_access_hdl,
377
378
#[ cfg( gdb) ]
@@ -407,7 +408,11 @@ impl Hypervisor for HypervWindowsDriver {
407
408
408
409
#[ instrument( err( Debug ) , skip_all, parent = Span :: current( ) , level = "Trace" ) ]
409
410
fn run ( & mut self ) -> Result < super :: HyperlightExit > {
411
+ self . interrupt_handle . running . store ( true , Ordering :: Relaxed ) ;
410
412
let exit_context: WHV_RUN_VP_EXIT_CONTEXT = self . processor . run ( ) ?;
413
+ self . interrupt_handle
414
+ . running
415
+ . store ( false , Ordering :: Relaxed ) ;
411
416
412
417
let result = match exit_context. ExitReason {
413
418
// WHvRunVpExitReasonX64IoPortAccess
@@ -481,8 +486,8 @@ impl Hypervisor for HypervWindowsDriver {
481
486
Ok ( result)
482
487
}
483
488
484
- fn get_partition_handle ( & self ) -> WHV_PARTITION_HANDLE {
485
- self . processor . get_partition_hdl ( )
489
+ fn interrupt_handle ( & self ) -> Arc < dyn InterruptHandle > {
490
+ self . interrupt_handle . clone ( )
486
491
}
487
492
488
493
#[ instrument( skip_all, parent = Span :: current( ) , level = "Trace" ) ]
@@ -496,28 +501,26 @@ impl Hypervisor for HypervWindowsDriver {
496
501
}
497
502
}
498
503
499
- #[ cfg( test) ]
500
- pub mod tests {
501
- use std:: sync:: { Arc , Mutex } ;
504
+ impl Drop for HypervWindowsDriver {
505
+ fn drop ( & mut self ) {
506
+ self . interrupt_handle . dropped . store ( true , Ordering :: Relaxed ) ;
507
+ }
508
+ }
502
509
503
- use serial_test:: serial;
510
+ pub struct WindowsInterruptHandle {
511
+ // `WHvCancelRunVirtualProcessor()` will return Ok even if the vcpu is not running, which is the reason we need this flag.
512
+ running : AtomicBool ,
513
+ partition_handle : WHV_PARTITION_HANDLE ,
514
+ dropped : AtomicBool ,
515
+ }
504
516
505
- use crate :: hypervisor:: handlers:: { MemAccessHandler , OutBHandler } ;
506
- use crate :: hypervisor:: tests:: test_initialise;
507
- use crate :: Result ;
517
+ impl InterruptHandle for WindowsInterruptHandle {
518
+ fn kill ( & self ) -> bool {
519
+ self . running . load ( Ordering :: Relaxed )
520
+ && unsafe { WHvCancelRunVirtualProcessor ( self . partition_handle , 0 , 0 ) . is_ok ( ) }
521
+ }
508
522
509
- #[ test]
510
- #[ serial]
511
- fn test_init ( ) {
512
- let outb_handler = {
513
- let func: Box < dyn FnMut ( u16 , u32 ) -> Result < ( ) > + Send > =
514
- Box :: new ( |_, _| -> Result < ( ) > { Ok ( ( ) ) } ) ;
515
- Arc :: new ( Mutex :: new ( OutBHandler :: from ( func) ) )
516
- } ;
517
- let mem_access_handler = {
518
- let func: Box < dyn FnMut ( ) -> Result < ( ) > + Send > = Box :: new ( || -> Result < ( ) > { Ok ( ( ) ) } ) ;
519
- Arc :: new ( Mutex :: new ( MemAccessHandler :: from ( func) ) )
520
- } ;
521
- test_initialise ( outb_handler, mem_access_handler) . unwrap ( ) ;
523
+ fn dropped ( & self ) -> bool {
524
+ self . dropped . load ( Ordering :: Relaxed )
522
525
}
523
526
}
0 commit comments