mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-10-05 21:15:45 +00:00
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:
parent
5bd63efa45
commit
a3d957ba4d
@ -270,7 +270,8 @@ mod tests {
|
|||||||
let ip: u64 = 0x1000;
|
let ip: u64 = 0x1000;
|
||||||
let cpu_id = 0;
|
let cpu_id = 0;
|
||||||
let insn = [0x48, 0x89, 0xd8];
|
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
|
let rax: u64 = vmm
|
||||||
.cpu_state(cpu_id)
|
.cpu_state(cpu_id)
|
||||||
@ -289,7 +290,8 @@ mod tests {
|
|||||||
let ip: u64 = 0x1000;
|
let ip: u64 = 0x1000;
|
||||||
let cpu_id = 0;
|
let cpu_id = 0;
|
||||||
let insn = [0x48, 0xb8, 0x44, 0x33, 0x22, 0x11, 0x44, 0x33, 0x22, 0x11];
|
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
|
let rax: u64 = vmm
|
||||||
.cpu_state(cpu_id)
|
.cpu_state(cpu_id)
|
||||||
@ -310,13 +312,12 @@ mod tests {
|
|||||||
let cpu_id = 0;
|
let cpu_id = 0;
|
||||||
let memory: [u8; 8] = target_rax.to_le_bytes();
|
let memory: [u8; 8] = target_rax.to_le_bytes();
|
||||||
let insn = [0x48, 0x8b, 0x04, 0x00];
|
let insn = [0x48, 0x8b, 0x04, 0x00];
|
||||||
let vmm = init_and_run(
|
let mut vmm = MockVMM::new(
|
||||||
cpu_id,
|
|
||||||
ip,
|
ip,
|
||||||
&insn,
|
|
||||||
hashmap![Register::RAX => rax],
|
hashmap![Register::RAX => rax],
|
||||||
Some((rax + rax, &memory)),
|
Some((rax + rax, &memory)),
|
||||||
);
|
);
|
||||||
|
vmm.emulate_first_insn(cpu_id, &insn);
|
||||||
|
|
||||||
rax = vmm
|
rax = vmm
|
||||||
.cpu_state(cpu_id)
|
.cpu_state(cpu_id)
|
||||||
@ -335,7 +336,8 @@ mod tests {
|
|||||||
let ip: u64 = 0x1000;
|
let ip: u64 = 0x1000;
|
||||||
let cpu_id = 0;
|
let cpu_id = 0;
|
||||||
let insn = [0xb0, 0x11];
|
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
|
let al = vmm
|
||||||
.cpu_state(cpu_id)
|
.cpu_state(cpu_id)
|
||||||
@ -354,7 +356,8 @@ mod tests {
|
|||||||
let ip: u64 = 0x1000;
|
let ip: u64 = 0x1000;
|
||||||
let cpu_id = 0;
|
let cpu_id = 0;
|
||||||
let insn = [0xb8, 0x11, 0x00, 0x00, 0x00];
|
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
|
let eax = vmm
|
||||||
.cpu_state(cpu_id)
|
.cpu_state(cpu_id)
|
||||||
@ -373,7 +376,8 @@ mod tests {
|
|||||||
let ip: u64 = 0x1000;
|
let ip: u64 = 0x1000;
|
||||||
let cpu_id = 0;
|
let cpu_id = 0;
|
||||||
let insn = [0x48, 0xc7, 0xc0, 0x44, 0x33, 0x22, 0x11];
|
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
|
let rax: u64 = vmm
|
||||||
.cpu_state(cpu_id)
|
.cpu_state(cpu_id)
|
||||||
@ -393,13 +397,12 @@ mod tests {
|
|||||||
let ip: u64 = 0x1000;
|
let ip: u64 = 0x1000;
|
||||||
let cpu_id = 0;
|
let cpu_id = 0;
|
||||||
let insn = [0x88, 0x30];
|
let insn = [0x88, 0x30];
|
||||||
let vmm = init_and_run(
|
let mut vmm = MockVMM::new(
|
||||||
cpu_id,
|
|
||||||
ip,
|
ip,
|
||||||
&insn,
|
|
||||||
hashmap![Register::RAX => rax, Register::DH => dh.into()],
|
hashmap![Register::RAX => rax, Register::DH => dh.into()],
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
vmm.emulate_first_insn(cpu_id, &insn);
|
||||||
|
|
||||||
let mut memory: [u8; 1] = [0; 1];
|
let mut memory: [u8; 1] = [0; 1];
|
||||||
vmm.read_memory(rax, &mut memory).unwrap();
|
vmm.read_memory(rax, &mut memory).unwrap();
|
||||||
@ -417,13 +420,12 @@ mod tests {
|
|||||||
let ip: u64 = 0x1000;
|
let ip: u64 = 0x1000;
|
||||||
let cpu_id = 0;
|
let cpu_id = 0;
|
||||||
let insn = [0x89, 0x30];
|
let insn = [0x89, 0x30];
|
||||||
let vmm = init_and_run(
|
let mut vmm = MockVMM::new(
|
||||||
cpu_id,
|
|
||||||
ip,
|
ip,
|
||||||
&insn,
|
|
||||||
hashmap![Register::RAX => rax, Register::ESI => esi.into()],
|
hashmap![Register::RAX => rax, Register::ESI => esi.into()],
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
vmm.emulate_first_insn(cpu_id, &insn);
|
||||||
|
|
||||||
let mut memory: [u8; 4] = [0; 4];
|
let mut memory: [u8; 4] = [0; 4];
|
||||||
vmm.read_memory(rax, &mut memory).unwrap();
|
vmm.read_memory(rax, &mut memory).unwrap();
|
||||||
@ -442,13 +444,12 @@ mod tests {
|
|||||||
let ip: u64 = 0x1000;
|
let ip: u64 = 0x1000;
|
||||||
let cpu_id = 0;
|
let cpu_id = 0;
|
||||||
let insn = [0x89, 0x3c, 0x05, 0x01, 0x00, 0x00, 0x00];
|
let insn = [0x89, 0x3c, 0x05, 0x01, 0x00, 0x00, 0x00];
|
||||||
let vmm = init_and_run(
|
let mut vmm = MockVMM::new(
|
||||||
cpu_id,
|
|
||||||
ip,
|
ip,
|
||||||
&insn,
|
|
||||||
hashmap![Register::RAX => rax, Register::EDI => edi.into()],
|
hashmap![Register::RAX => rax, Register::EDI => edi.into()],
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
vmm.emulate_first_insn(cpu_id, &insn);
|
||||||
|
|
||||||
let mut memory: [u8; 4] = [0; 4];
|
let mut memory: [u8; 4] = [0; 4];
|
||||||
vmm.read_memory(rax + displacement, &mut memory).unwrap();
|
vmm.read_memory(rax + displacement, &mut memory).unwrap();
|
||||||
@ -468,13 +469,12 @@ mod tests {
|
|||||||
let ip: u64 = 0x1000;
|
let ip: u64 = 0x1000;
|
||||||
let cpu_id = 0;
|
let cpu_id = 0;
|
||||||
let insn = [0x8b, 0x40, 0x10];
|
let insn = [0x8b, 0x40, 0x10];
|
||||||
let vmm = init_and_run(
|
let mut vmm = MockVMM::new(
|
||||||
cpu_id,
|
|
||||||
ip,
|
ip,
|
||||||
&insn,
|
|
||||||
hashmap![Register::RAX => rax],
|
hashmap![Register::RAX => rax],
|
||||||
Some((rax + displacement, &memory)),
|
Some((rax + displacement, &memory)),
|
||||||
);
|
);
|
||||||
|
vmm.emulate_first_insn(cpu_id, &insn);
|
||||||
|
|
||||||
let new_eax = vmm
|
let new_eax = vmm
|
||||||
.cpu_state(cpu_id)
|
.cpu_state(cpu_id)
|
||||||
@ -496,13 +496,12 @@ mod tests {
|
|||||||
let cpu_id = 0;
|
let cpu_id = 0;
|
||||||
let insn = [0x8a, 0x40, 0x10];
|
let insn = [0x8a, 0x40, 0x10];
|
||||||
let memory: [u8; 1] = al.to_le_bytes();
|
let memory: [u8; 1] = al.to_le_bytes();
|
||||||
let vmm = init_and_run(
|
let mut vmm = MockVMM::new(
|
||||||
cpu_id,
|
|
||||||
ip,
|
ip,
|
||||||
&insn,
|
|
||||||
hashmap![Register::RAX => rax],
|
hashmap![Register::RAX => rax],
|
||||||
Some((rax + displacement, &memory)),
|
Some((rax + displacement, &memory)),
|
||||||
);
|
);
|
||||||
|
vmm.emulate_first_insn(cpu_id, &insn);
|
||||||
|
|
||||||
let new_al = vmm
|
let new_al = vmm
|
||||||
.cpu_state(cpu_id)
|
.cpu_state(cpu_id)
|
||||||
@ -528,14 +527,8 @@ mod tests {
|
|||||||
0x48, 0xc7, 0xc0, 0x00, 0x01, 0x00, 0x00, // mov rax, 0x100
|
0x48, 0xc7, 0xc0, 0x00, 0x01, 0x00, 0x00, // mov rax, 0x100
|
||||||
0x48, 0x8b, 0x58, 0x10, // mov rbx, qword ptr [rax+10h]
|
0x48, 0x8b, 0x58, 0x10, // mov rbx, qword ptr [rax+10h]
|
||||||
];
|
];
|
||||||
|
let mut vmm = MockVMM::new(ip, hashmap![], Some((rax + displacement, &memory)));
|
||||||
let vmm = init_and_run(
|
vmm.emulate_first_insn(cpu_id, &insn);
|
||||||
cpu_id,
|
|
||||||
ip,
|
|
||||||
&insn,
|
|
||||||
hashmap![],
|
|
||||||
Some((rax + displacement, &memory)),
|
|
||||||
);
|
|
||||||
|
|
||||||
let rbx: u64 = vmm
|
let rbx: u64 = vmm
|
||||||
.cpu_state(cpu_id)
|
.cpu_state(cpu_id)
|
||||||
@ -562,15 +555,9 @@ mod tests {
|
|||||||
0x48, 0x8b, 0x58, 0x10, // mov rbx, qword ptr [rax+10h]
|
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.
|
// Only run the first instruction.
|
||||||
let vmm = _init_and_run(
|
vmm.emulate_insn(cpu_id, &insn, Some(1));
|
||||||
cpu_id,
|
|
||||||
ip,
|
|
||||||
&insn,
|
|
||||||
hashmap![],
|
|
||||||
Some((rax + displacement, &memory)),
|
|
||||||
Some(1),
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(ip + 7 as u64, vmm.cpu_state(cpu_id).unwrap().ip());
|
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
|
0x48, 0xc7, 0xc0, 0x00, 0x02, 0x00, 0x00, // mov rax, 0x200
|
||||||
];
|
];
|
||||||
|
|
||||||
// Only run the first instruction.
|
let mut vmm = MockVMM::new(ip, hashmap![], Some((rax + displacement, &memory)));
|
||||||
let vmm = _init_and_run(
|
// Run the 2 first instructions.
|
||||||
cpu_id,
|
vmm.emulate_insn(cpu_id, &insn, Some(2));
|
||||||
ip,
|
|
||||||
&insn,
|
|
||||||
hashmap![],
|
|
||||||
Some((rax + displacement, &memory)),
|
|
||||||
Some(2),
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(ip + 7 + 4 as u64, vmm.cpu_state(cpu_id).unwrap().ip());
|
assert_eq!(ip + 7 + 4 as u64, vmm.cpu_state(cpu_id).unwrap().ip());
|
||||||
|
|
||||||
|
@ -456,11 +456,46 @@ mod mock_vmm {
|
|||||||
pub type MockResult = Result<(), EmulationError<Exception>>;
|
pub type MockResult = Result<(), EmulationError<Exception>>;
|
||||||
|
|
||||||
impl MockVMM {
|
impl MockVMM {
|
||||||
pub fn new(state: CpuState) -> MockVMM {
|
pub fn new(ip: u64, regs: HashMap<Register, u64>, memory: Option<(u64, &[u8])>) -> MockVMM {
|
||||||
MockVMM {
|
let _ = env_logger::try_init();
|
||||||
memory: vec![0; 4096],
|
let cs_reg = segment_from_gdt(gdt_entry(0xc09b, 0, 0xffffffff), 1);
|
||||||
state: Arc::new(Mutex::new(state)),
|
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)
|
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