@@ -281,7 +281,8 @@ const EFI_METADATA_SIZE: usize = mem::size_of::<TagTypeId>() + 3 * mem::size_of:
281281#[ cfg( feature = "builder" ) ]
282282impl AsBytes for EFIMemoryDesc { }
283283
284- /// EFI memory map tag. The [`EFIMemoryDesc`] follows the EFI specification.
284+ /// EFI memory map tag. The embedded [`EFIMemoryDesc`]s follows the EFI
285+ /// specification.
285286#[ derive( ptr_meta:: Pointee , Debug , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
286287#[ repr( C ) ]
287288pub struct EFIMemoryMapTag {
@@ -308,18 +309,40 @@ impl EFIMemoryMapTag {
308309 /// Create a new EFI memory map tag with the given memory descriptors.
309310 /// Version and size can't be set because you're passing a slice of
310311 /// EFIMemoryDescs, not the ones you might have gotten from the firmware.
311- pub fn new ( descs : & [ EFIMemoryDesc ] ) -> BoxedDst < Self > {
312- // update this when updating EFIMemoryDesc
313- const MEMORY_DESCRIPTOR_VERSION : u32 = 1 ;
314- let mut bytes = [
315- ( mem:: size_of :: < EFIMemoryDesc > ( ) as u32 ) . to_le_bytes ( ) ,
316- MEMORY_DESCRIPTOR_VERSION . to_le_bytes ( ) ,
317- ]
318- . concat ( ) ;
312+ pub fn new_from_descs ( descs : & [ EFIMemoryDesc ] ) -> BoxedDst < Self > {
313+ let size_base = mem:: size_of :: < EFIMemoryDesc > ( ) ;
314+ // Taken from https://github.com/tianocore/edk2/blob/7142e648416ff5d3eac6c6d607874805f5de0ca8/MdeModulePkg/Core/PiSmmCore/Page.c#L1059
315+ let desc_size_diff = mem:: size_of :: < u64 > ( ) - size_base % mem:: size_of :: < u64 > ( ) ;
316+ let desc_size = size_base + desc_size_diff;
317+
318+ assert ! ( desc_size >= size_base) ;
319+
320+ let mut efi_mmap = alloc:: vec:: Vec :: with_capacity ( descs. len ( ) * desc_size) ;
319321 for desc in descs {
320- bytes. extend ( desc. as_bytes ( ) ) ;
322+ efi_mmap. extend ( desc. as_bytes ( ) ) ;
323+ // fill with zeroes
324+ efi_mmap. extend ( [ 0 ] . repeat ( desc_size_diff) ) ;
321325 }
322- BoxedDst :: new ( bytes. as_slice ( ) )
326+
327+ Self :: new_from_map (
328+ desc_size as u32 ,
329+ EFIMemoryDesc :: VERSION ,
330+ efi_mmap. as_slice ( ) ,
331+ )
332+ }
333+
334+ #[ cfg( feature = "builder" ) ]
335+ /// Create a new EFI memory map tag from the given EFI memory map.
336+ pub fn new_from_map ( desc_size : u32 , desc_version : u32 , efi_mmap : & [ u8 ] ) -> BoxedDst < Self > {
337+ assert ! ( desc_size > 0 ) ;
338+ assert_eq ! ( efi_mmap. len( ) % desc_size as usize , 0 ) ;
339+ let bytes = [
340+ & desc_size. to_le_bytes ( ) ,
341+ & desc_version. to_le_bytes ( ) ,
342+ efi_mmap,
343+ ]
344+ . concat ( ) ;
345+ BoxedDst :: new ( & bytes)
323346 }
324347
325348 /// Returns an iterator over the provided memory areas.
@@ -399,3 +422,38 @@ impl<'a> ExactSizeIterator for EFIMemoryAreaIter<'a> {
399422 self . entries
400423 }
401424}
425+
426+ #[ cfg( test) ]
427+ mod tests {
428+ use super :: * ;
429+
430+ #[ test]
431+ fn construction_and_parsing ( ) {
432+ let descs = [
433+ EFIMemoryDesc {
434+ ty : EFIMemoryAreaType :: CONVENTIONAL ,
435+ phys_start : 0x1000 ,
436+ virt_start : 0x1000 ,
437+ page_count : 1 ,
438+ att : Default :: default ( ) ,
439+ } ,
440+ EFIMemoryDesc {
441+ ty : EFIMemoryAreaType :: LOADER_DATA ,
442+ phys_start : 0x2000 ,
443+ virt_start : 0x2000 ,
444+ page_count : 3 ,
445+ att : Default :: default ( ) ,
446+ } ,
447+ ] ;
448+ let efi_mmap_tag = EFIMemoryMapTag :: new_from_descs ( & descs) ;
449+
450+ assert_eq ! ( efi_mmap_tag. desc_size, 48 /* 40 + 8 */ ) ;
451+
452+ let mut iter = efi_mmap_tag. memory_areas ( ) ;
453+
454+ assert_eq ! ( iter. next( ) , Some ( & descs[ 0 ] ) ) ;
455+ assert_eq ! ( iter. next( ) , Some ( & descs[ 1 ] ) ) ;
456+
457+ assert_eq ! ( iter. next( ) , None ) ;
458+ }
459+ }
0 commit comments