stage1: implement e820 memory detection
This commit is contained in:
parent
b175190db1
commit
21d33b6047
3 changed files with 115 additions and 1 deletions
|
@ -1,4 +1,5 @@
|
|||
use core::ptr::{read, write_volatile};
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
|
||||
// XXX This doesn't emit proper debug symbols for assembly sources
|
||||
|
||||
|
@ -58,7 +59,7 @@ extern "C" {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Default)]
|
||||
#[derive(Clone, Default)]
|
||||
pub struct BiosIntRegs {
|
||||
pub eax: u32,
|
||||
pub ecx: u32,
|
||||
|
@ -84,6 +85,7 @@ pub unsafe fn do_bios_int(number: u8, mut regs: BiosIntRegs) -> BiosResult {
|
|||
// this might be mildly unsafe
|
||||
write_volatile(&mut __bios_int_number, number);
|
||||
let cf = __do_bios_int(&mut regs);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
if cf == 0 {
|
||||
Ok(regs)
|
||||
} else {
|
||||
|
|
|
@ -7,6 +7,8 @@ use core::panic::PanicInfo;
|
|||
mod asm;
|
||||
/// BIOS disk access utilities
|
||||
mod disk;
|
||||
/// E820 memory detection
|
||||
mod mem;
|
||||
|
||||
use crate::disk::{get_sector_size, read_lba};
|
||||
use asm::{do_bios_int, get_boot_drive, get_boot_lba, BiosIntRegs};
|
||||
|
|
110
stage1/src/mem.rs
Normal file
110
stage1/src/mem.rs
Normal file
|
@ -0,0 +1,110 @@
|
|||
use crate::asm::{do_bios_int, BiosIntRegs};
|
||||
use core::cmp::Ordering;
|
||||
use core::mem::size_of;
|
||||
|
||||
#[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.
|
||||
///
|
||||
/// ## 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 {
|
||||
let mut offset: u32 = 0;
|
||||
let mut count: usize = 0;
|
||||
debug_assert!((dest as *mut MemMapEntry as usize) < 0x10_0000);
|
||||
|
||||
loop {
|
||||
dest.as_mut().unwrap_unchecked().acpi30_ext = 1;
|
||||
let regs = BiosIntRegs {
|
||||
eax: 0xe820,
|
||||
ecx: size_of::<MemMapEntry>() as u32,
|
||||
edx: SMAP,
|
||||
ebx: offset,
|
||||
edi: ((dest as usize) % 0x10) as u32,
|
||||
es: ((dest 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 {
|
||||
dest.as_mut().unwrap_unchecked().acpi30_ext = 1;
|
||||
}
|
||||
if result.eax != SMAP {
|
||||
break;
|
||||
}
|
||||
count += 1;
|
||||
dest = dest.add(1);
|
||||
if result.ebx == 0 {
|
||||
break;
|
||||
} else {
|
||||
offset += result.ebx;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue