From a44d96c9cc5476cb2db9acb8d7990b1ea069ffda Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Sat, 5 Dec 2020 23:31:59 +0000 Subject: [PATCH] hypervisor: emulator: switch to use vec in MockVMM The customized hashmap macro can't be lifted to common MockVMM code. MockVMM only needs a collection to iterate over to get initial register states. A vector is just as good as a hashmap. Switch to use a vector to store initial register states. This allows us to drop the hashmap macro everywhere. Signed-off-by: Wei Liu --- .../src/arch/x86/emulator/instructions/cmp.rs | 24 +++-------- .../src/arch/x86/emulator/instructions/mov.rs | 40 +++++++------------ hypervisor/src/arch/x86/emulator/mod.rs | 17 ++------ 3 files changed, 24 insertions(+), 57 deletions(-) diff --git a/hypervisor/src/arch/x86/emulator/instructions/cmp.rs b/hypervisor/src/arch/x86/emulator/instructions/cmp.rs index 40f6eca6a..497d0130c 100644 --- a/hypervisor/src/arch/x86/emulator/instructions/cmp.rs +++ b/hypervisor/src/arch/x86/emulator/instructions/cmp.rs @@ -241,14 +241,6 @@ mod tests { use super::*; use crate::arch::x86::emulator::mock_vmm::*; - macro_rules! hashmap { - ($( $key: expr => $val: expr ),*) => {{ - let mut map = ::std::collections::HashMap::new(); - $( map.insert($key, $val); )* - map - }} - } - #[test] // cmp ah,al fn test_cmp_rm8_r8_1() -> MockResult { @@ -256,7 +248,7 @@ mod tests { let ip: u64 = 0x1000; let cpu_id = 0; let insn = [0x38, 0xc4]; // cmp ah,al - let mut vmm = MockVMM::new(ip, hashmap![Register::RAX => rax], None); + let mut vmm = MockVMM::new(ip, vec![(Register::RAX, rax)], None); assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); let rflags: u64 = vmm.cpu_state(cpu_id).unwrap().flags() & FLAGS_MASK; @@ -272,7 +264,7 @@ mod tests { let ip: u64 = 0x1000; let cpu_id = 0; let insn = [0x83, 0xf8, 0x64]; // cmp eax,100 - let mut vmm = MockVMM::new(ip, hashmap![Register::RAX => rax], None); + let mut vmm = MockVMM::new(ip, vec![(Register::RAX, rax)], None); assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); let rflags: u64 = vmm.cpu_state(cpu_id).unwrap().flags() & FLAGS_MASK; @@ -288,7 +280,7 @@ mod tests { let ip: u64 = 0x1000; let cpu_id = 0; let insn = [0x83, 0xf8, 0xff]; // cmp eax,-1 - let mut vmm = MockVMM::new(ip, hashmap![Register::RAX => rax], None); + let mut vmm = MockVMM::new(ip, vec![(Register::RAX, rax)], None); assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); let rflags: u64 = vmm.cpu_state(cpu_id).unwrap().flags() & FLAGS_MASK; @@ -305,11 +297,7 @@ mod tests { let ip: u64 = 0x1000; let cpu_id = 0; let insn = [0x48, 0x39, 0xd8, 0x00, 0xc3]; // cmp rax,rbx + two bytes garbage - let mut vmm = MockVMM::new( - ip, - hashmap![Register::RAX => rax, Register::RBX => rbx], - None, - ); + let mut vmm = MockVMM::new(ip, vec![(Register::RAX, rax), (Register::RBX, rbx)], None); assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); let rflags: u64 = vmm.cpu_state(cpu_id).unwrap().flags() & FLAGS_MASK; @@ -336,7 +324,7 @@ mod tests { let insn = [0x48, 0x39, 0xd8]; // cmp rax,rbx let mut vmm = MockVMM::new( 0x1000, - hashmap![Register::RAX => rax, Register::RBX => rbx], + vec![(Register::RAX, rax), (Register::RBX, rbx)], None, ); assert!(vmm.emulate_first_insn(0, &insn).is_ok()); @@ -366,7 +354,7 @@ mod tests { let insn = [0x39, 0xd8]; // cmp eax,ebx let mut vmm = MockVMM::new( 0x1000, - hashmap![Register::RAX => rax, Register::RBX => rbx], + vec![(Register::RAX, rax), (Register::RBX, rbx)], None, ); assert!(vmm.emulate_first_insn(0, &insn).is_ok()); diff --git a/hypervisor/src/arch/x86/emulator/instructions/mov.rs b/hypervisor/src/arch/x86/emulator/instructions/mov.rs index 1b3beb11d..9657d05c2 100644 --- a/hypervisor/src/arch/x86/emulator/instructions/mov.rs +++ b/hypervisor/src/arch/x86/emulator/instructions/mov.rs @@ -216,14 +216,6 @@ mod tests { use super::*; use crate::arch::x86::emulator::mock_vmm::*; - macro_rules! hashmap { - ($( $key: expr => $val: expr ),*) => {{ - let mut map = ::std::collections::HashMap::new(); - $( map.insert($key, $val); )* - map - }} - } - #[test] // mov rax,rbx fn test_mov_r64_r64() -> MockResult { @@ -231,7 +223,7 @@ mod tests { let ip: u64 = 0x1000; let cpu_id = 0; let insn = [0x48, 0x89, 0xd8]; - let mut vmm = MockVMM::new(ip, hashmap![Register::RBX => rbx], None); + let mut vmm = MockVMM::new(ip, vec![(Register::RBX, rbx)], None); assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); let rax: u64 = vmm @@ -251,7 +243,7 @@ mod tests { let ip: u64 = 0x1000; let cpu_id = 0; let insn = [0x48, 0xb8, 0x44, 0x33, 0x22, 0x11, 0x44, 0x33, 0x22, 0x11]; - let mut vmm = MockVMM::new(ip, hashmap![], None); + let mut vmm = MockVMM::new(ip, vec![], None); assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); let rax: u64 = vmm @@ -273,11 +265,7 @@ mod tests { let cpu_id = 0; let memory: [u8; 8] = target_rax.to_le_bytes(); let insn = [0x48, 0x8b, 0x04, 0x00]; - let mut vmm = MockVMM::new( - ip, - hashmap![Register::RAX => rax], - Some((rax + rax, &memory)), - ); + let mut vmm = MockVMM::new(ip, vec![(Register::RAX, rax)], Some((rax + rax, &memory))); assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); rax = vmm @@ -297,7 +285,7 @@ mod tests { let ip: u64 = 0x1000; let cpu_id = 0; let insn = [0xb0, 0x11]; - let mut vmm = MockVMM::new(ip, hashmap![], None); + let mut vmm = MockVMM::new(ip, vec![], None); assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); let al = vmm @@ -317,7 +305,7 @@ mod tests { let ip: u64 = 0x1000; let cpu_id = 0; let insn = [0xb8, 0x11, 0x00, 0x00, 0x00]; - let mut vmm = MockVMM::new(ip, hashmap![], None); + let mut vmm = MockVMM::new(ip, vec![], None); assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); let eax = vmm @@ -337,7 +325,7 @@ mod tests { let ip: u64 = 0x1000; let cpu_id = 0; let insn = [0x48, 0xc7, 0xc0, 0x44, 0x33, 0x22, 0x11]; - let mut vmm = MockVMM::new(ip, hashmap![], None); + let mut vmm = MockVMM::new(ip, vec![], None); assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); let rax: u64 = vmm @@ -360,7 +348,7 @@ mod tests { let insn = [0x88, 0x30]; let mut vmm = MockVMM::new( ip, - hashmap![Register::RAX => rax, Register::DH => dh.into()], + vec![(Register::RAX, rax), (Register::DH, dh.into())], None, ); assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); @@ -383,7 +371,7 @@ mod tests { let insn = [0x89, 0x30]; let mut vmm = MockVMM::new( ip, - hashmap![Register::RAX => rax, Register::ESI => esi.into()], + vec![(Register::RAX, rax), (Register::ESI, esi.into())], None, ); assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); @@ -407,7 +395,7 @@ mod tests { let insn = [0x89, 0x3c, 0x05, 0x01, 0x00, 0x00, 0x00]; let mut vmm = MockVMM::new( ip, - hashmap![Register::RAX => rax, Register::EDI => edi.into()], + vec![(Register::RAX, rax), (Register::EDI, edi.into())], None, ); assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); @@ -432,7 +420,7 @@ mod tests { let insn = [0x8b, 0x40, 0x10]; let mut vmm = MockVMM::new( ip, - hashmap![Register::RAX => rax], + vec![(Register::RAX, rax)], Some((rax + displacement, &memory)), ); assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); @@ -459,7 +447,7 @@ mod tests { let memory: [u8; 1] = al.to_le_bytes(); let mut vmm = MockVMM::new( ip, - hashmap![Register::RAX => rax], + vec![(Register::RAX, rax)], Some((rax + displacement, &memory)), ); assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); @@ -488,7 +476,7 @@ mod tests { 0x48, 0xc7, 0xc0, 0x00, 0x01, 0x00, 0x00, // mov rax, 0x100 0x48, 0x8b, 0x58, 0x10, // mov rbx, qword ptr [rax+10h] ]; - let mut vmm = MockVMM::new(ip, hashmap![], Some((rax + displacement, &memory))); + let mut vmm = MockVMM::new(ip, vec![], Some((rax + displacement, &memory))); assert!(vmm.emulate_insn(cpu_id, &insn, Some(2)).is_ok()); let rbx: u64 = vmm @@ -516,7 +504,7 @@ mod tests { 0x48, 0x8b, 0x58, 0x10, // mov rbx, qword ptr [rax+10h] ]; - let mut vmm = MockVMM::new(ip, hashmap![], Some((rax + displacement, &memory))); + let mut vmm = MockVMM::new(ip, vec![], Some((rax + displacement, &memory))); // Only run the first instruction. assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); @@ -549,7 +537,7 @@ mod tests { 0x48, 0xc7, 0xc0, 0x00, 0x02, 0x00, 0x00, // mov rax, 0x200 ]; - let mut vmm = MockVMM::new(ip, hashmap![], Some((rax + displacement, &memory))); + let mut vmm = MockVMM::new(ip, vec![], Some((rax + displacement, &memory))); // Run the 2 first instructions. assert!(vmm.emulate_insn(cpu_id, &insn, Some(2)).is_ok()); diff --git a/hypervisor/src/arch/x86/emulator/mod.rs b/hypervisor/src/arch/x86/emulator/mod.rs index e5eda61df..c26b5faa2 100644 --- a/hypervisor/src/arch/x86/emulator/mod.rs +++ b/hypervisor/src/arch/x86/emulator/mod.rs @@ -639,7 +639,6 @@ mod 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)] @@ -653,7 +652,7 @@ mod mock_vmm { pub type MockResult = Result<(), EmulationError>; impl MockVMM { - pub fn new(ip: u64, regs: HashMap, memory: Option<(u64, &[u8])>) -> MockVMM { + pub fn new(ip: u64, regs: Vec<(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); @@ -761,14 +760,6 @@ mod tests { use super::*; use crate::arch::x86::emulator::mock_vmm::*; - macro_rules! hashmap { - ($( $key: expr => $val: expr ),*) => {{ - let mut map = ::std::collections::HashMap::new(); - $( map.insert($key, $val); )* - map - }} - } - #[test] // Emulate truncated instruction stream, which should cause a fetch. // @@ -791,7 +782,7 @@ mod tests { 0x48, 0xc7, 0xc0, 0x00, // mov rax, 0x1000 -- Missing bytes: 0x00, 0x10, 0x00, 0x00, ]; - let mut vmm = MockVMM::new(ip, hashmap![], Some((ip, &memory))); + let mut vmm = MockVMM::new(ip, vec![], Some((ip, &memory))); assert!(vmm.emulate_insn(cpu_id, &insn, Some(2)).is_ok()); let rax: u64 = vmm @@ -828,7 +819,7 @@ mod tests { 0x48, 0x8b, // Truncated mov rbx, qword ptr [rax+10h] -- missing [0x58, 0x10] ]; - let mut vmm = MockVMM::new(ip, hashmap![], Some((ip, &memory))); + let mut vmm = MockVMM::new(ip, vec![], Some((ip, &memory))); assert!(vmm.emulate_insn(cpu_id, &insn, Some(2)).is_ok()); let rbx: u64 = vmm @@ -860,7 +851,7 @@ mod tests { 0x48, 0xc7, 0xc0, 0x00, // mov rax, 0x1000 -- Missing bytes: 0x00, 0x10, 0x00, 0x00, ]; - let mut vmm = MockVMM::new(ip, hashmap![], Some((ip, &memory))); + let mut vmm = MockVMM::new(ip, vec![], Some((ip, &memory))); assert!(vmm.emulate_first_insn(cpu_id, &insn).is_err()); Ok(())