1 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause 2 // 3 // Copyright © 2024, Microsoft Corporation 4 // 5 6 use crate::arch::emulator::{PlatformEmulator, PlatformError}; 7 use crate::arch::x86::emulator::{CpuStateManager, EmulatorCpuState}; 8 use crate::cpu::Vcpu; 9 use crate::mshv::MshvVcpu; 10 use iced_x86::Register; 11 use mshv_bindings::*; 12 13 pub struct MshvEmulatorContext<'a> { 14 pub vcpu: &'a MshvVcpu, 15 pub map: (u64, u64), // Initial GVA to GPA mapping provided by the hypervisor 16 } 17 18 impl<'a> MshvEmulatorContext<'a> { 19 // Do the actual gva -> gpa translation 20 #[allow(non_upper_case_globals)] 21 fn translate(&self, gva: u64, flags: u32) -> Result<u64, PlatformError> { 22 if self.map.0 == gva { 23 return Ok(self.map.1); 24 } 25 26 let (gpa, result_code) = self 27 .vcpu 28 .translate_gva(gva, flags.into()) 29 .map_err(|e| PlatformError::TranslateVirtualAddress(anyhow!(e)))?; 30 31 match result_code { 32 hv_translate_gva_result_code_HV_TRANSLATE_GVA_SUCCESS => Ok(gpa), 33 _ => Err(PlatformError::TranslateVirtualAddress(anyhow!(result_code))), 34 } 35 } 36 37 fn read_memory_flags( 38 &self, 39 gva: u64, 40 data: &mut [u8], 41 flags: u32, 42 ) -> Result<(), PlatformError> { 43 let gpa = self.translate(gva, flags)?; 44 debug!( 45 "mshv emulator: memory read {} bytes from [{:#x} -> {:#x}]", 46 data.len(), 47 gva, 48 gpa 49 ); 50 51 if let Some(vm_ops) = &self.vcpu.vm_ops { 52 if vm_ops.guest_mem_read(gpa, data).is_err() { 53 vm_ops 54 .mmio_read(gpa, data) 55 .map_err(|e| PlatformError::MemoryReadFailure(e.into()))?; 56 } 57 } 58 59 Ok(()) 60 } 61 } 62 63 /// Platform emulation for Hyper-V 64 impl<'a> PlatformEmulator for MshvEmulatorContext<'a> { 65 type CpuState = EmulatorCpuState; 66 67 fn read_memory(&self, gva: u64, data: &mut [u8]) -> Result<(), PlatformError> { 68 self.read_memory_flags(gva, data, HV_TRANSLATE_GVA_VALIDATE_READ) 69 } 70 71 fn write_memory(&mut self, gva: u64, data: &[u8]) -> Result<(), PlatformError> { 72 let gpa = self.translate(gva, HV_TRANSLATE_GVA_VALIDATE_WRITE)?; 73 debug!( 74 "mshv emulator: memory write {} bytes at [{:#x} -> {:#x}]", 75 data.len(), 76 gva, 77 gpa 78 ); 79 80 if let Some(vm_ops) = &self.vcpu.vm_ops { 81 if vm_ops.guest_mem_write(gpa, data).is_err() { 82 vm_ops 83 .mmio_write(gpa, data) 84 .map_err(|e| PlatformError::MemoryWriteFailure(e.into()))?; 85 } 86 } 87 88 Ok(()) 89 } 90 91 fn cpu_state(&self, cpu_id: usize) -> Result<Self::CpuState, PlatformError> { 92 if cpu_id != self.vcpu.vp_index as usize { 93 return Err(PlatformError::GetCpuStateFailure(anyhow!( 94 "CPU id mismatch {:?} {:?}", 95 cpu_id, 96 self.vcpu.vp_index 97 ))); 98 } 99 100 let regs = self 101 .vcpu 102 .get_regs() 103 .map_err(|e| PlatformError::GetCpuStateFailure(e.into()))?; 104 let sregs = self 105 .vcpu 106 .get_sregs() 107 .map_err(|e| PlatformError::GetCpuStateFailure(e.into()))?; 108 109 debug!("mshv emulator: Getting new CPU state"); 110 debug!("mshv emulator: {:#x?}", regs); 111 112 Ok(EmulatorCpuState { regs, sregs }) 113 } 114 115 fn set_cpu_state(&self, cpu_id: usize, state: Self::CpuState) -> Result<(), PlatformError> { 116 if cpu_id != self.vcpu.vp_index as usize { 117 return Err(PlatformError::SetCpuStateFailure(anyhow!( 118 "CPU id mismatch {:?} {:?}", 119 cpu_id, 120 self.vcpu.vp_index 121 ))); 122 } 123 124 debug!("mshv emulator: Setting new CPU state"); 125 debug!("mshv emulator: {:#x?}", state.regs); 126 127 self.vcpu 128 .set_regs(&state.regs) 129 .map_err(|e| PlatformError::SetCpuStateFailure(e.into()))?; 130 self.vcpu 131 .set_sregs(&state.sregs) 132 .map_err(|e| PlatformError::SetCpuStateFailure(e.into())) 133 } 134 135 fn fetch(&self, ip: u64, instruction_bytes: &mut [u8]) -> Result<(), PlatformError> { 136 let rip = 137 self.cpu_state(self.vcpu.vp_index as usize)? 138 .linearize(Register::CS, ip, false)?; 139 self.read_memory_flags( 140 rip, 141 instruction_bytes, 142 HV_TRANSLATE_GVA_VALIDATE_READ | HV_TRANSLATE_GVA_VALIDATE_EXECUTE, 143 ) 144 } 145 } 146