From 5aba9b430806aec8751beddcae03fd566acfacf4 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsburskii Date: Tue, 13 Jan 2026 08:03:25 -0800 Subject: [PATCH] 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 --- hypervisor/src/arch/x86/emulator/mod.rs | 28 ++++++++++++++++--------- hypervisor/src/mshv/mod.rs | 9 ++++++-- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/hypervisor/src/arch/x86/emulator/mod.rs b/hypervisor/src/arch/x86/emulator/mod.rs index 3de545e47..35a35a0ec 100644 --- a/hypervisor/src/arch/x86/emulator/mod.rs +++ b/hypervisor/src/arch/x86/emulator/mod.rs @@ -538,16 +538,13 @@ impl Emulator<'_, T> { handler } - fn emulate_insn_stream( + pub fn emulate_insn_stream( &mut self, - cpu_id: usize, + old_state: &T, insn_stream: &[u8], num_insn: Option, ) -> EmulationResult { - let mut state = self - .platform - .cpu_state(cpu_id) - .map_err(EmulationError::PlatformEmulationError)?; + let mut state = old_state.clone(); let mut decoder = Decoder::new(64, insn_stream, DecoderOptions::NONE); let mut insn = Instruction::default(); let mut num_insn_emulated: usize = 0; @@ -627,7 +624,11 @@ impl Emulator<'_, T> { /// Emulate all instructions from the instructions stream. pub fn emulate(&mut self, cpu_id: usize, insn_stream: &[u8]) -> EmulationResult { - 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. @@ -640,7 +641,11 @@ impl Emulator<'_, T> { cpu_id: usize, insn_stream: &[u8], ) -> EmulationResult { - 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], num_insn: Option, ) -> 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 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() { assert_eq!(ip + insn.len() as u64, new_state.ip()); } diff --git a/hypervisor/src/mshv/mod.rs b/hypervisor/src/mshv/mod.rs index 8ef150294..43597ba6d 100644 --- a/hypervisor/src/mshv/mod.rs +++ b/hypervisor/src/mshv/mod.rs @@ -715,14 +715,19 @@ impl cpu::Vcpu for MshvVcpu { 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. let mut emul = Emulator::new(&mut context); // Emulate the trapped instruction, and only the first one. let new_state = emul - .emulate_first_insn( - self.vp_index as usize, + .emulate_insn_stream( + &old_state, &info.instruction_bytes[..insn_len], + Some(1), ) .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;