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