@@ -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 ) ) ) ]
428446mod 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