1use bitfield_struct::bitfield;
7use core::mem::size_of;
8use guid::Guid;
9use zerocopy::FromBytes;
10use zerocopy::Immutable;
11use zerocopy::IntoBytes;
12use zerocopy::KnownLayout;
13
14fn align_8(x: usize) -> usize {
15 (x + 7) & !7
16}
17
18#[derive(Debug)]
20pub struct Blob {
21 data: Vec<u8>,
22 count: u32,
23}
24
25impl Blob {
26 pub fn new() -> Self {
28 let mut blob = Self {
29 data: Vec::new(),
30 count: 0,
31 };
32 blob.add(&StructureCount {
33 total_structure_count: 0,
34 total_config_blob_size: 0,
35 });
36 blob
37 }
38
39 pub fn add<T: BlobStructure>(&mut self, data: &T) -> &mut Self {
41 self.add_raw(T::STRUCTURE_TYPE, data.as_bytes())
42 }
43
44 pub fn add_cstring(&mut self, structure_type: BlobStructureType, data: &[u8]) -> &mut Self {
53 if !data.is_empty() {
54 self.add_raw_inner(structure_type, data, !data.ends_with(&[0]))
55 } else {
56 self
57 }
58 }
59
60 pub fn add_raw(&mut self, structure_type: BlobStructureType, data: &[u8]) -> &mut Self {
63 self.add_raw_inner(structure_type, data, false)
64 }
65
66 fn add_raw_inner(
67 &mut self,
68 structure_type: BlobStructureType,
69 data: &[u8],
70 add_null_term: bool,
71 ) -> &mut Self {
72 let aligned_data_len = align_8(data.len() + add_null_term as usize);
74 self.data.extend_from_slice(
75 Header {
76 structure_type: structure_type as u32,
77 length: (size_of::<Header>() + aligned_data_len) as u32,
78 }
79 .as_bytes(),
80 );
81 self.data.extend_from_slice(data);
82 if add_null_term {
83 self.data.push(0);
84 }
85 self.data
87 .extend_from_slice(&[0; 7][..aligned_data_len - (data.len() + add_null_term as usize)]);
88 self.count += 1;
89 self
90 }
91
92 pub fn complete(mut self) -> Vec<u8> {
95 let total_config_blob_size = self.data.len() as u32;
96 self.data[size_of::<Header>()..size_of::<Header>() + size_of::<StructureCount>()]
97 .copy_from_slice(
98 StructureCount {
99 total_structure_count: self.count,
100 total_config_blob_size,
101 }
102 .as_bytes(),
103 );
104 self.data
105 }
106}
107
108impl Default for Blob {
109 fn default() -> Self {
110 Self::new()
111 }
112}
113
114pub trait BlobStructure: IntoBytes + FromBytes + Immutable + KnownLayout {
115 const STRUCTURE_TYPE: BlobStructureType;
116}
117
118macro_rules! blobtypes {
119 {
120 $($name:ident,)*
121 } => {
122 $(
123 impl BlobStructure for $name {
124 const STRUCTURE_TYPE: BlobStructureType = BlobStructureType::$name;
125 }
126 )*
127 }
128}
129
130blobtypes! {
131 StructureCount,
132 BiosInformation,
133 Entropy,
134 BiosGuid,
135 Smbios31ProcessorInformation,
136 Flags,
137 ProcessorInformation,
138 MmioRanges,
139 NvdimmCount,
140 VpciInstanceFilter,
141 Gic,
142}
143
144#[repr(u32)]
146pub enum BlobStructureType {
147 StructureCount = 0x00,
148 BiosInformation = 0x01,
149 #[deprecated(note = "use AcpiTable")]
150 Srat = 0x02,
151 MemoryMap = 0x03,
152 Entropy = 0x04,
153 BiosGuid = 0x05,
154 SmbiosSystemSerialNumber = 0x06,
155 SmbiosBaseSerialNumber = 0x07,
156 SmbiosChassisSerialNumber = 0x08,
157 SmbiosChassisAssetTag = 0x09,
158 SmbiosBiosLockString = 0x0A,
159 Smbios31ProcessorInformation = 0x0B,
160 SmbiosSocketDesignation = 0x0C,
161 SmbiosProcessorManufacturer = 0x0D,
162 SmbiosProcessorVersion = 0x0E,
163 SmbiosProcessorSerialNumber = 0x0F,
164 SmbiosProcessorAssetTag = 0x10,
165 SmbiosProcessorPartNumber = 0x11,
166 Flags = 0x12,
167 ProcessorInformation = 0x13,
168 MmioRanges = 0x14,
169 Aarch64Mpidr = 0x15,
170 AcpiTable = 0x16,
171 NvdimmCount = 0x17,
172 #[deprecated(note = "use AcpiTable")]
173 Madt = 0x18,
174 VpciInstanceFilter = 0x19,
175 SmbiosSystemManufacturer = 0x1A,
176 SmbiosSystemProductName = 0x1B,
177 SmbiosSystemVersion = 0x1C,
178 SmbiosSystemSkuNumber = 0x1D,
179 SmbiosSystemFamily = 0x1E,
180 SmbiosMemoryDeviceSerialNumber = 0x1F,
181 #[deprecated(note = "use AcpiTable")]
182 Slit = 0x20,
183 #[deprecated(note = "use AcpiTable")]
184 Aspt = 0x21,
185 #[deprecated(note = "use AcpiTable")]
186 Pptt = 0x22,
187 Gic = 0x23,
188 #[deprecated(note = "use AcpiTable")]
189 Mcfg = 0x24,
190 #[deprecated(note = "use AcpiTable")]
191 Ssdt = 0x25,
192 #[deprecated(note = "use AcpiTable")]
193 Hmat = 0x26,
194 #[deprecated(note = "use AcpiTable")]
195 Iort = 0x27,
196 PcieBarApertures = 0x28,
197}
198
199#[repr(C)]
214#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
215pub struct Header {
216 pub structure_type: u32,
217 pub length: u32,
218}
219
220#[repr(C)]
227#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
228pub struct StructureCount {
229 pub total_structure_count: u32,
230 pub total_config_blob_size: u32,
231}
232
233#[repr(C)]
234#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
235pub struct BiosInformation {
236 pub bios_size_pages: u32,
237 pub flags: u32,
242}
243
244pub const VM_MEMORY_RANGE_FLAG_PLATFORM_RESERVED: u32 = 0x1;
257pub const VM_MEMORY_RANGE_FLAG_PERSISTENT: u32 = 0x2;
258pub const VM_MEMORY_RANGE_FLAG_SPECIFIC_PURPOSE: u32 = 0x4;
259
260#[repr(C)]
261#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
262pub struct MemoryRangeV5 {
263 pub base_address: u64,
264 pub length: u64,
265 pub flags: u32,
266 pub reserved: u32,
267}
268
269#[repr(C)]
270#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
271pub struct Entropy(pub [u8; 64]);
272
273impl Default for Entropy {
274 fn default() -> Self {
275 Entropy([0; 64])
276 }
277}
278
279#[repr(C)]
280#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
281pub struct BiosGuid(pub Guid);
282
283#[repr(C)]
284#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
285pub struct Smbios31ProcessorInformation {
286 pub processor_id: u64,
287 pub external_clock: u16,
288 pub max_speed: u16,
289 pub current_speed: u16,
290 pub processor_characteristics: u16,
291 pub processor_family2: u16,
292 pub processor_type: u8,
293 pub voltage: u8,
294 pub status: u8,
295 pub processor_upgrade: u8,
296 pub reserved: u16,
297}
298
299#[bitfield(u64, debug = false)]
300#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
301pub struct Flags {
302 pub serial_controllers_enabled: bool,
303 pub pause_after_boot_failure: bool,
304 pub pxe_ip_v6: bool,
305 pub debugger_enabled: bool,
306 pub load_oemp_table: bool,
307 pub tpm_enabled: bool,
308 pub hibernate_enabled: bool,
309
310 #[bits(2)]
311 pub console: ConsolePort,
312
313 pub memory_attributes_table_enabled: bool,
314 pub virtual_battery_enabled: bool,
315 pub sgx_memory_enabled: bool,
316 pub is_vmbfs_boot: bool,
317 pub measure_additional_pcrs: bool,
318 pub disable_frontpage: bool,
319 pub default_boot_always_attempt: bool,
320 pub low_power_s0_idle_enabled: bool,
321 pub vpci_boot_enabled: bool,
322 pub proc_idle_enabled: bool,
323 pub disable_sha384_pcr: bool,
324 pub media_present_enabled_by_default: bool,
325
326 #[bits(2)]
327 pub memory_protection: MemoryProtection,
328
329 pub enable_imc_when_isolated: bool,
330 pub watchdog_enabled: bool,
331 pub tpm_locality_regs_enabled: bool,
332 pub dhcp6_link_layer_address: bool,
333 pub cxl_memory_enabled: bool,
334 pub mtrrs_initialized_at_load: bool,
335 _reserved_hv_sint: bool,
336 pub vmbus_disabled: bool,
337 pub pci_resources_pre_assigned: bool,
338 pub force_dma_bounce_enabled: bool,
339
340 #[bits(31)]
341 _reserved: u64,
342}
343
344#[derive(Clone, Copy)]
345pub enum ConsolePort {
346 Default = 0b00,
347 Com1 = 0b01,
348 Com2 = 0b10,
349 None = 0b11,
350}
351
352impl ConsolePort {
353 const fn from_bits(bits: u64) -> Self {
354 match bits {
355 0b00 => Self::Default,
356 0b01 => Self::Com1,
357 0b10 => Self::Com2,
358 0b11 => Self::None,
359 _ => unreachable!(),
360 }
361 }
362
363 const fn into_bits(self) -> u64 {
364 self as u64
365 }
366}
367
368pub enum MemoryProtection {
369 Disabled = 0b00,
370 Default = 0b01,
371 Strict = 0b10,
372 Relaxed = 0b11,
373}
374
375impl MemoryProtection {
376 const fn from_bits(bits: u64) -> Self {
377 match bits {
378 0b00 => Self::Disabled,
379 0b01 => Self::Default,
380 0b10 => Self::Strict,
381 0b11 => Self::Relaxed,
382 _ => unreachable!(),
383 }
384 }
385
386 const fn into_bits(self) -> u64 {
387 self as u64
388 }
389}
390
391#[repr(C)]
392#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
393pub struct ProcessorInformation {
394 pub max_processor_count: u32,
395 pub processor_count: u32,
396 pub processors_per_virtual_socket: u32,
397 pub threads_per_processor: u32,
398}
399
400#[repr(C)]
401#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Copy, Clone)]
402pub struct Mmio {
403 pub mmio_page_number_start: u64,
404 pub mmio_size_in_pages: u64,
405}
406
407#[repr(C)]
408#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
409pub struct MmioRanges(pub [Mmio; 2]);
410
411#[repr(C)]
412#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
413pub struct NvdimmCount {
414 pub count: u16,
415 pub padding: [u16; 3],
416}
417
418#[repr(C)]
419#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
420pub struct VpciInstanceFilter {
421 pub instance_guid: Guid,
422}
423
424#[repr(C)]
425#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
426pub struct Gic {
427 pub gic_distributor_base: u64,
428 pub gic_redistributors_base: u64,
429}
430
431#[repr(C)]
439#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
440pub struct PcieBarApertureEntry {
441 pub segment: u16,
442 pub start_bus: u8,
443 pub end_bus: u8,
444 pub uid: u32,
447 pub low_mmio_base: u64,
448 pub low_mmio_length: u64,
449 pub high_mmio_base: u64,
450 pub high_mmio_length: u64,
451}
452
453#[cfg(test)]
454mod tests {
455 use super::*;
456
457 fn read<T>(bytes: &[u8]) -> T
458 where
459 T: FromBytes + Immutable + KnownLayout,
460 {
461 T::read_from_prefix(bytes)
462 .expect("byte slice should always be big enough")
463 .0
464 }
465
466 fn add_one_dynamic(length: usize) {
467 let padded_length = align_8(length);
468 let madt = vec![0xCC; length];
469
470 let data = {
471 let mut blob = Blob::new();
472 blob.add_raw(BlobStructureType::AcpiTable, &madt);
473 blob.complete()
474 };
475
476 assert_eq!(data.len() % 8, 0);
477
478 let header: Header = read(&data[..]);
479 let structure: StructureCount = read(&data[size_of::<Header>()..]);
480
481 let header_exp = Header {
482 structure_type: 0x00,
483 length: (size_of::<Header>() + size_of::<StructureCount>()) as u32,
484 };
485 let structure_exp = StructureCount {
486 total_structure_count: 2,
487 total_config_blob_size: (2 * size_of::<Header>()
488 + size_of::<StructureCount>()
489 + padded_length) as u32,
490 };
491
492 assert_eq!(header.structure_type, header_exp.structure_type);
493 assert_eq!(header.length, header_exp.length);
494 assert_eq!(
495 structure.total_structure_count,
496 structure_exp.total_structure_count
497 );
498 assert_eq!(
499 structure.total_config_blob_size,
500 structure_exp.total_config_blob_size
501 );
502
503 let header: Header = read(&data[size_of::<Header>() + size_of::<StructureCount>()..]);
504 let structure = &data[2 * size_of::<Header>() + size_of::<StructureCount>()..][..length];
505
506 let header_exp = Header {
507 structure_type: 0x16,
508 length: (size_of::<Header>() + padded_length) as u32,
509 };
510 let structure_exp = &madt[..];
511
512 assert_eq!(header.structure_type, header_exp.structure_type);
513 assert_eq!(header.length, header_exp.length);
514 assert_eq!(structure, structure_exp);
515 }
516
517 #[test]
518 fn add_none() {
519 let data = {
520 let blob = Blob::new();
521 blob.complete()
522 };
523
524 assert_eq!(data.len() % 8, 0);
525
526 let header: Header = read(&data[..]);
527 let structure: StructureCount = read(&data[size_of::<Header>()..]);
528
529 let header_exp = Header {
530 structure_type: 0x00,
531 length: (size_of::<Header>() + size_of::<StructureCount>()) as u32,
532 };
533 let structure_exp = StructureCount {
534 total_structure_count: 1,
535 total_config_blob_size: (size_of::<Header>() + size_of::<StructureCount>()) as u32,
536 };
537
538 assert_eq!(header.structure_type, header_exp.structure_type);
539 assert_eq!(header.length, header_exp.length);
540 assert_eq!(
541 structure.total_structure_count,
542 structure_exp.total_structure_count
543 );
544 assert_eq!(
545 structure.total_config_blob_size,
546 structure_exp.total_config_blob_size
547 );
548 }
549
550 #[test]
551 fn add_one_fixed() {
552 let biosinfo = BiosInformation {
553 bios_size_pages: 12345678,
554 flags: 1 << 31,
555 };
556
557 let data = {
558 let mut blob = Blob::new();
559 blob.add(&BiosInformation {
560 bios_size_pages: 12345678,
561 flags: 1 << 31,
562 });
563 blob.complete()
564 };
565
566 assert_eq!(data.len() % 8, 0);
567
568 let header: Header = read(&data[..]);
569 let structure: StructureCount = read(&data[size_of::<Header>()..]);
570
571 let header_exp = Header {
572 structure_type: 0x00,
573 length: (size_of::<Header>() + size_of::<StructureCount>()) as u32,
574 };
575 let structure_exp = StructureCount {
576 total_structure_count: 2,
577 total_config_blob_size: (2 * size_of::<Header>()
578 + size_of::<StructureCount>()
579 + size_of::<BiosInformation>()) as u32,
580 };
581
582 assert_eq!(header.structure_type, header_exp.structure_type);
583 assert_eq!(header.length, header_exp.length);
584 assert_eq!(
585 structure.total_structure_count,
586 structure_exp.total_structure_count
587 );
588 assert_eq!(
589 structure.total_config_blob_size,
590 structure_exp.total_config_blob_size
591 );
592
593 let header: Header = read(&data[size_of::<Header>() + size_of::<StructureCount>()..]);
594 let structure: BiosInformation =
595 read(&data[2 * size_of::<Header>() + size_of::<StructureCount>()..]);
596
597 let header_exp = Header {
598 structure_type: 0x01,
599 length: (size_of::<Header>() + size_of::<BiosInformation>()) as u32,
600 };
601
602 assert_eq!(header.structure_type, header_exp.structure_type);
603 assert_eq!(header.length, header_exp.length);
604 assert_eq!(structure.bios_size_pages, biosinfo.bios_size_pages);
605 assert_eq!(structure.flags, biosinfo.flags);
606 }
607
608 #[test]
609 fn add_one_dynamic_misaligned() {
610 add_one_dynamic(43);
611 }
612
613 #[test]
614 fn add_one_dynamic_aligned() {
615 add_one_dynamic(40);
616 }
617
618 #[test]
619 fn add_two() {
620 const LENGTH: usize = 93;
621 const PADDED_LENGTH: usize = 96;
622 let madt = vec![0xCC; LENGTH];
623 let procinfo = ProcessorInformation {
624 max_processor_count: 4,
625 processor_count: 3,
626 processors_per_virtual_socket: 2,
627 threads_per_processor: 1,
628 };
629
630 let data = {
631 let mut blob = Blob::new();
632 blob.add_raw(BlobStructureType::AcpiTable, &madt)
633 .add(&procinfo);
634 blob.complete()
635 };
636
637 assert_eq!(data.len() % 8, 0);
638
639 let header: Header = read(&data[..]);
640 let structure: StructureCount = read(&data[size_of::<Header>()..]);
641
642 let header_exp = Header {
643 structure_type: 0x00,
644 length: (size_of::<Header>() + size_of::<StructureCount>()) as u32,
645 };
646 let structure_exp = StructureCount {
647 total_structure_count: 3,
648 total_config_blob_size: (3 * size_of::<Header>()
649 + size_of::<StructureCount>()
650 + PADDED_LENGTH
651 + size_of::<ProcessorInformation>()) as u32,
652 };
653
654 assert_eq!(header.structure_type, header_exp.structure_type);
655 assert_eq!(header.length, header_exp.length);
656 assert_eq!(
657 structure.total_structure_count,
658 structure_exp.total_structure_count
659 );
660 assert_eq!(
661 structure.total_config_blob_size,
662 structure_exp.total_config_blob_size
663 );
664
665 let header: Header = read(&data[size_of::<Header>() + size_of::<StructureCount>()..]);
666 let structure = &data[2 * size_of::<Header>() + size_of::<StructureCount>()..][..LENGTH];
667 let padding = &data[2 * size_of::<Header>() + size_of::<StructureCount>() + LENGTH..]
668 [..PADDED_LENGTH - LENGTH];
669
670 let header_exp = Header {
671 structure_type: 0x16,
672 length: (size_of::<Header>() + PADDED_LENGTH) as u32,
673 };
674 let structure_exp = &madt[..];
675
676 assert_eq!(header.structure_type, header_exp.structure_type);
677 assert_eq!(header.length, header_exp.length);
678 assert_eq!(structure.as_bytes(), structure_exp.as_bytes());
679 assert_eq!(padding, &[0; PADDED_LENGTH - LENGTH]);
680
681 let header: Header =
682 read(&data[2 * size_of::<Header>() + size_of::<StructureCount>() + PADDED_LENGTH..]);
683 let structure: ProcessorInformation =
684 read(&data[3 * size_of::<Header>() + size_of::<StructureCount>() + PADDED_LENGTH..]);
685
686 let header_exp = Header {
687 structure_type: 0x13,
688 length: (size_of::<Header>() + size_of::<ProcessorInformation>()) as u32,
689 };
690
691 assert_eq!(header.structure_type, header_exp.structure_type);
692 assert_eq!(header.length, header_exp.length);
693 assert_eq!(structure.max_processor_count, procinfo.max_processor_count);
694 assert_eq!(structure.processor_count, procinfo.processor_count);
695 assert_eq!(
696 structure.processors_per_virtual_socket,
697 procinfo.processors_per_virtual_socket
698 );
699 assert_eq!(
700 structure.threads_per_processor,
701 procinfo.threads_per_processor
702 );
703 }
704}