@@ -55,7 +55,10 @@ impl MemoryMapTag {
55
55
self . entry_version
56
56
}
57
57
58
- /// Return the slice with all memory areas.
58
+ /// Return the slice of the provided [`MemoryArea`]s.
59
+ ///
60
+ /// Usually, this should already reflect the memory consumed by the
61
+ /// code running this.
59
62
pub fn memory_areas ( & self ) -> & [ MemoryArea ] {
60
63
// If this ever fails, we need to model this differently in this crate.
61
64
assert_eq ! ( self . entry_size as usize , mem:: size_of:: <MemoryArea >( ) ) ;
@@ -74,7 +77,7 @@ impl TagTrait for MemoryMapTag {
74
77
}
75
78
}
76
79
77
- /// A memory area entry descriptor .
80
+ /// A descriptor for an available or taken area of physical memory .
78
81
#[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
79
82
#[ repr( C ) ]
80
83
pub struct MemoryArea {
@@ -284,9 +287,20 @@ impl AsBytes for EFIMemoryDesc {}
284
287
pub struct EFIMemoryMapTag {
285
288
typ : TagTypeId ,
286
289
size : u32 ,
290
+ /// Most likely a little more than the size of a [`EFIMemoryDesc`].
291
+ /// This is always the reference, and `size_of` never.
292
+ /// See <https://github.com/tianocore/edk2/blob/7142e648416ff5d3eac6c6d607874805f5de0ca8/MdeModulePkg/Core/PiSmmCore/Page.c#L1059>.
287
293
desc_size : u32 ,
294
+ /// Version of the tag. The spec leaves it open to extend the memory
295
+ /// descriptor in the future. However, this never happened so far.
296
+ /// At the moment, only version "1" is supported.
288
297
desc_version : u32 ,
289
- descs : [ EFIMemoryDesc ] ,
298
+ /// Contains the UEFI memory map.
299
+ ///
300
+ /// To follow the UEFI spec and to allow extendability for future UEFI
301
+ /// revisions, the length is a multiple of `desc_size` and not a multiple
302
+ /// of `size_of::<EfiMemoryDescriptor>()`.
303
+ memory_map : [ u8 ] ,
290
304
}
291
305
292
306
impl EFIMemoryMapTag {
@@ -308,20 +322,20 @@ impl EFIMemoryMapTag {
308
322
BoxedDst :: new ( bytes. as_slice ( ) )
309
323
}
310
324
311
- /// Return an iterator over ALL marked memory areas.
325
+ /// Returns an iterator over the provided memory areas.
312
326
///
313
- /// This differs from `MemoryMapTag` as for UEFI, the OS needs some non-
314
- /// available memory areas for tables and such .
327
+ /// Usually, this should already reflect the memory consumed by the
328
+ /// code running this .
315
329
pub fn memory_areas ( & self ) -> EFIMemoryAreaIter {
316
- let self_ptr = self as * const EFIMemoryMapTag ;
317
- let start_area = ( & self . descs [ 0 ] ) as * const EFIMemoryDesc ;
318
- EFIMemoryAreaIter {
319
- current_area : start_area as u64 ,
320
- // NOTE: `last_area` is only a bound, it doesn't necessarily point exactly to the last element
321
- last_area : ( self_ptr as * const ( ) as u64 + self . size as u64 ) ,
322
- entry_size : self . desc_size ,
323
- phantom : PhantomData ,
330
+ // If this ever fails, this needs to be refactored in a joint-effort
331
+ // with the uefi-rs project to have all corresponding typings.
332
+ assert_eq ! ( self . desc_version, EFIMemoryDesc :: VERSION ) ;
333
+
334
+ if self . desc_size as usize > mem:: size_of :: < EFIMemoryDesc > ( ) {
335
+ log:: debug!( "desc_size larger than expected typing. We might miss a few fields." ) ;
324
336
}
337
+
338
+ EFIMemoryAreaIter :: new ( self )
325
339
}
326
340
}
327
341
@@ -330,30 +344,58 @@ impl TagTrait for EFIMemoryMapTag {
330
344
331
345
fn dst_size ( base_tag : & Tag ) -> usize {
332
346
assert ! ( base_tag. size as usize >= EFI_METADATA_SIZE ) ;
333
- let size = base_tag. size as usize - EFI_METADATA_SIZE ;
334
- assert_eq ! ( size % mem:: size_of:: <EFIMemoryDesc >( ) , 0 ) ;
335
- size / mem:: size_of :: < EFIMemoryDesc > ( )
347
+ base_tag. size as usize - EFI_METADATA_SIZE
336
348
}
337
349
}
338
350
339
- /// An iterator over ALL EFI memory areas.
351
+ /// An iterator over the EFI memory areas emitting [`EFIMemoryDesc`] items .
340
352
#[ derive( Clone , Debug ) ]
341
353
pub struct EFIMemoryAreaIter < ' a > {
342
- current_area : u64 ,
343
- last_area : u64 ,
344
- entry_size : u32 ,
354
+ mmap_tag : & ' a EFIMemoryMapTag ,
355
+ i : usize ,
356
+ entries : usize ,
345
357
phantom : PhantomData < & ' a EFIMemoryDesc > ,
346
358
}
347
359
360
+ impl < ' a > EFIMemoryAreaIter < ' a > {
361
+ fn new ( mmap_tag : & ' a EFIMemoryMapTag ) -> Self {
362
+ let desc_size = mmap_tag. desc_size as usize ;
363
+ let mmap_len = mmap_tag. memory_map . len ( ) ;
364
+ assert_eq ! ( mmap_len % desc_size, 0 , "memory map length must be a multiple of `desc_size` by definition. The MBI seems to be corrupt." ) ;
365
+ Self {
366
+ mmap_tag,
367
+ i : 0 ,
368
+ entries : mmap_len / desc_size,
369
+ phantom : PhantomData ,
370
+ }
371
+ }
372
+ }
373
+
348
374
impl < ' a > Iterator for EFIMemoryAreaIter < ' a > {
349
375
type Item = & ' a EFIMemoryDesc ;
350
376
fn next ( & mut self ) -> Option < & ' a EFIMemoryDesc > {
351
- if self . current_area > self . last_area {
352
- None
353
- } else {
354
- let area = unsafe { & * ( self . current_area as * const EFIMemoryDesc ) } ;
355
- self . current_area += self . entry_size as u64 ;
356
- Some ( area)
377
+ if self . i >= self . entries {
378
+ return None ;
357
379
}
380
+
381
+ let desc = unsafe {
382
+ self . mmap_tag
383
+ . memory_map
384
+ . as_ptr ( )
385
+ . add ( self . i * self . mmap_tag . desc_size as usize )
386
+ . cast :: < EFIMemoryDesc > ( )
387
+ . as_ref ( )
388
+ . unwrap ( )
389
+ } ;
390
+
391
+ self . i += 1 ;
392
+
393
+ Some ( desc)
394
+ }
395
+ }
396
+
397
+ impl < ' a > ExactSizeIterator for EFIMemoryAreaIter < ' a > {
398
+ fn len ( & self ) -> usize {
399
+ self . entries
358
400
}
359
401
}
0 commit comments