mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
hypervisor: Instruction emulator for ARM64 guest on MSHV
Currently it would be using the syndrome register for instruction decoding which is what KVM has been using in-kernel to decode instructions for ARM64 guests. In future, it could be extended with an actual instruction emulator if required. But most Linux guests works well with the instruction decoder using syndrome register. Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
This commit is contained in:
113
hypervisor/src/mshv/aarch64/emulator.rs
Normal file
113
hypervisor/src/mshv/aarch64/emulator.rs
Normal file
@@ -0,0 +1,113 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
|
||||
//
|
||||
// Copyright © 2025, Microsoft Corporation
|
||||
//
|
||||
|
||||
use crate::arch::aarch64::regs::{EsrEl2, ExceptionClass, IssDataAbort};
|
||||
use crate::arch::emulator::PlatformError;
|
||||
use crate::cpu::Vcpu;
|
||||
use crate::mshv::MshvVcpu;
|
||||
|
||||
pub struct MshvEmulatorContext<'a> {
|
||||
pub vcpu: &'a MshvVcpu,
|
||||
pub map: (u64, u64), // Initial GVA to GPA mapping provided by the hypervisor
|
||||
pub syndrome: u64,
|
||||
pub instruction_bytes: [u8; 4],
|
||||
pub instruction_byte_count: u8,
|
||||
pub interruption_pending: bool,
|
||||
pub pc: u64,
|
||||
}
|
||||
|
||||
pub struct Emulator<'a> {
|
||||
pub context: MshvEmulatorContext<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Emulator<'a> {
|
||||
/// Create a new emulator instance.
|
||||
pub fn new(context: MshvEmulatorContext<'a>) -> Self {
|
||||
Emulator { context }
|
||||
}
|
||||
|
||||
/// Decode the instruction using the syndrome register.
|
||||
pub fn emulate_with_syndrome(&mut self) -> Result<bool, PlatformError> {
|
||||
let esr_el2 = EsrEl2::from(self.context.syndrome);
|
||||
if !matches!(
|
||||
ExceptionClass(esr_el2.ec()),
|
||||
ExceptionClass::DATA_ABORT | ExceptionClass::DATA_ABORT_LOWER
|
||||
) {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let iss = IssDataAbort::from(esr_el2.iss());
|
||||
if !iss.isv() {
|
||||
return Ok(false);
|
||||
}
|
||||
let len = 1 << iss.sas();
|
||||
let sign_extend = iss.sse();
|
||||
let reg_index = iss.srt();
|
||||
|
||||
let mut regs = self
|
||||
.context
|
||||
.vcpu
|
||||
.get_regs()
|
||||
.map_err(|e| PlatformError::GetCpuStateFailure(e.into()))?;
|
||||
let mut gprs = regs.get_regs();
|
||||
|
||||
if iss.wnr() {
|
||||
let data: [u8; 8] = match reg_index {
|
||||
0..=30 => gprs[reg_index as usize],
|
||||
31 => 0u64,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
.to_ne_bytes();
|
||||
|
||||
if let Some(vm_ops) = &self.context.vcpu.vm_ops {
|
||||
vm_ops
|
||||
.mmio_write(self.context.map.1, &data[0..len])
|
||||
.map_err(|e| PlatformError::MemoryWriteFailure(e.into()))?;
|
||||
}
|
||||
} else {
|
||||
let mut data = [0_u8; 8];
|
||||
if let Some(vm_ops) = &self.context.vcpu.vm_ops {
|
||||
vm_ops
|
||||
.mmio_read(self.context.map.1, &mut data[0..len])
|
||||
.map_err(|e| PlatformError::MemoryReadFailure(e.into()))?;
|
||||
}
|
||||
|
||||
let mut data = u64::from_ne_bytes(data);
|
||||
if sign_extend {
|
||||
let shift = 64 - len * 8;
|
||||
data = ((data as i64) << shift >> shift) as u64;
|
||||
if !iss.sf() {
|
||||
data &= 0xffffffff;
|
||||
}
|
||||
}
|
||||
gprs[reg_index as usize] = data;
|
||||
}
|
||||
|
||||
let pc = regs.get_pc();
|
||||
regs.set_pc(if esr_el2.il() { pc + 4 } else { pc + 2 });
|
||||
regs.set_regs(gprs);
|
||||
|
||||
self.context
|
||||
.vcpu
|
||||
.set_regs(®s)
|
||||
.map_err(|e| PlatformError::SetCpuStateFailure(e.into()))?;
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
/// Emulate the instruction.
|
||||
pub fn emulate(&mut self) -> Result<(), PlatformError> {
|
||||
match self.emulate_with_syndrome() {
|
||||
Ok(true) => Ok(()),
|
||||
Ok(false) => Err(PlatformError::InvalidState(anyhow!(
|
||||
"Failed to decode instruction using syndrome register"
|
||||
))),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
// TODO: Add support for instruction decoding in case of failure from
|
||||
// decode_with_syndrome. This will require aarch64 instruction emulator
|
||||
// implementation like x86_64.
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
//
|
||||
// Copyright © 2025, Microsoft Corporation
|
||||
//
|
||||
pub mod emulator;
|
||||
pub mod gic;
|
||||
use std::fmt;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user