@@ -14,17 +14,56 @@ See the License for the specific language governing permissions and
1414limitations under the License.
1515*/
1616
17- use crate :: Result ;
17+ #[ cfg( gdb) ]
18+ use std:: collections:: HashMap ;
19+ #[ cfg( crashdump) ]
20+ use std:: path:: Path ;
21+ #[ cfg( any( kvm, mshv3) ) ]
22+ use std:: sync:: atomic:: AtomicU64 ;
23+ use std:: sync:: atomic:: { AtomicBool , AtomicU8 } ;
24+ use std:: sync:: { Arc , Mutex } ;
25+
26+ use log:: LevelFilter ;
27+ use tracing:: { Span , instrument} ;
28+ #[ cfg( feature = "trace_guest" ) ]
29+ use tracing_opentelemetry:: OpenTelemetrySpanExt ;
1830
19- use crate :: hypervisor:: { Hypervisor , InterruptHandle } ;
20- use crate :: mem:: memory_region:: MemoryRegion ;
31+ #[ cfg( target_os = "windows" ) ]
32+ use super :: WindowsInterruptHandle ;
33+ #[ cfg( gdb) ]
34+ use super :: gdb:: { DebugCommChannel , DebugMsg , DebugResponse , DebuggableVm , VcpuStopReason , arch} ;
35+ use super :: regs:: { CommonFpu , CommonRegisters } ;
36+ use crate :: HyperlightError :: { ExecutionCanceledByHost , NoHypervisorFound } ;
37+ #[ cfg( not( gdb) ) ]
38+ use crate :: hypervisor:: Hypervisor ;
39+ #[ cfg( any( kvm, mshv3) ) ]
40+ use crate :: hypervisor:: LinuxInterruptHandle ;
41+ #[ cfg( crashdump) ]
42+ use crate :: hypervisor:: crashdump;
43+ #[ cfg( mshv3) ]
44+ use crate :: hypervisor:: hyperv_linux:: MshvVm ;
45+ #[ cfg( target_os = "windows" ) ]
46+ use crate :: hypervisor:: hyperv_windows:: WhpVm ;
47+ #[ cfg( kvm) ]
48+ use crate :: hypervisor:: kvm:: KvmVm ;
49+ use crate :: hypervisor:: regs:: CommonSpecialRegisters ;
50+ #[ cfg( target_os = "windows" ) ]
51+ use crate :: hypervisor:: wrappers:: HandleWrapper ;
52+ use crate :: hypervisor:: { HyperlightExit , InterruptHandle , InterruptHandleImpl , get_max_log_level} ;
53+ use crate :: mem:: memory_region:: { MemoryRegion , MemoryRegionFlags , MemoryRegionType } ;
2154use crate :: mem:: mgr:: SandboxMemoryManager ;
22- use crate :: mem:: ptr:: RawPtr ;
55+ use crate :: mem:: ptr:: { GuestPtr , RawPtr } ;
2356use crate :: mem:: shared_mem:: HostSharedMemory ;
57+ use crate :: metrics:: { METRIC_ERRONEOUS_VCPU_KICKS , METRIC_GUEST_CANCELLATION } ;
58+ use crate :: sandbox:: SandboxConfiguration ;
2459use crate :: sandbox:: host_funcs:: FunctionRegistry ;
25-
26- use log:: LevelFilter ;
27- use std:: sync:: { Arc , Mutex } ;
60+ use crate :: sandbox:: hypervisor:: { HypervisorType , get_available_hypervisor} ;
61+ use crate :: sandbox:: outb:: handle_outb;
62+ #[ cfg( feature = "mem_profile" ) ]
63+ use crate :: sandbox:: trace:: MemTraceInfo ;
64+ #[ cfg( crashdump) ]
65+ use crate :: sandbox:: uninitialized:: SandboxRuntimeConfig ;
66+ use crate :: { HyperlightError , Result , log_then_return, new_error} ;
2867
2968pub ( crate ) struct HyperlightVm {
3069 #[ cfg( gdb) ]
@@ -52,8 +91,124 @@ pub(crate) struct HyperlightVm {
5291}
5392
5493impl HyperlightVm {
55- pub ( crate ) fn new ( inner : Box < dyn Hypervisor > ) -> Self {
56- Self { vm : inner }
94+ /// Create a new HyperlightVm instance (will not run vm until calling `initialise`)
95+ #[ instrument( err( Debug ) , skip_all, parent = Span :: current( ) , level = "Trace" ) ]
96+ #[ allow( clippy:: too_many_arguments) ]
97+ pub ( crate ) fn new (
98+ mem_regions : Vec < MemoryRegion > ,
99+ _pml4_addr : u64 ,
100+ entrypoint : u64 ,
101+ rsp : u64 ,
102+ #[ cfg_attr( not( any( kvm, mshv3) ) , allow( unused_variables) ) ] config : & SandboxConfiguration ,
103+ #[ cfg( target_os = "windows" ) ] handle : HandleWrapper ,
104+ #[ cfg( target_os = "windows" ) ] raw_size : usize ,
105+ #[ cfg( gdb) ] gdb_conn : Option < DebugCommChannel < DebugResponse , DebugMsg > > ,
106+ #[ cfg( crashdump) ] rt_cfg : SandboxRuntimeConfig ,
107+ #[ cfg( feature = "mem_profile" ) ] trace_info : MemTraceInfo ,
108+ ) -> Result < Self > {
109+ #[ cfg( gdb) ]
110+ type VmType = Box < dyn DebuggableVm > ;
111+ #[ cfg( not( gdb) ) ]
112+ type VmType = Box < dyn Hypervisor > ;
113+
114+ #[ allow( unused_mut) ] // needs to be mutable when gdb is enabled
115+ let mut vm: VmType = match get_available_hypervisor ( ) {
116+ #[ cfg( kvm) ]
117+ Some ( HypervisorType :: Kvm ) => Box :: new ( KvmVm :: new ( ) ?) ,
118+ #[ cfg( mshv3) ]
119+ Some ( HypervisorType :: Mshv ) => Box :: new ( MshvVm :: new ( ) ?) ,
120+ #[ cfg( target_os = "windows" ) ]
121+ Some ( HypervisorType :: Whp ) => Box :: new ( WhpVm :: new ( handle, raw_size) ?) ,
122+ None => return Err ( NoHypervisorFound ( ) ) ,
123+ } ;
124+
125+ for ( i, region) in mem_regions. iter ( ) . enumerate ( ) {
126+ // Safety: slots are unique and region points to valid memory since we created the regions
127+ unsafe { vm. map_memory ( ( i as u32 , region) ) ? } ;
128+ }
129+
130+ // Mark initial setup as complete for Windows - subsequent map_memory calls will fail
131+ #[ cfg( target_os = "windows" ) ]
132+ vm. complete_initial_memory_setup ( ) ;
133+
134+ #[ cfg( feature = "init-paging" ) ]
135+ vm. set_sregs ( & CommonSpecialRegisters :: standard_64bit_defaults ( _pml4_addr) ) ?;
136+ #[ cfg( not( feature = "init-paging" ) ) ]
137+ vm. set_sregs ( & CommonSpecialRegisters :: standard_real_mode_defaults ( ) ) ?;
138+
139+ #[ cfg( gdb) ]
140+ let gdb_conn = if let Some ( gdb_conn) = gdb_conn {
141+ // Add breakpoint to the entry point address
142+ vm. set_debug ( true ) ?;
143+ vm. add_hw_breakpoint ( entrypoint) ?;
144+
145+ Some ( gdb_conn)
146+ } else {
147+ None
148+ } ;
149+
150+ let rsp_gp = GuestPtr :: try_from ( RawPtr :: from ( rsp) ) ?;
151+
152+ #[ cfg( any( kvm, mshv3) ) ]
153+ let interrupt_handle: Arc < dyn InterruptHandleImpl > = Arc :: new ( LinuxInterruptHandle {
154+ state : AtomicU8 :: new ( 0 ) ,
155+ #[ cfg( all(
156+ target_arch = "x86_64" ,
157+ target_vendor = "unknown" ,
158+ target_os = "linux" ,
159+ target_env = "musl"
160+ ) ) ]
161+ tid : AtomicU64 :: new ( unsafe { libc:: pthread_self ( ) as u64 } ) ,
162+ #[ cfg( not( all(
163+ target_arch = "x86_64" ,
164+ target_vendor = "unknown" ,
165+ target_os = "linux" ,
166+ target_env = "musl"
167+ ) ) ) ]
168+ tid : AtomicU64 :: new ( unsafe { libc:: pthread_self ( ) } ) ,
169+ retry_delay : config. get_interrupt_retry_delay ( ) ,
170+ sig_rt_min_offset : config. get_interrupt_vcpu_sigrtmin_offset ( ) ,
171+ dropped : AtomicBool :: new ( false ) ,
172+ } ) ;
173+
174+ #[ cfg( target_os = "windows" ) ]
175+ let interrupt_handle: Arc < dyn InterruptHandleImpl > = Arc :: new ( WindowsInterruptHandle {
176+ state : AtomicU8 :: new ( 0 ) ,
177+ partition_handle : vm. partition_handle ( ) ,
178+ dropped : AtomicBool :: new ( false ) ,
179+ } ) ;
180+
181+ #[ allow( unused_mut) ] // needs to be mutable when gdb is enabled
182+ let mut ret = Self {
183+ vm,
184+ entrypoint,
185+ orig_rsp : rsp_gp,
186+ interrupt_handle,
187+ page_size : 0 , // Will be set in `initialise`
188+
189+ next_slot : mem_regions. len ( ) as u32 ,
190+ sandbox_regions : mem_regions,
191+ mmap_regions : Vec :: new ( ) ,
192+ freed_slots : Vec :: new ( ) ,
193+
194+ #[ cfg( gdb) ]
195+ gdb_conn,
196+ #[ cfg( gdb) ]
197+ sw_breakpoints : HashMap :: new ( ) ,
198+ #[ cfg( feature = "mem_profile" ) ]
199+ trace_info,
200+ #[ cfg( crashdump) ]
201+ rt_cfg,
202+ } ;
203+
204+ // Send the interrupt handle to the GDB thread if debugging is enabled
205+ // This is used to allow the GDB thread to stop the vCPU
206+ #[ cfg( gdb) ]
207+ if ret. gdb_conn . is_some ( ) {
208+ ret. send_dbg_msg ( DebugResponse :: InterruptHandle ( ret. interrupt_handle . clone ( ) ) ) ?;
209+ }
210+
211+ Ok ( ret)
57212 }
58213
59214 /// Initialise the internally stored vCPU with the given PEB address and
@@ -178,14 +333,14 @@ impl HyperlightVm {
178333 }
179334
180335 pub ( crate ) fn interrupt_handle ( & self ) -> Arc < dyn InterruptHandle > {
181- self . vm . interrupt_handle ( )
336+ self . interrupt_handle . clone ( )
182337 }
183338
184339 pub ( crate ) fn clear_cancel ( & self ) {
185- self . vm . clear_cancel ( )
340+ self . interrupt_handle . clear_cancel ( ) ;
186341 }
187342
188- fn run (
343+ fn run (
189344 & mut self ,
190345 mem_mgr : & mut SandboxMemoryManager < HostSharedMemory > ,
191346 host_funcs : & Arc < Mutex < FunctionRegistry > > ,
@@ -626,7 +781,11 @@ impl HyperlightVm {
626781 }
627782 }
628783}
629- }
784+
785+ impl Drop for HyperlightVm {
786+ fn drop ( & mut self ) {
787+ self . interrupt_handle . set_dropped ( ) ;
788+ }
630789}
631790
632791/// The vCPU tried to access the given addr
0 commit comments