|
1 | 1 | use alloc::collections::VecDeque; |
| 2 | +use axaddrspace::device::AccessWidth; |
2 | 3 | use bit_field::BitField; |
3 | 4 | use core::fmt::{Debug, Formatter, Result}; |
4 | 5 | use core::{arch::naked_asm, mem::size_of}; |
5 | 6 | use raw_cpuid::CpuId; |
6 | 7 | use x86::bits64::vmx; |
7 | | -use x86::controlregs::{Xcr0, xcr0 as xcr0_read, xcr0_write}; |
| 8 | +use x86::controlregs::{xcr0 as xcr0_read, xcr0_write, Xcr0}; |
8 | 9 | use x86::dtables::{self, DescriptorTablePointer}; |
9 | 10 | use x86::segmentation::SegmentSelector; |
10 | 11 | use x86_64::registers::control::{Cr0, Cr0Flags, Cr3, Cr4, Cr4Flags, EferFlags}; |
11 | 12 |
|
12 | 13 | use axaddrspace::{GuestPhysAddr, GuestVirtAddr, HostPhysAddr, NestedPageFaultInfo}; |
13 | | -use axerrno::{AxResult, ax_err, ax_err_type}; |
14 | | -use axvcpu::{AccessWidth, AxArchVCpu, AxVCpuExitReason, AxVCpuHal}; |
| 14 | +use axerrno::{ax_err, ax_err_type, AxResult}; |
| 15 | +use axvcpu::{AxArchVCpu, AxVCpuExitReason, AxVCpuHal}; |
15 | 16 |
|
16 | | -use super::VmxExitInfo; |
17 | 17 | use super::as_axerr; |
18 | 18 | use super::definitions::VmxExitReason; |
19 | 19 | use super::structs::{IOBitmap, MsrBitmap, VmxRegion}; |
20 | 20 | use super::vmcs::{ |
21 | 21 | self, VmcsControl32, VmcsControl64, VmcsControlNW, VmcsGuest16, VmcsGuest32, VmcsGuest64, |
22 | 22 | VmcsGuestNW, VmcsHost16, VmcsHost32, VmcsHost64, VmcsHostNW, |
23 | 23 | }; |
| 24 | +use super::VmxExitInfo; |
24 | 25 | use crate::{ept::GuestPageWalkInfo, msr::Msr, regs::GeneralRegisters}; |
25 | 26 |
|
26 | 27 | const VMX_PREEMPTION_TIMER_SET_VALUE: u32 = 1_000_000; |
@@ -284,6 +285,11 @@ impl<H: AxVCpuHal> VmxVcpu<H> { |
284 | 285 | vmcs::exit_info() |
285 | 286 | } |
286 | 287 |
|
| 288 | + /// MMIO access information. |
| 289 | + pub fn mmio_access_info(&self) -> AxResult<vmcs::MmioAccessInfo> { |
| 290 | + vmcs::mmio_access_info() |
| 291 | + } |
| 292 | + |
287 | 293 | /// Raw information for VM Exits Due to Vectored Events, See SDM 25.9.2 |
288 | 294 | pub fn raw_interrupt_exit_info(&self) -> AxResult<u32> { |
289 | 295 | vmcs::raw_interrupt_exit_info() |
@@ -953,7 +959,7 @@ impl<H: AxVCpuHal> VmxVcpu<H> { |
953 | 959 | } |
954 | 960 |
|
955 | 961 | fn handle_cpuid(&mut self) -> AxResult { |
956 | | - use raw_cpuid::{CpuIdResult, cpuid}; |
| 962 | + use raw_cpuid::{cpuid, CpuIdResult}; |
957 | 963 |
|
958 | 964 | const VM_EXIT_INSTR_LEN_CPUID: u8 = 2; |
959 | 965 | const LEAF_FEATURE_INFO: u32 = 0x1; |
@@ -984,7 +990,7 @@ impl<H: AxVCpuHal> VmxVcpu<H> { |
984 | 990 | if regs_clone.rcx == 0 { |
985 | 991 | // Bit 05: WAITPKG. |
986 | 992 | res.ecx.set_bit(5, false); // clear waitpkg |
987 | | - // Bit 16: LA57. Supports 57-bit linear addresses and five-level paging if 1. |
| 993 | + // Bit 16: LA57. Supports 57-bit linear addresses and five-level paging if 1. |
988 | 994 | res.ecx.set_bit(16, false); // clear LA57 |
989 | 995 | } |
990 | 996 |
|
@@ -1028,7 +1034,9 @@ impl<H: AxVCpuHal> VmxVcpu<H> { |
1028 | 1034 |
|
1029 | 1035 | trace!( |
1030 | 1036 | "VM exit: CPUID({:#x}, {:#x}): {:?}", |
1031 | | - regs_clone.rax, regs_clone.rcx, res |
| 1037 | + regs_clone.rax, |
| 1038 | + regs_clone.rcx, |
| 1039 | + res |
1032 | 1040 | ); |
1033 | 1041 |
|
1034 | 1042 | let regs = self.regs_mut(); |
@@ -1229,6 +1237,50 @@ impl<H: AxVCpuHal> AxArchVCpu for VmxVcpu<H> { |
1229 | 1237 | } |
1230 | 1238 | } |
1231 | 1239 | } |
| 1240 | + VmxExitReason::EPT_VIOLATION => { |
| 1241 | + // SDM Vol. 3C, Section 27.2.1, Table 27-7 |
| 1242 | + if let Ok(mmio_info) = self.mmio_access_info() { |
| 1243 | + if mmio_info.is_read && !mmio_info.is_write { |
| 1244 | + // MMIO access |
| 1245 | + self.advance_rip(exit_info.exit_instruction_length as _)?; |
| 1246 | + error!( |
| 1247 | + "VMX unsupported MMIO-Exit: {:#x?} of {:#x?}", |
| 1248 | + mmio_info, exit_info |
| 1249 | + ); |
| 1250 | + error!("VCpu {:#x?}", self); |
| 1251 | + self.set_gpr(0, 0x1234); |
| 1252 | + AxVCpuExitReason::Nothing |
| 1253 | + // AxVCpuExitReason::MmioRead { |
| 1254 | + // addr: mmio_info.addr, |
| 1255 | + // width: mmio_info.access_width, |
| 1256 | + // reg: mmio_info.register.unwrap_or(0) as usize, |
| 1257 | + // reg_width: mmio_info.access_width, |
| 1258 | + // } |
| 1259 | + } else if mmio_info.is_write && !mmio_info.is_read { |
| 1260 | + // MMIO access |
| 1261 | + self.advance_rip(exit_info.exit_instruction_length as _)?; |
| 1262 | + AxVCpuExitReason::MmioWrite { |
| 1263 | + addr: mmio_info.addr, |
| 1264 | + width: mmio_info.access_width, |
| 1265 | + data: self.regs().get_reg_of_index( |
| 1266 | + mmio_info.register.unwrap_or(0) as u8, |
| 1267 | + ), |
| 1268 | + } |
| 1269 | + } |
| 1270 | + else { |
| 1271 | + warn!( |
| 1272 | + "VMX unsupported EPT-Exit: {:#x?} of {:#x?}", |
| 1273 | + mmio_info, exit_info |
| 1274 | + ); |
| 1275 | + warn!("VCpu {:#x?}", self); |
| 1276 | + AxVCpuExitReason::Halt |
| 1277 | + } |
| 1278 | + } else { |
| 1279 | + warn!("VMX unsupported EPT-Exit: {:#x?}", exit_info); |
| 1280 | + warn!("VCpu {:#x?}", self); |
| 1281 | + AxVCpuExitReason::Halt |
| 1282 | + } |
| 1283 | + } |
1232 | 1284 | _ => { |
1233 | 1285 | warn!("VMX unsupported VM-Exit: {:#x?}", exit_info); |
1234 | 1286 | warn!("VCpu {:#x?}", self); |
|
0 commit comments