1use bitfield_struct::bitfield;
7use core::mem::size_of;
8use hvdef::HV_PAGE_SIZE;
9#[cfg(feature = "inspect")]
10use inspect::Inspect;
11use open_enum::open_enum;
12use static_assertions::const_assert_eq;
13use zerocopy::FromBytes;
14use zerocopy::Immutable;
15use zerocopy::IntoBytes;
16use zerocopy::KnownLayout;
17
18pub const PARAVISOR_CONFIG_SLIT_SIZE_PAGES: u64 = 20;
22pub const PARAVISOR_CONFIG_PPTT_SIZE_PAGES: u64 = 20;
24pub const PARAVISOR_CONFIG_DEVICE_TREE_SIZE_PAGES: u64 = 64;
26
27pub const PARAVISOR_UNMEASURED_VTL2_CONFIG_REGION_PAGE_COUNT_MAX: u64 =
29 PARAVISOR_CONFIG_SLIT_SIZE_PAGES
30 + PARAVISOR_CONFIG_PPTT_SIZE_PAGES
31 + PARAVISOR_CONFIG_DEVICE_TREE_SIZE_PAGES;
32
33pub const PARAVISOR_CONFIG_SLIT_PAGE_INDEX: u64 = 0;
36pub const PARAVISOR_CONFIG_PPTT_PAGE_INDEX: u64 =
38 PARAVISOR_CONFIG_SLIT_PAGE_INDEX + PARAVISOR_CONFIG_SLIT_SIZE_PAGES;
39pub const PARAVISOR_CONFIG_DEVICE_TREE_PAGE_INDEX: u64 =
41 PARAVISOR_CONFIG_PPTT_PAGE_INDEX + PARAVISOR_CONFIG_PPTT_SIZE_PAGES;
42pub const PARAVISOR_UNMEASURED_VTL2_CONFIG_REGION_BASE_INDEX: u64 =
44 PARAVISOR_CONFIG_SLIT_PAGE_INDEX;
45
46pub const PARAVISOR_RESERVED_VTL2_SNP_CPUID_SIZE_PAGES: u64 = 2;
48pub const PARAVISOR_RESERVED_VTL2_SNP_VMSA_SIZE_PAGES: u64 = 1;
50pub const PARAVISOR_RESERVED_VTL2_SNP_SECRETS_SIZE_PAGES: u64 = 1;
52
53pub const PARAVISOR_RESERVED_VTL2_PAGE_COUNT_MAX: u64 = PARAVISOR_RESERVED_VTL2_SNP_CPUID_SIZE_PAGES
55 + PARAVISOR_RESERVED_VTL2_SNP_VMSA_SIZE_PAGES
56 + PARAVISOR_RESERVED_VTL2_SNP_SECRETS_SIZE_PAGES;
57
58pub const PARAVISOR_RESERVED_VTL2_SNP_VMSA_PAGE_INDEX: u64 = 0;
67pub const PARAVISOR_RESERVED_VTL2_SNP_CPUID_PAGE_INDEX: u64 =
69 PARAVISOR_RESERVED_VTL2_SNP_VMSA_PAGE_INDEX + PARAVISOR_RESERVED_VTL2_SNP_VMSA_SIZE_PAGES;
70pub const PARAVISOR_RESERVED_VTL2_SNP_SECRETS_PAGE_INDEX: u64 =
72 PARAVISOR_RESERVED_VTL2_SNP_CPUID_PAGE_INDEX + PARAVISOR_RESERVED_VTL2_SNP_CPUID_SIZE_PAGES;
73
74pub const PARAVISOR_MEASURED_VTL2_CONFIG_ACCEPTED_MEMORY_SIZE_PAGES: u64 = 1;
78
79pub const PARAVISOR_MEASURED_VTL2_CONFIG_SIZE_PAGES: u64 = 1;
81
82pub const PARAVISOR_MEASURED_VTL2_CONFIG_REGION_PAGE_COUNT: u64 =
84 PARAVISOR_MEASURED_VTL2_CONFIG_ACCEPTED_MEMORY_SIZE_PAGES
85 + PARAVISOR_MEASURED_VTL2_CONFIG_SIZE_PAGES;
86
87pub const PARAVISOR_MEASURED_VTL2_CONFIG_ACCEPTED_MEMORY_PAGE_INDEX: u64 =
90 PARAVISOR_UNMEASURED_VTL2_CONFIG_REGION_BASE_INDEX
91 + PARAVISOR_UNMEASURED_VTL2_CONFIG_REGION_PAGE_COUNT_MAX;
92
93pub const PARAVISOR_MEASURED_VTL2_CONFIG_PAGE_INDEX: u64 =
95 PARAVISOR_MEASURED_VTL2_CONFIG_ACCEPTED_MEMORY_PAGE_INDEX
96 + PARAVISOR_MEASURED_VTL2_CONFIG_ACCEPTED_MEMORY_SIZE_PAGES;
97
98pub const PARAVISOR_VTL2_CONFIG_REGION_PAGE_COUNT_MAX: u64 =
100 PARAVISOR_UNMEASURED_VTL2_CONFIG_REGION_PAGE_COUNT_MAX
101 + PARAVISOR_MEASURED_VTL2_CONFIG_REGION_PAGE_COUNT; pub const PARAVISOR_DEFAULT_MEMORY_BASE_ADDRESS: u64 = 128 * 1024 * 1024;
106pub const PARAVISOR_DEFAULT_MEMORY_PAGE_COUNT: u64 = 64 * 1024 * 1024 / HV_PAGE_SIZE;
108pub const PARAVISOR_LOCAL_MAP_VA: u64 = 0x200000;
110pub const PARAVISOR_LOCAL_MAP_SIZE: u64 = 0x200000;
112
113open_enum! {
114 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
116 pub enum CommandLinePolicy : u16 {
117 STATIC = 0,
119 APPEND_CHOSEN = 1,
122 }
123}
124
125pub const COMMAND_LINE_SIZE: usize = 4092;
127
128#[repr(C)]
130#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
131pub struct ParavisorCommandLine {
132 pub policy: CommandLinePolicy,
134 pub static_command_line_len: u16,
136 pub static_command_line: [u8; COMMAND_LINE_SIZE],
141}
142
143impl ParavisorCommandLine {
144 pub fn command_line(&self) -> Option<&str> {
147 core::str::from_utf8(&self.static_command_line[..self.static_command_line_len as usize])
148 .ok()
149 }
150}
151
152const_assert_eq!(size_of::<ParavisorCommandLine>(), HV_PAGE_SIZE as usize);
153
154#[repr(C)]
156#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq)]
157pub struct PageRegionDescriptor {
158 pub base_page_number: u64,
160 pub page_count: u64,
162}
163
164#[cfg(feature = "inspect")]
165impl Inspect for PageRegionDescriptor {
166 fn inspect(&self, req: inspect::Request<'_>) {
167 let pages = self.pages();
168
169 match pages {
170 None => {
171 req.ignore();
172 }
173 Some((base, count)) => {
174 req.respond()
175 .field("base_page_number", base)
176 .field("page_count", count);
177 }
178 }
179 }
180}
181
182impl PageRegionDescriptor {
183 pub const EMPTY: Self = PageRegionDescriptor {
185 base_page_number: 0,
186 page_count: 0,
187 };
188
189 pub fn new(base_page_number: u64, page_count: u64) -> Self {
191 PageRegionDescriptor {
192 base_page_number,
193 page_count,
194 }
195 }
196
197 pub fn pages(&self) -> Option<(u64, u64)> {
199 if self.page_count != 0 {
200 Some((self.base_page_number, self.page_count))
201 } else {
202 None
203 }
204 }
205}
206
207#[repr(C)]
209#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq)]
210pub struct ImportedRegionsPageHeader {
211 pub sha384_hash: [u8; 48],
213}
214
215#[repr(C)]
217#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq)]
218pub struct ImportedRegionDescriptor {
219 pub base_page_number: u64,
221 pub page_count: u64,
223 pub accepted: u8,
225 padding: [u8; 7],
227}
228
229#[cfg(feature = "inspect")]
230impl Inspect for ImportedRegionDescriptor {
231 fn inspect(&self, req: inspect::Request<'_>) {
232 let pages = self.pages();
233
234 match pages {
235 None => {
236 req.ignore();
237 }
238 Some((base, count, accepted)) => {
239 req.respond()
240 .field("base_page_number", base)
241 .field("page_count", count)
242 .field("accepted", accepted);
243 }
244 }
245 }
246}
247
248impl ImportedRegionDescriptor {
249 pub const EMPTY: Self = ImportedRegionDescriptor {
251 base_page_number: 0,
252 page_count: 0,
253 accepted: false as u8,
254 padding: [0; 7],
255 };
256
257 pub fn new(base_page_number: u64, page_count: u64, accepted: bool) -> Self {
259 ImportedRegionDescriptor {
260 base_page_number,
261 page_count,
262 accepted: accepted as u8,
263 padding: [0; 7],
264 }
265 }
266
267 pub fn pages(&self) -> Option<(u64, u64, bool)> {
269 if self.page_count != 0 {
270 Some((self.base_page_number, self.page_count, self.accepted != 0))
271 } else {
272 None
273 }
274 }
275}
276
277#[repr(C)]
279#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
280#[cfg_attr(feature = "inspect", derive(Inspect))]
281pub struct LinuxInfo {
282 pub kernel_region: PageRegionDescriptor,
284 pub kernel_entrypoint: u64,
286 pub initrd_region: PageRegionDescriptor,
288 pub initrd_size: u64,
290 pub command_line: PageRegionDescriptor,
292}
293
294#[repr(C)]
296#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
297#[cfg_attr(feature = "inspect", derive(Inspect))]
298pub struct UefiInfo {
299 pub firmware: PageRegionDescriptor,
301 pub vtl0_vp_context: PageRegionDescriptor,
303}
304
305#[cfg_attr(feature = "inspect", derive(Inspect))]
307#[bitfield(u64)]
308#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
309pub struct SupportedVtl0LoadInfo {
310 #[bits(1)]
312 pub uefi_supported: bool,
313 #[bits(1)]
315 pub pcat_supported: bool,
316 #[bits(1)]
318 pub linux_direct_supported: bool,
319 #[bits(61)]
321 pub reserved: u64,
322}
323
324#[repr(C)]
329#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
330#[cfg_attr(feature = "inspect", derive(Inspect))]
331pub struct ParavisorMeasuredVtl0Config {
332 pub magic: u64,
334 pub supported_vtl0: SupportedVtl0LoadInfo,
336 pub uefi_info: UefiInfo,
338 pub linux_info: LinuxInfo,
340}
341
342impl ParavisorMeasuredVtl0Config {
343 pub const MAGIC: u64 = 0x4F48434C56544C30;
345}
346
347pub const PARAVISOR_VTL0_MEASURED_CONFIG_BASE_PAGE_X64: u64 = 0;
351
352pub const PARAVISOR_VTL0_MEASURED_CONFIG_BASE_PAGE_AARCH64: u64 = 16 << (20 - 12);
359
360#[repr(C)]
366#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
367#[cfg_attr(feature = "inspect", derive(Inspect))]
368pub struct ParavisorMeasuredVtl2Config {
369 pub magic: u64,
371 pub vtom_offset_bit: u8,
373 pub padding: [u8; 7],
375 pub product_policy_size: u32,
378 pub reserved: [u8; 4],
380}
381
382impl ParavisorMeasuredVtl2Config {
383 pub const MAGIC: u64 = 0x4F48434C56544C32;
385}
386
387pub const PRODUCT_POLICY_INLINE_OFFSET: usize = size_of::<ParavisorMeasuredVtl2Config>();
390
391pub const PRODUCT_POLICY_MAX_SIZE_BYTES: usize =
393 (PARAVISOR_MEASURED_VTL2_CONFIG_SIZE_PAGES as usize) * (HV_PAGE_SIZE as usize)
394 - PRODUCT_POLICY_INLINE_OFFSET;
395
396#[cfg(test)]
397mod tests {
398 use super::*;
399 #[test]
404 fn measured_vtl2_config_field_offsets() {
405 let cfg = ParavisorMeasuredVtl2Config {
406 magic: 0x1122_3344_5566_7788,
407 vtom_offset_bit: 0x99,
408 padding: [0; 7],
409 product_policy_size: 0xABCDu32,
410 reserved: [0; 4],
411 };
412 let bytes = cfg.as_bytes();
413 assert_eq!(&bytes[0..8], &0x1122_3344_5566_7788u64.to_le_bytes());
414 assert_eq!(bytes[8], 0x99);
415 assert_eq!(&bytes[9..16], &[0u8; 7]);
416 assert_eq!(&bytes[16..20], &0xABCDu32.to_le_bytes());
417 assert_eq!(&bytes[20..24], &[0u8; 4]);
418 assert_eq!(bytes.len(), 24);
419 }
420
421 #[test]
422 fn measured_vtl2_config_round_trips() {
423 let cfg = ParavisorMeasuredVtl2Config {
424 magic: ParavisorMeasuredVtl2Config::MAGIC,
425 vtom_offset_bit: 47,
426 padding: [0; 7],
427 product_policy_size: 256,
428 reserved: [0; 4],
429 };
430 let bytes = cfg.as_bytes().to_vec();
431 let (decoded, rest) = ParavisorMeasuredVtl2Config::ref_from_prefix(&bytes).unwrap();
432 assert!(rest.is_empty());
433 assert_eq!(decoded.magic, ParavisorMeasuredVtl2Config::MAGIC);
434 assert_eq!(decoded.vtom_offset_bit, 47);
435 assert_eq!(decoded.product_policy_size, 256);
436 }
437
438 #[test]
439 fn pre_feature_zeroed_page_decodes_as_absent() {
440 let mut page = [0u8; HV_PAGE_SIZE as usize];
443 page[0..8].copy_from_slice(&ParavisorMeasuredVtl2Config::MAGIC.to_le_bytes());
444 page[8] = 17;
445 let (decoded, _rest) = ParavisorMeasuredVtl2Config::ref_from_prefix(&page).unwrap();
446 assert_eq!(decoded.magic, ParavisorMeasuredVtl2Config::MAGIC);
447 assert_eq!(decoded.vtom_offset_bit, 17);
448 assert_eq!(decoded.product_policy_size, 0);
449 }
450}