mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-08-21 23:41:15 +00:00
hypervisor: x86: emulate MOVS instruction
Signed-off-by: Wei Liu <liuwe@microsoft.com>
This commit is contained in:
parent
b59243f6cf
commit
e22b6ec768
@ -13,6 +13,7 @@ use iced_x86::*;
|
|||||||
|
|
||||||
pub mod cmp;
|
pub mod cmp;
|
||||||
pub mod mov;
|
pub mod mov;
|
||||||
|
pub mod movs;
|
||||||
|
|
||||||
fn get_op<T: CpuStateManager>(
|
fn get_op<T: CpuStateManager>(
|
||||||
insn: &Instruction,
|
insn: &Instruction,
|
||||||
|
147
hypervisor/src/arch/x86/emulator/instructions/movs.rs
Normal file
147
hypervisor/src/arch/x86/emulator/instructions/movs.rs
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
//
|
||||||
|
// Copyright © 2021 Microsoft
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
|
//
|
||||||
|
// MOVS - Move Data from String to String
|
||||||
|
//
|
||||||
|
|
||||||
|
extern crate iced_x86;
|
||||||
|
|
||||||
|
use crate::arch::emulator::{EmulationError, PlatformEmulator};
|
||||||
|
use crate::arch::x86::emulator::instructions::*;
|
||||||
|
use crate::arch::x86::regs::DF;
|
||||||
|
use crate::arch::x86::Exception;
|
||||||
|
|
||||||
|
pub struct Movsd_m32_m32;
|
||||||
|
impl<T: CpuStateManager> InstructionHandler<T> for Movsd_m32_m32 {
|
||||||
|
fn emulate(
|
||||||
|
&self,
|
||||||
|
insn: &Instruction,
|
||||||
|
state: &mut T,
|
||||||
|
platform: &mut dyn PlatformEmulator<CpuState = T>,
|
||||||
|
) -> Result<(), EmulationError<Exception>> {
|
||||||
|
let mut count: u64 = if insn.has_rep_prefix() {
|
||||||
|
state
|
||||||
|
.read_reg(Register::ECX)
|
||||||
|
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut rsi = state
|
||||||
|
.read_reg(Register::RSI)
|
||||||
|
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||||
|
let mut rdi = state
|
||||||
|
.read_reg(Register::RDI)
|
||||||
|
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||||
|
|
||||||
|
let df = (state.flags() & DF) != 0;
|
||||||
|
let len = std::mem::size_of::<u32>();
|
||||||
|
|
||||||
|
while count > 0 {
|
||||||
|
let mut memory: [u8; 4] = [0; 4];
|
||||||
|
|
||||||
|
let src = state
|
||||||
|
.linearize(Register::DS, rsi, false)
|
||||||
|
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||||
|
let dst = state
|
||||||
|
.linearize(Register::ES, rdi, true)
|
||||||
|
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||||
|
|
||||||
|
platform
|
||||||
|
.read_memory(src, &mut memory[0..len])
|
||||||
|
.map_err(EmulationError::PlatformEmulationError)?;
|
||||||
|
platform
|
||||||
|
.write_memory(dst, &memory[0..len])
|
||||||
|
.map_err(EmulationError::PlatformEmulationError)?;
|
||||||
|
|
||||||
|
if df {
|
||||||
|
rsi = rsi.wrapping_sub(len as u64);
|
||||||
|
rdi = rdi.wrapping_sub(len as u64);
|
||||||
|
} else {
|
||||||
|
rsi = rsi.wrapping_add(len as u64);
|
||||||
|
rdi = rdi.wrapping_add(len as u64);
|
||||||
|
}
|
||||||
|
count -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
state
|
||||||
|
.write_reg(Register::RSI, rsi)
|
||||||
|
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||||
|
state
|
||||||
|
.write_reg(Register::RDI, rdi)
|
||||||
|
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||||
|
if insn.has_rep_prefix() {
|
||||||
|
state
|
||||||
|
.write_reg(Register::ECX, 0)
|
||||||
|
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#![allow(unused_mut)]
|
||||||
|
use super::*;
|
||||||
|
use crate::arch::x86::emulator::mock_vmm::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rep_movsd_m32_m32() {
|
||||||
|
let ip: u64 = 0x1000;
|
||||||
|
let memory: [u8; 24] = [
|
||||||
|
0x78, 0x56, 0x34, 0x12, // 0x12345678
|
||||||
|
0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd
|
||||||
|
0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5
|
||||||
|
0x00, 0x00, 0x00, 0x00, // 0x00000000
|
||||||
|
0x00, 0x00, 0x00, 0x00, // 0x00000000
|
||||||
|
0x00, 0x00, 0x00, 0x00, // 0x00000000
|
||||||
|
];
|
||||||
|
let insn = [0xf3, 0xa5]; // rep movsd
|
||||||
|
let regs = vec![(Register::ECX, 3), (Register::ESI, 0), (Register::EDI, 0xc)];
|
||||||
|
let mut data = [0u8; 4];
|
||||||
|
|
||||||
|
let mut vmm = MockVMM::new(ip, regs, Some((0, &memory)));
|
||||||
|
|
||||||
|
assert!(vmm.emulate_first_insn(0, &insn).is_ok());
|
||||||
|
|
||||||
|
vmm.read_memory(0xc, &mut data).unwrap();
|
||||||
|
assert_eq!(0x12345678, <u32>::from_le_bytes(data));
|
||||||
|
vmm.read_memory(0xc + 4, &mut data).unwrap();
|
||||||
|
assert_eq!(0xaabbccdd, <u32>::from_le_bytes(data));
|
||||||
|
vmm.read_memory(0xc + 8, &mut data).unwrap();
|
||||||
|
assert_eq!(0x5aa55aa5, <u32>::from_le_bytes(data));
|
||||||
|
// The rest should be default value 0 from MockVMM
|
||||||
|
vmm.read_memory(0xc + 12, &mut data).unwrap();
|
||||||
|
assert_eq!(0x0, <u32>::from_le_bytes(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_movsd_m32_m32() {
|
||||||
|
let ip: u64 = 0x1000;
|
||||||
|
let memory: [u8; 4] = [
|
||||||
|
0x78, 0x56, 0x34, 0x12, // 0x12345678
|
||||||
|
];
|
||||||
|
let insn = [0xa5]; // movsd
|
||||||
|
let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)];
|
||||||
|
let mut data = [0u8; 4];
|
||||||
|
|
||||||
|
let mut vmm = MockVMM::new(ip, regs, Some((0, &memory)));
|
||||||
|
|
||||||
|
assert!(vmm.emulate_first_insn(0, &insn).is_ok());
|
||||||
|
|
||||||
|
vmm.read_memory(0x8, &mut data).unwrap();
|
||||||
|
assert_eq!(0x12345678, <u32>::from_le_bytes(data));
|
||||||
|
// The rest should be default value 0 from MockVMM
|
||||||
|
vmm.read_memory(0x4, &mut data).unwrap();
|
||||||
|
assert_eq!(0x0, <u32>::from_le_bytes(data));
|
||||||
|
vmm.read_memory(0x8 + 8, &mut data).unwrap();
|
||||||
|
assert_eq!(0x0, <u32>::from_le_bytes(data));
|
||||||
|
}
|
||||||
|
}
|
@ -524,7 +524,9 @@ impl<'a, T: CpuStateManager> Emulator<'a, T> {
|
|||||||
(mov, Movzx_r32_rm8),
|
(mov, Movzx_r32_rm8),
|
||||||
(mov, Movzx_r64_rm8),
|
(mov, Movzx_r64_rm8),
|
||||||
(mov, Movzx_r32_rm16),
|
(mov, Movzx_r32_rm16),
|
||||||
(mov, Movzx_r64_rm16)
|
(mov, Movzx_r64_rm16),
|
||||||
|
// MOVS
|
||||||
|
(movs, Movsd_m32_m32)
|
||||||
);
|
);
|
||||||
|
|
||||||
handler
|
handler
|
||||||
|
@ -22,6 +22,7 @@ pub const PF_SHIFT: usize = 2;
|
|||||||
pub const AF_SHIFT: usize = 4;
|
pub const AF_SHIFT: usize = 4;
|
||||||
pub const ZF_SHIFT: usize = 6;
|
pub const ZF_SHIFT: usize = 6;
|
||||||
pub const SF_SHIFT: usize = 7;
|
pub const SF_SHIFT: usize = 7;
|
||||||
|
pub const DF_SHIFT: usize = 10;
|
||||||
pub const OF_SHIFT: usize = 11;
|
pub const OF_SHIFT: usize = 11;
|
||||||
|
|
||||||
pub const CF: u64 = 1 << CF_SHIFT;
|
pub const CF: u64 = 1 << CF_SHIFT;
|
||||||
@ -29,4 +30,5 @@ pub const PF: u64 = 1 << PF_SHIFT;
|
|||||||
pub const AF: u64 = 1 << AF_SHIFT;
|
pub const AF: u64 = 1 << AF_SHIFT;
|
||||||
pub const ZF: u64 = 1 << ZF_SHIFT;
|
pub const ZF: u64 = 1 << ZF_SHIFT;
|
||||||
pub const SF: u64 = 1 << SF_SHIFT;
|
pub const SF: u64 = 1 << SF_SHIFT;
|
||||||
|
pub const DF: u64 = 1 << DF_SHIFT;
|
||||||
pub const OF: u64 = 1 << OF_SHIFT;
|
pub const OF: u64 = 1 << OF_SHIFT;
|
||||||
|
Loading…
Reference in New Issue
Block a user