diff --git a/stage1/src/mem.rs b/stage1/src/mem.rs index e585579..dca48ca 100644 --- a/stage1/src/mem.rs +++ b/stage1/src/mem.rs @@ -1,6 +1,7 @@ use crate::asm::{do_bios_int, BiosIntRegs}; use core::cmp::Ordering; use core::mem::size_of; +use core::ptr::slice_from_raw_parts_mut; #[derive(Eq, PartialEq)] #[repr(C)] @@ -14,26 +15,28 @@ pub struct MemMapEntry { const SMAP: u32 = 0x534d4150; /// Use int15/e820 to detect the entire installed system memory. +/// The entries are sorted by ascending start address. /// /// ## Safety /// /// `dest` must be aligned to at least 8 bytes, accessible from real mode, /// and have enough capacity to store the entire memory map. In practice, /// we use a 64 K segment, which should be way more than sufficient. -pub unsafe fn read_bios_mmap(mut dest: *mut MemMapEntry) -> usize { +pub unsafe fn read_bios_mmap(dest: *mut MemMapEntry) -> usize { let mut offset: u32 = 0; let mut count: usize = 0; debug_assert!((dest as *mut MemMapEntry as usize) < 0x10_0000); + let mut pos = dest; loop { - dest.as_mut().unwrap_unchecked().acpi30_ext = 1; + pos.as_mut().unwrap_unchecked().acpi30_ext = 1; let regs = BiosIntRegs { eax: 0xe820, ecx: size_of::() as u32, edx: SMAP, ebx: offset, - edi: ((dest as usize) % 0x10) as u32, - es: ((dest as usize) / 0x10) as u16, + edi: ((pos as usize) % 0x10) as u32, + es: ((pos as usize) / 0x10) as u16, ..Default::default() }; let result = match do_bios_int(0x15, regs) { @@ -42,13 +45,13 @@ pub unsafe fn read_bios_mmap(mut dest: *mut MemMapEntry) -> usize { }; if result.ecx < size_of::() as u32 { - dest.as_mut().unwrap_unchecked().acpi30_ext = 1; + pos.as_mut().unwrap_unchecked().acpi30_ext = 1; } if result.eax != SMAP { break; } count += 1; - dest = dest.add(1); + pos = pos.add(1); if result.ebx == 0 { break; } else { @@ -56,6 +59,11 @@ pub unsafe fn read_bios_mmap(mut dest: *mut MemMapEntry) -> usize { } } + let mmap_mut = slice_from_raw_parts_mut(dest, count) + .as_mut() + .unwrap_unchecked(); + mmap_mut.sort_unstable(); + count }