@@ -281,7 +281,8 @@ const EFI_METADATA_SIZE: usize = mem::size_of::<TagTypeId>() + 3 * mem::size_of:
281
281
#[ cfg( feature = "builder" ) ]
282
282
impl AsBytes for EFIMemoryDesc { }
283
283
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.
285
286
#[ derive( ptr_meta:: Pointee , Debug , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
286
287
#[ repr( C ) ]
287
288
pub struct EFIMemoryMapTag {
@@ -308,18 +309,40 @@ impl EFIMemoryMapTag {
308
309
/// Create a new EFI memory map tag with the given memory descriptors.
309
310
/// Version and size can't be set because you're passing a slice of
310
311
/// 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) ;
319
321
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) ) ;
321
325
}
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)
323
346
}
324
347
325
348
/// Returns an iterator over the provided memory areas.
@@ -401,3 +424,38 @@ impl<'a> ExactSizeIterator for EFIMemoryAreaIter<'a> {
401
424
self . entries
402
425
}
403
426
}
427
+
428
+ #[ cfg( test) ]
429
+ mod tests {
430
+ use super :: * ;
431
+
432
+ #[ test]
433
+ fn construction_and_parsing ( ) {
434
+ let descs = [
435
+ EFIMemoryDesc {
436
+ ty : EFIMemoryAreaType :: CONVENTIONAL ,
437
+ phys_start : 0x1000 ,
438
+ virt_start : 0x1000 ,
439
+ page_count : 1 ,
440
+ att : Default :: default ( ) ,
441
+ } ,
442
+ EFIMemoryDesc {
443
+ ty : EFIMemoryAreaType :: LOADER_DATA ,
444
+ phys_start : 0x2000 ,
445
+ virt_start : 0x2000 ,
446
+ page_count : 3 ,
447
+ att : Default :: default ( ) ,
448
+ } ,
449
+ ] ;
450
+ let efi_mmap_tag = EFIMemoryMapTag :: new_from_descs ( & descs) ;
451
+
452
+ assert_eq ! ( efi_mmap_tag. desc_size, 48 /* 40 + 8 */ ) ;
453
+
454
+ let mut iter = efi_mmap_tag. memory_areas ( ) ;
455
+
456
+ assert_eq ! ( iter. next( ) , Some ( & descs[ 0 ] ) ) ;
457
+ assert_eq ! ( iter. next( ) , Some ( & descs[ 1 ] ) ) ;
458
+
459
+ assert_eq ! ( iter. next( ) , None ) ;
460
+ }
461
+ }
0 commit comments