xref: /cloud-hypervisor/hypervisor/src/arch/x86/emulator/instructions/mod.rs (revision 0f4f30dbde1a2e7dd2154d6963918ca453cf2eaa)
1 //
2 // Copyright © 2020 Intel Corporation
3 //
4 // SPDX-License-Identifier: Apache-2.0
5 //
6 
7 extern crate 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 use iced_x86::*;
13 use std::collections::HashMap;
14 use std::sync::{Arc, Mutex};
15 
16 pub mod mov;
17 
18 // Returns the linear a.k.a. virtual address for a memory operand.
19 fn memory_operand_address<T: CpuStateManager>(
20     insn: &Instruction,
21     state: &T,
22 ) -> Result<u64, PlatformError> {
23     let mut address: u64 = 0;
24 
25     // Get the DS or override segment base first
26     let segment_base = state.read_segment(insn.memory_segment())?.base;
27     address += segment_base;
28 
29     if insn.memory_base() != iced_x86::Register::None {
30         let base: u64 = state.read_reg(insn.memory_base())?;
31         address += base;
32     }
33 
34     if insn.memory_index() != iced_x86::Register::None {
35         let mut index: u64 = state.read_reg(insn.memory_index())?;
36         index *= insn.memory_index_scale() as u64;
37 
38         address += index;
39     }
40 
41     address += insn.memory_displacement() as u64;
42 
43     Ok(address)
44 }
45 
46 pub trait InstructionHandler<T: CpuStateManager> {
47     fn emulate(
48         &self,
49         insn: &Instruction,
50         state: &mut T,
51         platform: Arc<Mutex<dyn PlatformEmulator<CpuState = T>>>,
52     ) -> Result<(), EmulationError<Exception>>;
53 }
54 
55 pub struct InstructionMap<T: CpuStateManager> {
56     pub instructions: HashMap<Code, Box<Box<dyn InstructionHandler<T> + Sync + Send>>>,
57 }
58 
59 impl<T: CpuStateManager> InstructionMap<T> {
60     pub fn new() -> InstructionMap<T> {
61         InstructionMap {
62             instructions: HashMap::new(),
63         }
64     }
65 
66     pub fn add_insn(
67         &mut self,
68         insn: Code,
69         insn_handler: Box<dyn InstructionHandler<T> + Sync + Send>,
70     ) {
71         self.instructions.insert(insn, Box::new(insn_handler));
72     }
73 }
74 
75 impl<T: CpuStateManager> Default for InstructionMap<T> {
76     fn default() -> Self {
77         Self::new()
78     }
79 }
80 
81 macro_rules! insn_add {
82     ($insn_map:ident, $mnemonic:ident, $code:ident) => {
83         $insn_map.add_insn(Code::$code, Box::new($mnemonic::$code {}));
84     };
85 }
86