1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
 * Copyright (c) 2021 Bitdefender
 * SPDX-License-Identifier: Apache-2.0
 */
//! Offers information about the CPU modes in which an instruction is supported.
//!
//! # Examples
//!
//! ```
//! # use bddisasm::DecodeError;
//! #
//! # fn main() -> Result<(), DecodeError> {
//! use bddisasm::{DecodedInstruction, DecodeMode, Mnemonic};
//!
//! // `VMXON     qword ptr [rax]`
//! let ins = DecodedInstruction::decode(&[0xf3, 0x0f, 0xc7, 0x30], DecodeMode::Bits64)?;
//! let modes = ins.valid_cpu_modes();
//!
//! // Check if the instruction is available from user mode
//! if modes.privilege_level.ring3 {
//!     println!("Available in user mode");
//! } else {
//!     println!("Not available in user mode");
//! }
//!
//! # Ok(())
//! # }

// TODO: maybe use something like the `bitflags` crate and have all these as flags?

/// Privilege levels (rings) in which an instruction is supported.
#[allow(clippy::struct_excessive_bools)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct PrivilegeLevel {
    /// Instruction is valid in ring 0.
    pub ring0: bool,

    /// Instruction is valid in ring 1.
    pub ring1: bool,

    /// Instruction is valid in ring 2.
    pub ring2: bool,

    /// Instruction is valid in ring 3.
    pub ring3: bool,
}

/// Operating modes in which an instruction is supported.
#[allow(clippy::struct_excessive_bools)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct OperatingMode {
    /// The instruction is valid in real mode.
    pub real: bool,

    /// The instruction is valid in Virtual 8086 mode.
    pub v8086: bool,

    /// The instruction is valid in protected mode (32 bit).
    pub protected: bool,

    /// The instruction is valid in compatibility mode (32 bit in 64 bit).
    pub compat: bool,

    /// The instruction is valid in long mode.
    pub long: bool,
}

/// Special modes - these may be active inside other modes (example: `TSX` in `Long mode`).
#[allow(clippy::struct_excessive_bools)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct SpecialModes {
    /// The instruction is valid in System Management Mode.
    pub smm: bool,

    /// The instruction is valid outside System Management Mode.
    pub smm_off: bool,

    /// The instruction is valid in SGX mode.
    pub sgx: bool,

    /// The instruction is valid outside SGX mode.
    pub sgx_off: bool,

    /// The instruction is valid in transactional regions.
    pub tsx: bool,

    /// The instruction is valid in transactional regions.
    pub tsx_off: bool,
}

/// VMX mode - they engulf all the other modes.
#[allow(clippy::struct_excessive_bools)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct VmxMode {
    /// The instruction is valid in VMX root mode.
    pub root: bool,

    /// The instruction is valid in VMX non root mode.
    pub non_root: bool,

    /// The instruction is valid in VMX root SEAM.
    pub root_seam: bool,

    /// The instruction is valid in VMX non-root SEAM.
    pub non_root_seam: bool,

    /// The instruction is valid outside VMX operation.
    pub off: bool,
}

/// Indicates in which modes the instruction is valid in
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct CpuModes {
    pub privilege_level: PrivilegeLevel,
    pub operating_mode: OperatingMode,
    pub special_modes: SpecialModes,
    pub vmx: VmxMode,
}

#[doc(hidden)]
impl CpuModes {
    pub(crate) fn from_raw(raw: ffi::ND_VALID_MODES) -> Self {
        let raw = unsafe { raw.__bindgen_anon_1 };

        Self {
            privilege_level: PrivilegeLevel {
                ring0: raw.Ring0() != 0,
                ring1: raw.Ring1() != 0,
                ring2: raw.Ring2() != 0,
                ring3: raw.Ring3() != 0,
            },
            operating_mode: OperatingMode {
                real: raw.Real() != 0,
                v8086: raw.V8086() != 0,
                protected: raw.Protected() != 0,
                compat: raw.Compat() != 0,
                long: raw.Long() != 0,
            },
            special_modes: SpecialModes {
                smm: raw.Smm() != 0,
                smm_off: raw.SmmOff() != 0,
                sgx: raw.Sgx() != 0,
                sgx_off: raw.SgxOff() != 0,
                tsx: raw.Tsx() != 0,
                tsx_off: raw.TsxOff() != 0,
            },
            vmx: VmxMode {
                root: raw.VmxRoot() != 0,
                non_root: raw.VmxNonRoot() != 0,
                root_seam: raw.VmxRootSeam() != 0,
                non_root_seam: raw.VmxNonRootSeam() != 0,
                off: raw.VmxOff() != 0,
            },
        }
    }
}