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