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