Skip to content

Commit d211e48

Browse files
committed
multiboot2: add unit test for uefi memory map with real-world data
1 parent 2df795f commit d211e48

File tree

2 files changed

+146
-4
lines changed

2 files changed

+146
-4
lines changed

multiboot2/Changelog.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# CHANGELOG for crate `multiboot2`
22

3-
## 0.20.1
3+
## 0.20.1 (2024-05-26)
44

55
- fixed the handling of `EFIMemoryMapTag` and `EFIMemoryAreaIter`
66
- **BREAKING** Fixed wrong creation of `EFIMemoryMapTag`.

multiboot2/src/memory_map.rs

+145-3
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,9 @@ pub struct EFIMemoryMapTag {
302302
/// To follow the UEFI spec and to allow extendability for future UEFI
303303
/// revisions, the length is a multiple of `desc_size` and not a multiple
304304
/// of `size_of::<EfiMemoryDescriptor>()`.
305+
///
306+
/// This tag is properly `align_of::<EFIMemoryDesc>` aligned, if the tag
307+
/// itself is also 8 byte aligned, which every sane MBI guarantees.
305308
memory_map: [u8],
306309
}
307310

@@ -311,6 +314,9 @@ impl EFIMemoryMapTag {
311314
/// Version and size can't be set because you're passing a slice of
312315
/// EFIMemoryDescs, not the ones you might have gotten from the firmware.
313316
pub fn new_from_descs(descs: &[EFIMemoryDesc]) -> BoxedDst<Self> {
317+
// TODO replace this EfiMemorydesc::uefi_desc_size() in the next uefi_raw
318+
// release.
319+
314320
let size_base = mem::size_of::<EFIMemoryDesc>();
315321
// Taken from https://github.com/tianocore/edk2/blob/7142e648416ff5d3eac6c6d607874805f5de0ca8/MdeModulePkg/Core/PiSmmCore/Page.c#L1059
316322
let desc_size_diff = mem::size_of::<u64>() - size_base % mem::size_of::<u64>();
@@ -337,6 +343,12 @@ impl EFIMemoryMapTag {
337343
pub fn new_from_map(desc_size: u32, desc_version: u32, efi_mmap: &[u8]) -> BoxedDst<Self> {
338344
assert!(desc_size > 0);
339345
assert_eq!(efi_mmap.len() % desc_size as usize, 0);
346+
assert_eq!(
347+
efi_mmap
348+
.as_ptr()
349+
.align_offset(mem::align_of::<EFIMemoryDesc>()),
350+
0
351+
);
340352
let bytes = [
341353
&desc_size.to_le_bytes(),
342354
&desc_version.to_le_bytes(),
@@ -354,6 +366,12 @@ impl EFIMemoryMapTag {
354366
// If this ever fails, this needs to be refactored in a joint-effort
355367
// with the uefi-rs project to have all corresponding typings.
356368
assert_eq!(self.desc_version, EFIMemoryDesc::VERSION);
369+
assert_eq!(
370+
self.memory_map
371+
.as_ptr()
372+
.align_offset(mem::align_of::<EFIMemoryDesc>()),
373+
0
374+
);
357375

358376
if self.desc_size as usize > mem::size_of::<EFIMemoryDesc>() {
359377
log::debug!("desc_size larger than expected typing. We might miss a few fields.");
@@ -424,13 +442,12 @@ impl<'a> ExactSizeIterator for EFIMemoryAreaIter<'a> {
424442
}
425443
}
426444

427-
#[cfg(test)]
445+
#[cfg(all(test, feature = "builder", not(miri)))]
428446
mod tests {
429447
use super::*;
448+
use std::mem::size_of;
430449

431450
#[test]
432-
#[cfg(feature = "builder")]
433-
#[cfg_attr(miri, ignore)]
434451
fn construction_and_parsing() {
435452
let descs = [
436453
EFIMemoryDesc {
@@ -459,4 +476,129 @@ mod tests {
459476

460477
assert_eq!(iter.next(), None);
461478
}
479+
480+
/// Tests the EFI memory map parsing using a real world efi memory map.
481+
/// This is taken from the uefi-rs repository. See
482+
/// <https://github.com/rust-osdev/uefi-rs/pull/1175> for more info.
483+
#[test]
484+
fn test_real_data() {
485+
const DESC_SIZE: u32 = 48;
486+
const DESC_VERSION: u32 = 1;
487+
/// Sample with 10 entries of a real UEFI memory map extracted from our
488+
/// UEFI test runner.
489+
const MMAP_RAW: [u64; 60] = [
490+
3, 0, 0, 1, 15, 0, 7, 4096, 0, 134, 15, 0, 4, 552960, 0, 1, 15, 0, 7, 557056, 0, 24,
491+
15, 0, 7, 1048576, 0, 1792, 15, 0, 10, 8388608, 0, 8, 15, 0, 7, 8421376, 0, 3, 15, 0,
492+
10, 8433664, 0, 1, 15, 0, 7, 8437760, 0, 4, 15, 0, 10, 8454144, 0, 240, 15, 0,
493+
];
494+
let buf = MMAP_RAW;
495+
let buf = unsafe {
496+
core::slice::from_raw_parts(buf.as_ptr().cast::<u8>(), buf.len() * size_of::<u64>())
497+
};
498+
let tag = EFIMemoryMapTag::new_from_map(DESC_SIZE, DESC_VERSION, buf);
499+
let entries = tag.memory_areas().copied().collect::<alloc::vec::Vec<_>>();
500+
let expected = [
501+
EFIMemoryDesc {
502+
ty: EFIMemoryAreaType::BOOT_SERVICES_CODE,
503+
phys_start: 0x0,
504+
virt_start: 0x0,
505+
page_count: 0x1,
506+
att: EFIMemoryAttribute::UNCACHEABLE
507+
| EFIMemoryAttribute::WRITE_COMBINE
508+
| EFIMemoryAttribute::WRITE_THROUGH
509+
| EFIMemoryAttribute::WRITE_BACK,
510+
},
511+
EFIMemoryDesc {
512+
ty: EFIMemoryAreaType::CONVENTIONAL,
513+
phys_start: 0x1000,
514+
virt_start: 0x0,
515+
page_count: 0x86,
516+
att: EFIMemoryAttribute::UNCACHEABLE
517+
| EFIMemoryAttribute::WRITE_COMBINE
518+
| EFIMemoryAttribute::WRITE_THROUGH
519+
| EFIMemoryAttribute::WRITE_BACK,
520+
},
521+
EFIMemoryDesc {
522+
ty: EFIMemoryAreaType::BOOT_SERVICES_DATA,
523+
phys_start: 0x87000,
524+
virt_start: 0x0,
525+
page_count: 0x1,
526+
att: EFIMemoryAttribute::UNCACHEABLE
527+
| EFIMemoryAttribute::WRITE_COMBINE
528+
| EFIMemoryAttribute::WRITE_THROUGH
529+
| EFIMemoryAttribute::WRITE_BACK,
530+
},
531+
EFIMemoryDesc {
532+
ty: EFIMemoryAreaType::CONVENTIONAL,
533+
phys_start: 0x88000,
534+
virt_start: 0x0,
535+
page_count: 0x18,
536+
att: EFIMemoryAttribute::UNCACHEABLE
537+
| EFIMemoryAttribute::WRITE_COMBINE
538+
| EFIMemoryAttribute::WRITE_THROUGH
539+
| EFIMemoryAttribute::WRITE_BACK,
540+
},
541+
EFIMemoryDesc {
542+
ty: EFIMemoryAreaType::CONVENTIONAL,
543+
phys_start: 0x100000,
544+
virt_start: 0x0,
545+
page_count: 0x700,
546+
att: EFIMemoryAttribute::UNCACHEABLE
547+
| EFIMemoryAttribute::WRITE_COMBINE
548+
| EFIMemoryAttribute::WRITE_THROUGH
549+
| EFIMemoryAttribute::WRITE_BACK,
550+
},
551+
EFIMemoryDesc {
552+
ty: EFIMemoryAreaType::ACPI_NON_VOLATILE,
553+
phys_start: 0x800000,
554+
virt_start: 0x0,
555+
page_count: 0x8,
556+
att: EFIMemoryAttribute::UNCACHEABLE
557+
| EFIMemoryAttribute::WRITE_COMBINE
558+
| EFIMemoryAttribute::WRITE_THROUGH
559+
| EFIMemoryAttribute::WRITE_BACK,
560+
},
561+
EFIMemoryDesc {
562+
ty: EFIMemoryAreaType::CONVENTIONAL,
563+
phys_start: 0x808000,
564+
virt_start: 0x0,
565+
page_count: 0x3,
566+
att: EFIMemoryAttribute::UNCACHEABLE
567+
| EFIMemoryAttribute::WRITE_COMBINE
568+
| EFIMemoryAttribute::WRITE_THROUGH
569+
| EFIMemoryAttribute::WRITE_BACK,
570+
},
571+
EFIMemoryDesc {
572+
ty: EFIMemoryAreaType::ACPI_NON_VOLATILE,
573+
phys_start: 0x80b000,
574+
virt_start: 0x0,
575+
page_count: 0x1,
576+
att: EFIMemoryAttribute::UNCACHEABLE
577+
| EFIMemoryAttribute::WRITE_COMBINE
578+
| EFIMemoryAttribute::WRITE_THROUGH
579+
| EFIMemoryAttribute::WRITE_BACK,
580+
},
581+
EFIMemoryDesc {
582+
ty: EFIMemoryAreaType::CONVENTIONAL,
583+
phys_start: 0x80c000,
584+
virt_start: 0x0,
585+
page_count: 0x4,
586+
att: EFIMemoryAttribute::UNCACHEABLE
587+
| EFIMemoryAttribute::WRITE_COMBINE
588+
| EFIMemoryAttribute::WRITE_THROUGH
589+
| EFIMemoryAttribute::WRITE_BACK,
590+
},
591+
EFIMemoryDesc {
592+
ty: EFIMemoryAreaType::ACPI_NON_VOLATILE,
593+
phys_start: 0x810000,
594+
virt_start: 0x0,
595+
page_count: 0xf0,
596+
att: EFIMemoryAttribute::UNCACHEABLE
597+
| EFIMemoryAttribute::WRITE_COMBINE
598+
| EFIMemoryAttribute::WRITE_THROUGH
599+
| EFIMemoryAttribute::WRITE_BACK,
600+
},
601+
];
602+
assert_eq!(entries.as_slice(), &expected);
603+
}
462604
}

0 commit comments

Comments
 (0)