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