xref: /cloud-hypervisor/hypervisor/src/arch/x86/emulator/instructions/movs.rs (revision 9af2968a7dc47b89bf07ea9dc5e735084efcfa3a)
1 //
2 // Copyright © 2021 Microsoft
3 //
4 // SPDX-License-Identifier: Apache-2.0
5 //
6 
7 #![allow(non_camel_case_types)]
8 
9 //
10 // MOVS - Move Data from String to String
11 //
12 
13 use crate::arch::emulator::{EmulationError, PlatformEmulator};
14 use crate::arch::x86::emulator::instructions::*;
15 use crate::arch::x86::regs::DF;
16 use crate::arch::x86::Exception;
17 
18 pub struct Movsd_m32_m32;
19 impl<T: CpuStateManager> InstructionHandler<T> for Movsd_m32_m32 {
20     fn emulate(
21         &self,
22         insn: &Instruction,
23         state: &mut T,
24         platform: &mut dyn PlatformEmulator<CpuState = T>,
25     ) -> Result<(), EmulationError<Exception>> {
26         let mut count: u64 = if insn.has_rep_prefix() {
27             state
28                 .read_reg(Register::ECX)
29                 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?
30         } else {
31             1
32         };
33 
34         let mut rsi = state
35             .read_reg(Register::RSI)
36             .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
37         let mut rdi = state
38             .read_reg(Register::RDI)
39             .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
40 
41         let df = (state.flags() & DF) != 0;
42         let len = std::mem::size_of::<u32>();
43 
44         while count > 0 {
45             let mut memory: [u8; 4] = [0; 4];
46 
47             let src = state
48                 .linearize(Register::DS, rsi, false)
49                 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
50             let dst = state
51                 .linearize(Register::ES, rdi, true)
52                 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
53 
54             platform
55                 .read_memory(src, &mut memory[0..len])
56                 .map_err(EmulationError::PlatformEmulationError)?;
57             platform
58                 .write_memory(dst, &memory[0..len])
59                 .map_err(EmulationError::PlatformEmulationError)?;
60 
61             if df {
62                 rsi = rsi.wrapping_sub(len as u64);
63                 rdi = rdi.wrapping_sub(len as u64);
64             } else {
65                 rsi = rsi.wrapping_add(len as u64);
66                 rdi = rdi.wrapping_add(len as u64);
67             }
68             count -= 1;
69         }
70 
71         state
72             .write_reg(Register::RSI, rsi)
73             .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
74         state
75             .write_reg(Register::RDI, rdi)
76             .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
77         if insn.has_rep_prefix() {
78             state
79                 .write_reg(Register::ECX, 0)
80                 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
81         }
82 
83         Ok(())
84     }
85 }
86 
87 #[cfg(test)]
88 mod tests {
89     #![allow(unused_mut)]
90     use super::*;
91     use crate::arch::x86::emulator::mock_vmm::*;
92 
93     #[test]
94     fn test_rep_movsd_m32_m32() {
95         let ip: u64 = 0x1000;
96         let memory: [u8; 24] = [
97             0x78, 0x56, 0x34, 0x12, // 0x12345678
98             0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd
99             0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5
100             0x00, 0x00, 0x00, 0x00, // 0x00000000
101             0x00, 0x00, 0x00, 0x00, // 0x00000000
102             0x00, 0x00, 0x00, 0x00, // 0x00000000
103         ];
104         let insn = [0xf3, 0xa5]; // rep movsd
105         let regs = vec![(Register::ECX, 3), (Register::ESI, 0), (Register::EDI, 0xc)];
106         let mut data = [0u8; 4];
107 
108         let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
109 
110         assert!(vmm.emulate_first_insn(0, &insn).is_ok());
111 
112         vmm.read_memory(0xc, &mut data).unwrap();
113         assert_eq!(0x12345678, <u32>::from_le_bytes(data));
114         vmm.read_memory(0xc + 4, &mut data).unwrap();
115         assert_eq!(0xaabbccdd, <u32>::from_le_bytes(data));
116         vmm.read_memory(0xc + 8, &mut data).unwrap();
117         assert_eq!(0x5aa55aa5, <u32>::from_le_bytes(data));
118         // The rest should be default value 0 from MockVmm
119         vmm.read_memory(0xc + 12, &mut data).unwrap();
120         assert_eq!(0x0, <u32>::from_le_bytes(data));
121     }
122 
123     #[test]
124     fn test_movsd_m32_m32() {
125         let ip: u64 = 0x1000;
126         let memory: [u8; 4] = [
127             0x78, 0x56, 0x34, 0x12, // 0x12345678
128         ];
129         let insn = [0xa5]; // movsd
130         let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)];
131         let mut data = [0u8; 4];
132 
133         let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
134 
135         assert!(vmm.emulate_first_insn(0, &insn).is_ok());
136 
137         vmm.read_memory(0x8, &mut data).unwrap();
138         assert_eq!(0x12345678, <u32>::from_le_bytes(data));
139         // The rest should be default value 0 from MockVmm
140         vmm.read_memory(0x4, &mut data).unwrap();
141         assert_eq!(0x0, <u32>::from_le_bytes(data));
142         vmm.read_memory(0x8 + 8, &mut data).unwrap();
143         assert_eq!(0x0, <u32>::from_le_bytes(data));
144     }
145 }
146