From a3d957ba4d5fc55cdc86d6687e482056baa94c20 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 27 Nov 2020 12:51:27 +0100 Subject: [PATCH] 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 --- .../src/arch/x86/emulator/instructions/mov.rs | 77 ++++++---------- hypervisor/src/arch/x86/emulator/mod.rs | 90 ++++++++----------- 2 files changed, 68 insertions(+), 99 deletions(-) diff --git a/hypervisor/src/arch/x86/emulator/instructions/mov.rs b/hypervisor/src/arch/x86/emulator/instructions/mov.rs index 7c9550f07..70d1b5bae 100644 --- a/hypervisor/src/arch/x86/emulator/instructions/mov.rs +++ b/hypervisor/src/arch/x86/emulator/instructions/mov.rs @@ -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()); diff --git a/hypervisor/src/arch/x86/emulator/mod.rs b/hypervisor/src/arch/x86/emulator/mod.rs index b7c343c3f..0f4285eee 100644 --- a/hypervisor/src/arch/x86/emulator/mod.rs +++ b/hypervisor/src/arch/x86/emulator/mod.rs @@ -456,11 +456,46 @@ mod mock_vmm { pub type MockResult = Result<(), EmulationError>; 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, 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) { + 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, - memory: Option<(u64, &[u8])>, - num_insn: Option, - ) -> 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, - memory: Option<(u64, &[u8])>, - ) -> MockVMM { - _init_and_run(cpu_id, ip, insn, regs, memory, None) - } }