hypervisor: emulator: Clean the MockVMM initialization path

Separate the standalone _init_and_run() function into 2 MockVMM methods:
new() and emulate_insn().

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
Samuel Ortiz 2020-11-27 12:51:27 +01:00
parent 5bd63efa45
commit a3d957ba4d
2 changed files with 68 additions and 99 deletions

View File

@ -270,7 +270,8 @@ mod tests {
let ip: u64 = 0x1000;
let cpu_id = 0;
let insn = [0x48, 0x89, 0xd8];
let vmm = init_and_run(cpu_id, ip, &insn, hashmap![Register::RBX => rbx], None);
let mut vmm = MockVMM::new(ip, hashmap![Register::RBX => rbx], None);
vmm.emulate_first_insn(cpu_id, &insn);
let rax: u64 = vmm
.cpu_state(cpu_id)
@ -289,7 +290,8 @@ mod tests {
let ip: u64 = 0x1000;
let cpu_id = 0;
let insn = [0x48, 0xb8, 0x44, 0x33, 0x22, 0x11, 0x44, 0x33, 0x22, 0x11];
let vmm = init_and_run(cpu_id, ip, &insn, hashmap![], None);
let mut vmm = MockVMM::new(ip, hashmap![], None);
vmm.emulate_first_insn(cpu_id, &insn);
let rax: u64 = vmm
.cpu_state(cpu_id)
@ -310,13 +312,12 @@ mod tests {
let cpu_id = 0;
let memory: [u8; 8] = target_rax.to_le_bytes();
let insn = [0x48, 0x8b, 0x04, 0x00];
let vmm = init_and_run(
cpu_id,
let mut vmm = MockVMM::new(
ip,
&insn,
hashmap![Register::RAX => rax],
Some((rax + rax, &memory)),
);
vmm.emulate_first_insn(cpu_id, &insn);
rax = vmm
.cpu_state(cpu_id)
@ -335,7 +336,8 @@ mod tests {
let ip: u64 = 0x1000;
let cpu_id = 0;
let insn = [0xb0, 0x11];
let vmm = init_and_run(cpu_id, ip, &insn, hashmap![], None);
let mut vmm = MockVMM::new(ip, hashmap![], None);
vmm.emulate_first_insn(cpu_id, &insn);
let al = vmm
.cpu_state(cpu_id)
@ -354,7 +356,8 @@ mod tests {
let ip: u64 = 0x1000;
let cpu_id = 0;
let insn = [0xb8, 0x11, 0x00, 0x00, 0x00];
let vmm = init_and_run(cpu_id, ip, &insn, hashmap![], None);
let mut vmm = MockVMM::new(ip, hashmap![], None);
vmm.emulate_first_insn(cpu_id, &insn);
let eax = vmm
.cpu_state(cpu_id)
@ -373,7 +376,8 @@ mod tests {
let ip: u64 = 0x1000;
let cpu_id = 0;
let insn = [0x48, 0xc7, 0xc0, 0x44, 0x33, 0x22, 0x11];
let vmm = init_and_run(cpu_id, ip, &insn, hashmap![], None);
let mut vmm = MockVMM::new(ip, hashmap![], None);
vmm.emulate_first_insn(cpu_id, &insn);
let rax: u64 = vmm
.cpu_state(cpu_id)
@ -393,13 +397,12 @@ mod tests {
let ip: u64 = 0x1000;
let cpu_id = 0;
let insn = [0x88, 0x30];
let vmm = init_and_run(
cpu_id,
let mut vmm = MockVMM::new(
ip,
&insn,
hashmap![Register::RAX => rax, Register::DH => dh.into()],
None,
);
vmm.emulate_first_insn(cpu_id, &insn);
let mut memory: [u8; 1] = [0; 1];
vmm.read_memory(rax, &mut memory).unwrap();
@ -417,13 +420,12 @@ mod tests {
let ip: u64 = 0x1000;
let cpu_id = 0;
let insn = [0x89, 0x30];
let vmm = init_and_run(
cpu_id,
let mut vmm = MockVMM::new(
ip,
&insn,
hashmap![Register::RAX => rax, Register::ESI => esi.into()],
None,
);
vmm.emulate_first_insn(cpu_id, &insn);
let mut memory: [u8; 4] = [0; 4];
vmm.read_memory(rax, &mut memory).unwrap();
@ -442,13 +444,12 @@ mod tests {
let ip: u64 = 0x1000;
let cpu_id = 0;
let insn = [0x89, 0x3c, 0x05, 0x01, 0x00, 0x00, 0x00];
let vmm = init_and_run(
cpu_id,
let mut vmm = MockVMM::new(
ip,
&insn,
hashmap![Register::RAX => rax, Register::EDI => edi.into()],
None,
);
vmm.emulate_first_insn(cpu_id, &insn);
let mut memory: [u8; 4] = [0; 4];
vmm.read_memory(rax + displacement, &mut memory).unwrap();
@ -468,13 +469,12 @@ mod tests {
let ip: u64 = 0x1000;
let cpu_id = 0;
let insn = [0x8b, 0x40, 0x10];
let vmm = init_and_run(
cpu_id,
let mut vmm = MockVMM::new(
ip,
&insn,
hashmap![Register::RAX => rax],
Some((rax + displacement, &memory)),
);
vmm.emulate_first_insn(cpu_id, &insn);
let new_eax = vmm
.cpu_state(cpu_id)
@ -496,13 +496,12 @@ mod tests {
let cpu_id = 0;
let insn = [0x8a, 0x40, 0x10];
let memory: [u8; 1] = al.to_le_bytes();
let vmm = init_and_run(
cpu_id,
let mut vmm = MockVMM::new(
ip,
&insn,
hashmap![Register::RAX => rax],
Some((rax + displacement, &memory)),
);
vmm.emulate_first_insn(cpu_id, &insn);
let new_al = vmm
.cpu_state(cpu_id)
@ -528,14 +527,8 @@ mod tests {
0x48, 0xc7, 0xc0, 0x00, 0x01, 0x00, 0x00, // mov rax, 0x100
0x48, 0x8b, 0x58, 0x10, // mov rbx, qword ptr [rax+10h]
];
let vmm = init_and_run(
cpu_id,
ip,
&insn,
hashmap![],
Some((rax + displacement, &memory)),
);
let mut vmm = MockVMM::new(ip, hashmap![], Some((rax + displacement, &memory)));
vmm.emulate_first_insn(cpu_id, &insn);
let rbx: u64 = vmm
.cpu_state(cpu_id)
@ -562,15 +555,9 @@ mod tests {
0x48, 0x8b, 0x58, 0x10, // mov rbx, qword ptr [rax+10h]
];
let mut vmm = MockVMM::new(ip, hashmap![], Some((rax + displacement, &memory)));
// Only run the first instruction.
let vmm = _init_and_run(
cpu_id,
ip,
&insn,
hashmap![],
Some((rax + displacement, &memory)),
Some(1),
);
vmm.emulate_insn(cpu_id, &insn, Some(1));
assert_eq!(ip + 7 as u64, vmm.cpu_state(cpu_id).unwrap().ip());
@ -601,15 +588,9 @@ mod tests {
0x48, 0xc7, 0xc0, 0x00, 0x02, 0x00, 0x00, // mov rax, 0x200
];
// Only run the first instruction.
let vmm = _init_and_run(
cpu_id,
ip,
&insn,
hashmap![],
Some((rax + displacement, &memory)),
Some(2),
);
let mut vmm = MockVMM::new(ip, hashmap![], Some((rax + displacement, &memory)));
// Run the 2 first instructions.
vmm.emulate_insn(cpu_id, &insn, Some(2));
assert_eq!(ip + 7 + 4 as u64, vmm.cpu_state(cpu_id).unwrap().ip());

View File

@ -456,11 +456,46 @@ mod mock_vmm {
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)),
pub fn new(ip: u64, regs: HashMap<Register, u64>, memory: Option<(u64, &[u8])>) -> 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 {
memory: vec![0; 4096],
state: Arc::new(Mutex::new(initial_state)),
};
if let Some(mem) = memory {
vmm.write_memory(mem.0, &mem.1).unwrap();
}
vmm
}
pub fn emulate_insn(&mut self, cpu_id: usize, insn: &[u8], num_insn: Option<usize>) {
let ip = self.cpu_state(cpu_id).unwrap().ip();
let mut emulator = Emulator::new(self);
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());
}
self.set_cpu_state(cpu_id, new_state).unwrap();
}
pub fn emulate_first_insn(&mut self, cpu_id: usize, insn: &[u8]) {
self.emulate_insn(cpu_id, insn, None)
}
}
@ -507,51 +542,4 @@ mod mock_vmm {
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)
}
}