From b73d94f969a763515ee36309f4b6ffd5af13d691 Mon Sep 17 00:00:00 2001 From: Jinank Jain Date: Sat, 13 Jul 2024 20:45:40 +0530 Subject: [PATCH] hypervisor: mshv: Refactor x86 emulator into different module This is a preparatory work to make space for ARM64 emulator. There is no functional change in this commit, just moving code from one file to another. Signed-off-by: Jinank Jain --- hypervisor/src/mshv/mod.rs | 167 ++----------------------- hypervisor/src/mshv/x86_64/emulator.rs | 145 +++++++++++++++++++++ hypervisor/src/mshv/x86_64/mod.rs | 2 + 3 files changed, 158 insertions(+), 156 deletions(-) create mode 100644 hypervisor/src/mshv/x86_64/emulator.rs diff --git a/hypervisor/src/mshv/mod.rs b/hypervisor/src/mshv/mod.rs index 3c50cce85..5fcff642c 100644 --- a/hypervisor/src/mshv/mod.rs +++ b/hypervisor/src/mshv/mod.rs @@ -3,18 +3,15 @@ // Copyright © 2020, Microsoft Corporation // -use crate::arch::emulator::{PlatformEmulator, PlatformError}; - +use crate::arch::emulator::PlatformEmulator; #[cfg(target_arch = "x86_64")] -use crate::arch::x86::emulator::{CpuStateManager, Emulator, EmulatorCpuState}; +use crate::arch::x86::emulator::Emulator; use crate::cpu; -use crate::cpu::Vcpu; use crate::hypervisor; +use crate::mshv::emulator::MshvEmulatorContext; use crate::vec_with_array_field; use crate::vm::{self, InterruptSourceConfig, VmOps}; use crate::HypervisorType; -#[cfg(target_arch = "x86_64")] -use iced_x86::Register; use mshv_bindings::*; use mshv_ioctls::{set_registers_64, InterruptRequest, Mshv, NoDatamatch, VcpuFd, VmFd, VmType}; use std::any::Any; @@ -22,18 +19,15 @@ use std::collections::HashMap; use std::sync::{Arc, RwLock}; use vfio_ioctls::VfioDeviceFd; use vm::DataMatch; - #[cfg(feature = "sev_snp")] mod snp_constants; // x86_64 dependencies #[cfg(target_arch = "x86_64")] pub mod x86_64; -#[cfg(feature = "sev_snp")] -use snp_constants::*; - +#[cfg(target_arch = "x86_64")] +use crate::arch::x86::{CpuIdEntry, FpuState, MsrEntry}; #[cfg(target_arch = "x86_64")] use crate::ClockData; - use crate::{ CpuState, IoEventAddress, IrqRoutingEntry, MpState, UserMemoryRegion, USER_MEMORY_REGION_ADJUSTABLE, USER_MEMORY_REGION_EXECUTE, USER_MEMORY_REGION_READ, @@ -41,18 +35,16 @@ use crate::{ }; #[cfg(feature = "sev_snp")] use igvm_defs::IGVM_VHS_SNP_ID_BLOCK; -use vmm_sys_util::eventfd::EventFd; -#[cfg(target_arch = "x86_64")] -pub use x86_64::VcpuMshvState; -#[cfg(target_arch = "x86_64")] -pub use x86_64::*; - +#[cfg(feature = "sev_snp")] +use snp_constants::*; #[cfg(target_arch = "x86_64")] use std::fs::File; use std::os::unix::io::AsRawFd; - +use vmm_sys_util::eventfd::EventFd; #[cfg(target_arch = "x86_64")] -use crate::arch::x86::{CpuIdEntry, FpuState, MsrEntry}; +pub use x86_64::*; +#[cfg(target_arch = "x86_64")] +pub use x86_64::{emulator, VcpuMshvState}; const DIRTY_BITMAP_CLEAR_DIRTY: u64 = 0x4; const DIRTY_BITMAP_SET_DIRTY: u64 = 0x8; @@ -1520,143 +1512,6 @@ impl MshvVcpu { } } -#[cfg(target_arch = "x86_64")] -struct MshvEmulatorContext<'a> { - vcpu: &'a MshvVcpu, - map: (u64, u64), // Initial GVA to GPA mapping provided by the hypervisor -} - -#[cfg(target_arch = "x86_64")] -impl<'a> MshvEmulatorContext<'a> { - // Do the actual gva -> gpa translation - #[allow(non_upper_case_globals)] - fn translate(&self, gva: u64, flags: u32) -> Result { - if self.map.0 == gva { - return Ok(self.map.1); - } - - let (gpa, result_code) = self - .vcpu - .translate_gva(gva, flags.into()) - .map_err(|e| PlatformError::TranslateVirtualAddress(anyhow!(e)))?; - - match result_code { - hv_translate_gva_result_code_HV_TRANSLATE_GVA_SUCCESS => Ok(gpa), - _ => Err(PlatformError::TranslateVirtualAddress(anyhow!(result_code))), - } - } - - fn read_memory_flags( - &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}]", - data.len(), - gva, - gpa - ); - - if let Some(vm_ops) = &self.vcpu.vm_ops { - if vm_ops.guest_mem_read(gpa, data).is_err() { - vm_ops - .mmio_read(gpa, data) - .map_err(|e| PlatformError::MemoryReadFailure(e.into()))?; - } - } - - Ok(()) - } -} - -#[cfg(target_arch = "x86_64")] -/// Platform emulation for Hyper-V -impl<'a> PlatformEmulator for MshvEmulatorContext<'a> { - 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 gpa = self.translate(gva, HV_TRANSLATE_GVA_VALIDATE_WRITE)?; - debug!( - "mshv emulator: memory write {} bytes at [{:#x} -> {:#x}]", - data.len(), - gva, - gpa - ); - - if let Some(vm_ops) = &self.vcpu.vm_ops { - if vm_ops.guest_mem_write(gpa, data).is_err() { - vm_ops - .mmio_write(gpa, data) - .map_err(|e| PlatformError::MemoryWriteFailure(e.into()))?; - } - } - - Ok(()) - } - - fn cpu_state(&self, cpu_id: usize) -> Result { - if cpu_id != self.vcpu.vp_index as usize { - return Err(PlatformError::GetCpuStateFailure(anyhow!( - "CPU id mismatch {:?} {:?}", - cpu_id, - self.vcpu.vp_index - ))); - } - - let regs = self - .vcpu - .get_regs() - .map_err(|e| PlatformError::GetCpuStateFailure(e.into()))?; - let sregs = self - .vcpu - .get_sregs() - .map_err(|e| PlatformError::GetCpuStateFailure(e.into()))?; - - debug!("mshv emulator: Getting new CPU state"); - debug!("mshv emulator: {:#x?}", regs); - - Ok(EmulatorCpuState { regs, sregs }) - } - - fn set_cpu_state(&self, cpu_id: usize, state: Self::CpuState) -> Result<(), PlatformError> { - if cpu_id != self.vcpu.vp_index as usize { - return Err(PlatformError::SetCpuStateFailure(anyhow!( - "CPU id mismatch {:?} {:?}", - cpu_id, - self.vcpu.vp_index - ))); - } - - debug!("mshv emulator: Setting new CPU state"); - debug!("mshv emulator: {:#x?}", state.regs); - - self.vcpu - .set_regs(&state.regs) - .map_err(|e| PlatformError::SetCpuStateFailure(e.into()))?; - self.vcpu - .set_sregs(&state.sregs) - .map_err(|e| PlatformError::SetCpuStateFailure(e.into())) - } - - fn fetch(&self, ip: u64, instruction_bytes: &mut [u8]) -> Result<(), PlatformError> { - let rip = - self.cpu_state(self.vcpu.vp_index as usize)? - .linearize(Register::CS, ip, false)?; - self.read_memory_flags( - rip, - instruction_bytes, - HV_TRANSLATE_GVA_VALIDATE_READ | HV_TRANSLATE_GVA_VALIDATE_EXECUTE, - ) - } -} - /// Wrapper over Mshv VM ioctls. pub struct MshvVm { fd: Arc, diff --git a/hypervisor/src/mshv/x86_64/emulator.rs b/hypervisor/src/mshv/x86_64/emulator.rs new file mode 100644 index 000000000..104234cc7 --- /dev/null +++ b/hypervisor/src/mshv/x86_64/emulator.rs @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause +// +// Copyright © 2024, Microsoft Corporation +// + +use crate::arch::emulator::{PlatformEmulator, PlatformError}; +use crate::arch::x86::emulator::{CpuStateManager, EmulatorCpuState}; +use crate::cpu::Vcpu; +use crate::mshv::MshvVcpu; +use iced_x86::Register; +use mshv_bindings::*; + +pub struct MshvEmulatorContext<'a> { + pub vcpu: &'a MshvVcpu, + pub map: (u64, u64), // Initial GVA to GPA mapping provided by the hypervisor +} + +impl<'a> MshvEmulatorContext<'a> { + // Do the actual gva -> gpa translation + #[allow(non_upper_case_globals)] + fn translate(&self, gva: u64, flags: u32) -> Result { + if self.map.0 == gva { + return Ok(self.map.1); + } + + let (gpa, result_code) = self + .vcpu + .translate_gva(gva, flags.into()) + .map_err(|e| PlatformError::TranslateVirtualAddress(anyhow!(e)))?; + + match result_code { + hv_translate_gva_result_code_HV_TRANSLATE_GVA_SUCCESS => Ok(gpa), + _ => Err(PlatformError::TranslateVirtualAddress(anyhow!(result_code))), + } + } + + fn read_memory_flags( + &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}]", + data.len(), + gva, + gpa + ); + + if let Some(vm_ops) = &self.vcpu.vm_ops { + if vm_ops.guest_mem_read(gpa, data).is_err() { + vm_ops + .mmio_read(gpa, data) + .map_err(|e| PlatformError::MemoryReadFailure(e.into()))?; + } + } + + Ok(()) + } +} + +/// Platform emulation for Hyper-V +impl<'a> PlatformEmulator for MshvEmulatorContext<'a> { + 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 gpa = self.translate(gva, HV_TRANSLATE_GVA_VALIDATE_WRITE)?; + debug!( + "mshv emulator: memory write {} bytes at [{:#x} -> {:#x}]", + data.len(), + gva, + gpa + ); + + if let Some(vm_ops) = &self.vcpu.vm_ops { + if vm_ops.guest_mem_write(gpa, data).is_err() { + vm_ops + .mmio_write(gpa, data) + .map_err(|e| PlatformError::MemoryWriteFailure(e.into()))?; + } + } + + Ok(()) + } + + fn cpu_state(&self, cpu_id: usize) -> Result { + if cpu_id != self.vcpu.vp_index as usize { + return Err(PlatformError::GetCpuStateFailure(anyhow!( + "CPU id mismatch {:?} {:?}", + cpu_id, + self.vcpu.vp_index + ))); + } + + let regs = self + .vcpu + .get_regs() + .map_err(|e| PlatformError::GetCpuStateFailure(e.into()))?; + let sregs = self + .vcpu + .get_sregs() + .map_err(|e| PlatformError::GetCpuStateFailure(e.into()))?; + + debug!("mshv emulator: Getting new CPU state"); + debug!("mshv emulator: {:#x?}", regs); + + Ok(EmulatorCpuState { regs, sregs }) + } + + fn set_cpu_state(&self, cpu_id: usize, state: Self::CpuState) -> Result<(), PlatformError> { + if cpu_id != self.vcpu.vp_index as usize { + return Err(PlatformError::SetCpuStateFailure(anyhow!( + "CPU id mismatch {:?} {:?}", + cpu_id, + self.vcpu.vp_index + ))); + } + + debug!("mshv emulator: Setting new CPU state"); + debug!("mshv emulator: {:#x?}", state.regs); + + self.vcpu + .set_regs(&state.regs) + .map_err(|e| PlatformError::SetCpuStateFailure(e.into()))?; + self.vcpu + .set_sregs(&state.sregs) + .map_err(|e| PlatformError::SetCpuStateFailure(e.into())) + } + + fn fetch(&self, ip: u64, instruction_bytes: &mut [u8]) -> Result<(), PlatformError> { + let rip = + self.cpu_state(self.vcpu.vp_index as usize)? + .linearize(Register::CS, ip, false)?; + self.read_memory_flags( + rip, + instruction_bytes, + HV_TRANSLATE_GVA_VALIDATE_READ | HV_TRANSLATE_GVA_VALIDATE_EXECUTE, + ) + } +} diff --git a/hypervisor/src/mshv/x86_64/mod.rs b/hypervisor/src/mshv/x86_64/mod.rs index 2c42e1456..45a97b84a 100644 --- a/hypervisor/src/mshv/x86_64/mod.rs +++ b/hypervisor/src/mshv/x86_64/mod.rs @@ -14,6 +14,8 @@ use crate::arch::x86::{ use serde::{Deserialize, Serialize}; use std::fmt; +pub mod emulator; + /// /// Export generically-named wrappers of mshv_bindings for Unix-based platforms ///