1461e31e6SJinank Jain // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause 2461e31e6SJinank Jain // 3461e31e6SJinank Jain // Copyright © 2025, Microsoft Corporation 4461e31e6SJinank Jain // 5461e31e6SJinank Jain 6461e31e6SJinank Jain use crate::arch::aarch64::regs::{EsrEl2, ExceptionClass, IssDataAbort}; 7461e31e6SJinank Jain use crate::arch::emulator::PlatformError; 8461e31e6SJinank Jain use crate::cpu::Vcpu; 9461e31e6SJinank Jain use crate::mshv::MshvVcpu; 10461e31e6SJinank Jain 11461e31e6SJinank Jain pub struct MshvEmulatorContext<'a> { 12461e31e6SJinank Jain pub vcpu: &'a MshvVcpu, 13461e31e6SJinank Jain pub map: (u64, u64), // Initial GVA to GPA mapping provided by the hypervisor 14461e31e6SJinank Jain pub syndrome: u64, 15461e31e6SJinank Jain pub instruction_bytes: [u8; 4], 16461e31e6SJinank Jain pub instruction_byte_count: u8, 17461e31e6SJinank Jain pub interruption_pending: bool, 18461e31e6SJinank Jain pub pc: u64, 19461e31e6SJinank Jain } 20461e31e6SJinank Jain 21461e31e6SJinank Jain pub struct Emulator<'a> { 22461e31e6SJinank Jain pub context: MshvEmulatorContext<'a>, 23461e31e6SJinank Jain } 24461e31e6SJinank Jain 25461e31e6SJinank Jain impl<'a> Emulator<'a> { 26461e31e6SJinank Jain /// Create a new emulator instance. new(context: MshvEmulatorContext<'a>) -> Self27461e31e6SJinank Jain pub fn new(context: MshvEmulatorContext<'a>) -> Self { 28461e31e6SJinank Jain Emulator { context } 29461e31e6SJinank Jain } 30461e31e6SJinank Jain 31*d374101fSJinank Jain /// Decode & emulate the instruction using the syndrome register. emulate_with_syndrome(&mut self) -> Result<bool, PlatformError>32461e31e6SJinank Jain pub fn emulate_with_syndrome(&mut self) -> Result<bool, PlatformError> { 33461e31e6SJinank Jain let esr_el2 = EsrEl2::from(self.context.syndrome); 34461e31e6SJinank Jain if !matches!( 35461e31e6SJinank Jain ExceptionClass(esr_el2.ec()), 36461e31e6SJinank Jain ExceptionClass::DATA_ABORT | ExceptionClass::DATA_ABORT_LOWER 37461e31e6SJinank Jain ) { 38461e31e6SJinank Jain return Ok(false); 39461e31e6SJinank Jain } 40461e31e6SJinank Jain 41461e31e6SJinank Jain let iss = IssDataAbort::from(esr_el2.iss()); 42461e31e6SJinank Jain if !iss.isv() { 43461e31e6SJinank Jain return Ok(false); 44461e31e6SJinank Jain } 45461e31e6SJinank Jain let len = 1 << iss.sas(); 46461e31e6SJinank Jain let sign_extend = iss.sse(); 47461e31e6SJinank Jain let reg_index = iss.srt(); 48461e31e6SJinank Jain 49461e31e6SJinank Jain let mut regs = self 50461e31e6SJinank Jain .context 51461e31e6SJinank Jain .vcpu 52461e31e6SJinank Jain .get_regs() 53461e31e6SJinank Jain .map_err(|e| PlatformError::GetCpuStateFailure(e.into()))?; 54461e31e6SJinank Jain let mut gprs = regs.get_regs(); 55461e31e6SJinank Jain 56461e31e6SJinank Jain if iss.wnr() { 57461e31e6SJinank Jain let data: [u8; 8] = match reg_index { 58461e31e6SJinank Jain 0..=30 => gprs[reg_index as usize], 59461e31e6SJinank Jain 31 => 0u64, 60461e31e6SJinank Jain _ => unreachable!(), 61461e31e6SJinank Jain } 62461e31e6SJinank Jain .to_ne_bytes(); 63461e31e6SJinank Jain 64461e31e6SJinank Jain if let Some(vm_ops) = &self.context.vcpu.vm_ops { 65461e31e6SJinank Jain vm_ops 66461e31e6SJinank Jain .mmio_write(self.context.map.1, &data[0..len]) 67461e31e6SJinank Jain .map_err(|e| PlatformError::MemoryWriteFailure(e.into()))?; 68461e31e6SJinank Jain } 69461e31e6SJinank Jain } else { 70461e31e6SJinank Jain let mut data = [0_u8; 8]; 71461e31e6SJinank Jain if let Some(vm_ops) = &self.context.vcpu.vm_ops { 72461e31e6SJinank Jain vm_ops 73461e31e6SJinank Jain .mmio_read(self.context.map.1, &mut data[0..len]) 74461e31e6SJinank Jain .map_err(|e| PlatformError::MemoryReadFailure(e.into()))?; 75461e31e6SJinank Jain } 76461e31e6SJinank Jain 77461e31e6SJinank Jain let mut data = u64::from_ne_bytes(data); 78461e31e6SJinank Jain if sign_extend { 79461e31e6SJinank Jain let shift = 64 - len * 8; 80461e31e6SJinank Jain data = ((data as i64) << shift >> shift) as u64; 81461e31e6SJinank Jain if !iss.sf() { 82461e31e6SJinank Jain data &= 0xffffffff; 83461e31e6SJinank Jain } 84461e31e6SJinank Jain } 85461e31e6SJinank Jain gprs[reg_index as usize] = data; 86461e31e6SJinank Jain } 87461e31e6SJinank Jain 88461e31e6SJinank Jain let pc = regs.get_pc(); 89461e31e6SJinank Jain regs.set_pc(if esr_el2.il() { pc + 4 } else { pc + 2 }); 90461e31e6SJinank Jain regs.set_regs(gprs); 91461e31e6SJinank Jain 92461e31e6SJinank Jain self.context 93461e31e6SJinank Jain .vcpu 94461e31e6SJinank Jain .set_regs(®s) 95461e31e6SJinank Jain .map_err(|e| PlatformError::SetCpuStateFailure(e.into()))?; 96461e31e6SJinank Jain 97461e31e6SJinank Jain Ok(true) 98461e31e6SJinank Jain } 99461e31e6SJinank Jain 100461e31e6SJinank Jain /// Emulate the instruction. emulate(&mut self) -> Result<(), PlatformError>101461e31e6SJinank Jain pub fn emulate(&mut self) -> Result<(), PlatformError> { 102461e31e6SJinank Jain match self.emulate_with_syndrome() { 103461e31e6SJinank Jain Ok(true) => Ok(()), 104461e31e6SJinank Jain Ok(false) => Err(PlatformError::InvalidState(anyhow!( 105461e31e6SJinank Jain "Failed to decode instruction using syndrome register" 106461e31e6SJinank Jain ))), 107461e31e6SJinank Jain Err(e) => Err(e), 108461e31e6SJinank Jain } 109461e31e6SJinank Jain // TODO: Add support for instruction decoding in case of failure from 110461e31e6SJinank Jain // decode_with_syndrome. This will require aarch64 instruction emulator 111461e31e6SJinank Jain // implementation like x86_64. 112461e31e6SJinank Jain } 113461e31e6SJinank Jain } 114