From 108e8f9dff2392f05f57e668c2a0ab4557f1d354 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Sat, 22 Feb 2025 01:53:09 +0000 Subject: [PATCH] hypervisor: mshv: handle cross-page access in emulator Signed-off-by: Wei Liu --- hypervisor/src/mshv/x86_64/emulator.rs | 76 +++++++++++++++++++++----- 1 file changed, 63 insertions(+), 13 deletions(-) diff --git a/hypervisor/src/mshv/x86_64/emulator.rs b/hypervisor/src/mshv/x86_64/emulator.rs index e6b0a83ca..a8f38ba86 100644 --- a/hypervisor/src/mshv/x86_64/emulator.rs +++ b/hypervisor/src/mshv/x86_64/emulator.rs @@ -35,12 +35,7 @@ impl MshvEmulatorContext<'_> { } } - fn read_memory_flags( - &self, - gva: u64, - data: &mut [u8], - flags: u32, - ) -> Result<(), PlatformError> { + fn r(&self, gva: u64, data: &mut [u8], flags: u32) -> Result<(), PlatformError> { let gpa = self.translate(gva, flags)?; debug!( "mshv emulator: memory read {} bytes from [{:#x} -> {:#x}]", @@ -59,17 +54,38 @@ impl MshvEmulatorContext<'_> { Ok(()) } -} -/// Platform emulation for Hyper-V -impl PlatformEmulator for MshvEmulatorContext<'_> { - type CpuState = EmulatorCpuState; + fn read_memory_flags( + &self, + gva: u64, + data: &mut [u8], + flags: u32, + ) -> Result<(), PlatformError> { + let mut len = data.len() as u64; - fn read_memory(&self, gva: u64, data: &mut [u8]) -> Result<(), PlatformError> { - self.read_memory_flags(gva, data, HV_TRANSLATE_GVA_VALIDATE_READ) + // Compare the page number of the first and last byte. If they are different, this is a + // cross-page access. + let pg1 = gva >> HV_HYP_PAGE_SHIFT; + let pg2 = (gva + len - 1) >> HV_HYP_PAGE_SHIFT; + let cross_page = pg1 != pg2; + + if cross_page { + // We only handle one page cross-page access + assert!(pg1 + 1 == pg2); + let n = (gva + len) & HV_HYP_PAGE_MASK as u64; + len -= n; + } + + self.r(gva, &mut data[..len as usize], flags)?; + + if cross_page { + self.r(gva + len, &mut data[len as usize..], flags)?; + } + + Ok(()) } - fn write_memory(&mut self, gva: u64, data: &[u8]) -> Result<(), PlatformError> { + fn w(&mut self, gva: u64, data: &[u8]) -> Result<(), PlatformError> { let gpa = self.translate(gva, HV_TRANSLATE_GVA_VALIDATE_WRITE)?; debug!( "mshv emulator: memory write {} bytes at [{:#x} -> {:#x}]", @@ -88,6 +104,40 @@ impl PlatformEmulator for MshvEmulatorContext<'_> { Ok(()) } +} + +/// Platform emulation for Hyper-V +impl PlatformEmulator for MshvEmulatorContext<'_> { + type CpuState = EmulatorCpuState; + + fn read_memory(&self, gva: u64, data: &mut [u8]) -> Result<(), PlatformError> { + self.read_memory_flags(gva, data, HV_TRANSLATE_GVA_VALIDATE_READ) + } + + fn write_memory(&mut self, gva: u64, data: &[u8]) -> Result<(), PlatformError> { + let mut len = data.len() as u64; + + // Compare the page number of the first and last byte. If they are different, this is a + // cross-page access. + let pg1 = gva >> HV_HYP_PAGE_SHIFT; + let pg2 = (gva + len - 1) >> HV_HYP_PAGE_SHIFT; + let cross_page = pg1 != pg2; + + if cross_page { + // We only handle one page cross-page access + assert!(pg1 + 1 == pg2); + let n = (gva + len) & HV_HYP_PAGE_MASK as u64; + len -= n; + } + + self.w(gva, &data[..len as usize])?; + + if cross_page { + self.w(gva + len, &data[len as usize..])?; + } + + Ok(()) + } fn cpu_state(&self, cpu_id: usize) -> Result { if cpu_id != self.vcpu.vp_index as usize {