xref: /cloud-hypervisor/hypervisor/src/arch/x86/emulator/instructions/movs.rs (revision 3ce0fef7fd546467398c914dbc74d8542e45cf6f)
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 macro_rules! movs {
19     ($bound:ty) => {
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::<$bound>();
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 
88 pub struct Movsd_m32_m32;
89 impl<T: CpuStateManager> InstructionHandler<T> for Movsd_m32_m32 {
90     movs!(u32);
91 }
92 
93 pub struct Movsw_m16_m16;
94 impl<T: CpuStateManager> InstructionHandler<T> for Movsw_m16_m16 {
95     movs!(u16);
96 }
97 
98 pub struct Movsb_m8_m8;
99 impl<T: CpuStateManager> InstructionHandler<T> for Movsb_m8_m8 {
100     movs!(u8);
101 }
102 
103 #[cfg(test)]
104 mod tests {
105     #![allow(unused_mut)]
106     use super::*;
107     use crate::arch::x86::emulator::mock_vmm::*;
108 
109     #[test]
110     fn test_rep_movsd_m32_m32() {
111         let ip: u64 = 0x1000;
112         let memory: [u8; 24] = [
113             0x78, 0x56, 0x34, 0x12, // 0x12345678
114             0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd
115             0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5
116             0x00, 0x00, 0x00, 0x00, // 0x00000000
117             0x00, 0x00, 0x00, 0x00, // 0x00000000
118             0x00, 0x00, 0x00, 0x00, // 0x00000000
119         ];
120         let insn = [0xf3, 0xa5]; // rep movsd
121         let regs = vec![(Register::ECX, 3), (Register::ESI, 0), (Register::EDI, 0xc)];
122         let mut data = [0u8; 4];
123 
124         let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
125 
126         assert!(vmm.emulate_first_insn(0, &insn).is_ok());
127 
128         vmm.read_memory(0xc, &mut data).unwrap();
129         assert_eq!(0x12345678, <u32>::from_le_bytes(data));
130         vmm.read_memory(0xc + 4, &mut data).unwrap();
131         assert_eq!(0xaabbccdd, <u32>::from_le_bytes(data));
132         vmm.read_memory(0xc + 8, &mut data).unwrap();
133         assert_eq!(0x5aa55aa5, <u32>::from_le_bytes(data));
134         // The rest should be default value 0 from MockVmm
135         vmm.read_memory(0xc + 12, &mut data).unwrap();
136         assert_eq!(0x0, <u32>::from_le_bytes(data));
137     }
138 
139     #[test]
140     fn test_movsd_m32_m32() {
141         let ip: u64 = 0x1000;
142         let memory: [u8; 4] = [
143             0x78, 0x56, 0x34, 0x12, // 0x12345678
144         ];
145         let insn = [0xa5]; // movsd
146         let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)];
147         let mut data = [0u8; 4];
148 
149         let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
150 
151         assert!(vmm.emulate_first_insn(0, &insn).is_ok());
152 
153         vmm.read_memory(0x8, &mut data).unwrap();
154         assert_eq!(0x12345678, <u32>::from_le_bytes(data));
155         // The rest should be default value 0 from MockVmm
156         vmm.read_memory(0x4, &mut data).unwrap();
157         assert_eq!(0x0, <u32>::from_le_bytes(data));
158         vmm.read_memory(0x8 + 8, &mut data).unwrap();
159         assert_eq!(0x0, <u32>::from_le_bytes(data));
160     }
161 
162     #[test]
163     fn test_rep_movsw_m16_m16() {
164         let ip: u64 = 0x1000;
165         let memory: [u8; 24] = [
166             0x78, 0x56, 0x34, 0x12, // 0x12345678
167             0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd
168             0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5
169             0x00, 0x00, 0x00, 0x00, // 0x00000000
170             0x00, 0x00, 0x00, 0x00, // 0x00000000
171             0x00, 0x00, 0x00, 0x00, // 0x00000000
172         ];
173         let insn = [0x66, 0xf3, 0xa5]; // rep movsw
174         let regs = vec![(Register::ECX, 6), (Register::ESI, 0), (Register::EDI, 0xc)];
175         let mut data = [0u8; 2];
176 
177         let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
178 
179         assert!(vmm.emulate_first_insn(0, &insn).is_ok());
180 
181         vmm.read_memory(0xc, &mut data).unwrap();
182         assert_eq!(0x5678, <u16>::from_le_bytes(data));
183         vmm.read_memory(0xc + 2, &mut data).unwrap();
184         assert_eq!(0x1234, <u16>::from_le_bytes(data));
185         vmm.read_memory(0xc + 4, &mut data).unwrap();
186         assert_eq!(0xccdd, <u16>::from_le_bytes(data));
187         vmm.read_memory(0xc + 6, &mut data).unwrap();
188         assert_eq!(0xaabb, <u16>::from_le_bytes(data));
189         vmm.read_memory(0xc + 8, &mut data).unwrap();
190         assert_eq!(0x5aa5, <u16>::from_le_bytes(data));
191         vmm.read_memory(0xc + 10, &mut data).unwrap();
192         assert_eq!(0x5aa5, <u16>::from_le_bytes(data));
193         // The rest should be default value 0 from MockVmm
194         vmm.read_memory(0xc + 12, &mut data).unwrap();
195         assert_eq!(0x0, <u16>::from_le_bytes(data));
196     }
197 
198     #[test]
199     fn test_movsw_m16_m16() {
200         let ip: u64 = 0x1000;
201         let memory: [u8; 4] = [
202             0x78, 0x56, 0x34, 0x12, // 0x12345678
203         ];
204         let insn = [0x66, 0xa5]; // movsw
205         let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)];
206         let mut data = [0u8; 2];
207 
208         let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
209 
210         assert!(vmm.emulate_first_insn(0, &insn).is_ok());
211 
212         vmm.read_memory(0x8, &mut data).unwrap();
213         assert_eq!(0x5678, <u16>::from_le_bytes(data));
214         // Only two bytes were copied, so the value at 0xa should be zero
215         vmm.read_memory(0xa, &mut data).unwrap();
216         assert_eq!(0x0, <u16>::from_le_bytes(data));
217         // The rest should be default value 0 from MockVmm
218         vmm.read_memory(0x4, &mut data).unwrap();
219         assert_eq!(0x0, <u16>::from_le_bytes(data));
220         vmm.read_memory(0x8 + 8, &mut data).unwrap();
221         assert_eq!(0x0, <u16>::from_le_bytes(data));
222     }
223 
224     #[test]
225     fn test_movsb_m8_m8() {
226         let ip: u64 = 0x1000;
227         let memory: [u8; 4] = [
228             0x78, 0x56, 0x34, 0x12, // 0x12345678
229         ];
230         let insn = [0x66, 0xa4]; // movsb
231         let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)];
232         let mut data = [0u8; 1];
233 
234         let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
235 
236         assert!(vmm.emulate_first_insn(0, &insn).is_ok());
237 
238         vmm.read_memory(0x8, &mut data).unwrap();
239         assert_eq!(0x78, data[0]);
240         // Only one byte was copied, so the value at 0x9 should be zero
241         vmm.read_memory(0x9, &mut data).unwrap();
242         assert_eq!(0x0, data[0]);
243         // The rest should be default value 0 from MockVmm
244         vmm.read_memory(0x4, &mut data).unwrap();
245         assert_eq!(0x0, data[0]);
246         // the src value is left as is after movb
247         vmm.read_memory(0x0, &mut data).unwrap();
248         assert_eq!(0x78, data[0]);
249     }
250 
251     #[test]
252     fn test_rep_movsb_m8_m8() {
253         let ip: u64 = 0x1000;
254         let memory: [u8; 16] = [
255             0x78, 0x56, 0x34, 0x12, // 0x12345678
256             0xbb, 0xaa, 0x00, 0x00, // 0x0000aabb
257             0x00, 0x00, 0x00, 0x00, // 0x00000000
258             0x00, 0x00, 0x00, 0x00, // 0x00000000
259         ];
260         let insn = [0x66, 0xf3, 0xa4]; // rep movsw
261         let regs = vec![(Register::ECX, 6), (Register::ESI, 0), (Register::EDI, 0x8)];
262         let mut data = [0u8; 1];
263 
264         let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
265 
266         assert!(vmm.emulate_first_insn(0, &insn).is_ok());
267 
268         vmm.read_memory(0x8, &mut data).unwrap();
269         assert_eq!(0x78, data[0]);
270         vmm.read_memory(0x8 + 1, &mut data).unwrap();
271         assert_eq!(0x56, data[0]);
272         vmm.read_memory(0x8 + 2, &mut data).unwrap();
273         assert_eq!(0x34, data[0]);
274         vmm.read_memory(0x8 + 3, &mut data).unwrap();
275         assert_eq!(0x12, data[0]);
276         vmm.read_memory(0x8 + 4, &mut data).unwrap();
277         assert_eq!(0xbb, data[0]);
278         vmm.read_memory(0x8 + 5, &mut data).unwrap();
279         assert_eq!(0xaa, data[0]);
280         // The rest should be default value 0 from MockVmm
281         vmm.read_memory(0x8 + 6, &mut data).unwrap();
282         assert_eq!(0x0, data[0]);
283     }
284 }
285