xref: /cloud-hypervisor/hypervisor/src/arch/x86/emulator/instructions/movs.rs (revision adb318f4cd0079246b3cb07e01c4e978330445d2)
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::x86::emulator::instructions::*;
14 use crate::arch::x86::regs::DF;
15 
16 macro_rules! movs {
17     ($bound:ty) => {
18         fn emulate(
19             &self,
20             insn: &Instruction,
21             state: &mut T,
22             platform: &mut dyn PlatformEmulator<CpuState = T>,
23         ) -> Result<(), EmulationError<Exception>> {
24             let mut count: u64 = if insn.has_rep_prefix() {
25                 state
26                     .read_reg(Register::ECX)
27                     .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?
28             } else {
29                 1
30             };
31 
32             let mut rsi = state
33                 .read_reg(Register::RSI)
34                 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
35             let mut rdi = state
36                 .read_reg(Register::RDI)
37                 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
38 
39             let df = (state.flags() & DF) != 0;
40             let len = std::mem::size_of::<$bound>();
41 
42             while count > 0 {
43                 let mut memory: [u8; 4] = [0; 4];
44 
45                 let src = state
46                     .linearize(Register::DS, rsi, false)
47                     .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
48                 let dst = state
49                     .linearize(Register::ES, rdi, true)
50                     .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
51 
52                 platform
53                     .read_memory(src, &mut memory[0..len])
54                     .map_err(EmulationError::PlatformEmulationError)?;
55                 platform
56                     .write_memory(dst, &memory[0..len])
57                     .map_err(EmulationError::PlatformEmulationError)?;
58 
59                 if df {
60                     rsi = rsi.wrapping_sub(len as u64);
61                     rdi = rdi.wrapping_sub(len as u64);
62                 } else {
63                     rsi = rsi.wrapping_add(len as u64);
64                     rdi = rdi.wrapping_add(len as u64);
65                 }
66                 count -= 1;
67             }
68 
69             state
70                 .write_reg(Register::RSI, rsi)
71                 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
72             state
73                 .write_reg(Register::RDI, rdi)
74                 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
75             if insn.has_rep_prefix() {
76                 state
77                     .write_reg(Register::ECX, 0)
78                     .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
79             }
80 
81             Ok(())
82         }
83     };
84 }
85 
86 pub struct Movsd_m32_m32;
87 impl<T: CpuStateManager> InstructionHandler<T> for Movsd_m32_m32 {
88     movs!(u32);
89 }
90 
91 pub struct Movsw_m16_m16;
92 impl<T: CpuStateManager> InstructionHandler<T> for Movsw_m16_m16 {
93     movs!(u16);
94 }
95 
96 pub struct Movsb_m8_m8;
97 impl<T: CpuStateManager> InstructionHandler<T> for Movsb_m8_m8 {
98     movs!(u8);
99 }
100 
101 #[cfg(test)]
102 mod tests {
103     #![allow(unused_mut)]
104     use super::*;
105     use crate::arch::x86::emulator::mock_vmm::*;
106 
107     #[test]
108     fn test_rep_movsd_m32_m32() {
109         let ip: u64 = 0x1000;
110         let memory: [u8; 24] = [
111             0x78, 0x56, 0x34, 0x12, // 0x12345678
112             0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd
113             0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5
114             0x00, 0x00, 0x00, 0x00, // 0x00000000
115             0x00, 0x00, 0x00, 0x00, // 0x00000000
116             0x00, 0x00, 0x00, 0x00, // 0x00000000
117         ];
118         let insn = [0xf3, 0xa5]; // rep movsd
119         let regs = vec![(Register::ECX, 3), (Register::ESI, 0), (Register::EDI, 0xc)];
120         let mut data = [0u8; 4];
121 
122         let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
123 
124         assert!(vmm.emulate_first_insn(0, &insn).is_ok());
125 
126         vmm.read_memory(0xc, &mut data).unwrap();
127         assert_eq!(0x12345678, <u32>::from_le_bytes(data));
128         vmm.read_memory(0xc + 4, &mut data).unwrap();
129         assert_eq!(0xaabbccdd, <u32>::from_le_bytes(data));
130         vmm.read_memory(0xc + 8, &mut data).unwrap();
131         assert_eq!(0x5aa55aa5, <u32>::from_le_bytes(data));
132         // The rest should be default value 0 from MockVmm
133         vmm.read_memory(0xc + 12, &mut data).unwrap();
134         assert_eq!(0x0, <u32>::from_le_bytes(data));
135     }
136 
137     #[test]
138     fn test_movsd_m32_m32() {
139         let ip: u64 = 0x1000;
140         let memory: [u8; 4] = [
141             0x78, 0x56, 0x34, 0x12, // 0x12345678
142         ];
143         let insn = [0xa5]; // movsd
144         let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)];
145         let mut data = [0u8; 4];
146 
147         let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
148 
149         assert!(vmm.emulate_first_insn(0, &insn).is_ok());
150 
151         vmm.read_memory(0x8, &mut data).unwrap();
152         assert_eq!(0x12345678, <u32>::from_le_bytes(data));
153         // The rest should be default value 0 from MockVmm
154         vmm.read_memory(0x4, &mut data).unwrap();
155         assert_eq!(0x0, <u32>::from_le_bytes(data));
156         vmm.read_memory(0x8 + 8, &mut data).unwrap();
157         assert_eq!(0x0, <u32>::from_le_bytes(data));
158     }
159 
160     #[test]
161     fn test_rep_movsw_m16_m16() {
162         let ip: u64 = 0x1000;
163         let memory: [u8; 24] = [
164             0x78, 0x56, 0x34, 0x12, // 0x12345678
165             0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd
166             0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5
167             0x00, 0x00, 0x00, 0x00, // 0x00000000
168             0x00, 0x00, 0x00, 0x00, // 0x00000000
169             0x00, 0x00, 0x00, 0x00, // 0x00000000
170         ];
171         let insn = [0x66, 0xf3, 0xa5]; // rep movsw
172         let regs = vec![(Register::ECX, 6), (Register::ESI, 0), (Register::EDI, 0xc)];
173         let mut data = [0u8; 2];
174 
175         let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
176 
177         assert!(vmm.emulate_first_insn(0, &insn).is_ok());
178 
179         vmm.read_memory(0xc, &mut data).unwrap();
180         assert_eq!(0x5678, <u16>::from_le_bytes(data));
181         vmm.read_memory(0xc + 2, &mut data).unwrap();
182         assert_eq!(0x1234, <u16>::from_le_bytes(data));
183         vmm.read_memory(0xc + 4, &mut data).unwrap();
184         assert_eq!(0xccdd, <u16>::from_le_bytes(data));
185         vmm.read_memory(0xc + 6, &mut data).unwrap();
186         assert_eq!(0xaabb, <u16>::from_le_bytes(data));
187         vmm.read_memory(0xc + 8, &mut data).unwrap();
188         assert_eq!(0x5aa5, <u16>::from_le_bytes(data));
189         vmm.read_memory(0xc + 10, &mut data).unwrap();
190         assert_eq!(0x5aa5, <u16>::from_le_bytes(data));
191         // The rest should be default value 0 from MockVmm
192         vmm.read_memory(0xc + 12, &mut data).unwrap();
193         assert_eq!(0x0, <u16>::from_le_bytes(data));
194     }
195 
196     #[test]
197     fn test_movsw_m16_m16() {
198         let ip: u64 = 0x1000;
199         let memory: [u8; 4] = [
200             0x78, 0x56, 0x34, 0x12, // 0x12345678
201         ];
202         let insn = [0x66, 0xa5]; // movsw
203         let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)];
204         let mut data = [0u8; 2];
205 
206         let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
207 
208         assert!(vmm.emulate_first_insn(0, &insn).is_ok());
209 
210         vmm.read_memory(0x8, &mut data).unwrap();
211         assert_eq!(0x5678, <u16>::from_le_bytes(data));
212         // Only two bytes were copied, so the value at 0xa should be zero
213         vmm.read_memory(0xa, &mut data).unwrap();
214         assert_eq!(0x0, <u16>::from_le_bytes(data));
215         // The rest should be default value 0 from MockVmm
216         vmm.read_memory(0x4, &mut data).unwrap();
217         assert_eq!(0x0, <u16>::from_le_bytes(data));
218         vmm.read_memory(0x8 + 8, &mut data).unwrap();
219         assert_eq!(0x0, <u16>::from_le_bytes(data));
220     }
221 
222     #[test]
223     fn test_movsb_m8_m8() {
224         let ip: u64 = 0x1000;
225         let memory: [u8; 4] = [
226             0x78, 0x56, 0x34, 0x12, // 0x12345678
227         ];
228         let insn = [0x66, 0xa4]; // movsb
229         let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)];
230         let mut data = [0u8; 1];
231 
232         let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
233 
234         assert!(vmm.emulate_first_insn(0, &insn).is_ok());
235 
236         vmm.read_memory(0x8, &mut data).unwrap();
237         assert_eq!(0x78, data[0]);
238         // Only one byte was copied, so the value at 0x9 should be zero
239         vmm.read_memory(0x9, &mut data).unwrap();
240         assert_eq!(0x0, data[0]);
241         // The rest should be default value 0 from MockVmm
242         vmm.read_memory(0x4, &mut data).unwrap();
243         assert_eq!(0x0, data[0]);
244         // the src value is left as is after movb
245         vmm.read_memory(0x0, &mut data).unwrap();
246         assert_eq!(0x78, data[0]);
247     }
248 
249     #[test]
250     fn test_rep_movsb_m8_m8() {
251         let ip: u64 = 0x1000;
252         let memory: [u8; 16] = [
253             0x78, 0x56, 0x34, 0x12, // 0x12345678
254             0xbb, 0xaa, 0x00, 0x00, // 0x0000aabb
255             0x00, 0x00, 0x00, 0x00, // 0x00000000
256             0x00, 0x00, 0x00, 0x00, // 0x00000000
257         ];
258         let insn = [0x66, 0xf3, 0xa4]; // rep movsw
259         let regs = vec![(Register::ECX, 6), (Register::ESI, 0), (Register::EDI, 0x8)];
260         let mut data = [0u8; 1];
261 
262         let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
263 
264         assert!(vmm.emulate_first_insn(0, &insn).is_ok());
265 
266         vmm.read_memory(0x8, &mut data).unwrap();
267         assert_eq!(0x78, data[0]);
268         vmm.read_memory(0x8 + 1, &mut data).unwrap();
269         assert_eq!(0x56, data[0]);
270         vmm.read_memory(0x8 + 2, &mut data).unwrap();
271         assert_eq!(0x34, data[0]);
272         vmm.read_memory(0x8 + 3, &mut data).unwrap();
273         assert_eq!(0x12, data[0]);
274         vmm.read_memory(0x8 + 4, &mut data).unwrap();
275         assert_eq!(0xbb, data[0]);
276         vmm.read_memory(0x8 + 5, &mut data).unwrap();
277         assert_eq!(0xaa, data[0]);
278         // The rest should be default value 0 from MockVmm
279         vmm.read_memory(0x8 + 6, &mut data).unwrap();
280         assert_eq!(0x0, data[0]);
281     }
282 }
283