hypervisor: emulator: Pass CPU context to instruction stream emulator

This is a precursor change to overall ioctl and hypercall reduction
effort. The old (current) CPU state can be compared to the new to
determine what has changed and avoid unnecessary register updates.

Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
This commit is contained in:
Stanislav Kinsburskii
2026-01-13 08:03:25 -08:00
committed by Rob Bradford
parent 03252f5851
commit 5aba9b4308
2 changed files with 25 additions and 12 deletions

View File

@@ -538,16 +538,13 @@ impl<T: CpuStateManager> Emulator<'_, T> {
handler handler
} }
fn emulate_insn_stream( pub fn emulate_insn_stream(
&mut self, &mut self,
cpu_id: usize, old_state: &T,
insn_stream: &[u8], insn_stream: &[u8],
num_insn: Option<usize>, num_insn: Option<usize>,
) -> EmulationResult<T, Exception> { ) -> EmulationResult<T, Exception> {
let mut state = self let mut state = old_state.clone();
.platform
.cpu_state(cpu_id)
.map_err(EmulationError::PlatformEmulationError)?;
let mut decoder = Decoder::new(64, insn_stream, DecoderOptions::NONE); let mut decoder = Decoder::new(64, insn_stream, DecoderOptions::NONE);
let mut insn = Instruction::default(); let mut insn = Instruction::default();
let mut num_insn_emulated: usize = 0; let mut num_insn_emulated: usize = 0;
@@ -627,7 +624,11 @@ impl<T: CpuStateManager> Emulator<'_, T> {
/// Emulate all instructions from the instructions stream. /// Emulate all instructions from the instructions stream.
pub fn emulate(&mut self, cpu_id: usize, insn_stream: &[u8]) -> EmulationResult<T, Exception> { pub fn emulate(&mut self, cpu_id: usize, insn_stream: &[u8]) -> EmulationResult<T, Exception> {
self.emulate_insn_stream(cpu_id, insn_stream, None) let state = self
.platform
.cpu_state(cpu_id)
.map_err(EmulationError::PlatformEmulationError)?;
self.emulate_insn_stream(&state, insn_stream, None)
} }
/// Only emulate the first instruction from the stream. /// Only emulate the first instruction from the stream.
@@ -640,7 +641,11 @@ impl<T: CpuStateManager> Emulator<'_, T> {
cpu_id: usize, cpu_id: usize,
insn_stream: &[u8], insn_stream: &[u8],
) -> EmulationResult<T, Exception> { ) -> EmulationResult<T, Exception> {
self.emulate_insn_stream(cpu_id, insn_stream, Some(1)) let state = self
.platform
.cpu_state(cpu_id)
.map_err(EmulationError::PlatformEmulationError)?;
self.emulate_insn_stream(&state, insn_stream, Some(1))
} }
} }
@@ -706,10 +711,13 @@ mod mock_vmm {
insn: &[u8], insn: &[u8],
num_insn: Option<usize>, num_insn: Option<usize>,
) -> MockResult { ) -> MockResult {
let ip = self.cpu_state(cpu_id).unwrap().ip(); let mut state = self
.cpu_state(cpu_id)
.map_err(EmulationError::PlatformEmulationError)?;
let ip = state.ip();
let mut emulator = Emulator::new(self); let mut emulator = Emulator::new(self);
let new_state = emulator.emulate_insn_stream(cpu_id, insn, num_insn)?; let new_state = emulator.emulate_insn_stream(&state, insn, num_insn)?;
if num_insn.is_none() { if num_insn.is_none() {
assert_eq!(ip + insn.len() as u64, new_state.ip()); assert_eq!(ip + insn.len() as u64, new_state.ip());
} }

View File

@@ -715,14 +715,19 @@ impl cpu::Vcpu for MshvVcpu {
map: (gva, gpa), map: (gva, gpa),
}; };
let old_state = context
.cpu_state(self.vp_index as usize)
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
// Create a new emulator. // Create a new emulator.
let mut emul = Emulator::new(&mut context); let mut emul = Emulator::new(&mut context);
// Emulate the trapped instruction, and only the first one. // Emulate the trapped instruction, and only the first one.
let new_state = emul let new_state = emul
.emulate_first_insn( .emulate_insn_stream(
self.vp_index as usize, &old_state,
&info.instruction_bytes[..insn_len], &info.instruction_bytes[..insn_len],
Some(1),
) )
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;