You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
2.9 KiB
Rust

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)]
pub struct MemMapEntry {
start: u64,
len: u64,
typ: u32,
acpi30_ext: u32,
}
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(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 {
pos.as_mut().unwrap_unchecked().acpi30_ext = 1;
let regs = BiosIntRegs {
eax: 0xe820,
ecx: size_of::<MemMapEntry>() as u32,
edx: SMAP,
ebx: offset,
edi: ((pos as usize) % 0x10) as u32,
es: ((pos as usize) / 0x10) as u16,
..Default::default()
};
let result = match do_bios_int(0x15, regs) {
Ok(regs) => regs,
Err(_) => break,
};
if result.ecx < size_of::<MemMapEntry>() as u32 {
pos.as_mut().unwrap_unchecked().acpi30_ext = 1;
}
if result.eax != SMAP {
break;
}
count += 1;
pos = pos.add(1);
if result.ebx == 0 {
break;
} else {
offset += result.ebx;
}
}
let mmap_mut = slice_from_raw_parts_mut(dest, count)
.as_mut()
.unwrap_unchecked();
mmap_mut.sort_unstable();
count
}
impl MemMapEntry {
pub fn start(&self) -> u64 {
self.start
}
pub fn len(&self) -> u64 {
self.len
}
pub fn end(&self) -> u64 {
self.start() + self.len()
}
pub fn contains_raw<T>(&self, addr: *const T) -> bool {
let addr = addr as u64;
addr >= self.start && addr < (self.start + self.len)
}
pub fn type_desc(&self) -> &'static str {
if self.acpi30_ext & 1 == 0 {
return "ignored";
}
match self.typ {
1 => "available",
2 => "reserved",
3 => "ACPI reclaimable",
4 => "ACPI NVS",
5 => "bad memory",
_ => "unknown",
}
}
pub fn is_available(&self) -> bool {
self.typ == 1 && ((self.acpi30_ext & 1) == 1)
}
}
impl PartialOrd for MemMapEntry {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.start.partial_cmp(&other.start)
}
}
impl Ord for MemMapEntry {
fn cmp(&self, other: &Self) -> Ordering {
self.start.cmp(&other.start)
}
}