1e22b6ec7SWei Liu // 2e22b6ec7SWei Liu // Copyright © 2021 Microsoft 3e22b6ec7SWei Liu // 4e22b6ec7SWei Liu // SPDX-License-Identifier: Apache-2.0 5e22b6ec7SWei Liu // 6e22b6ec7SWei Liu 7e22b6ec7SWei Liu #![allow(non_camel_case_types)] 8e22b6ec7SWei Liu 9e22b6ec7SWei Liu // 10e22b6ec7SWei Liu // MOVS - Move Data from String to String 11e22b6ec7SWei Liu // 12e22b6ec7SWei Liu 13e22b6ec7SWei Liu use crate::arch::x86::emulator::instructions::*; 14e22b6ec7SWei Liu use crate::arch::x86::regs::DF; 15e22b6ec7SWei Liu 161bfa07f4SWei Liu macro_rules! movs { 171bfa07f4SWei Liu ($bound:ty) => { 18e22b6ec7SWei Liu fn emulate( 19e22b6ec7SWei Liu &self, 20e22b6ec7SWei Liu insn: &Instruction, 21e22b6ec7SWei Liu state: &mut T, 22e22b6ec7SWei Liu platform: &mut dyn PlatformEmulator<CpuState = T>, 23e22b6ec7SWei Liu ) -> Result<(), EmulationError<Exception>> { 24e22b6ec7SWei Liu let mut count: u64 = if insn.has_rep_prefix() { 25e22b6ec7SWei Liu state 26e22b6ec7SWei Liu .read_reg(Register::ECX) 27e22b6ec7SWei Liu .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))? 28e22b6ec7SWei Liu } else { 29e22b6ec7SWei Liu 1 30e22b6ec7SWei Liu }; 31e22b6ec7SWei Liu 32e22b6ec7SWei Liu let mut rsi = state 33e22b6ec7SWei Liu .read_reg(Register::RSI) 34e22b6ec7SWei Liu .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 35e22b6ec7SWei Liu let mut rdi = state 36e22b6ec7SWei Liu .read_reg(Register::RDI) 37e22b6ec7SWei Liu .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 38e22b6ec7SWei Liu 39e22b6ec7SWei Liu let df = (state.flags() & DF) != 0; 401bfa07f4SWei Liu let len = std::mem::size_of::<$bound>(); 41e22b6ec7SWei Liu 42e22b6ec7SWei Liu while count > 0 { 431c7997c5SWei Liu let mut memory: [u8; 8] = [0; 8]; 44e22b6ec7SWei Liu 45e22b6ec7SWei Liu let src = state 46e22b6ec7SWei Liu .linearize(Register::DS, rsi, false) 47e22b6ec7SWei Liu .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 48e22b6ec7SWei Liu let dst = state 49e22b6ec7SWei Liu .linearize(Register::ES, rdi, true) 50e22b6ec7SWei Liu .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 51e22b6ec7SWei Liu 52e22b6ec7SWei Liu platform 53e22b6ec7SWei Liu .read_memory(src, &mut memory[0..len]) 54e22b6ec7SWei Liu .map_err(EmulationError::PlatformEmulationError)?; 55e22b6ec7SWei Liu platform 56e22b6ec7SWei Liu .write_memory(dst, &memory[0..len]) 57e22b6ec7SWei Liu .map_err(EmulationError::PlatformEmulationError)?; 58e22b6ec7SWei Liu 59e22b6ec7SWei Liu if df { 60e22b6ec7SWei Liu rsi = rsi.wrapping_sub(len as u64); 61e22b6ec7SWei Liu rdi = rdi.wrapping_sub(len as u64); 62e22b6ec7SWei Liu } else { 63e22b6ec7SWei Liu rsi = rsi.wrapping_add(len as u64); 64e22b6ec7SWei Liu rdi = rdi.wrapping_add(len as u64); 65e22b6ec7SWei Liu } 66e22b6ec7SWei Liu count -= 1; 67e22b6ec7SWei Liu } 68e22b6ec7SWei Liu 69e22b6ec7SWei Liu state 70e22b6ec7SWei Liu .write_reg(Register::RSI, rsi) 71e22b6ec7SWei Liu .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 72e22b6ec7SWei Liu state 73e22b6ec7SWei Liu .write_reg(Register::RDI, rdi) 74e22b6ec7SWei Liu .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 75e22b6ec7SWei Liu if insn.has_rep_prefix() { 76e22b6ec7SWei Liu state 77e22b6ec7SWei Liu .write_reg(Register::ECX, 0) 78e22b6ec7SWei Liu .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 79e22b6ec7SWei Liu } 80e22b6ec7SWei Liu 81e22b6ec7SWei Liu Ok(()) 82e22b6ec7SWei Liu } 831bfa07f4SWei Liu }; 841bfa07f4SWei Liu } 851bfa07f4SWei Liu 861c7997c5SWei Liu pub struct Movsq_m64_m64; 871c7997c5SWei Liu impl<T: CpuStateManager> InstructionHandler<T> for Movsq_m64_m64 { 881c7997c5SWei Liu movs!(u64); 891c7997c5SWei Liu } 901c7997c5SWei Liu 911bfa07f4SWei Liu pub struct Movsd_m32_m32; 921bfa07f4SWei Liu impl<T: CpuStateManager> InstructionHandler<T> for Movsd_m32_m32 { 931bfa07f4SWei Liu movs!(u32); 94e22b6ec7SWei Liu } 95e22b6ec7SWei Liu 963a225aaaSWei Liu pub struct Movsw_m16_m16; 973a225aaaSWei Liu impl<T: CpuStateManager> InstructionHandler<T> for Movsw_m16_m16 { 983a225aaaSWei Liu movs!(u16); 993a225aaaSWei Liu } 1003a225aaaSWei Liu 101ad202f9bSPraveen K Paladugu pub struct Movsb_m8_m8; 102ad202f9bSPraveen K Paladugu impl<T: CpuStateManager> InstructionHandler<T> for Movsb_m8_m8 { 103ad202f9bSPraveen K Paladugu movs!(u8); 104ad202f9bSPraveen K Paladugu } 105ad202f9bSPraveen K Paladugu 106e22b6ec7SWei Liu #[cfg(test)] 107e22b6ec7SWei Liu mod tests { 108e22b6ec7SWei Liu use super::*; 109e22b6ec7SWei Liu use crate::arch::x86::emulator::mock_vmm::*; 110e22b6ec7SWei Liu 111e22b6ec7SWei Liu #[test] test_rep_movsq_m64_m64()1121c7997c5SWei Liu fn test_rep_movsq_m64_m64() { 1131c7997c5SWei Liu let ip: u64 = 0x1000; 1141c7997c5SWei Liu let memory: [u8; 32] = [ 1151c7997c5SWei Liu 0x78, 0x56, 0x34, 0x12, // 0x12345678 1161c7997c5SWei Liu 0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd 1171c7997c5SWei Liu 0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5 1181c7997c5SWei Liu 0xcd, 0xcd, 0xcd, 0xcd, // 0xcdcdcdcd 1191c7997c5SWei Liu 0x00, 0x00, 0x00, 0x00, // 0x00000000 1201c7997c5SWei Liu 0x00, 0x00, 0x00, 0x00, // 0x00000000 1211c7997c5SWei Liu 0x00, 0x00, 0x00, 0x00, // 0x00000000 1221c7997c5SWei Liu 0x00, 0x00, 0x00, 0x00, // 0x00000000 1231c7997c5SWei Liu ]; 1241c7997c5SWei Liu let insn = [0xf3, 0x48, 0xa5]; // rep movsq 1251c7997c5SWei Liu let regs = vec![ 1261c7997c5SWei Liu (Register::ECX, 2), 1271c7997c5SWei Liu (Register::ESI, 0), 1281c7997c5SWei Liu (Register::EDI, 0x10), 1291c7997c5SWei Liu ]; 1301c7997c5SWei Liu let mut data = [0u8; 8]; 1311c7997c5SWei Liu 1321c7997c5SWei Liu let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 1331c7997c5SWei Liu 134*297236a7SRuoqing He vmm.emulate_first_insn(0, &insn).unwrap(); 1351c7997c5SWei Liu 1361c7997c5SWei Liu vmm.read_memory(0x10, &mut data).unwrap(); 1371c7997c5SWei Liu assert_eq!(0xaabbccdd12345678, <u64>::from_le_bytes(data)); 1381c7997c5SWei Liu vmm.read_memory(0x18, &mut data).unwrap(); 1391c7997c5SWei Liu assert_eq!(0xcdcdcdcd5aa55aa5, <u64>::from_le_bytes(data)); 1401c7997c5SWei Liu // The rest should be default value 0 from MockVmm 1411c7997c5SWei Liu vmm.read_memory(0x20, &mut data).unwrap(); 1421c7997c5SWei Liu assert_eq!(0x0, <u64>::from_le_bytes(data)); 1431c7997c5SWei Liu } 1441c7997c5SWei Liu 1451c7997c5SWei Liu #[test] test_rep_movsd_m32_m32()146e22b6ec7SWei Liu fn test_rep_movsd_m32_m32() { 147e22b6ec7SWei Liu let ip: u64 = 0x1000; 148e22b6ec7SWei Liu let memory: [u8; 24] = [ 149e22b6ec7SWei Liu 0x78, 0x56, 0x34, 0x12, // 0x12345678 150e22b6ec7SWei Liu 0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd 151e22b6ec7SWei Liu 0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5 152e22b6ec7SWei Liu 0x00, 0x00, 0x00, 0x00, // 0x00000000 153e22b6ec7SWei Liu 0x00, 0x00, 0x00, 0x00, // 0x00000000 154e22b6ec7SWei Liu 0x00, 0x00, 0x00, 0x00, // 0x00000000 155e22b6ec7SWei Liu ]; 156e22b6ec7SWei Liu let insn = [0xf3, 0xa5]; // rep movsd 157e22b6ec7SWei Liu let regs = vec![(Register::ECX, 3), (Register::ESI, 0), (Register::EDI, 0xc)]; 158e22b6ec7SWei Liu let mut data = [0u8; 4]; 159e22b6ec7SWei Liu 1600c27f69fSRob Bradford let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 161e22b6ec7SWei Liu 162*297236a7SRuoqing He vmm.emulate_first_insn(0, &insn).unwrap(); 163e22b6ec7SWei Liu 164e22b6ec7SWei Liu vmm.read_memory(0xc, &mut data).unwrap(); 165e22b6ec7SWei Liu assert_eq!(0x12345678, <u32>::from_le_bytes(data)); 166e22b6ec7SWei Liu vmm.read_memory(0xc + 4, &mut data).unwrap(); 167e22b6ec7SWei Liu assert_eq!(0xaabbccdd, <u32>::from_le_bytes(data)); 168e22b6ec7SWei Liu vmm.read_memory(0xc + 8, &mut data).unwrap(); 169e22b6ec7SWei Liu assert_eq!(0x5aa55aa5, <u32>::from_le_bytes(data)); 1700c27f69fSRob Bradford // The rest should be default value 0 from MockVmm 171e22b6ec7SWei Liu vmm.read_memory(0xc + 12, &mut data).unwrap(); 172e22b6ec7SWei Liu assert_eq!(0x0, <u32>::from_le_bytes(data)); 173e22b6ec7SWei Liu } 174e22b6ec7SWei Liu 175e22b6ec7SWei Liu #[test] test_movsd_m32_m32()176e22b6ec7SWei Liu fn test_movsd_m32_m32() { 177e22b6ec7SWei Liu let ip: u64 = 0x1000; 178e22b6ec7SWei Liu let memory: [u8; 4] = [ 179e22b6ec7SWei Liu 0x78, 0x56, 0x34, 0x12, // 0x12345678 180e22b6ec7SWei Liu ]; 181e22b6ec7SWei Liu let insn = [0xa5]; // movsd 182e22b6ec7SWei Liu let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)]; 183e22b6ec7SWei Liu let mut data = [0u8; 4]; 184e22b6ec7SWei Liu 1850c27f69fSRob Bradford let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 186e22b6ec7SWei Liu 187*297236a7SRuoqing He vmm.emulate_first_insn(0, &insn).unwrap(); 188e22b6ec7SWei Liu 189e22b6ec7SWei Liu vmm.read_memory(0x8, &mut data).unwrap(); 190e22b6ec7SWei Liu assert_eq!(0x12345678, <u32>::from_le_bytes(data)); 1910c27f69fSRob Bradford // The rest should be default value 0 from MockVmm 192e22b6ec7SWei Liu vmm.read_memory(0x4, &mut data).unwrap(); 193e22b6ec7SWei Liu assert_eq!(0x0, <u32>::from_le_bytes(data)); 194e22b6ec7SWei Liu vmm.read_memory(0x8 + 8, &mut data).unwrap(); 195e22b6ec7SWei Liu assert_eq!(0x0, <u32>::from_le_bytes(data)); 196e22b6ec7SWei Liu } 1973a225aaaSWei Liu 1983a225aaaSWei Liu #[test] test_rep_movsw_m16_m16()1993a225aaaSWei Liu fn test_rep_movsw_m16_m16() { 2003a225aaaSWei Liu let ip: u64 = 0x1000; 2013a225aaaSWei Liu let memory: [u8; 24] = [ 2023a225aaaSWei Liu 0x78, 0x56, 0x34, 0x12, // 0x12345678 2033a225aaaSWei Liu 0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd 2043a225aaaSWei Liu 0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5 2053a225aaaSWei Liu 0x00, 0x00, 0x00, 0x00, // 0x00000000 2063a225aaaSWei Liu 0x00, 0x00, 0x00, 0x00, // 0x00000000 2073a225aaaSWei Liu 0x00, 0x00, 0x00, 0x00, // 0x00000000 2083a225aaaSWei Liu ]; 2093a225aaaSWei Liu let insn = [0x66, 0xf3, 0xa5]; // rep movsw 2103a225aaaSWei Liu let regs = vec![(Register::ECX, 6), (Register::ESI, 0), (Register::EDI, 0xc)]; 2113a225aaaSWei Liu let mut data = [0u8; 2]; 2123a225aaaSWei Liu 2133a225aaaSWei Liu let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 2143a225aaaSWei Liu 215*297236a7SRuoqing He vmm.emulate_first_insn(0, &insn).unwrap(); 2163a225aaaSWei Liu 2173a225aaaSWei Liu vmm.read_memory(0xc, &mut data).unwrap(); 2183a225aaaSWei Liu assert_eq!(0x5678, <u16>::from_le_bytes(data)); 2193a225aaaSWei Liu vmm.read_memory(0xc + 2, &mut data).unwrap(); 2203a225aaaSWei Liu assert_eq!(0x1234, <u16>::from_le_bytes(data)); 2213a225aaaSWei Liu vmm.read_memory(0xc + 4, &mut data).unwrap(); 2223a225aaaSWei Liu assert_eq!(0xccdd, <u16>::from_le_bytes(data)); 2233a225aaaSWei Liu vmm.read_memory(0xc + 6, &mut data).unwrap(); 2243a225aaaSWei Liu assert_eq!(0xaabb, <u16>::from_le_bytes(data)); 2253a225aaaSWei Liu vmm.read_memory(0xc + 8, &mut data).unwrap(); 2263a225aaaSWei Liu assert_eq!(0x5aa5, <u16>::from_le_bytes(data)); 2273a225aaaSWei Liu vmm.read_memory(0xc + 10, &mut data).unwrap(); 2283a225aaaSWei Liu assert_eq!(0x5aa5, <u16>::from_le_bytes(data)); 2293a225aaaSWei Liu // The rest should be default value 0 from MockVmm 2303a225aaaSWei Liu vmm.read_memory(0xc + 12, &mut data).unwrap(); 2313a225aaaSWei Liu assert_eq!(0x0, <u16>::from_le_bytes(data)); 2323a225aaaSWei Liu } 2333a225aaaSWei Liu 2343a225aaaSWei Liu #[test] test_movsw_m16_m16()2353a225aaaSWei Liu fn test_movsw_m16_m16() { 2363a225aaaSWei Liu let ip: u64 = 0x1000; 2373a225aaaSWei Liu let memory: [u8; 4] = [ 2383a225aaaSWei Liu 0x78, 0x56, 0x34, 0x12, // 0x12345678 2393a225aaaSWei Liu ]; 2403a225aaaSWei Liu let insn = [0x66, 0xa5]; // movsw 2413a225aaaSWei Liu let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)]; 2423a225aaaSWei Liu let mut data = [0u8; 2]; 2433a225aaaSWei Liu 2443a225aaaSWei Liu let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 2453a225aaaSWei Liu 246*297236a7SRuoqing He vmm.emulate_first_insn(0, &insn).unwrap(); 2473a225aaaSWei Liu 2483a225aaaSWei Liu vmm.read_memory(0x8, &mut data).unwrap(); 2493a225aaaSWei Liu assert_eq!(0x5678, <u16>::from_le_bytes(data)); 2503a225aaaSWei Liu // Only two bytes were copied, so the value at 0xa should be zero 2513a225aaaSWei Liu vmm.read_memory(0xa, &mut data).unwrap(); 2523a225aaaSWei Liu assert_eq!(0x0, <u16>::from_le_bytes(data)); 2533a225aaaSWei Liu // The rest should be default value 0 from MockVmm 2543a225aaaSWei Liu vmm.read_memory(0x4, &mut data).unwrap(); 2553a225aaaSWei Liu assert_eq!(0x0, <u16>::from_le_bytes(data)); 2563a225aaaSWei Liu vmm.read_memory(0x8 + 8, &mut data).unwrap(); 2573a225aaaSWei Liu assert_eq!(0x0, <u16>::from_le_bytes(data)); 2583a225aaaSWei Liu } 259ad202f9bSPraveen K Paladugu 260ad202f9bSPraveen K Paladugu #[test] test_movsb_m8_m8()261ad202f9bSPraveen K Paladugu fn test_movsb_m8_m8() { 262ad202f9bSPraveen K Paladugu let ip: u64 = 0x1000; 263ad202f9bSPraveen K Paladugu let memory: [u8; 4] = [ 264ad202f9bSPraveen K Paladugu 0x78, 0x56, 0x34, 0x12, // 0x12345678 265ad202f9bSPraveen K Paladugu ]; 266ad202f9bSPraveen K Paladugu let insn = [0x66, 0xa4]; // movsb 267ad202f9bSPraveen K Paladugu let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)]; 268ad202f9bSPraveen K Paladugu let mut data = [0u8; 1]; 269ad202f9bSPraveen K Paladugu 270ad202f9bSPraveen K Paladugu let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 271ad202f9bSPraveen K Paladugu 272*297236a7SRuoqing He vmm.emulate_first_insn(0, &insn).unwrap(); 273ad202f9bSPraveen K Paladugu 274ad202f9bSPraveen K Paladugu vmm.read_memory(0x8, &mut data).unwrap(); 275ad202f9bSPraveen K Paladugu assert_eq!(0x78, data[0]); 276ad202f9bSPraveen K Paladugu // Only one byte was copied, so the value at 0x9 should be zero 277ad202f9bSPraveen K Paladugu vmm.read_memory(0x9, &mut data).unwrap(); 278ad202f9bSPraveen K Paladugu assert_eq!(0x0, data[0]); 279ad202f9bSPraveen K Paladugu // The rest should be default value 0 from MockVmm 280ad202f9bSPraveen K Paladugu vmm.read_memory(0x4, &mut data).unwrap(); 281ad202f9bSPraveen K Paladugu assert_eq!(0x0, data[0]); 282ad202f9bSPraveen K Paladugu // the src value is left as is after movb 283ad202f9bSPraveen K Paladugu vmm.read_memory(0x0, &mut data).unwrap(); 284ad202f9bSPraveen K Paladugu assert_eq!(0x78, data[0]); 285ad202f9bSPraveen K Paladugu } 286ad202f9bSPraveen K Paladugu 287ad202f9bSPraveen K Paladugu #[test] test_rep_movsb_m8_m8()288ad202f9bSPraveen K Paladugu fn test_rep_movsb_m8_m8() { 289ad202f9bSPraveen K Paladugu let ip: u64 = 0x1000; 290ad202f9bSPraveen K Paladugu let memory: [u8; 16] = [ 291ad202f9bSPraveen K Paladugu 0x78, 0x56, 0x34, 0x12, // 0x12345678 292ad202f9bSPraveen K Paladugu 0xbb, 0xaa, 0x00, 0x00, // 0x0000aabb 293ad202f9bSPraveen K Paladugu 0x00, 0x00, 0x00, 0x00, // 0x00000000 294ad202f9bSPraveen K Paladugu 0x00, 0x00, 0x00, 0x00, // 0x00000000 295ad202f9bSPraveen K Paladugu ]; 296ad202f9bSPraveen K Paladugu let insn = [0x66, 0xf3, 0xa4]; // rep movsw 297ad202f9bSPraveen K Paladugu let regs = vec![(Register::ECX, 6), (Register::ESI, 0), (Register::EDI, 0x8)]; 298ad202f9bSPraveen K Paladugu let mut data = [0u8; 1]; 299ad202f9bSPraveen K Paladugu 300ad202f9bSPraveen K Paladugu let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 301ad202f9bSPraveen K Paladugu 302*297236a7SRuoqing He vmm.emulate_first_insn(0, &insn).unwrap(); 303ad202f9bSPraveen K Paladugu 304ad202f9bSPraveen K Paladugu vmm.read_memory(0x8, &mut data).unwrap(); 305ad202f9bSPraveen K Paladugu assert_eq!(0x78, data[0]); 306ad202f9bSPraveen K Paladugu vmm.read_memory(0x8 + 1, &mut data).unwrap(); 307ad202f9bSPraveen K Paladugu assert_eq!(0x56, data[0]); 308ad202f9bSPraveen K Paladugu vmm.read_memory(0x8 + 2, &mut data).unwrap(); 309ad202f9bSPraveen K Paladugu assert_eq!(0x34, data[0]); 310ad202f9bSPraveen K Paladugu vmm.read_memory(0x8 + 3, &mut data).unwrap(); 311ad202f9bSPraveen K Paladugu assert_eq!(0x12, data[0]); 312ad202f9bSPraveen K Paladugu vmm.read_memory(0x8 + 4, &mut data).unwrap(); 313ad202f9bSPraveen K Paladugu assert_eq!(0xbb, data[0]); 314ad202f9bSPraveen K Paladugu vmm.read_memory(0x8 + 5, &mut data).unwrap(); 315ad202f9bSPraveen K Paladugu assert_eq!(0xaa, data[0]); 316ad202f9bSPraveen K Paladugu // The rest should be default value 0 from MockVmm 317ad202f9bSPraveen K Paladugu vmm.read_memory(0x8 + 6, &mut data).unwrap(); 318ad202f9bSPraveen K Paladugu assert_eq!(0x0, data[0]); 319ad202f9bSPraveen K Paladugu } 320e22b6ec7SWei Liu } 321