hypervisor: mshv: handle cross-page access in emulator

Signed-off-by: Wei Liu <liuwe@microsoft.com>
This commit is contained in:
Wei Liu
2025-02-22 01:53:09 +00:00
committed by Wei Liu
parent 5ab2feae70
commit 108e8f9dff

View File

@@ -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<Self::CpuState, PlatformError> {
if cpu_id != self.vcpu.vp_index as usize {