mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-02-22 11:22:26 +00:00
hypervisor: x86: Add an instruction emulator
The emulator gets a CPU state from a CpuStateManager instance, emulates the passed instructions stream and returns the modified CPU state. The emulator is a skeleton for now since it comes with an empty instruction mnemonic map. Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
parent
1fc97e91a4
commit
12b7a498d9
@ -6,9 +6,12 @@
|
||||
|
||||
extern crate iced_x86;
|
||||
|
||||
use crate::arch::emulator::PlatformError;
|
||||
use crate::arch::emulator::{EmulationError, EmulationResult, PlatformEmulator, PlatformError};
|
||||
use crate::arch::x86::emulator::instructions::*;
|
||||
use crate::arch::x86::Exception;
|
||||
use crate::x86_64::{SegmentRegister, SpecialRegisters, StandardRegisters};
|
||||
use iced_x86::*;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
mod instructions;
|
||||
|
||||
@ -344,3 +347,73 @@ impl CpuStateManager for EmulatorCpuState {
|
||||
self.regs.rflags = flags;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Emulator<T: CpuStateManager> {
|
||||
platform: Arc<Mutex<dyn PlatformEmulator<CpuState = T>>>,
|
||||
insn_map: InstructionMap<T>,
|
||||
}
|
||||
|
||||
impl<T: CpuStateManager> Emulator<T> {
|
||||
pub fn new(platform: Arc<Mutex<dyn PlatformEmulator<CpuState = T>>>) -> Emulator<T> {
|
||||
let mut insn_map = InstructionMap::<T>::new();
|
||||
|
||||
Emulator {
|
||||
platform: Arc::clone(&platform),
|
||||
insn_map,
|
||||
}
|
||||
}
|
||||
|
||||
fn emulate_insn_stream(
|
||||
&mut self,
|
||||
cpu_id: usize,
|
||||
insn_stream: &[u8],
|
||||
num_insn: Option<usize>,
|
||||
) -> EmulationResult<T, Exception> {
|
||||
let mut state = self
|
||||
.platform
|
||||
.lock()
|
||||
.unwrap()
|
||||
.cpu_state(cpu_id)
|
||||
.map_err(EmulationError::PlatformEmulationError)?;
|
||||
let mut decoder = Decoder::new(64, insn_stream, DecoderOptions::NONE);
|
||||
decoder.set_ip(state.ip());
|
||||
|
||||
for (index, insn) in &mut decoder.iter().enumerate() {
|
||||
self.insn_map
|
||||
.instructions
|
||||
.get(&insn.code())
|
||||
.ok_or_else(|| {
|
||||
EmulationError::UnsupportedInstruction(anyhow!("{:?}", insn.mnemonic()))
|
||||
})?
|
||||
.emulate(&insn, &mut state, Arc::clone(&self.platform))?;
|
||||
|
||||
if let Some(num_insn) = num_insn {
|
||||
if index + 1 >= num_insn {
|
||||
// Exit the decoding loop, do not decode the next instruction.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state.set_ip(decoder.ip());
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
/// Emulate all instructions from the instructions stream.
|
||||
pub fn emulate(&mut self, cpu_id: usize, insn_stream: &[u8]) -> EmulationResult<T, Exception> {
|
||||
self.emulate_insn_stream(cpu_id, insn_stream, None)
|
||||
}
|
||||
|
||||
/// Only emulate the first instruction from the stream.
|
||||
///
|
||||
/// This is useful for cases where we get readahead instruction stream
|
||||
/// but implicitly must only emulate the first instruction, and then return
|
||||
/// to the guest.
|
||||
pub fn emulate_first_insn(
|
||||
&mut self,
|
||||
cpu_id: usize,
|
||||
insn_stream: &[u8],
|
||||
) -> EmulationResult<T, Exception> {
|
||||
self.emulate_insn_stream(cpu_id, insn_stream, Some(1))
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user