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