xref: /cloud-hypervisor/hypervisor/src/arch/x86/emulator/instructions/mod.rs (revision 4ad44caa5217cf55eed512fc10fd68416a37d31c)
1 //
2 // Copyright © 2020 Intel Corporation
3 //
4 // SPDX-License-Identifier: Apache-2.0
5 //
6 
7 use crate::arch::emulator::{EmulationError, PlatformEmulator, PlatformError};
8 use crate::arch::x86::emulator::CpuStateManager;
9 use crate::arch::x86::Exception;
10 use iced_x86::*;
11 
12 pub mod cmp;
13 pub mod mov;
14 pub mod movs;
15 pub mod or;
16 pub mod stos;
17 
18 fn get_op<T: CpuStateManager>(
19     insn: &Instruction,
20     op_index: u32,
21     op_size: usize,
22     state: &T,
23     platform: &dyn PlatformEmulator<CpuState = T>,
24 ) -> Result<u64, PlatformError> {
25     if insn.op_count() < op_index + 1 {
26         return Err(PlatformError::InvalidOperand(anyhow!(
27             "Invalid operand {:?}",
28             op_index
29         )));
30     }
31 
32     if !matches!(op_size, 1 | 2 | 4 | 8) {
33         return Err(PlatformError::InvalidOperand(anyhow!(
34             "Invalid operand size {:?}",
35             op_size
36         )));
37     }
38 
39     let value = match insn
40         .try_op_kind(op_index)
41         .map_err(|e| PlatformError::InvalidOperand(e.into()))?
42     {
43         OpKind::Register => state.read_reg(
44             insn.try_op_register(op_index)
45                 .map_err(|e| PlatformError::InvalidOperand(e.into()))?,
46         )?,
47         OpKind::Memory => {
48             let addr = memory_operand_address(insn, state, false)?;
49             let mut memory: [u8; 8] = [0; 8];
50             platform.read_memory(addr, &mut memory[0..op_size])?;
51             <u64>::from_le_bytes(memory)
52         }
53         OpKind::Immediate8 => insn.immediate8() as u64,
54         OpKind::Immediate8to16 => insn.immediate8to16() as u64,
55         OpKind::Immediate8to32 => insn.immediate8to32() as u64,
56         OpKind::Immediate8to64 => insn.immediate8to64() as u64,
57         OpKind::Immediate16 => insn.immediate16() as u64,
58         OpKind::Immediate32 => insn.immediate32() as u64,
59         OpKind::Immediate32to64 => insn.immediate32to64() as u64,
60         OpKind::Immediate64 => insn.immediate64(),
61         k => return Err(PlatformError::InvalidOperand(anyhow!("{:?}", k))),
62     };
63 
64     Ok(value)
65 }
66 
67 fn set_op<T: CpuStateManager>(
68     insn: &Instruction,
69     op_index: u32,
70     op_size: usize,
71     state: &mut T,
72     platform: &mut dyn PlatformEmulator<CpuState = T>,
73     value: u64,
74 ) -> Result<(), PlatformError> {
75     if insn.op_count() < op_index + 1 {
76         return Err(PlatformError::InvalidOperand(anyhow!(
77             "Invalid operand {:?}",
78             op_index
79         )));
80     }
81 
82     if !matches!(op_size, 1 | 2 | 4 | 8) {
83         return Err(PlatformError::InvalidOperand(anyhow!(
84             "Invalid operand size {:?}",
85             op_size
86         )));
87     }
88 
89     match insn
90         .try_op_kind(op_index)
91         .map_err(|e| PlatformError::InvalidOperand(e.into()))?
92     {
93         OpKind::Register => state.write_reg(
94             insn.try_op_register(op_index)
95                 .map_err(|e| PlatformError::InvalidOperand(e.into()))?,
96             value,
97         )?,
98         OpKind::Memory => {
99             let addr = memory_operand_address(insn, state, true)?;
100             platform.write_memory(addr, &value.to_le_bytes()[..op_size])?;
101         }
102         k => return Err(PlatformError::InvalidOperand(anyhow!("{:?}", k))),
103     };
104 
105     Ok(())
106 }
107 
108 // Returns the linear a.k.a. virtual address for a memory operand.
109 fn memory_operand_address<T: CpuStateManager>(
110     insn: &Instruction,
111     state: &T,
112     write: bool,
113 ) -> Result<u64, PlatformError> {
114     let mut address: u64 = 0;
115 
116     if insn.memory_base() != iced_x86::Register::None {
117         let base: u64 = state.read_reg(insn.memory_base())?;
118         address += base;
119     }
120 
121     if insn.memory_index() != iced_x86::Register::None {
122         let mut index: u64 = state.read_reg(insn.memory_index())?;
123         index *= insn.memory_index_scale() as u64;
124 
125         address += index;
126     }
127 
128     address = address.wrapping_add(insn.memory_displacement64());
129 
130     // Translate to a linear address.
131     state.linearize(insn.memory_segment(), address, write)
132 }
133 
134 pub trait InstructionHandler<T: CpuStateManager> {
135     fn emulate(
136         &self,
137         insn: &Instruction,
138         state: &mut T,
139         platform: &mut dyn PlatformEmulator<CpuState = T>,
140     ) -> Result<(), EmulationError<Exception>>;
141 }
142 
143 macro_rules! insn_format {
144     ($insn:ident) => {{
145         let mut output = String::new();
146         let mut formatter = FastFormatter::new();
147         formatter
148             .options_mut()
149             .set_space_after_operand_separator(true);
150         formatter.format(&$insn, &mut output);
151 
152         output
153     }};
154 }
155