1 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause 2 // 3 // Copyright © 2025, Microsoft Corporation 4 // 5 6 use crate::arch::aarch64::regs::{EsrEl2, ExceptionClass, IssDataAbort}; 7 use crate::arch::emulator::PlatformError; 8 use crate::cpu::Vcpu; 9 use crate::mshv::MshvVcpu; 10 11 pub struct MshvEmulatorContext<'a> { 12 pub vcpu: &'a MshvVcpu, 13 pub map: (u64, u64), // Initial GVA to GPA mapping provided by the hypervisor 14 pub syndrome: u64, 15 pub instruction_bytes: [u8; 4], 16 pub instruction_byte_count: u8, 17 pub interruption_pending: bool, 18 pub pc: u64, 19 } 20 21 pub struct Emulator<'a> { 22 pub context: MshvEmulatorContext<'a>, 23 } 24 25 impl<'a> Emulator<'a> { 26 /// Create a new emulator instance. 27 pub fn new(context: MshvEmulatorContext<'a>) -> Self { 28 Emulator { context } 29 } 30 31 /// Decode & emulate the instruction using the syndrome register. 32 pub fn emulate_with_syndrome(&mut self) -> Result<bool, PlatformError> { 33 let esr_el2 = EsrEl2::from(self.context.syndrome); 34 if !matches!( 35 ExceptionClass(esr_el2.ec()), 36 ExceptionClass::DATA_ABORT | ExceptionClass::DATA_ABORT_LOWER 37 ) { 38 return Ok(false); 39 } 40 41 let iss = IssDataAbort::from(esr_el2.iss()); 42 if !iss.isv() { 43 return Ok(false); 44 } 45 let len = 1 << iss.sas(); 46 let sign_extend = iss.sse(); 47 let reg_index = iss.srt(); 48 49 let mut regs = self 50 .context 51 .vcpu 52 .get_regs() 53 .map_err(|e| PlatformError::GetCpuStateFailure(e.into()))?; 54 let mut gprs = regs.get_regs(); 55 56 if iss.wnr() { 57 let data: [u8; 8] = match reg_index { 58 0..=30 => gprs[reg_index as usize], 59 31 => 0u64, 60 _ => unreachable!(), 61 } 62 .to_ne_bytes(); 63 64 if let Some(vm_ops) = &self.context.vcpu.vm_ops { 65 vm_ops 66 .mmio_write(self.context.map.1, &data[0..len]) 67 .map_err(|e| PlatformError::MemoryWriteFailure(e.into()))?; 68 } 69 } else { 70 let mut data = [0_u8; 8]; 71 if let Some(vm_ops) = &self.context.vcpu.vm_ops { 72 vm_ops 73 .mmio_read(self.context.map.1, &mut data[0..len]) 74 .map_err(|e| PlatformError::MemoryReadFailure(e.into()))?; 75 } 76 77 let mut data = u64::from_ne_bytes(data); 78 if sign_extend { 79 let shift = 64 - len * 8; 80 data = ((data as i64) << shift >> shift) as u64; 81 if !iss.sf() { 82 data &= 0xffffffff; 83 } 84 } 85 gprs[reg_index as usize] = data; 86 } 87 88 let pc = regs.get_pc(); 89 regs.set_pc(if esr_el2.il() { pc + 4 } else { pc + 2 }); 90 regs.set_regs(gprs); 91 92 self.context 93 .vcpu 94 .set_regs(®s) 95 .map_err(|e| PlatformError::SetCpuStateFailure(e.into()))?; 96 97 Ok(true) 98 } 99 100 /// Emulate the instruction. 101 pub fn emulate(&mut self) -> Result<(), PlatformError> { 102 match self.emulate_with_syndrome() { 103 Ok(true) => Ok(()), 104 Ok(false) => Err(PlatformError::InvalidState(anyhow!( 105 "Failed to decode instruction using syndrome register" 106 ))), 107 Err(e) => Err(e), 108 } 109 // TODO: Add support for instruction decoding in case of failure from 110 // decode_with_syndrome. This will require aarch64 instruction emulator 111 // implementation like x86_64. 112 } 113 } 114