mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-08-21 15:31:15 +00:00
hypervisor: emulator: Move MockVMM into a shared test module
The MockVMM platform will be used by other instructions emulation implementations, but also by the emulator framework. Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
parent
66b001665f
commit
5bd63efa45
@ -253,22 +253,7 @@ mod tests {
|
|||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::arch::emulator::{EmulationError, PlatformEmulator};
|
use crate::arch::x86::emulator::mock_vmm::*;
|
||||||
use crate::arch::x86::emulator::{Emulator, EmulatorCpuState as CpuState};
|
|
||||||
use crate::arch::x86::gdt::{gdt_entry, segment_from_gdt};
|
|
||||||
use crate::arch::x86::Exception;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
struct MockVMM {
|
|
||||||
memory: Vec<u8>,
|
|
||||||
state: Arc<Mutex<CpuState>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Sync for MockVMM {}
|
|
||||||
|
|
||||||
type MockResult = Result<(), EmulationError<Exception>>;
|
|
||||||
|
|
||||||
macro_rules! hashmap {
|
macro_rules! hashmap {
|
||||||
($( $key: expr => $val: expr ),*) => {{
|
($( $key: expr => $val: expr ),*) => {{
|
||||||
@ -278,106 +263,6 @@ mod tests {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MockVMM {
|
|
||||||
pub fn new(state: CpuState) -> MockVMM {
|
|
||||||
MockVMM {
|
|
||||||
memory: vec![0; 4096],
|
|
||||||
state: Arc::new(Mutex::new(state)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PlatformEmulator for MockVMM {
|
|
||||||
type CpuState = CpuState;
|
|
||||||
|
|
||||||
fn read_memory(&self, gva: u64, data: &mut [u8]) -> Result<(), PlatformError> {
|
|
||||||
debug!(
|
|
||||||
"Memory read {} bytes from [{:#x} -> {:#x}]",
|
|
||||||
data.len(),
|
|
||||||
gva,
|
|
||||||
gva
|
|
||||||
);
|
|
||||||
data.copy_from_slice(&self.memory[gva as usize..gva as usize + data.len()]);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_memory(&mut self, gva: u64, data: &[u8]) -> Result<(), PlatformError> {
|
|
||||||
debug!(
|
|
||||||
"Memory write {} bytes at [{:#x} -> {:#x}]",
|
|
||||||
data.len(),
|
|
||||||
gva,
|
|
||||||
gva
|
|
||||||
);
|
|
||||||
self.memory[gva as usize..gva as usize + data.len()].copy_from_slice(data);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cpu_state(&self, _cpu_id: usize) -> Result<CpuState, PlatformError> {
|
|
||||||
Ok(self.state.lock().unwrap().clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_cpu_state(
|
|
||||||
&self,
|
|
||||||
_cpu_id: usize,
|
|
||||||
state: Self::CpuState,
|
|
||||||
) -> Result<(), PlatformError> {
|
|
||||||
*self.state.lock().unwrap() = state;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gva_to_gpa(&self, gva: u64) -> Result<u64, PlatformError> {
|
|
||||||
Ok(gva)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn _init_and_run(
|
|
||||||
cpu_id: usize,
|
|
||||||
ip: u64,
|
|
||||||
insn: &[u8],
|
|
||||||
regs: HashMap<Register, u64>,
|
|
||||||
memory: Option<(u64, &[u8])>,
|
|
||||||
num_insn: Option<usize>,
|
|
||||||
) -> MockVMM {
|
|
||||||
let _ = env_logger::try_init();
|
|
||||||
let cs_reg = segment_from_gdt(gdt_entry(0xc09b, 0, 0xffffffff), 1);
|
|
||||||
let ds_reg = segment_from_gdt(gdt_entry(0xc093, 0, 0xffffffff), 2);
|
|
||||||
let mut initial_state = CpuState::default();
|
|
||||||
initial_state.set_ip(ip);
|
|
||||||
initial_state.write_segment(Register::CS, cs_reg).unwrap();
|
|
||||||
initial_state.write_segment(Register::DS, ds_reg).unwrap();
|
|
||||||
for (reg, value) in regs {
|
|
||||||
initial_state.write_reg(reg, value).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut vmm = MockVMM::new(initial_state);
|
|
||||||
if let Some(mem) = memory {
|
|
||||||
vmm.write_memory(mem.0, &mem.1).unwrap();
|
|
||||||
}
|
|
||||||
let mut emulator = Emulator::new(&mut vmm);
|
|
||||||
|
|
||||||
let new_state = emulator
|
|
||||||
.emulate_insn_stream(cpu_id, &insn, num_insn)
|
|
||||||
.unwrap();
|
|
||||||
if num_insn.is_none() {
|
|
||||||
assert_eq!(ip + insn.len() as u64, new_state.ip());
|
|
||||||
}
|
|
||||||
|
|
||||||
vmm.set_cpu_state(cpu_id, new_state).unwrap();
|
|
||||||
|
|
||||||
vmm
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_and_run(
|
|
||||||
cpu_id: usize,
|
|
||||||
ip: u64,
|
|
||||||
insn: &[u8],
|
|
||||||
regs: HashMap<Register, u64>,
|
|
||||||
memory: Option<(u64, &[u8])>,
|
|
||||||
) -> MockVMM {
|
|
||||||
_init_and_run(cpu_id, ip, insn, regs, memory, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
// mov rax,rbx
|
// mov rax,rbx
|
||||||
fn test_mov_r64_r64() -> MockResult {
|
fn test_mov_r64_r64() -> MockResult {
|
||||||
|
@ -430,3 +430,128 @@ impl<'a, T: CpuStateManager> Emulator<'a, T> {
|
|||||||
self.emulate_insn_stream(cpu_id, insn_stream, Some(1))
|
self.emulate_insn_stream(cpu_id, insn_stream, Some(1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod mock_vmm {
|
||||||
|
#![allow(unused_mut)]
|
||||||
|
|
||||||
|
extern crate env_logger;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::arch::emulator::{EmulationError, PlatformEmulator};
|
||||||
|
use crate::arch::x86::emulator::{Emulator, EmulatorCpuState as CpuState};
|
||||||
|
use crate::arch::x86::gdt::{gdt_entry, segment_from_gdt};
|
||||||
|
use crate::arch::x86::Exception;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct MockVMM {
|
||||||
|
memory: Vec<u8>,
|
||||||
|
state: Arc<Mutex<CpuState>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for MockVMM {}
|
||||||
|
|
||||||
|
pub type MockResult = Result<(), EmulationError<Exception>>;
|
||||||
|
|
||||||
|
impl MockVMM {
|
||||||
|
pub fn new(state: CpuState) -> MockVMM {
|
||||||
|
MockVMM {
|
||||||
|
memory: vec![0; 4096],
|
||||||
|
state: Arc::new(Mutex::new(state)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlatformEmulator for MockVMM {
|
||||||
|
type CpuState = CpuState;
|
||||||
|
|
||||||
|
fn read_memory(&self, gva: u64, data: &mut [u8]) -> Result<(), PlatformError> {
|
||||||
|
debug!(
|
||||||
|
"Memory read {} bytes from [{:#x} -> {:#x}]",
|
||||||
|
data.len(),
|
||||||
|
gva,
|
||||||
|
gva
|
||||||
|
);
|
||||||
|
data.copy_from_slice(&self.memory[gva as usize..gva as usize + data.len()]);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_memory(&mut self, gva: u64, data: &[u8]) -> Result<(), PlatformError> {
|
||||||
|
debug!(
|
||||||
|
"Memory write {} bytes at [{:#x} -> {:#x}]",
|
||||||
|
data.len(),
|
||||||
|
gva,
|
||||||
|
gva
|
||||||
|
);
|
||||||
|
self.memory[gva as usize..gva as usize + data.len()].copy_from_slice(data);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cpu_state(&self, _cpu_id: usize) -> Result<CpuState, PlatformError> {
|
||||||
|
Ok(self.state.lock().unwrap().clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_cpu_state(
|
||||||
|
&self,
|
||||||
|
_cpu_id: usize,
|
||||||
|
state: Self::CpuState,
|
||||||
|
) -> Result<(), PlatformError> {
|
||||||
|
*self.state.lock().unwrap() = state;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gva_to_gpa(&self, gva: u64) -> Result<u64, PlatformError> {
|
||||||
|
Ok(gva)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _init_and_run(
|
||||||
|
cpu_id: usize,
|
||||||
|
ip: u64,
|
||||||
|
insn: &[u8],
|
||||||
|
regs: HashMap<Register, u64>,
|
||||||
|
memory: Option<(u64, &[u8])>,
|
||||||
|
num_insn: Option<usize>,
|
||||||
|
) -> MockVMM {
|
||||||
|
let _ = env_logger::try_init();
|
||||||
|
let cs_reg = segment_from_gdt(gdt_entry(0xc09b, 0, 0xffffffff), 1);
|
||||||
|
let ds_reg = segment_from_gdt(gdt_entry(0xc093, 0, 0xffffffff), 2);
|
||||||
|
let mut initial_state = CpuState::default();
|
||||||
|
initial_state.set_ip(ip);
|
||||||
|
initial_state.write_segment(Register::CS, cs_reg).unwrap();
|
||||||
|
initial_state.write_segment(Register::DS, ds_reg).unwrap();
|
||||||
|
for (reg, value) in regs {
|
||||||
|
initial_state.write_reg(reg, value).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut vmm = MockVMM::new(initial_state);
|
||||||
|
if let Some(mem) = memory {
|
||||||
|
vmm.write_memory(mem.0, &mem.1).unwrap();
|
||||||
|
}
|
||||||
|
let mut emulator = Emulator::new(&mut vmm);
|
||||||
|
|
||||||
|
let new_state = emulator
|
||||||
|
.emulate_insn_stream(cpu_id, &insn, num_insn)
|
||||||
|
.unwrap();
|
||||||
|
if num_insn.is_none() {
|
||||||
|
assert_eq!(ip + insn.len() as u64, new_state.ip());
|
||||||
|
}
|
||||||
|
|
||||||
|
vmm.set_cpu_state(cpu_id, new_state).unwrap();
|
||||||
|
|
||||||
|
vmm
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_and_run(
|
||||||
|
cpu_id: usize,
|
||||||
|
ip: u64,
|
||||||
|
insn: &[u8],
|
||||||
|
regs: HashMap<Register, u64>,
|
||||||
|
memory: Option<(u64, &[u8])>,
|
||||||
|
) -> MockVMM {
|
||||||
|
_init_and_run(cpu_id, ip, insn, regs, memory, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user