Skip to main content

ostd/arch/x86/vm/
types.rs

1// SPDX-License-Identifier: MPL-2.0
2
3//! Types that represent guest-visible x86 CPU state.
4
5/// Guest general-purpose registers, instruction pointer, and flags.
6#[repr(C)]
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8pub struct VcpuRegs {
9    /// The `RAX` register.
10    pub rax: usize,
11    /// The `RBX` register.
12    pub rbx: usize,
13    /// The `RCX` register.
14    pub rcx: usize,
15    /// The `RDX` register.
16    pub rdx: usize,
17    /// The `RSI` register.
18    pub rsi: usize,
19    /// The `RDI` register.
20    pub rdi: usize,
21    /// The `RBP` register.
22    pub rbp: usize,
23    /// The stack pointer.
24    pub rsp: usize,
25    /// The `R8` register.
26    pub r8: usize,
27    /// The `R9` register.
28    pub r9: usize,
29    /// The `R10` register.
30    pub r10: usize,
31    /// The `R11` register.
32    pub r11: usize,
33    /// The `R12` register.
34    pub r12: usize,
35    /// The `R13` register.
36    pub r13: usize,
37    /// The `R14` register.
38    pub r14: usize,
39    /// The `R15` register.
40    pub r15: usize,
41    /// The instruction pointer.
42    pub rip: usize,
43    /// The flags register.
44    pub rflags: usize,
45}
46
47impl VcpuRegs {
48    /// Creates zeroed registers with the fixed bit of `RFLAGS` set.
49    pub const fn new() -> Self {
50        const RFLAGS_FIXED_BIT: usize = 1 << 1;
51
52        Self {
53            rax: 0,
54            rbx: 0,
55            rcx: 0,
56            rdx: 0,
57            rsi: 0,
58            rdi: 0,
59            rbp: 0,
60            rsp: 0,
61            r8: 0,
62            r9: 0,
63            r10: 0,
64            r11: 0,
65            r12: 0,
66            r13: 0,
67            r14: 0,
68            r15: 0,
69            rip: 0,
70            rflags: RFLAGS_FIXED_BIT,
71        }
72    }
73}
74
75impl Default for VcpuRegs {
76    fn default() -> Self {
77        Self::new()
78    }
79}
80
81/// Guest special-register state.
82#[repr(C)]
83#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
84pub struct VcpuSregs {
85    /// The code segment.
86    pub cs: VcpuSegment,
87    /// The data segment.
88    pub ds: VcpuSegment,
89    /// The extra data segment.
90    pub es: VcpuSegment,
91    /// The `FS` segment, including the `IA32_FS_BASE` MSR value.
92    pub fs: VcpuSegment,
93    /// The `GS` segment, including the `IA32_GS_BASE` MSR value.
94    pub gs: VcpuSegment,
95    /// The stack segment.
96    pub ss: VcpuSegment,
97    /// The task register and its cached segment descriptor.
98    pub tr: VcpuSegment,
99    /// The local descriptor-table register and its cached segment descriptor.
100    pub ldt: VcpuSegment,
101    /// The global descriptor-table register.
102    pub gdt: VcpuDescTable,
103    /// The interrupt descriptor-table register.
104    pub idt: VcpuDescTable,
105    /// The `CR0` control register.
106    pub cr0: u64,
107    /// The page-fault linear address.
108    pub cr2: u64,
109    /// The page-table root and control bits.
110    pub cr3: u64,
111    /// The `CR4` control register.
112    pub cr4: u64,
113    /// The extended feature enable register.
114    pub efer: u64,
115    /// The local APIC base address and control bits.
116    pub apic_base: u64,
117    /// The pending interrupt vectors, with one bit per vector.
118    pub interrupt_bitmap: [u64; 4],
119}
120
121impl VcpuSregs {
122    /// Creates real-mode state with zero-based 64-KiB segments and paging disabled.
123    pub fn new_real_mode() -> Self {
124        const CR0_EXTENSION_TYPE: u64 = 1 << 4;
125        const DATA_READ_WRITE_ACCESSED: u8 = 0x3;
126        const CODE_EXEC_READ_ACCESSED: u8 = 0xb;
127        const BUSY_TSS: u8 = 0xb;
128
129        let data = VcpuSegment {
130            limit: 0xffff,
131            type_: DATA_READ_WRITE_ACCESSED,
132            present: 1,
133            s: 1,
134            ..VcpuSegment::default()
135        };
136
137        Self {
138            cs: VcpuSegment {
139                type_: CODE_EXEC_READ_ACCESSED,
140                ..data
141            },
142            ds: data,
143            es: data,
144            fs: data,
145            gs: data,
146            ss: data,
147            tr: VcpuSegment {
148                type_: BUSY_TSS,
149                s: 0,
150                ..data
151            },
152            ldt: VcpuSegment {
153                unusable: 1,
154                ..VcpuSegment::default()
155            },
156            cr0: CR0_EXTENSION_TYPE,
157            ..Self::default()
158        }
159    }
160}
161
162/// Guest segment-register state.
163///
164/// Refer to: Intel SDM Vol. 3A, 3.4.5 "Segment Descriptors".
165#[repr(C)]
166#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
167pub struct VcpuSegment {
168    /// The segment base address.
169    pub base: u64,
170    /// The effective segment limit in bytes, with granularity already applied.
171    pub limit: u32,
172    /// The segment selector.
173    pub selector: u16,
174    /// The four-bit segment type.
175    pub type_: u8,
176    /// The segment-present bit.
177    pub present: u8,
178    /// The descriptor privilege level.
179    pub dpl: u8,
180    /// The default operation size or upper-bound bit.
181    pub db: u8,
182    /// The descriptor class bit: zero for system, one for code or data.
183    pub s: u8,
184    /// The 64-bit code-segment bit.
185    pub l: u8,
186    /// The granularity bit: zero for byte, one for 4-KiB granularity.
187    pub g: u8,
188    /// The descriptor bit available to software.
189    pub avl: u8,
190    /// The VMX unusable-segment bit.
191    pub unusable: u8,
192    /// The reserved padding byte.
193    pub padding: u8,
194}
195
196/// Guest descriptor-table state.
197#[repr(C)]
198#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
199pub struct VcpuDescTable {
200    /// The linear base address of the descriptor table.
201    pub base: u64,
202    /// The table size in bytes minus one.
203    pub limit: u16,
204    /// The reserved padding words.
205    pub padding: [u16; 3],
206}
207
208/// Guest MSR state that is not already stored in [`VcpuSregs`].
209#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
210pub struct VcpuMsrs {
211    /// The page attribute table.
212    pub pat: u64,
213    /// The kernel GS base exchanged by `SWAPGS`.
214    pub kernel_gs_base: u64,
215    /// The `SYSCALL` and `SYSRET` segment selectors.
216    pub star: u64,
217    /// The 64-bit `SYSCALL` entry point.
218    pub lstar: u64,
219    /// The flags cleared on `SYSCALL` entry.
220    pub syscall_mask: u64,
221    /// The accumulated TSC adjustment.
222    pub tsc_adjust: u64,
223    /// The auxiliary TSC value returned by `RDTSCP`.
224    pub tsc_aux: u64,
225    /// The `SYSENTER` code-segment selector.
226    pub sysenter_cs: u64,
227    /// The `SYSENTER` stack pointer.
228    pub sysenter_esp: u64,
229    /// The `SYSENTER` instruction pointer.
230    pub sysenter_eip: u64,
231    /// The miscellaneous processor feature controls.
232    pub misc_enable: u64,
233}
234
235/// A guest external interrupt.
236#[derive(Clone, Copy, Debug, Eq, PartialEq)]
237pub struct GuestInterrupt {
238    /// The interrupt vector, in the range 32 through 255.
239    pub vector: u8,
240}
241
242/// An instant on the guest's TSC timeline.
243#[derive(Clone, Copy, Debug, Eq, PartialEq)]
244pub struct GuestTimerInstant {
245    /// The timestamp-counter value.
246    pub tsc: u64,
247}