loader_defs/shim.rs
1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Loader definitions for the openhcl boot loader (`openhcl_boot`).
5
6use open_enum::open_enum;
7use zerocopy::FromBytes;
8use zerocopy::Immutable;
9use zerocopy::IntoBytes;
10use zerocopy::KnownLayout;
11
12/// Shim parameters set by the loader at IGVM build time. These contain shim
13/// base relative offsets and sizes instead of absolute addresses. Sizes are in
14/// bytes.
15#[repr(C)]
16#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
17pub struct ShimParamsRaw {
18 /// The offset to the Linux kernel entry point.
19 pub kernel_entry_offset: i64,
20 /// The offset to the [`crate::paravisor::ParavisorCommandLine`] structure.
21 pub cmdline_offset: i64,
22 /// The offset to the initrd.
23 pub initrd_offset: i64,
24 /// The size of the initrd.
25 pub initrd_size: u64,
26 /// The crc32 of the initrd.
27 pub initrd_crc: u32,
28 /// Isolation type supported by the igvm file.
29 pub supported_isolation_type: SupportedIsolationType,
30 /// The offset to the start of the VTL2 memory region.
31 pub memory_start_offset: i64,
32 /// The size of the VTL2 memory region.
33 pub memory_size: u64,
34 /// The offset to the parameter region.
35 pub parameter_region_offset: i64,
36 /// The size of the parameter region.
37 pub parameter_region_size: u64,
38 /// The offset to the VTL2 reserved region.
39 pub vtl2_reserved_region_offset: i64,
40 /// The size of the VTL2 reserved region.
41 pub vtl2_reserved_region_size: u64,
42 /// The offset to the sidecar memory region.
43 pub sidecar_offset: i64,
44 /// The size of the sidecar memory region.
45 pub sidecar_size: u64,
46 /// The offset to the entry point for the sidecar.
47 pub sidecar_entry_offset: i64,
48 /// The offset to the populated portion of VTL2 memory.
49 pub used_start: i64,
50 /// The offset to the end of the populated portion of VTL2 memory.
51 pub used_end: i64,
52 /// The offset to the bounce buffer range. This is 0 if unavailable.
53 pub bounce_buffer_start: i64,
54 /// The size of the bounce buffer range. This is 0 if unavailable.
55 pub bounce_buffer_size: u64,
56 /// The offset to the persisted bootshim log buffer.
57 pub log_buffer_start: i64,
58 /// The size of the persisted bootshim log buffer.
59 pub log_buffer_size: u64,
60 /// The offset to the start of the bootshim heap.
61 pub heap_start_offset: i64,
62 /// The size of the bootshim heap.
63 pub heap_size: u64,
64 /// The offset to the start of the supported persisted state region.
65 pub persisted_state_region_offset: i64,
66 /// The size of the supported persisted state region.
67 pub persisted_state_region_size: u64,
68}
69
70open_enum! {
71 /// Possible isolation types supported by the shim.
72 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
73 pub enum SupportedIsolationType: u32 {
74 // Starting from 1 for consistency with None usually being 0, but
75 // the IGVM file for None and Vbs will likely be the same, so None will
76 // not be enumerated here.At runtime, calls will be made to query
77 // the actual isolation type of the partition.
78 /// VBS-isolation is supported.
79 VBS = 1,
80 /// AMD SEV-SNP isolation is supported
81 SNP = 2,
82 /// Intel TDX isolation is supported
83 TDX = 3,
84 }
85}
86
87open_enum! {
88 /// The memory type reported from the bootshim to usermode, for which VTL a
89 /// given memory range is for.
90 #[cfg_attr(feature = "save_restore", derive(mesh_protobuf::Protobuf))]
91 #[cfg_attr(feature = "save_restore", mesh(package = "openhcl.openhcl_boot"))]
92 pub enum MemoryVtlType: u32 {
93 /// This memory is for VTL0.
94 VTL0 = 0,
95 /// This memory is used by VTL2 as regular ram.
96 VTL2_RAM = 1,
97 /// This memory holds VTL2 config data, which is marked as reserved to
98 /// the kernel.
99 VTL2_CONFIG = 2,
100 /// This memory is used by the VTL2 sidecar as it's image, and is marked
101 /// as reserved to the kernel.
102 VTL2_SIDECAR_IMAGE = 3,
103 /// This memory is used by the VTL2 sidecar as node memory, and is
104 /// marked as reserved to the kernel.
105 VTL2_SIDECAR_NODE = 4,
106 /// This range is mmio for VTL0.
107 VTL0_MMIO = 5,
108 /// This range is mmio for VTL2.
109 VTL2_MMIO = 6,
110 /// This memory holds VTL2 data which should be preserved by the kernel
111 /// and usermode. Today, this is only used for SNP: VMSA, CPUID pages,
112 /// and secrets pages.
113 VTL2_RESERVED = 7,
114 /// This memory is used by VTL2 usermode as a persisted GPA page pool.
115 /// This memory is part of VTL2's address space, not VTL0's. It is
116 /// marked as reserved to the kernel.
117 VTL2_GPA_POOL = 8,
118 /// This memory is used by VTL2 for TDX AP startup page tables, and is
119 /// marked as reserved to the kernel.
120 VTL2_TDX_PAGE_TABLES = 9,
121 /// This memory is used by VTL2 to store in-memory bootshim logs. It is
122 /// marked as reserved to the kernel.
123 VTL2_BOOTSHIM_LOG_BUFFER = 10,
124 /// This memory is used by VTL2 to store a persisted state header. This
125 /// memory is marked as reserved to the kernel.
126 VTL2_PERSISTED_STATE_HEADER = 11,
127 /// This memory is used by VTL2 to store the persisted protobuf payload.
128 /// This memory is marked as reserved to the kernel.
129 VTL2_PERSISTED_STATE_PROTOBUF = 12,
130 }
131}
132
133impl MemoryVtlType {
134 /// Returns true if this range is a ram type.
135 pub fn ram(&self) -> bool {
136 matches!(
137 *self,
138 MemoryVtlType::VTL0
139 | MemoryVtlType::VTL2_RAM
140 | MemoryVtlType::VTL2_CONFIG
141 | MemoryVtlType::VTL2_SIDECAR_IMAGE
142 | MemoryVtlType::VTL2_SIDECAR_NODE
143 | MemoryVtlType::VTL2_RESERVED
144 | MemoryVtlType::VTL2_GPA_POOL
145 | MemoryVtlType::VTL2_TDX_PAGE_TABLES
146 | MemoryVtlType::VTL2_BOOTSHIM_LOG_BUFFER
147 | MemoryVtlType::VTL2_PERSISTED_STATE_HEADER
148 | MemoryVtlType::VTL2_PERSISTED_STATE_PROTOBUF
149 )
150 }
151
152 /// Returns true if this range is used by VTL2.
153 pub fn vtl2(&self) -> bool {
154 matches!(
155 *self,
156 MemoryVtlType::VTL2_RAM
157 | MemoryVtlType::VTL2_CONFIG
158 | MemoryVtlType::VTL2_SIDECAR_IMAGE
159 | MemoryVtlType::VTL2_SIDECAR_NODE
160 | MemoryVtlType::VTL2_MMIO
161 | MemoryVtlType::VTL2_RESERVED
162 | MemoryVtlType::VTL2_GPA_POOL
163 | MemoryVtlType::VTL2_TDX_PAGE_TABLES
164 | MemoryVtlType::VTL2_BOOTSHIM_LOG_BUFFER
165 | MemoryVtlType::VTL2_PERSISTED_STATE_HEADER
166 | MemoryVtlType::VTL2_PERSISTED_STATE_PROTOBUF
167 )
168 }
169}
170
171/// This structure describes the initial state of the TD VP. When a VP (both BSP and AP)
172/// starts at ResetVector (RV), this is loaded at the beginning of the RV page.
173/// Fields in the trampoline context must be loaded from memory by the
174/// trampoline code.
175///
176/// Note that this trampoline context must also be used for bringing up APs, as
177/// the code placed in the reset vector will use this format to figure out what
178/// register state to load.
179#[repr(C)]
180#[derive(Debug, Default, Clone, Copy, IntoBytes, Immutable)]
181pub struct TdxTrampolineContext {
182 /// Mailbox command
183 pub mailbox_command: u16,
184 /// Reserved
185 pub mailbox_reserved: u16,
186 /// Mailbox APIC ID
187 pub mailbox_apic_id: u32,
188 /// AP wakeup vector
189 pub mailbox_wakeup_vector: u64,
190 /// Padding
191 pub padding_1: u32,
192 /// Data selector
193 pub data_selector: u16,
194 /// Static GDT limit
195 pub static_gdt_limit: u16,
196 /// Static GDT base
197 pub static_gdt_base: u32,
198 /// Task selector
199 pub task_selector: u16,
200 /// IDTR limit
201 pub idtr_limit: u16,
202 /// IDTR base
203 pub idtr_base: u64,
204 /// Initial RIP
205 pub initial_rip: u64,
206 /// CS
207 pub code_selector: u16,
208 /// Padding
209 pub padding_2: [u16; 2],
210 /// GDTR limit
211 pub gdtr_limit: u16,
212 /// GDTR base
213 pub gdtr_base: u64,
214 /// RSP
215 pub rsp: u64,
216 /// RBP
217 pub rbp: u64,
218 /// RSI
219 pub rsi: u64,
220 /// R8
221 pub r8: u64,
222 /// R9
223 pub r9: u64,
224 /// R10
225 pub r10: u64,
226 /// R11
227 pub r11: u64,
228 /// CR0
229 pub cr0: u64,
230 /// CR3
231 pub cr3: u64,
232 /// CR4
233 pub cr4: u64,
234 /// Transistion CR3
235 pub transition_cr3: u32,
236 /// Padding
237 pub padding_3: u32,
238 /// Statuc GDT
239 pub static_gdt: [u8; 16],
240}
241
242/// This is the header used to describe the overall persisted state region. By
243/// convention, the header resides at the start of VTL2 memory, taking a single
244/// page.
245///
246/// This header should never change, instead for new information to be stored
247/// add it to the protobuf payload described below.
248#[repr(C)]
249#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
250pub struct PersistedStateHeader {
251 /// A magic value. If this is not set to [`PersistedStateHeader::MAGIC`],
252 /// then the previous instance did not support this region.
253 pub magic: u64,
254 /// The gpa for the start of the protobuf region. This must be 4K aligned.
255 pub protobuf_base: u64,
256 /// The size of the protobuf region in bytes.
257 pub protobuf_region_len: u64,
258 /// The size of the protobuf payload in bytes.
259 /// This must be less than or equal to `protobuf_region_len`.
260 pub protobuf_payload_len: u64,
261}
262
263impl PersistedStateHeader {
264 /// "OHCLPHDR" in ASCII.
265 pub const MAGIC: u64 = u64::from_le_bytes(*b"OHCLPHDR");
266}
267
268/// Definitions used for save/restore between boots.
269#[cfg(feature = "save_restore")]
270pub mod save_restore {
271 extern crate alloc;
272
273 use super::MemoryVtlType;
274 use alloc::vec::Vec;
275 use memory_range::MemoryRange;
276
277 /// A local newtype wrapper that represents a [`igvm_defs::MemoryMapEntryType`].
278 ///
279 /// This is required to make it protobuf deriveable.
280 #[derive(mesh_protobuf::Protobuf, Clone, Debug, PartialEq)]
281 #[mesh(package = "openhcl.openhcl_boot")]
282 pub struct IgvmMemoryType(#[mesh(1)] u16);
283
284 impl From<igvm_defs::MemoryMapEntryType> for IgvmMemoryType {
285 fn from(igvm_type: igvm_defs::MemoryMapEntryType) -> Self {
286 Self(igvm_type.0)
287 }
288 }
289
290 impl From<IgvmMemoryType> for igvm_defs::MemoryMapEntryType {
291 fn from(igvm_type: IgvmMemoryType) -> Self {
292 igvm_defs::MemoryMapEntryType(igvm_type.0)
293 }
294 }
295
296 /// A memory entry describing what range of address space described as memory is
297 /// used for what.
298 #[derive(mesh_protobuf::Protobuf, Debug)]
299 #[mesh(package = "openhcl.openhcl_boot")]
300 pub struct MemoryEntry {
301 /// The range of memory.
302 #[mesh(1)]
303 pub range: MemoryRange,
304 /// The numa vnode for this range.
305 #[mesh(2)]
306 pub vnode: u32,
307 /// The VTL type for this range.
308 #[mesh(3)]
309 pub vtl_type: MemoryVtlType,
310 /// The IGVM type for this range, which was reported by the host originally.
311 #[mesh(4)]
312 pub igvm_type: IgvmMemoryType,
313 }
314
315 /// A mmio entry describing what range of address space described as mmio is
316 /// used for what.
317 #[derive(mesh_protobuf::Protobuf, Debug)]
318 #[mesh(package = "openhcl.openhcl_boot")]
319 pub struct MmioEntry {
320 /// The range of mmio.
321 #[mesh(1)]
322 pub range: MemoryRange,
323 /// The VTL type for this range, which should always be an mmio type.
324 #[mesh(2)]
325 pub vtl_type: MemoryVtlType,
326 }
327
328 /// The format for saved state between the previous instance of OpenHCL and the
329 /// next.
330 #[derive(mesh_protobuf::Protobuf, Debug)]
331 #[mesh(package = "openhcl.openhcl_boot")]
332 pub struct SavedState {
333 /// The memory entries describing memory for the whole partition.
334 #[mesh(1)]
335 pub partition_memory: Vec<MemoryEntry>,
336 /// The mmio entries describing mmio for the whole partition.
337 #[mesh(2)]
338 pub partition_mmio: Vec<MmioEntry>,
339 /// The list of CPUs with mapped device interrupts present at save time
340 /// that do not have outstanding IO (those CPUs are counted in
341 /// `cpus_with_outstanding_io`).
342 ///
343 /// DEFAULT: For save state from prior versions, this will be empty.
344 /// This is fine: the restore heuristics might be less optimal, but will
345 /// still be functionally correct.
346 #[mesh(3)]
347 pub cpus_with_mapped_interrupts_no_io: Vec<u32>,
348 /// The list of CPUs with mapped device interrupts present at save time,
349 /// and that also have outstanding IO on that CPU.
350 ///
351 /// DEFAULT: For save state from prior versions, this will be empty.
352 /// This is fine: the restore heuristics might be less optimal, but will
353 /// still be functionally correct.
354 #[mesh(4)]
355 pub cpus_with_outstanding_io: Vec<u32>,
356 }
357}