Skip to content

Commit ae9550b

Browse files
committed
feat(vmx): enhance MMIO access information with guest register data
- Add new function `mmio_access_info_with_regs` to retrieve detailed MMIO access information - Include actual data for write operations by using guest general-purpose registers - Improve `mmio_access_info` function to provide more accurate information - Update `VmxVcpu` to use the new function for better handling of MMIO accesses
1 parent 7c34f2a commit ae9550b

File tree

2 files changed

+76
-5
lines changed

2 files changed

+76
-5
lines changed

src/vmx/vcpu.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,11 @@ impl<H: AxVCpuHal> VmxVcpu<H> {
873873
vmcs::mmio_access_info()
874874
}
875875

876+
/// MMIO access information with guest register data.
877+
pub fn mmio_access_info_with_regs(&self) -> AxResult<vmcs::MmioAccessInfo> {
878+
vmcs::mmio_access_info_with_regs(&self.guest_regs)
879+
}
880+
876881
/// Try to inject a pending event before next VM entry.
877882
fn inject_pending_events(&mut self) -> AxResult {
878883
if let Some(event) = self.pending_events.front() {
@@ -1238,7 +1243,7 @@ impl<H: AxVCpuHal> AxArchVCpu for VmxVcpu<H> {
12381243
VmxExitReason::EPT_VIOLATION => {
12391244
self.advance_rip(exit_info.exit_instruction_length as _)?;
12401245
self.advance_rip(exit_info.exit_instruction_length as _)?;
1241-
let mmio_info = self.mmio_access_info();
1246+
let mmio_info = self.mmio_access_info_with_regs();
12421247
error!("VMX EPT Violation: {:#x?} of {:#x?}", mmio_info, exit_info);
12431248
if let Ok(mmio_info) = mmio_info {
12441249
if mmio_info.is_read {

src/vmx/vmcs.rs

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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
797797
pub 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

Comments
 (0)