@@ -55,7 +55,10 @@ impl MemoryMapTag {
5555 self . entry_version
5656 }
5757
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.
5962 pub fn memory_areas ( & self ) -> & [ MemoryArea ] {
6063 // If this ever fails, we need to model this differently in this crate.
6164 assert_eq ! ( self . entry_size as usize , mem:: size_of:: <MemoryArea >( ) ) ;
@@ -74,7 +77,7 @@ impl TagTrait for MemoryMapTag {
7477 }
7578}
7679
77- /// A memory area entry descriptor .
80+ /// A descriptor for an available or taken area of physical memory .
7881#[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
7982#[ repr( C ) ]
8083pub struct MemoryArea {
@@ -284,9 +287,20 @@ impl AsBytes for EFIMemoryDesc {}
284287pub struct EFIMemoryMapTag {
285288 typ : TagTypeId ,
286289 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>.
287293 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.
288297 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 ] ,
290304}
291305
292306impl EFIMemoryMapTag {
@@ -308,20 +322,20 @@ impl EFIMemoryMapTag {
308322 BoxedDst :: new ( bytes. as_slice ( ) )
309323 }
310324
311- /// Return an iterator over ALL marked memory areas.
325+ /// Returns an iterator over the provided memory areas.
312326 ///
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 .
315329 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." ) ;
324336 }
337+
338+ EFIMemoryAreaIter :: new ( self )
325339 }
326340}
327341
@@ -330,30 +344,58 @@ impl TagTrait for EFIMemoryMapTag {
330344
331345 fn dst_size ( base_tag : & Tag ) -> usize {
332346 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
336348 }
337349}
338350
339- /// An iterator over ALL EFI memory areas.
351+ /// An iterator over the EFI memory areas emitting [`EFIMemoryDesc`] items .
340352#[ derive( Clone , Debug ) ]
341353pub 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 ,
345357 phantom : PhantomData < & ' a EFIMemoryDesc > ,
346358}
347359
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+
348374impl < ' a > Iterator for EFIMemoryAreaIter < ' a > {
349375 type Item = & ' a EFIMemoryDesc ;
350376 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 ;
357379 }
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
358400 }
359401}
0 commit comments