@@ -45,11 +45,11 @@ use super::gdb::{
4545 DebugCommChannel , DebugMemoryAccess , DebugMsg , DebugResponse , GuestDebug , MshvDebug ,
4646 VcpuStopReason ,
4747} ;
48- use super :: { HyperlightExit , Hypervisor , LinuxInterruptHandle , VirtualCPU } ;
48+ use super :: { Hypervisor , LinuxInterruptHandle } ;
4949#[ cfg( gdb) ]
5050use crate :: HyperlightError ;
5151use crate :: hypervisor:: regs:: CommonFpu ;
52- use crate :: hypervisor:: { InterruptHandle , InterruptHandleImpl , get_memory_access_violation } ;
52+ use crate :: hypervisor:: { InterruptHandle , InterruptHandleImpl , HyperlightExit } ;
5353use crate :: mem:: memory_region:: { MemoryRegion , MemoryRegionFlags } ;
5454use crate :: mem:: mgr:: SandboxMemoryManager ;
5555use crate :: mem:: ptr:: { GuestPtr , RawPtr } ;
@@ -273,9 +273,6 @@ pub(crate) struct HypervLinuxDriver {
273273 entrypoint : u64 ,
274274 interrupt_handle : Arc < dyn InterruptHandleImpl > ,
275275
276- sandbox_regions : Vec < MemoryRegion > , // Initially mapped regions when sandbox is created
277- mmap_regions : Vec < MemoryRegion > , // Later mapped regions
278-
279276 #[ cfg( gdb) ]
280277 debug : Option < MshvDebug > ,
281278 #[ cfg( gdb) ]
@@ -299,7 +296,6 @@ impl HypervLinuxDriver {
299296 // TODO: refactor this function to take fewer arguments. Add trace_info to rt_cfg
300297 #[ instrument( skip_all, parent = Span :: current( ) , level = "Trace" ) ]
301298 pub ( crate ) fn new (
302- mem_regions : Vec < MemoryRegion > ,
303299 entrypoint_ptr : GuestPtr ,
304300 rsp_ptr : GuestPtr ,
305301 pml4_ptr : GuestPtr ,
@@ -365,11 +361,6 @@ impl HypervLinuxDriver {
365361 ( None , None )
366362 } ;
367363
368- mem_regions. iter ( ) . try_for_each ( |region| {
369- let mshv_region = region. to_owned ( ) . into ( ) ;
370- vm_fd. map_user_memory ( mshv_region)
371- } ) ?;
372-
373364 let interrupt_handle: Arc < dyn InterruptHandleImpl > = Arc :: new ( LinuxInterruptHandle {
374365 state : AtomicU8 :: new ( 0 ) ,
375366 #[ cfg( all(
@@ -396,8 +387,6 @@ impl HypervLinuxDriver {
396387 page_size : 0 ,
397388 vm_fd,
398389 vcpu_fd,
399- sandbox_regions : mem_regions,
400- mmap_regions : Vec :: new ( ) ,
401390 entrypoint : entrypoint_ptr. absolute ( ) ?,
402391 orig_rsp : rsp_ptr,
403392 interrupt_handle : interrupt_handle. clone ( ) ,
@@ -431,13 +420,6 @@ impl Debug for HypervLinuxDriver {
431420 f. field ( "Entrypoint" , & self . entrypoint )
432421 . field ( "Original RSP" , & self . orig_rsp ) ;
433422
434- for region in & self . sandbox_regions {
435- f. field ( "Sandbox Memory Region" , & region) ;
436- }
437- for region in & self . mmap_regions {
438- f. field ( "Mapped Memory Region" , & region) ;
439- }
440-
441423 let regs = self . vcpu_fd . get_regs ( ) ;
442424
443425 if let Ok ( regs) = regs {
@@ -488,51 +470,22 @@ impl Hypervisor for HypervLinuxDriver {
488470 } ;
489471 self . vcpu_fd . set_regs ( & regs) ?;
490472
491- let interrupt_handle = self . interrupt_handle . clone ( ) ;
492-
493- VirtualCPU :: run (
494- self . as_mut_hypervisor ( ) ,
495- interrupt_handle,
496- mem_mgr,
497- host_funcs,
498- #[ cfg( gdb) ]
499- dbg_mem_access_fn,
500- )
473+ Ok ( ( ) )
501474 }
502475
503- #[ instrument( err( Debug ) , skip_all, parent = Span :: current( ) , level = "Trace" ) ]
504- unsafe fn map_region ( & mut self , rgn : & MemoryRegion ) -> Result < ( ) > {
505- if [
506- rgn. guest_region . start ,
507- rgn. guest_region . end ,
508- rgn. host_region . start ,
509- rgn. host_region . end ,
510- ]
511- . iter ( )
512- . any ( |x| x % self . page_size != 0 )
513- {
514- log_then_return ! ( "region is not page-aligned" ) ;
515- }
516- let mshv_region: mshv_user_mem_region = rgn. to_owned ( ) . into ( ) ;
476+ /// # Safety
477+ /// The caller must ensure that the memory region is valid and points to valid memory,
478+ /// and lives long enough for the VM to use it.
479+ unsafe fn map_memory ( & mut self , ( _slot, region) : ( u32 , & MemoryRegion ) ) -> Result < ( ) > {
480+ let mshv_region: mshv_user_mem_region = region. into ( ) ;
517481 self . vm_fd . map_user_memory ( mshv_region) ?;
518- self . mmap_regions . push ( rgn. to_owned ( ) ) ;
519482 Ok ( ( ) )
520483 }
521484
522- #[ instrument( err( Debug ) , skip_all, parent = Span :: current( ) , level = "Trace" ) ]
523- unsafe fn unmap_region ( & mut self , region : & MemoryRegion ) -> Result < ( ) > {
524- if let Some ( pos) = self . mmap_regions . iter ( ) . position ( |r| r == region) {
525- let removed_region = self . mmap_regions . remove ( pos) ;
526- let mshv_region: mshv_user_mem_region = removed_region. into ( ) ;
527- self . vm_fd . unmap_user_memory ( mshv_region) ?;
528- Ok ( ( ) )
529- } else {
530- Err ( new_error ! ( "Tried to unmap region that is not mapped" ) )
531- }
532- }
533-
534- fn get_mapped_regions ( & self ) -> Box < dyn ExactSizeIterator < Item = & MemoryRegion > + ' _ > {
535- Box :: new ( self . mmap_regions . iter ( ) )
485+ fn unmap_memory ( & mut self , ( _slot, region) : ( u32 , & MemoryRegion ) ) -> Result < ( ) > {
486+ let mshv_region: mshv_user_mem_region = region. into ( ) ;
487+ self . vm_fd . unmap_user_memory ( mshv_region) ?;
488+ Ok ( ( ) )
536489 }
537490
538491 #[ instrument( err( Debug ) , skip_all, parent = Span :: current( ) , level = "Trace" ) ]
@@ -555,61 +508,11 @@ impl Hypervisor for HypervLinuxDriver {
555508 // reset fpu state
556509 self . set_fpu ( & CommonFpu :: default ( ) ) ?;
557510
558- let interrupt_handle = self . interrupt_handle . clone ( ) ;
559-
560511 // run
561- VirtualCPU :: run (
562- self . as_mut_hypervisor ( ) ,
563- interrupt_handle,
564- mem_mgr,
565- host_funcs,
566- #[ cfg( gdb) ]
567- dbg_mem_access_fn,
568- )
569- }
570-
571- #[ instrument( err( Debug ) , skip_all, parent = Span :: current( ) , level = "Trace" ) ]
572- fn handle_io (
573- & mut self ,
574- port : u16 ,
575- data : Vec < u8 > ,
576- rip : u64 ,
577- instruction_length : u64 ,
578- mem_mgr : & mut SandboxMemoryManager < HostSharedMemory > ,
579- host_funcs : & Arc < Mutex < FunctionRegistry > > ,
580- ) -> Result < ( ) > {
581- let mut padded = [ 0u8 ; 4 ] ;
582- let copy_len = data. len ( ) . min ( 4 ) ;
583- padded[ ..copy_len] . copy_from_slice ( & data[ ..copy_len] ) ;
584- let val = u32:: from_le_bytes ( padded) ;
585-
586- #[ cfg( feature = "mem_profile" ) ]
587- {
588- let regs = self . regs ( ) ?;
589- let trace_info = self . trace_info_mut ( ) ;
590- handle_outb ( mem_mgr, host_funcs, port, val, & regs, trace_info) ?;
591- }
592- #[ cfg( not( feature = "mem_profile" ) ) ]
593- {
594- handle_outb ( mem_mgr, host_funcs, port, val) ?;
595- }
596-
597- // update rip
598- self . vcpu_fd . set_reg ( & [ hv_register_assoc {
599- name : hv_register_name_HV_X64_REGISTER_RIP,
600- value : hv_register_value {
601- reg64 : rip + instruction_length,
602- } ,
603- ..Default :: default ( )
604- } ] ) ?;
605512 Ok ( ( ) )
606513 }
607514
608- #[ instrument( err( Debug ) , skip_all, parent = Span :: current( ) , level = "Trace" ) ]
609- fn run (
610- & mut self ,
611- #[ cfg( feature = "trace_guest" ) ] tc : & mut crate :: sandbox:: trace:: TraceContext ,
612- ) -> Result < super :: HyperlightExit > {
515+ fn run_vcpu ( & mut self ) -> Result < HyperlightExit > {
613516 const HALT_MESSAGE : hv_message_type = hv_message_type_HVMSG_X64_HALT;
614517 const IO_PORT_INTERCEPT_MESSAGE : hv_message_type =
615518 hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT;
@@ -618,97 +521,67 @@ impl Hypervisor for HypervLinuxDriver {
618521 #[ cfg( gdb) ]
619522 const EXCEPTION_INTERCEPT : hv_message_type = hv_message_type_HVMSG_X64_EXCEPTION_INTERCEPT;
620523
621- #[ cfg( feature = "trace_guest" ) ]
622- tc. setup_guest_trace ( Span :: current ( ) . context ( ) ) ;
623-
624524 let exit_reason = self . vcpu_fd . run ( ) ;
625525
626526 let result = match exit_reason {
627527 Ok ( m) => match m. header . message_type {
628- HALT_MESSAGE => {
629- crate :: debug!( "mshv - Halt Details : {:#?}" , & self ) ;
630- HyperlightExit :: Halt ( )
631- }
528+ HALT_MESSAGE => HyperlightExit :: Halt ( ) ,
632529 IO_PORT_INTERCEPT_MESSAGE => {
633530 let io_message = m. to_ioport_info ( ) . map_err ( mshv_ioctls:: MshvError :: from) ?;
634531 let port_number = io_message. port_number ;
635532 let rip = io_message. header . rip ;
636533 let rax = io_message. rax ;
637534 let instruction_length = io_message. header . instruction_length ( ) as u64 ;
638- crate :: debug!( "mshv IO Details : \n Port : {}\n {:#?}" , port_number, & self ) ;
639- HyperlightExit :: IoOut (
640- port_number,
641- rax. to_le_bytes ( ) . to_vec ( ) ,
642- rip,
643- instruction_length,
644- )
535+
536+ // mshv, unlike kvm, does not automatically increment RIP
537+ self . vcpu_fd . set_reg ( & [ hv_register_assoc {
538+ name : hv_register_name_HV_X64_REGISTER_RIP,
539+ value : hv_register_value {
540+ reg64 : rip + instruction_length,
541+ } ,
542+ ..Default :: default ( )
543+ } ] ) ?;
544+ HyperlightExit :: IoOut ( port_number, rax. to_le_bytes ( ) . to_vec ( ) )
645545 }
646546 UNMAPPED_GPA_MESSAGE => {
647547 let mimo_message = m. to_memory_info ( ) . map_err ( mshv_ioctls:: MshvError :: from) ?;
648548 let addr = mimo_message. guest_physical_address ;
649- crate :: debug!(
650- "mshv MMIO unmapped GPA -Details: Address: {} \n {:#?}" ,
651- addr,
652- & self
653- ) ;
654- HyperlightExit :: Mmio ( addr)
549+ match MemoryRegionFlags :: try_from ( mimo_message) ? {
550+ MemoryRegionFlags :: READ => HyperlightExit :: MmioRead ( addr) ,
551+ MemoryRegionFlags :: WRITE => HyperlightExit :: MmioWrite ( addr) ,
552+ _ => HyperlightExit :: Unknown ( "Unknown MMIO access" . to_string ( ) ) ,
553+ }
655554 }
656555 INVALID_GPA_ACCESS_MESSAGE => {
657556 let mimo_message = m. to_memory_info ( ) . map_err ( mshv_ioctls:: MshvError :: from) ?;
658557 let gpa = mimo_message. guest_physical_address ;
659558 let access_info = MemoryRegionFlags :: try_from ( mimo_message) ?;
660- crate :: debug!(
661- "mshv MMIO invalid GPA access -Details: Address: {} \n {:#?}" ,
662- gpa,
663- & self
664- ) ;
665- match get_memory_access_violation (
666- gpa as usize ,
667- self . sandbox_regions . iter ( ) . chain ( self . mmap_regions . iter ( ) ) ,
668- access_info,
669- ) {
670- Some ( access_info_violation) => access_info_violation,
671- None => HyperlightExit :: Mmio ( gpa) ,
559+ match access_info {
560+ MemoryRegionFlags :: READ => HyperlightExit :: MmioRead ( gpa) ,
561+ MemoryRegionFlags :: WRITE => HyperlightExit :: MmioWrite ( gpa) ,
562+ _ => HyperlightExit :: Unknown ( "Unknown MMIO access" . to_string ( ) ) ,
672563 }
673564 }
674- // The only case an intercept exit is expected is when debugging is enabled
675- // and the intercepts are installed.
676- // Provide the extra information about the exception to accurately determine
677- // the stop reason
678565 #[ cfg( gdb) ]
679566 EXCEPTION_INTERCEPT => {
680- // Extract exception info from the message so we can figure out
681- // more information about the vCPU state
682- let ex_info = match m. to_exception_info ( ) . map_err ( mshv_ioctls:: MshvError :: from)
683- {
684- Ok ( info) => info,
685- Err ( e) => {
686- log_then_return ! ( "Error converting to exception info: {:?}" , e) ;
687- }
688- } ;
689-
690- match self . get_stop_reason ( ex_info) {
691- Ok ( reason) => HyperlightExit :: Debug ( reason) ,
692- Err ( e) => {
693- log_then_return ! ( "Error getting stop reason: {:?}" , e) ;
694- }
567+ use mshv_bindings:: DebugRegisters ;
568+
569+ let ex_info = m
570+ . to_exception_info ( )
571+ . map_err ( mshv_ioctls:: MshvError :: from) ?;
572+ let DebugRegisters { dr6, .. } = self . vcpu_fd . get_debug_regs ( ) ?;
573+ HyperlightExit :: Debug {
574+ dr6,
575+ exception : ex_info. exception_vector as u32 ,
695576 }
696577 }
697- other => {
698- crate :: debug!( "mshv Other Exit: Exit: {:#?} \n {:#?}" , other, & self ) ;
699- #[ cfg( crashdump) ]
700- let _ = crashdump:: generate_crashdump ( self ) ;
701- log_then_return ! ( "unknown Hyper-V run message type {:?}" , other) ;
702- }
578+ other => HyperlightExit :: Unknown ( format ! ( "Unknown MSHV VCPU exit: {:?}" , other) ) ,
703579 } ,
704580 Err ( e) => match e. errno ( ) {
705- // We send a signal (SIGRTMIN+offset) to interrupt the vcpu, which causes EINTR
581+ // InterruptHandle::kill() sends a signal (SIGRTMIN+offset) to interrupt the vcpu, which causes EINTR
706582 libc:: EINTR => HyperlightExit :: Cancelled ( ) ,
707583 libc:: EAGAIN => HyperlightExit :: Retry ( ) ,
708- _ => {
709- crate :: debug!( "mshv Error - Details: Error: {} \n {:#?}" , e, & self ) ;
710- log_then_return ! ( "Error running VCPU {:?}" , e) ;
711- }
584+ _ => HyperlightExit :: Unknown ( format ! ( "Unknown MSHV VCPU error: {}" , e) ) ,
712585 } ,
713586 } ;
714587 Ok ( result)
@@ -747,11 +620,6 @@ impl Hypervisor for HypervLinuxDriver {
747620 Ok ( ( ) )
748621 }
749622
750- #[ instrument( skip_all, parent = Span :: current( ) , level = "Trace" ) ]
751- fn as_mut_hypervisor ( & mut self ) -> & mut dyn Hypervisor {
752- self as & mut dyn Hypervisor
753- }
754-
755623 fn interrupt_handle ( & self ) -> Arc < dyn InterruptHandle > {
756624 self . interrupt_handle . clone ( )
757625 }
@@ -970,13 +838,6 @@ impl Drop for HypervLinuxDriver {
970838 #[ instrument( skip_all, parent = Span :: current( ) , level = "Trace" ) ]
971839 fn drop ( & mut self ) {
972840 self . interrupt_handle . set_dropped ( ) ;
973- for region in self . sandbox_regions . iter ( ) . chain ( self . mmap_regions . iter ( ) ) {
974- let mshv_region: mshv_user_mem_region = region. to_owned ( ) . into ( ) ;
975- match self . vm_fd . unmap_user_memory ( mshv_region) {
976- Ok ( _) => ( ) ,
977- Err ( e) => error ! ( "Failed to unmap user memory in HyperVOnLinux ({:?})" , e) ,
978- }
979- }
980841 }
981842}
982843
@@ -1036,7 +897,6 @@ mod tests {
1036897 let config: SandboxConfiguration = Default :: default ( ) ;
1037898
1038899 super :: HypervLinuxDriver :: new (
1039- regions. build ( ) ,
1040900 entrypoint_ptr,
1041901 rsp_ptr,
1042902 pml4_ptr,
0 commit comments