xref: /cloud-hypervisor/hypervisor/src/arch/x86/emulator/instructions/mov.rs (revision 297236a7c0b462e9756853c40114f4f2f4eb551b)
1fe540122SSamuel Ortiz //
2fe540122SSamuel Ortiz // Copyright © 2020 Intel Corporation
3fe540122SSamuel Ortiz //
4fe540122SSamuel Ortiz // SPDX-License-Identifier: Apache-2.0
5fe540122SSamuel Ortiz //
6fe540122SSamuel Ortiz 
7fe540122SSamuel Ortiz #![allow(non_camel_case_types)]
8fe540122SSamuel Ortiz 
9fe540122SSamuel Ortiz //
10fe540122SSamuel Ortiz // MOV-Move
11fe540122SSamuel Ortiz // SDM Volume 1, Chapter 4.3
12fe540122SSamuel Ortiz //   Copies the second operand (source operand) to the first operand (destination operand).
13fe540122SSamuel Ortiz //
14fe540122SSamuel Ortiz 
15fe540122SSamuel Ortiz use crate::arch::x86::emulator::instructions::*;
16fe540122SSamuel Ortiz 
17fe540122SSamuel Ortiz macro_rules! mov_rm_r {
18fe540122SSamuel Ortiz     ($bound:ty) => {
19fe540122SSamuel Ortiz         fn emulate(
20fe540122SSamuel Ortiz             &self,
21fe540122SSamuel Ortiz             insn: &Instruction,
22fe540122SSamuel Ortiz             state: &mut T,
23c8b65549SWei Liu             platform: &mut dyn PlatformEmulator<CpuState = T>,
24fe540122SSamuel Ortiz         ) -> Result<(), EmulationError<Exception>> {
250c3ef986SWei Liu             let src_reg_value = get_op(&insn, 1, std::mem::size_of::<$bound>(), state, platform)
26fe540122SSamuel Ortiz                 .map_err(EmulationError::PlatformEmulationError)?;
27fe540122SSamuel Ortiz 
280c3ef986SWei Liu             set_op(
290c3ef986SWei Liu                 &insn,
300c3ef986SWei Liu                 0,
310c3ef986SWei Liu                 std::mem::size_of::<$bound>(),
320c3ef986SWei Liu                 state,
330c3ef986SWei Liu                 platform,
340c3ef986SWei Liu                 src_reg_value,
350c3ef986SWei Liu             )
3666b00166SWei Liu             .map_err(EmulationError::PlatformEmulationError)?;
37fe540122SSamuel Ortiz 
38fe540122SSamuel Ortiz             Ok(())
39fe540122SSamuel Ortiz         }
40fe540122SSamuel Ortiz     };
41fe540122SSamuel Ortiz }
42fe540122SSamuel Ortiz 
43fe540122SSamuel Ortiz macro_rules! mov_rm_imm {
440c3ef986SWei Liu     ($bound:ty) => {
45fe540122SSamuel Ortiz         fn emulate(
46fe540122SSamuel Ortiz             &self,
47fe540122SSamuel Ortiz             insn: &Instruction,
48fe540122SSamuel Ortiz             state: &mut T,
49c8b65549SWei Liu             platform: &mut dyn PlatformEmulator<CpuState = T>,
50fe540122SSamuel Ortiz         ) -> Result<(), EmulationError<Exception>> {
510c3ef986SWei Liu             let imm = get_op(&insn, 1, std::mem::size_of::<$bound>(), state, platform)
5266b00166SWei Liu                 .map_err(EmulationError::PlatformEmulationError)?;
5366b00166SWei Liu 
540c3ef986SWei Liu             set_op(
550c3ef986SWei Liu                 &insn,
560c3ef986SWei Liu                 0,
570c3ef986SWei Liu                 std::mem::size_of::<$bound>(),
580c3ef986SWei Liu                 state,
590c3ef986SWei Liu                 platform,
600c3ef986SWei Liu                 imm,
610c3ef986SWei Liu             )
620c3ef986SWei Liu             .map_err(EmulationError::PlatformEmulationError)?;
63fe540122SSamuel Ortiz 
64fe540122SSamuel Ortiz             Ok(())
65fe540122SSamuel Ortiz         }
66fe540122SSamuel Ortiz     };
67fe540122SSamuel Ortiz }
68fe540122SSamuel Ortiz 
695ada3f59SSamuel Ortiz macro_rules! movzx {
7049214cf0SWei Liu     ($dest_op_size:ty, $src_op_size:ty) => {
71fe540122SSamuel Ortiz         fn emulate(
72fe540122SSamuel Ortiz             &self,
73fe540122SSamuel Ortiz             insn: &Instruction,
74fe540122SSamuel Ortiz             state: &mut T,
75c8b65549SWei Liu             platform: &mut dyn PlatformEmulator<CpuState = T>,
76fe540122SSamuel Ortiz         ) -> Result<(), EmulationError<Exception>> {
775ada3f59SSamuel Ortiz             let src_value = get_op(
785ada3f59SSamuel Ortiz                 &insn,
795ada3f59SSamuel Ortiz                 1,
805ada3f59SSamuel Ortiz                 std::mem::size_of::<$src_op_size>(),
815ada3f59SSamuel Ortiz                 state,
825ada3f59SSamuel Ortiz                 platform,
835ada3f59SSamuel Ortiz             )
84fe540122SSamuel Ortiz             .map_err(EmulationError::PlatformEmulationError)?;
85fe540122SSamuel Ortiz 
860c3ef986SWei Liu             set_op(
870c3ef986SWei Liu                 &insn,
880c3ef986SWei Liu                 0,
895ada3f59SSamuel Ortiz                 std::mem::size_of::<$dest_op_size>(),
900c3ef986SWei Liu                 state,
910c3ef986SWei Liu                 platform,
920c3ef986SWei Liu                 src_value,
930c3ef986SWei Liu             )
94fe540122SSamuel Ortiz             .map_err(EmulationError::PlatformEmulationError)?;
95fe540122SSamuel Ortiz 
96fe540122SSamuel Ortiz             Ok(())
97fe540122SSamuel Ortiz         }
98fe540122SSamuel Ortiz     };
99fe540122SSamuel Ortiz }
100fe540122SSamuel Ortiz 
1015ada3f59SSamuel Ortiz // MOV r/rm is a special case of MOVZX, where both operands have the same size.
1025ada3f59SSamuel Ortiz macro_rules! mov_r_rm {
1035ada3f59SSamuel Ortiz     ($op_size:ty) => {
1045ada3f59SSamuel Ortiz         movzx!($op_size, $op_size);
1055ada3f59SSamuel Ortiz     };
1065ada3f59SSamuel Ortiz }
1075ada3f59SSamuel Ortiz 
108fe540122SSamuel Ortiz macro_rules! mov_r_imm {
1090c3ef986SWei Liu     ($bound:ty) => {
110fe540122SSamuel Ortiz         fn emulate(
111fe540122SSamuel Ortiz             &self,
112fe540122SSamuel Ortiz             insn: &Instruction,
113fe540122SSamuel Ortiz             state: &mut T,
1140c3ef986SWei Liu             platform: &mut dyn PlatformEmulator<CpuState = T>,
115fe540122SSamuel Ortiz         ) -> Result<(), EmulationError<Exception>> {
1160c3ef986SWei Liu             let imm = get_op(&insn, 1, std::mem::size_of::<$bound>(), state, platform)
1170c3ef986SWei Liu                 .map_err(EmulationError::PlatformEmulationError)?;
1180c3ef986SWei Liu 
1190c3ef986SWei Liu             set_op(
1200c3ef986SWei Liu                 &insn,
1210c3ef986SWei Liu                 0,
1220c3ef986SWei Liu                 std::mem::size_of::<$bound>(),
1230c3ef986SWei Liu                 state,
1240c3ef986SWei Liu                 platform,
1250c3ef986SWei Liu                 imm,
1260c3ef986SWei Liu             )
127fe540122SSamuel Ortiz             .map_err(EmulationError::PlatformEmulationError)?;
128fe540122SSamuel Ortiz 
129fe540122SSamuel Ortiz             Ok(())
130fe540122SSamuel Ortiz         }
131fe540122SSamuel Ortiz     };
132fe540122SSamuel Ortiz }
133fe540122SSamuel Ortiz 
13490ae4676SWei Liu pub struct Mov_r8_rm8;
135fe540122SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Mov_r8_rm8 {
136fe540122SSamuel Ortiz     mov_r_rm!(u8);
137fe540122SSamuel Ortiz }
138fe540122SSamuel Ortiz 
13990ae4676SWei Liu pub struct Mov_r8_imm8;
140fe540122SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Mov_r8_imm8 {
141fe540122SSamuel Ortiz     mov_r_imm!(u8);
142fe540122SSamuel Ortiz }
143fe540122SSamuel Ortiz 
14490ae4676SWei Liu pub struct Mov_r16_rm16;
145fe540122SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Mov_r16_rm16 {
146fe540122SSamuel Ortiz     mov_r_rm!(u16);
147fe540122SSamuel Ortiz }
148fe540122SSamuel Ortiz 
14990ae4676SWei Liu pub struct Mov_r16_imm16;
150fe540122SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Mov_r16_imm16 {
151fe540122SSamuel Ortiz     mov_r_imm!(u16);
152fe540122SSamuel Ortiz }
153fe540122SSamuel Ortiz 
15490ae4676SWei Liu pub struct Mov_r32_rm32;
155fe540122SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Mov_r32_rm32 {
156fe540122SSamuel Ortiz     mov_r_rm!(u32);
157fe540122SSamuel Ortiz }
158fe540122SSamuel Ortiz 
15990ae4676SWei Liu pub struct Mov_r32_imm32;
160fe540122SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Mov_r32_imm32 {
161fe540122SSamuel Ortiz     mov_r_imm!(u32);
162fe540122SSamuel Ortiz }
163fe540122SSamuel Ortiz 
16490ae4676SWei Liu pub struct Mov_r64_rm64;
165fe540122SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Mov_r64_rm64 {
166fe540122SSamuel Ortiz     mov_r_rm!(u64);
167fe540122SSamuel Ortiz }
168fe540122SSamuel Ortiz 
16990ae4676SWei Liu pub struct Mov_r64_imm64;
170fe540122SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Mov_r64_imm64 {
171fe540122SSamuel Ortiz     mov_r_imm!(u64);
172fe540122SSamuel Ortiz }
173fe540122SSamuel Ortiz 
17490ae4676SWei Liu pub struct Mov_rm8_imm8;
175fe540122SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Mov_rm8_imm8 {
176fe540122SSamuel Ortiz     mov_rm_imm!(u8);
177fe540122SSamuel Ortiz }
178fe540122SSamuel Ortiz 
17990ae4676SWei Liu pub struct Mov_rm8_r8;
180fe540122SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Mov_rm8_r8 {
181fe540122SSamuel Ortiz     mov_rm_r!(u8);
182fe540122SSamuel Ortiz }
183fe540122SSamuel Ortiz 
18490ae4676SWei Liu pub struct Mov_rm16_imm16;
185fe540122SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Mov_rm16_imm16 {
186fe540122SSamuel Ortiz     mov_rm_imm!(u16);
187fe540122SSamuel Ortiz }
188fe540122SSamuel Ortiz 
18990ae4676SWei Liu pub struct Mov_rm16_r16;
190fe540122SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Mov_rm16_r16 {
191fe540122SSamuel Ortiz     mov_rm_r!(u16);
192fe540122SSamuel Ortiz }
193fe540122SSamuel Ortiz 
19490ae4676SWei Liu pub struct Mov_rm32_imm32;
195fe540122SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Mov_rm32_imm32 {
196fe540122SSamuel Ortiz     mov_rm_imm!(u32);
197fe540122SSamuel Ortiz }
198fe540122SSamuel Ortiz 
19990ae4676SWei Liu pub struct Mov_rm32_r32;
200fe540122SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Mov_rm32_r32 {
201fe540122SSamuel Ortiz     mov_rm_r!(u32);
202fe540122SSamuel Ortiz }
203fe540122SSamuel Ortiz 
20490ae4676SWei Liu pub struct Mov_rm64_imm32;
205fe540122SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Mov_rm64_imm32 {
2060c3ef986SWei Liu     mov_rm_imm!(u32);
207fe540122SSamuel Ortiz }
208fe540122SSamuel Ortiz 
20990ae4676SWei Liu pub struct Mov_rm64_r64;
210fe540122SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Mov_rm64_r64 {
211fe540122SSamuel Ortiz     mov_rm_r!(u64);
212fe540122SSamuel Ortiz }
213fe540122SSamuel Ortiz 
2145ada3f59SSamuel Ortiz // MOVZX
2155ada3f59SSamuel Ortiz pub struct Movzx_r16_rm8;
2165ada3f59SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Movzx_r16_rm8 {
2175ada3f59SSamuel Ortiz     movzx!(u16, u8);
2185ada3f59SSamuel Ortiz }
2195ada3f59SSamuel Ortiz 
2205ada3f59SSamuel Ortiz pub struct Movzx_r32_rm8;
2215ada3f59SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Movzx_r32_rm8 {
2225ada3f59SSamuel Ortiz     movzx!(u32, u8);
2235ada3f59SSamuel Ortiz }
2245ada3f59SSamuel Ortiz 
2255ada3f59SSamuel Ortiz pub struct Movzx_r64_rm8;
2265ada3f59SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Movzx_r64_rm8 {
2275ada3f59SSamuel Ortiz     movzx!(u64, u8);
2285ada3f59SSamuel Ortiz }
2295ada3f59SSamuel Ortiz 
2305ada3f59SSamuel Ortiz pub struct Movzx_r32_rm16;
2315ada3f59SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Movzx_r32_rm16 {
2325ada3f59SSamuel Ortiz     movzx!(u32, u16);
2335ada3f59SSamuel Ortiz }
2345ada3f59SSamuel Ortiz 
2355ada3f59SSamuel Ortiz pub struct Movzx_r64_rm16;
2365ada3f59SSamuel Ortiz impl<T: CpuStateManager> InstructionHandler<T> for Movzx_r64_rm16 {
2375ada3f59SSamuel Ortiz     movzx!(u64, u16);
2385ada3f59SSamuel Ortiz }
2395ada3f59SSamuel Ortiz 
240442ac905SPhilipp Schuster pub struct Mov_moffs16_AX;
241442ac905SPhilipp Schuster impl<T: CpuStateManager> InstructionHandler<T> for Mov_moffs16_AX {
242442ac905SPhilipp Schuster     movzx!(u16, u16);
243442ac905SPhilipp Schuster }
244442ac905SPhilipp Schuster 
245442ac905SPhilipp Schuster pub struct Mov_AX_moffs16;
246442ac905SPhilipp Schuster impl<T: CpuStateManager> InstructionHandler<T> for Mov_AX_moffs16 {
247442ac905SPhilipp Schuster     movzx!(u16, u16);
248442ac905SPhilipp Schuster }
249442ac905SPhilipp Schuster 
250442ac905SPhilipp Schuster pub struct Mov_moffs32_EAX;
251442ac905SPhilipp Schuster impl<T: CpuStateManager> InstructionHandler<T> for Mov_moffs32_EAX {
252442ac905SPhilipp Schuster     movzx!(u32, u32);
253442ac905SPhilipp Schuster }
254442ac905SPhilipp Schuster 
255442ac905SPhilipp Schuster pub struct Mov_EAX_moffs32;
256442ac905SPhilipp Schuster impl<T: CpuStateManager> InstructionHandler<T> for Mov_EAX_moffs32 {
257442ac905SPhilipp Schuster     movzx!(u32, u32);
258442ac905SPhilipp Schuster }
259442ac905SPhilipp Schuster 
260442ac905SPhilipp Schuster pub struct Mov_moffs64_RAX;
261442ac905SPhilipp Schuster impl<T: CpuStateManager> InstructionHandler<T> for Mov_moffs64_RAX {
262442ac905SPhilipp Schuster     movzx!(u64, u64);
263442ac905SPhilipp Schuster }
264442ac905SPhilipp Schuster 
265442ac905SPhilipp Schuster pub struct Mov_RAX_moffs64;
266442ac905SPhilipp Schuster impl<T: CpuStateManager> InstructionHandler<T> for Mov_RAX_moffs64 {
267442ac905SPhilipp Schuster     movzx!(u64, u64);
268442ac905SPhilipp Schuster }
269442ac905SPhilipp Schuster 
270fe540122SSamuel Ortiz #[cfg(test)]
271fe540122SSamuel Ortiz mod tests {
272fe540122SSamuel Ortiz     use super::*;
2735bd63efaSSamuel Ortiz     use crate::arch::x86::emulator::mock_vmm::*;
274fe540122SSamuel Ortiz 
275fe540122SSamuel Ortiz     #[test]
276fe540122SSamuel Ortiz     // mov rax,rbx
test_mov_r64_r64()2779c5be6f6SRob Bradford     fn test_mov_r64_r64() {
278fe540122SSamuel Ortiz         let rbx: u64 = 0x8899aabbccddeeff;
279fe540122SSamuel Ortiz         let ip: u64 = 0x1000;
280fe540122SSamuel Ortiz         let cpu_id = 0;
281fe540122SSamuel Ortiz         let insn = [0x48, 0x89, 0xd8];
2820c27f69fSRob Bradford         let mut vmm = MockVmm::new(ip, vec![(Register::RBX, rbx)], None);
283*297236a7SRuoqing He         vmm.emulate_first_insn(cpu_id, &insn).unwrap();
284fe540122SSamuel Ortiz 
285fe540122SSamuel Ortiz         let rax: u64 = vmm
286fe540122SSamuel Ortiz             .cpu_state(cpu_id)
287fe540122SSamuel Ortiz             .unwrap()
288fe540122SSamuel Ortiz             .read_reg(Register::RAX)
289fe540122SSamuel Ortiz             .unwrap();
290fe540122SSamuel Ortiz         assert_eq!(rax, rbx);
291fe540122SSamuel Ortiz     }
292fe540122SSamuel Ortiz 
293fe540122SSamuel Ortiz     #[test]
294fe540122SSamuel Ortiz     // mov rax,0x1122334411223344
test_mov_r64_imm64()2959c5be6f6SRob Bradford     fn test_mov_r64_imm64() {
296fe540122SSamuel Ortiz         let imm64: u64 = 0x1122334411223344;
297fe540122SSamuel Ortiz         let ip: u64 = 0x1000;
298fe540122SSamuel Ortiz         let cpu_id = 0;
299fe540122SSamuel Ortiz         let insn = [0x48, 0xb8, 0x44, 0x33, 0x22, 0x11, 0x44, 0x33, 0x22, 0x11];
3000c27f69fSRob Bradford         let mut vmm = MockVmm::new(ip, vec![], None);
301*297236a7SRuoqing He         vmm.emulate_first_insn(cpu_id, &insn).unwrap();
302fe540122SSamuel Ortiz 
303fe540122SSamuel Ortiz         let rax: u64 = vmm
304fe540122SSamuel Ortiz             .cpu_state(cpu_id)
305fe540122SSamuel Ortiz             .unwrap()
306fe540122SSamuel Ortiz             .read_reg(Register::RAX)
307fe540122SSamuel Ortiz             .unwrap();
308fe540122SSamuel Ortiz         assert_eq!(rax, imm64);
309fe540122SSamuel Ortiz     }
310fe540122SSamuel Ortiz 
311fe540122SSamuel Ortiz     #[test]
312fe540122SSamuel Ortiz     // mov rax, [rax+rax]
test_mov_r64_m64()3139c5be6f6SRob Bradford     fn test_mov_r64_m64() {
314fe540122SSamuel Ortiz         let target_rax: u64 = 0x1234567812345678;
315fe540122SSamuel Ortiz         let mut rax: u64 = 0x100;
316fe540122SSamuel Ortiz         let ip: u64 = 0x1000;
317fe540122SSamuel Ortiz         let cpu_id = 0;
318fe540122SSamuel Ortiz         let memory: [u8; 8] = target_rax.to_le_bytes();
319fe540122SSamuel Ortiz         let insn = [0x48, 0x8b, 0x04, 0x00];
3200c27f69fSRob Bradford         let mut vmm = MockVmm::new(ip, vec![(Register::RAX, rax)], Some((rax + rax, &memory)));
321*297236a7SRuoqing He         vmm.emulate_first_insn(cpu_id, &insn).unwrap();
322fe540122SSamuel Ortiz 
323fe540122SSamuel Ortiz         rax = vmm
324fe540122SSamuel Ortiz             .cpu_state(cpu_id)
325fe540122SSamuel Ortiz             .unwrap()
326fe540122SSamuel Ortiz             .read_reg(Register::RAX)
327fe540122SSamuel Ortiz             .unwrap();
328fe540122SSamuel Ortiz         assert_eq!(rax, target_rax);
329fe540122SSamuel Ortiz     }
330fe540122SSamuel Ortiz 
331fe540122SSamuel Ortiz     #[test]
332fe540122SSamuel Ortiz     // mov al,0x11
test_mov_r8_imm8()3339c5be6f6SRob Bradford     fn test_mov_r8_imm8() {
334fe540122SSamuel Ortiz         let imm8: u8 = 0x11;
335fe540122SSamuel Ortiz         let ip: u64 = 0x1000;
336fe540122SSamuel Ortiz         let cpu_id = 0;
337fe540122SSamuel Ortiz         let insn = [0xb0, 0x11];
3380c27f69fSRob Bradford         let mut vmm = MockVmm::new(ip, vec![], None);
339*297236a7SRuoqing He         vmm.emulate_first_insn(cpu_id, &insn).unwrap();
340fe540122SSamuel Ortiz 
341fe540122SSamuel Ortiz         let al = vmm
342fe540122SSamuel Ortiz             .cpu_state(cpu_id)
343fe540122SSamuel Ortiz             .unwrap()
344fe540122SSamuel Ortiz             .read_reg(Register::AL)
345fe540122SSamuel Ortiz             .unwrap();
346fe540122SSamuel Ortiz         assert_eq!(al as u8, imm8);
347fe540122SSamuel Ortiz     }
348fe540122SSamuel Ortiz 
349fe540122SSamuel Ortiz     #[test]
350fe540122SSamuel Ortiz     // mov eax,0x11
test_mov_r32_imm8()3519c5be6f6SRob Bradford     fn test_mov_r32_imm8() {
352fe540122SSamuel Ortiz         let imm8: u8 = 0x11;
353fe540122SSamuel Ortiz         let ip: u64 = 0x1000;
354fe540122SSamuel Ortiz         let cpu_id = 0;
355fe540122SSamuel Ortiz         let insn = [0xb8, 0x11, 0x00, 0x00, 0x00];
3560c27f69fSRob Bradford         let mut vmm = MockVmm::new(ip, vec![], None);
357*297236a7SRuoqing He         vmm.emulate_first_insn(cpu_id, &insn).unwrap();
358fe540122SSamuel Ortiz 
359fe540122SSamuel Ortiz         let eax = vmm
360fe540122SSamuel Ortiz             .cpu_state(cpu_id)
361fe540122SSamuel Ortiz             .unwrap()
362fe540122SSamuel Ortiz             .read_reg(Register::EAX)
363fe540122SSamuel Ortiz             .unwrap();
364fe540122SSamuel Ortiz         assert_eq!(eax as u8, imm8);
365fe540122SSamuel Ortiz     }
366fe540122SSamuel Ortiz 
367fe540122SSamuel Ortiz     #[test]
368fe540122SSamuel Ortiz     // mov rax,0x11223344
test_mov_r64_imm32()3699c5be6f6SRob Bradford     fn test_mov_r64_imm32() {
370fe540122SSamuel Ortiz         let imm32: u32 = 0x11223344;
371fe540122SSamuel Ortiz         let ip: u64 = 0x1000;
372fe540122SSamuel Ortiz         let cpu_id = 0;
373fe540122SSamuel Ortiz         let insn = [0x48, 0xc7, 0xc0, 0x44, 0x33, 0x22, 0x11];
3740c27f69fSRob Bradford         let mut vmm = MockVmm::new(ip, vec![], None);
375*297236a7SRuoqing He         vmm.emulate_first_insn(cpu_id, &insn).unwrap();
376fe540122SSamuel Ortiz 
377fe540122SSamuel Ortiz         let rax: u64 = vmm
378fe540122SSamuel Ortiz             .cpu_state(cpu_id)
379fe540122SSamuel Ortiz             .unwrap()
380fe540122SSamuel Ortiz             .read_reg(Register::RAX)
381fe540122SSamuel Ortiz             .unwrap();
382fe540122SSamuel Ortiz         assert_eq!(rax, imm32 as u64);
383fe540122SSamuel Ortiz     }
384fe540122SSamuel Ortiz 
385fe540122SSamuel Ortiz     #[test]
386fe540122SSamuel Ortiz     // mov byte ptr [rax],dh
test_mov_m8_r8()3879c5be6f6SRob Bradford     fn test_mov_m8_r8() {
388fe540122SSamuel Ortiz         let rax: u64 = 0x100;
389fe540122SSamuel Ortiz         let dh: u8 = 0x99;
390fe540122SSamuel Ortiz         let ip: u64 = 0x1000;
391fe540122SSamuel Ortiz         let cpu_id = 0;
392fe540122SSamuel Ortiz         let insn = [0x88, 0x30];
3930c27f69fSRob Bradford         let mut vmm = MockVmm::new(
394fe540122SSamuel Ortiz             ip,
395a44d96c9SWei Liu             vec![(Register::RAX, rax), (Register::DH, dh.into())],
396fe540122SSamuel Ortiz             None,
397fe540122SSamuel Ortiz         );
398*297236a7SRuoqing He         vmm.emulate_first_insn(cpu_id, &insn).unwrap();
399fe540122SSamuel Ortiz 
400fe540122SSamuel Ortiz         let mut memory: [u8; 1] = [0; 1];
401c8b65549SWei Liu         vmm.read_memory(rax, &mut memory).unwrap();
402fe540122SSamuel Ortiz 
403fe540122SSamuel Ortiz         assert_eq!(u8::from_le_bytes(memory), dh);
404fe540122SSamuel Ortiz     }
405fe540122SSamuel Ortiz 
406fe540122SSamuel Ortiz     #[test]
407fe540122SSamuel Ortiz     // mov dword ptr [rax],esi
test_mov_m32_r32()4089c5be6f6SRob Bradford     fn test_mov_m32_r32() {
409fe540122SSamuel Ortiz         let rax: u64 = 0x100;
410fe540122SSamuel Ortiz         let esi: u32 = 0x8899;
411fe540122SSamuel Ortiz         let ip: u64 = 0x1000;
412fe540122SSamuel Ortiz         let cpu_id = 0;
413fe540122SSamuel Ortiz         let insn = [0x89, 0x30];
4140c27f69fSRob Bradford         let mut vmm = MockVmm::new(
415fe540122SSamuel Ortiz             ip,
416a44d96c9SWei Liu             vec![(Register::RAX, rax), (Register::ESI, esi.into())],
417fe540122SSamuel Ortiz             None,
418fe540122SSamuel Ortiz         );
419*297236a7SRuoqing He         vmm.emulate_first_insn(cpu_id, &insn).unwrap();
420fe540122SSamuel Ortiz 
421fe540122SSamuel Ortiz         let mut memory: [u8; 4] = [0; 4];
422c8b65549SWei Liu         vmm.read_memory(rax, &mut memory).unwrap();
423fe540122SSamuel Ortiz 
424fe540122SSamuel Ortiz         assert_eq!(u32::from_le_bytes(memory), esi);
425fe540122SSamuel Ortiz     }
426fe540122SSamuel Ortiz 
427fe540122SSamuel Ortiz     #[test]
428fe540122SSamuel Ortiz     // mov dword ptr [rax+0x00000001],edi
test_mov_m32imm32_r32()4299c5be6f6SRob Bradford     fn test_mov_m32imm32_r32() {
430fe540122SSamuel Ortiz         let rax: u64 = 0x100;
431fe540122SSamuel Ortiz         let displacement: u64 = 0x1;
432fe540122SSamuel Ortiz         let edi: u32 = 0x8899;
433fe540122SSamuel Ortiz         let ip: u64 = 0x1000;
434fe540122SSamuel Ortiz         let cpu_id = 0;
435fe540122SSamuel Ortiz         let insn = [0x89, 0x3c, 0x05, 0x01, 0x00, 0x00, 0x00];
4360c27f69fSRob Bradford         let mut vmm = MockVmm::new(
437fe540122SSamuel Ortiz             ip,
438a44d96c9SWei Liu             vec![(Register::RAX, rax), (Register::EDI, edi.into())],
439fe540122SSamuel Ortiz             None,
440fe540122SSamuel Ortiz         );
441*297236a7SRuoqing He         vmm.emulate_first_insn(cpu_id, &insn).unwrap();
442fe540122SSamuel Ortiz 
443fe540122SSamuel Ortiz         let mut memory: [u8; 4] = [0; 4];
444c8b65549SWei Liu         vmm.read_memory(rax + displacement, &mut memory).unwrap();
445fe540122SSamuel Ortiz 
446fe540122SSamuel Ortiz         assert_eq!(u32::from_le_bytes(memory), edi);
447fe540122SSamuel Ortiz     }
448fe540122SSamuel Ortiz 
449fe540122SSamuel Ortiz     #[test]
450fe540122SSamuel Ortiz     // mov eax,dword ptr [rax+10h]
test_mov_r32_m32imm32()4519c5be6f6SRob Bradford     fn test_mov_r32_m32imm32() {
452fe540122SSamuel Ortiz         let rax: u64 = 0x100;
453fe540122SSamuel Ortiz         let displacement: u64 = 0x10;
454fe540122SSamuel Ortiz         let eax: u32 = 0xaabbccdd;
455fe540122SSamuel Ortiz         let memory: [u8; 4] = eax.to_le_bytes();
456fe540122SSamuel Ortiz         let ip: u64 = 0x1000;
457fe540122SSamuel Ortiz         let cpu_id = 0;
458fe540122SSamuel Ortiz         let insn = [0x8b, 0x40, 0x10];
4590c27f69fSRob Bradford         let mut vmm = MockVmm::new(
460fe540122SSamuel Ortiz             ip,
461a44d96c9SWei Liu             vec![(Register::RAX, rax)],
462fe540122SSamuel Ortiz             Some((rax + displacement, &memory)),
463fe540122SSamuel Ortiz         );
464*297236a7SRuoqing He         vmm.emulate_first_insn(cpu_id, &insn).unwrap();
465fe540122SSamuel Ortiz 
466fe540122SSamuel Ortiz         let new_eax = vmm
467fe540122SSamuel Ortiz             .cpu_state(cpu_id)
468fe540122SSamuel Ortiz             .unwrap()
469fe540122SSamuel Ortiz             .read_reg(Register::EAX)
470fe540122SSamuel Ortiz             .unwrap();
471fe540122SSamuel Ortiz         assert_eq!(new_eax, eax as u64);
472fe540122SSamuel Ortiz     }
473fe540122SSamuel Ortiz 
474fe540122SSamuel Ortiz     #[test]
475fe540122SSamuel Ortiz     // mov al,byte ptr [rax+10h]
test_mov_r8_m32imm32()4769c5be6f6SRob Bradford     fn test_mov_r8_m32imm32() {
477fe540122SSamuel Ortiz         let rax: u64 = 0x100;
478fe540122SSamuel Ortiz         let displacement: u64 = 0x10;
479fe540122SSamuel Ortiz         let al: u8 = 0xaa;
480fe540122SSamuel Ortiz         let ip: u64 = 0x1000;
481fe540122SSamuel Ortiz         let cpu_id = 0;
482fe540122SSamuel Ortiz         let insn = [0x8a, 0x40, 0x10];
483fe540122SSamuel Ortiz         let memory: [u8; 1] = al.to_le_bytes();
4840c27f69fSRob Bradford         let mut vmm = MockVmm::new(
485fe540122SSamuel Ortiz             ip,
486a44d96c9SWei Liu             vec![(Register::RAX, rax)],
487fe540122SSamuel Ortiz             Some((rax + displacement, &memory)),
488fe540122SSamuel Ortiz         );
489*297236a7SRuoqing He         vmm.emulate_first_insn(cpu_id, &insn).unwrap();
490fe540122SSamuel Ortiz 
491fe540122SSamuel Ortiz         let new_al = vmm
492fe540122SSamuel Ortiz             .cpu_state(cpu_id)
493fe540122SSamuel Ortiz             .unwrap()
494fe540122SSamuel Ortiz             .read_reg(Register::AL)
495fe540122SSamuel Ortiz             .unwrap();
496fe540122SSamuel Ortiz         assert_eq!(new_al, al as u64);
497fe540122SSamuel Ortiz     }
498fe540122SSamuel Ortiz 
499fe540122SSamuel Ortiz     #[test]
500fe540122SSamuel Ortiz     // mov rax, 0x100
501fe540122SSamuel Ortiz     // mov rbx, qword ptr [rax+10h]
test_mov_r64_imm64_and_r64_m64()5029c5be6f6SRob Bradford     fn test_mov_r64_imm64_and_r64_m64() {
503fe540122SSamuel Ortiz         let target_rax: u64 = 0x1234567812345678;
504fe540122SSamuel Ortiz         let rax: u64 = 0x100;
505fe540122SSamuel Ortiz         let displacement: u64 = 0x10;
506fe540122SSamuel Ortiz         let ip: u64 = 0x1000;
507fe540122SSamuel Ortiz         let cpu_id = 0;
508fe540122SSamuel Ortiz         let memory: [u8; 8] = target_rax.to_le_bytes();
509fe540122SSamuel Ortiz         let insn = [
510fe540122SSamuel Ortiz             0x48, 0xc7, 0xc0, 0x00, 0x01, 0x00, 0x00, // mov rax, 0x100
511fe540122SSamuel Ortiz             0x48, 0x8b, 0x58, 0x10, // mov rbx, qword ptr [rax+10h]
512fe540122SSamuel Ortiz         ];
5130c27f69fSRob Bradford         let mut vmm = MockVmm::new(ip, vec![], Some((rax + displacement, &memory)));
514*297236a7SRuoqing He         vmm.emulate_insn(cpu_id, &insn, Some(2)).unwrap();
515fe540122SSamuel Ortiz 
516fe540122SSamuel Ortiz         let rbx: u64 = vmm
517fe540122SSamuel Ortiz             .cpu_state(cpu_id)
518fe540122SSamuel Ortiz             .unwrap()
519fe540122SSamuel Ortiz             .read_reg(Register::RBX)
520fe540122SSamuel Ortiz             .unwrap();
521fe540122SSamuel Ortiz         assert_eq!(rbx, target_rax);
522fe540122SSamuel Ortiz     }
523fe540122SSamuel Ortiz 
524fe540122SSamuel Ortiz     #[test]
525fe540122SSamuel Ortiz     // mov rax, 0x100
526fe540122SSamuel Ortiz     // mov rbx, qword ptr [rax+10h]
test_mov_r64_imm64_and_r64_m64_first_insn()5279c5be6f6SRob Bradford     fn test_mov_r64_imm64_and_r64_m64_first_insn() {
528fe540122SSamuel Ortiz         let target_rax: u64 = 0x1234567812345678;
529fe540122SSamuel Ortiz         let rax: u64 = 0x100;
530fe540122SSamuel Ortiz         let displacement: u64 = 0x10;
531fe540122SSamuel Ortiz         let ip: u64 = 0x1000;
532fe540122SSamuel Ortiz         let cpu_id = 0;
533fe540122SSamuel Ortiz         let memory: [u8; 8] = target_rax.to_le_bytes();
534fe540122SSamuel Ortiz         let insn = [
535fe540122SSamuel Ortiz             0x48, 0xc7, 0xc0, 0x00, 0x01, 0x00, 0x00, // mov rax, 0x100
536fe540122SSamuel Ortiz             0x48, 0x8b, 0x58, 0x10, // mov rbx, qword ptr [rax+10h]
537fe540122SSamuel Ortiz         ];
538fe540122SSamuel Ortiz 
5390c27f69fSRob Bradford         let mut vmm = MockVmm::new(ip, vec![], Some((rax + displacement, &memory)));
540fe540122SSamuel Ortiz         // Only run the first instruction.
541*297236a7SRuoqing He         vmm.emulate_first_insn(cpu_id, &insn).unwrap();
542fe540122SSamuel Ortiz 
543fabd6307SRob Bradford         assert_eq!(ip + 7, vmm.cpu_state(cpu_id).unwrap().ip());
544fe540122SSamuel Ortiz 
545fe540122SSamuel Ortiz         let new_rax: u64 = vmm
546fe540122SSamuel Ortiz             .cpu_state(cpu_id)
547fe540122SSamuel Ortiz             .unwrap()
548fe540122SSamuel Ortiz             .read_reg(Register::RAX)
549fe540122SSamuel Ortiz             .unwrap();
550fe540122SSamuel Ortiz         assert_eq!(rax, new_rax);
551fe540122SSamuel Ortiz     }
552fe540122SSamuel Ortiz 
553fe540122SSamuel Ortiz     #[test]
554fe540122SSamuel Ortiz     // mov rax, 0x100
555fe540122SSamuel Ortiz     // mov rbx, qword ptr [rax+10h]
556fe540122SSamuel Ortiz     // mov rax, 0x200
test_mov_r64_imm64_and_r64_m64_two_insns()5579c5be6f6SRob Bradford     fn test_mov_r64_imm64_and_r64_m64_two_insns() {
558fe540122SSamuel Ortiz         let target_rax: u64 = 0x1234567812345678;
559fe540122SSamuel Ortiz         let rax: u64 = 0x100;
560fe540122SSamuel Ortiz         let displacement: u64 = 0x10;
561fe540122SSamuel Ortiz         let ip: u64 = 0x1000;
562fe540122SSamuel Ortiz         let cpu_id = 0;
563fe540122SSamuel Ortiz         let memory: [u8; 8] = target_rax.to_le_bytes();
564fe540122SSamuel Ortiz         let insn = [
565fe540122SSamuel Ortiz             0x48, 0xc7, 0xc0, 0x00, 0x01, 0x00, 0x00, // mov rax, 0x100
566fe540122SSamuel Ortiz             0x48, 0x8b, 0x58, 0x10, // mov rbx, qword ptr [rax+10h]
567fe540122SSamuel Ortiz             0x48, 0xc7, 0xc0, 0x00, 0x02, 0x00, 0x00, // mov rax, 0x200
568fe540122SSamuel Ortiz         ];
569fe540122SSamuel Ortiz 
5700c27f69fSRob Bradford         let mut vmm = MockVmm::new(ip, vec![], Some((rax + displacement, &memory)));
571a3d957baSSamuel Ortiz         // Run the 2 first instructions.
572*297236a7SRuoqing He         vmm.emulate_insn(cpu_id, &insn, Some(2)).unwrap();
573fe540122SSamuel Ortiz 
574fabd6307SRob Bradford         assert_eq!(ip + 7 + 4, vmm.cpu_state(cpu_id).unwrap().ip());
575fe540122SSamuel Ortiz 
576fe540122SSamuel Ortiz         let rbx: u64 = vmm
577fe540122SSamuel Ortiz             .cpu_state(cpu_id)
578fe540122SSamuel Ortiz             .unwrap()
579fe540122SSamuel Ortiz             .read_reg(Register::RBX)
580fe540122SSamuel Ortiz             .unwrap();
581fe540122SSamuel Ortiz         assert_eq!(rbx, target_rax);
582fe540122SSamuel Ortiz 
583fe540122SSamuel Ortiz         // Check that rax is still at 0x100
584fe540122SSamuel Ortiz         let new_rax: u64 = vmm
585fe540122SSamuel Ortiz             .cpu_state(cpu_id)
586fe540122SSamuel Ortiz             .unwrap()
587fe540122SSamuel Ortiz             .read_reg(Register::RAX)
588fe540122SSamuel Ortiz             .unwrap();
589fe540122SSamuel Ortiz         assert_eq!(rax, new_rax);
590fe540122SSamuel Ortiz     }
591eee218f1SSamuel Ortiz 
592eee218f1SSamuel Ortiz     #[test]
593eee218f1SSamuel Ortiz     // movzx eax, bl
test_movzx_r32_r8l()5949c5be6f6SRob Bradford     fn test_movzx_r32_r8l() {
595eee218f1SSamuel Ortiz         let bx: u16 = 0x8899;
596eee218f1SSamuel Ortiz         let ip: u64 = 0x1000;
597eee218f1SSamuel Ortiz         let cpu_id = 0;
598eee218f1SSamuel Ortiz         let insn = [0x0f, 0xb6, 0xc3];
5990c27f69fSRob Bradford         let mut vmm = MockVmm::new(ip, vec![(Register::BX, bx as u64)], None);
600*297236a7SRuoqing He         vmm.emulate_first_insn(cpu_id, &insn).unwrap();
601eee218f1SSamuel Ortiz 
602eee218f1SSamuel Ortiz         let eax: u64 = vmm
603eee218f1SSamuel Ortiz             .cpu_state(cpu_id)
604eee218f1SSamuel Ortiz             .unwrap()
605eee218f1SSamuel Ortiz             .read_reg(Register::EAX)
606eee218f1SSamuel Ortiz             .unwrap();
607eee218f1SSamuel Ortiz         assert_eq!(eax, (bx & 0xff) as u64);
608eee218f1SSamuel Ortiz     }
609eee218f1SSamuel Ortiz 
610eee218f1SSamuel Ortiz     #[test]
611eee218f1SSamuel Ortiz     // movzx eax, bh
test_movzx_r32_r8h()6129c5be6f6SRob Bradford     fn test_movzx_r32_r8h() {
613eee218f1SSamuel Ortiz         let bx: u16 = 0x8899;
614eee218f1SSamuel Ortiz         let ip: u64 = 0x1000;
615eee218f1SSamuel Ortiz         let cpu_id = 0;
616eee218f1SSamuel Ortiz         let insn = [0x0f, 0xb6, 0xc7];
6170c27f69fSRob Bradford         let mut vmm = MockVmm::new(ip, vec![(Register::BX, bx as u64)], None);
618*297236a7SRuoqing He         vmm.emulate_first_insn(cpu_id, &insn).unwrap();
619eee218f1SSamuel Ortiz 
620eee218f1SSamuel Ortiz         let eax: u64 = vmm
621eee218f1SSamuel Ortiz             .cpu_state(cpu_id)
622eee218f1SSamuel Ortiz             .unwrap()
623eee218f1SSamuel Ortiz             .read_reg(Register::EAX)
624eee218f1SSamuel Ortiz             .unwrap();
625eee218f1SSamuel Ortiz         assert_eq!(eax, (bx >> 8) as u64);
626eee218f1SSamuel Ortiz     }
627eee218f1SSamuel Ortiz 
628eee218f1SSamuel Ortiz     #[test]
629eee218f1SSamuel Ortiz     // movzx eax, byte ptr [rbx]
test_movzx_r32_m8()6309c5be6f6SRob Bradford     fn test_movzx_r32_m8() {
631eee218f1SSamuel Ortiz         let rbx: u64 = 0x100;
632eee218f1SSamuel Ortiz         let value: u8 = 0xaa;
633eee218f1SSamuel Ortiz         let ip: u64 = 0x1000;
634eee218f1SSamuel Ortiz         let cpu_id = 0;
635eee218f1SSamuel Ortiz         let insn = [0x0f, 0xb7, 0x03];
636eee218f1SSamuel Ortiz         let memory: [u8; 1] = value.to_le_bytes();
6370c27f69fSRob Bradford         let mut vmm = MockVmm::new(ip, vec![(Register::RBX, rbx)], Some((rbx, &memory)));
638*297236a7SRuoqing He         vmm.emulate_first_insn(cpu_id, &insn).unwrap();
639eee218f1SSamuel Ortiz 
640eee218f1SSamuel Ortiz         let eax: u64 = vmm
641eee218f1SSamuel Ortiz             .cpu_state(cpu_id)
642eee218f1SSamuel Ortiz             .unwrap()
643eee218f1SSamuel Ortiz             .read_reg(Register::EAX)
644eee218f1SSamuel Ortiz             .unwrap();
645eee218f1SSamuel Ortiz         assert_eq!(eax, value as u64);
646eee218f1SSamuel Ortiz     }
647442ac905SPhilipp Schuster 
648442ac905SPhilipp Schuster     #[test]
649442ac905SPhilipp Schuster     // movabs ax, ds:0x1337
650442ac905SPhilipp Schuster     // movabs eax, ds:0x1337
651442ac905SPhilipp Schuster     // movabs rax, ds:0x1337
test_mov_memoff_ax()652442ac905SPhilipp Schuster     fn test_mov_memoff_ax() {
653442ac905SPhilipp Schuster         let test_inputs: [(Register, &[u8]); 3] = [
654442ac905SPhilipp Schuster             (Register::AX, &[0x66, 0xa1]),
655442ac905SPhilipp Schuster             (Register::EAX, &[0xa1]),
656442ac905SPhilipp Schuster             (Register::RAX, &[0x48, 0xa1]),
657442ac905SPhilipp Schuster         ];
658442ac905SPhilipp Schuster 
659442ac905SPhilipp Schuster         // Constructs the instruction with the provided inputs and emulates it.
660442ac905SPhilipp Schuster         fn helper(register: Register, instruction_prefix: &[u8]) {
661442ac905SPhilipp Schuster             let mem_addr: u64 = 0x1337;
662442ac905SPhilipp Schuster             let mem_value: u64 = 0x13371337deadbeef;
663442ac905SPhilipp Schuster             let ip: u64 = 0x1000;
664442ac905SPhilipp Schuster             let cpu_id = 0;
665442ac905SPhilipp Schuster 
666442ac905SPhilipp Schuster             let mut instruction_bytes = Vec::new();
667442ac905SPhilipp Schuster             // instruction prefix with specified register
668442ac905SPhilipp Schuster             instruction_bytes.extend(instruction_prefix);
669442ac905SPhilipp Schuster             // 64-bit memory operand
670442ac905SPhilipp Schuster             instruction_bytes.extend([
671442ac905SPhilipp Schuster                 mem_addr.to_le_bytes()[0],
672442ac905SPhilipp Schuster                 mem_addr.to_le_bytes()[1],
673442ac905SPhilipp Schuster                 0,
674442ac905SPhilipp Schuster                 0,
675442ac905SPhilipp Schuster                 0,
676442ac905SPhilipp Schuster                 0,
677442ac905SPhilipp Schuster                 0,
678442ac905SPhilipp Schuster                 0,
679442ac905SPhilipp Schuster             ]);
680442ac905SPhilipp Schuster 
681442ac905SPhilipp Schuster             let memory: [u8; 8] = mem_value.to_le_bytes();
682442ac905SPhilipp Schuster             let mut vmm = MockVmm::new(ip, vec![], Some((mem_addr, &memory)));
683*297236a7SRuoqing He             vmm.emulate_first_insn(cpu_id, &instruction_bytes).unwrap();
684442ac905SPhilipp Schuster 
685442ac905SPhilipp Schuster             let ax: u64 = vmm.cpu_state(cpu_id).unwrap().read_reg(register).unwrap();
686442ac905SPhilipp Schuster 
687442ac905SPhilipp Schuster             match register {
688442ac905SPhilipp Schuster                 Register::AX => {
689442ac905SPhilipp Schuster                     assert_eq!(ax as u16, mem_value as u16);
690442ac905SPhilipp Schuster                 }
691442ac905SPhilipp Schuster                 Register::EAX => {
692442ac905SPhilipp Schuster                     assert_eq!(ax as u32, mem_value as u32);
693442ac905SPhilipp Schuster                 }
694442ac905SPhilipp Schuster                 Register::RAX => {
695442ac905SPhilipp Schuster                     assert_eq!(ax, mem_value);
696442ac905SPhilipp Schuster                 }
697442ac905SPhilipp Schuster                 _ => panic!(),
698442ac905SPhilipp Schuster             }
699442ac905SPhilipp Schuster         }
700442ac905SPhilipp Schuster 
701442ac905SPhilipp Schuster         for (register, instruction_prefix) in test_inputs {
702442ac905SPhilipp Schuster             helper(register, instruction_prefix)
703442ac905SPhilipp Schuster         }
704442ac905SPhilipp Schuster     }
705442ac905SPhilipp Schuster 
706442ac905SPhilipp Schuster     #[test]
707442ac905SPhilipp Schuster     // movabs ds:0x1337, ax
708442ac905SPhilipp Schuster     // movabs ds:0x1337, eax
709442ac905SPhilipp Schuster     // movabs ds:0x1337, rax
test_mov_ax_memoff()710442ac905SPhilipp Schuster     fn test_mov_ax_memoff() {
711442ac905SPhilipp Schuster         let test_inputs: [(Register, &[u8]); 3] = [
712442ac905SPhilipp Schuster             (Register::AX, &[0x66, 0xa3]),
713442ac905SPhilipp Schuster             (Register::EAX, &[0xa3]),
714442ac905SPhilipp Schuster             (Register::RAX, &[0x48, 0xa3]),
715442ac905SPhilipp Schuster         ];
716442ac905SPhilipp Schuster 
717442ac905SPhilipp Schuster         // Constructs the instruction with the provided inputs and emulates it.
718442ac905SPhilipp Schuster         fn helper(register: Register, instruction_prefix: &[u8]) {
719442ac905SPhilipp Schuster             let mem_addr: u64 = 0x1337;
720442ac905SPhilipp Schuster             let ax: u64 = 0x13371337deadbeef;
721442ac905SPhilipp Schuster             let ip: u64 = 0x1000;
722442ac905SPhilipp Schuster             let cpu_id = 0;
723442ac905SPhilipp Schuster 
724442ac905SPhilipp Schuster             let mut instruction_bytes = Vec::new();
725442ac905SPhilipp Schuster             // instruction prefix with specified register
726442ac905SPhilipp Schuster             instruction_bytes.extend(instruction_prefix);
727442ac905SPhilipp Schuster             // 64-bit memory operand
728442ac905SPhilipp Schuster             instruction_bytes.extend([
729442ac905SPhilipp Schuster                 mem_addr.to_le_bytes()[0],
730442ac905SPhilipp Schuster                 mem_addr.to_le_bytes()[1],
731442ac905SPhilipp Schuster                 0,
732442ac905SPhilipp Schuster                 0,
733442ac905SPhilipp Schuster                 0,
734442ac905SPhilipp Schuster                 0,
735442ac905SPhilipp Schuster                 0,
736442ac905SPhilipp Schuster                 0,
737442ac905SPhilipp Schuster             ]);
738442ac905SPhilipp Schuster 
739442ac905SPhilipp Schuster             let mut vmm = MockVmm::new(ip, vec![(Register::RAX, ax)], None);
740*297236a7SRuoqing He             vmm.emulate_first_insn(cpu_id, &instruction_bytes).unwrap();
741442ac905SPhilipp Schuster 
742442ac905SPhilipp Schuster             match register {
743442ac905SPhilipp Schuster                 Register::AX => {
744442ac905SPhilipp Schuster                     let mut memory: [u8; 2] = [0; 2];
745442ac905SPhilipp Schuster                     vmm.read_memory(mem_addr, &mut memory).unwrap();
746442ac905SPhilipp Schuster                     assert_eq!(u16::from_le_bytes(memory), ax as u16);
747442ac905SPhilipp Schuster                 }
748442ac905SPhilipp Schuster                 Register::EAX => {
749442ac905SPhilipp Schuster                     let mut memory: [u8; 4] = [0; 4];
750442ac905SPhilipp Schuster                     vmm.read_memory(mem_addr, &mut memory).unwrap();
751442ac905SPhilipp Schuster                     assert_eq!(u32::from_le_bytes(memory), ax as u32);
752442ac905SPhilipp Schuster                 }
753442ac905SPhilipp Schuster                 Register::RAX => {
754442ac905SPhilipp Schuster                     let mut memory: [u8; 8] = [0; 8];
755442ac905SPhilipp Schuster                     vmm.read_memory(mem_addr, &mut memory).unwrap();
756442ac905SPhilipp Schuster                     assert_eq!(u64::from_le_bytes(memory), ax);
757442ac905SPhilipp Schuster                 }
758442ac905SPhilipp Schuster                 _ => panic!(),
759442ac905SPhilipp Schuster             }
760442ac905SPhilipp Schuster         }
761442ac905SPhilipp Schuster 
762442ac905SPhilipp Schuster         for (register, instruction_prefix) in test_inputs {
763442ac905SPhilipp Schuster             helper(register, instruction_prefix)
764442ac905SPhilipp Schuster         }
765442ac905SPhilipp Schuster     }
766fe540122SSamuel Ortiz }
767