@@ -786,19 +786,73 @@ pub fn cr_access_info() -> AxResult<CrAccessInfo> {
786786}
787787
788788/// Extract detailed MMIO access information from EPT violation.
789- ///
789+ ///
790790/// This function provides comprehensive information about MMIO device access
791791/// that triggered an EPT violation, including the access address, width,
792792/// read/write direction, and instruction details.
793- ///
793+ ///
794794/// # Returns
795795/// * `Ok(MmioAccessInfo)` - Detailed MMIO access information
796796/// * `Err(AxError)` - If VMCS read operations fail
797797pub fn mmio_access_info ( ) -> AxResult < MmioAccessInfo > {
798798 let qualification = VmcsReadOnlyNW :: EXIT_QUALIFICATION . read ( ) ?;
799799 let instruction_info = VmcsReadOnly32 :: VMEXIT_INSTRUCTION_INFO . read ( ) ?;
800800 let fault_guest_paddr = VmcsReadOnly64 :: GUEST_PHYSICAL_ADDR . read ( ) ? as usize ;
801- // VmcsGuestNW::CR0.write(guest_rax).unwrap(); // Example write to CR0, replace with actual logic
801+
802+ // Extract access type from qualification
803+ error ! ( "qualification: {:#x}" , qualification) ;
804+ let is_read = qualification. get_bit ( 0 ) ;
805+ // Access type is determined by the second bit in the qualification
806+ let is_write = qualification. get_bit ( 1 ) ;
807+ // Decode instruction information to get access width and register
808+
809+ let operand_size = instruction_info. get_bits ( 0 ..3 ) ;
810+ let access_width = match operand_size + 1 {
811+ 0 => AccessWidth :: Word , // 16-bit
812+ 1 => AccessWidth :: Dword , // 32-bit
813+ 2 => AccessWidth :: Qword , // 64-bit
814+ 3 => AccessWidth :: Byte , // 8-bit
815+ _ => AccessWidth :: Dword , // Default to 32-bit for unknown encodings
816+ } ;
817+
818+ let addr = GuestPhysAddr :: from ( fault_guest_paddr) ;
819+ let reg_index: u8 = instruction_info. get_bits ( 7 ..10 ) as u8 ;
820+
821+ // For write operations, we need to get the data from guest registers
822+ // This will be set by the caller who has access to guest registers
823+ let data = if is_write {
824+ Some ( 0 as u64 ) // Placeholder - will be filled by caller
825+ } else {
826+ None
827+ } ;
828+
829+ Ok ( MmioAccessInfo {
830+ addr,
831+ access_width,
832+ is_read,
833+ is_write,
834+ register : reg_index,
835+ data,
836+ } )
837+ }
838+
839+ /// Extract detailed MMIO access information from EPT violation with guest register data.
840+ ///
841+ /// This function provides comprehensive information about MMIO device access
842+ /// that triggered an EPT violation, including the access address, width,
843+ /// read/write direction, instruction details, and actual data for write operations.
844+ ///
845+ /// # Arguments
846+ /// * `guest_regs` - Reference to guest general-purpose registers
847+ ///
848+ /// # Returns
849+ /// * `Ok(MmioAccessInfo)` - Detailed MMIO access information with actual data
850+ /// * `Err(AxError)` - If VMCS read operations fail
851+ pub fn mmio_access_info_with_regs ( guest_regs : & crate :: regs:: GeneralRegisters ) -> AxResult < MmioAccessInfo > {
852+ let qualification = VmcsReadOnlyNW :: EXIT_QUALIFICATION . read ( ) ?;
853+ let instruction_info = VmcsReadOnly32 :: VMEXIT_INSTRUCTION_INFO . read ( ) ?;
854+ let fault_guest_paddr = VmcsReadOnly64 :: GUEST_PHYSICAL_ADDR . read ( ) ? as usize ;
855+
802856 // Extract access type from qualification
803857 error ! ( "qualification: {:#x}" , qualification) ;
804858 let is_read = qualification. get_bit ( 0 ) ;
@@ -818,8 +872,20 @@ pub fn mmio_access_info() -> AxResult<MmioAccessInfo> {
818872 let addr = GuestPhysAddr :: from ( fault_guest_paddr) ;
819873 let reg_index: u8 = instruction_info. get_bits ( 7 ..10 ) as u8 ;
820874
875+ // For write operations, get the actual data from the guest register
821876 let data = if is_write {
822- Some ( 0 as u64 )
877+ // Get the full register value
878+ let reg_value = guest_regs. get_reg_of_index ( reg_index) ;
879+
880+ // Mask the value based on access width to get only the relevant bits
881+ let masked_value = match access_width {
882+ AccessWidth :: Byte => reg_value & 0xFF ,
883+ AccessWidth :: Word => reg_value & 0xFFFF ,
884+ AccessWidth :: Dword => reg_value & 0xFFFFFFFF ,
885+ AccessWidth :: Qword => reg_value,
886+ } ;
887+
888+ Some ( masked_value)
823889 } else {
824890 None
825891 } ;
0 commit comments