Prechádzať zdrojové kódy

multiboot2: Fix EFI Memory Map 'last_area' calculation

Correct EFI 'last_area' calculation so it correctly describes the greatest possible starting
address of the last record.

(Previously, iterating the EFI Memory map resulted in a superfluous entry as it ran over the next tag)

This revision also cleans up the E820/EFI parsing to use 0-length arrays for the records
and to faciliate a more natural 'sizeof' operation on the Multiboot2 tag.
Alex Olson 2 rokov pred
rodič
commit
ec1847842f
2 zmenil súbory, kde vykonal 23 pridanie a 8 odobranie
  1. 12 2
      multiboot2/src/lib.rs
  2. 11 6
      multiboot2/src/memory_map.rs

+ 12 - 2
multiboot2/src/lib.rs

@@ -1415,13 +1415,23 @@ mod tests {
         assert!(efi_mmap.is_none());
     }
 
+    #[test]
+    /// Compile time test for `MemoryMapTag`.
+    fn e820_memory_map_tag_size() {
+        use super::MemoryMapTag;
+        unsafe {
+            // `MemoryMapTag` is 16 bytes without the 1st entry
+            core::mem::transmute::<[u8; 16], MemoryMapTag>([0u8; 16]);
+        }
+    }
+
     #[test]
     /// Compile time test for `EFIMemoryMapTag`.
     fn efi_memory_map_tag_size() {
         use super::EFIMemoryMapTag;
         unsafe {
-            // `EFIMemoryMapTag` is 16 bytes + `EFIMemoryDesc` is 40 bytes.
-            core::mem::transmute::<[u8; 56], EFIMemoryMapTag>([0u8; 56]);
+            // `EFIMemoryMapTag` is 16 bytes without the 1st entry
+            core::mem::transmute::<[u8; 16], EFIMemoryMapTag>([0u8; 16]);
         }
     }
 }

+ 11 - 6
multiboot2/src/memory_map.rs

@@ -18,7 +18,7 @@ pub struct MemoryMapTag {
     size: u32,
     entry_size: u32,
     entry_version: u32,
-    first_area: MemoryArea,
+    first_area: [MemoryArea; 0],
 }
 
 impl MemoryMapTag {
@@ -31,10 +31,13 @@ impl MemoryMapTag {
     /// Return an iterator over all marked memory areas.
     pub fn all_memory_areas(&self) -> impl Iterator<Item = &MemoryArea> {
         let self_ptr = self as *const MemoryMapTag;
-        let start_area = (&self.first_area) as *const MemoryArea;
+        let start_area = self.first_area.as_ptr();
+
         MemoryAreaIter {
             current_area: start_area as u64,
-            last_area: (self_ptr as u64 + (self.size - self.entry_size) as u64),
+            // NOTE: `last_area` is only a bound, it doesn't necessarily point exactly to the last element
+            last_area: (self_ptr as u64
+                + (self.size as u64 - core::mem::size_of::<MemoryMapTag>() as u64)),
             entry_size: self.entry_size,
             phantom: PhantomData,
         }
@@ -127,7 +130,7 @@ pub struct EFIMemoryMapTag {
     size: u32,
     desc_size: u32,
     desc_version: u32,
-    first_desc: EFIMemoryDesc,
+    first_desc: [EFIMemoryDesc; 0],
 }
 
 impl EFIMemoryMapTag {
@@ -137,10 +140,12 @@ impl EFIMemoryMapTag {
     /// available memory areas for tables and such.
     pub fn memory_areas(&self) -> EFIMemoryAreaIter {
         let self_ptr = self as *const EFIMemoryMapTag;
-        let start_area = (&self.first_desc) as *const EFIMemoryDesc;
+        let start_area = self.first_desc.as_ptr();
         EFIMemoryAreaIter {
             current_area: start_area as u64,
-            last_area: (self_ptr as u64 + self.size as u64),
+            // NOTE: `last_area` is only a bound, it doesn't necessarily point exactly to the last element
+            last_area: (self_ptr as u64
+                + (self.size as u64 - core::mem::size_of::<EFIMemoryMapTag>() as u64)),
             entry_size: self.desc_size,
             phantom: PhantomData,
         }