aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTianhao Wang <shrik3@mailbox.org>2024-05-29 19:53:52 +0200
committerTianhao Wang <shrik3@mailbox.org>2024-06-11 15:17:11 +0200
commitcd658673a35df8b0da3551e819e26d35c18b89f2 (patch)
tree74c209b519290eb43545e800b88ddf9dfa796a7a
parent9cf85e88211512b0410f9bb9f2f19ea4ce9a8190 (diff)
mm: add stack based PMA
use 8MiB reserved array to manage up to 4GiB of physical memory (4K Pages only) Signed-off-by: Tianhao Wang <shrik3@mailbox.org>
-rw-r--r--boot/startup-x86_64.s7
-rw-r--r--defs/x86_64-linker.ld11
-rw-r--r--src/defs.rs59
-rw-r--r--src/lib.rs28
-rw-r--r--src/machine/multiboot.rs10
-rw-r--r--src/mm/heap_allocator.rs1
-rw-r--r--src/mm/mod.rs51
-rw-r--r--src/mm/pma.rs99
8 files changed, 199 insertions, 67 deletions
diff --git a/boot/startup-x86_64.s b/boot/startup-x86_64.s
index 6392d0f..a8b44c2 100644
--- a/boot/startup-x86_64.s
+++ b/boot/startup-x86_64.s
@@ -186,3 +186,10 @@ pml4:
pdp:
resb 4096
alignb 4096
+
+; reserve 8MiB for frame alloc.
+; (see linker file)
+[SECTION .global_free_page_stack]
+free_page_stack:
+ resb 8388608
+ alignb 4096
diff --git a/defs/x86_64-linker.ld b/defs/x86_64-linker.ld
index 39d8876..ac4a86c 100644
--- a/defs/x86_64-linker.ld
+++ b/defs/x86_64-linker.ld
@@ -84,5 +84,16 @@ SECTIONS
}
. = ALIGN(4096);
+ /* reserve space for a premitive stack based physical frame allocator */
+ /* each frame is 4KiB in size and has a 64bit (physical) address. e.g. */
+ /* for every 1 GiB physical memory we need 2 MiB space reserved for the */
+ /* free stack. For a easier bootstraping we are using a fix-sized stack */
+ /* array. Currently using 4GiB, therefore reserve 8MiB. */
+ PROVIDE (___FREE_PAGE_STACK__ = .);
+ .global_free_page_stack ALIGN(4096) (NOLOAD) :
+ {
+ *("..global_free_page_stack")
+ }
+ . = ALIGN(4096);
PROVIDE (___KERNEL_END__ = .);
}
diff --git a/src/defs.rs b/src/defs.rs
index cec17c9..3724c41 100644
--- a/src/defs.rs
+++ b/src/defs.rs
@@ -1,16 +1,59 @@
+// exported symbols from asm/linker.
+// They are always unsafe.
+extern "C" {
+ fn ___KERNEL_START__();
+ fn ___KERNEL_END__();
+ fn ___BSS_START__();
+ fn ___BSS_END__();
+}
+
+pub fn pmap_kernel_start() -> u64 {
+ return ___KERNEL_START__ as u64;
+}
+
+pub fn pmap_kernel_end() -> u64 {
+ return ___KERNEL_END__ as u64;
+}
+pub fn pmap_bss_start() -> u64 {
+ return ___BSS_START__ as u64;
+}
+
+pub fn pmap_bss_end() -> u64 {
+ return ___BSS_END__ as u64;
+}
+
pub struct Mem;
pub struct VAddr(u64);
+#[derive(Debug)]
+pub struct Range {
+ pub addr: u64,
+ pub len: u64,
+}
+
+pub fn roundup_4k(addr: u64) -> u64 {
+ return (addr + 0x1000) & 0xffff_ffff_ffff_0000;
+}
+
+pub fn rounddown_4k(addr: u64) -> u64 {
+ return addr & 0xffff_ffff_ffff_0000;
+}
+
+impl Range {
+ pub fn contains(&self, addr: u64) -> bool {
+ return self.addr <= addr && addr < self.addr + self.len;
+ }
+}
impl Mem {
// units
- pub const K: usize = 1024;
- pub const M: usize = 1024 * Mem::K;
- pub const G: usize = 1024 * Mem::M;
+ pub const K: u64 = 1024;
+ pub const M: u64 = 1024 * Mem::K;
+ pub const G: u64 = 1024 * Mem::M;
// physical memory layout: qemu defaults to 128 MiB phy Memory
- pub const PHY_TOP: usize = 128 * Mem::M;
+ pub const PHY_TOP: u64 = 128 * Mem::M;
// 4 lv 4K paging
- pub const PAGE_SIZE: usize = 0x1000;
- pub const PAGE_SHIFT: usize = 12;
+ pub const PAGE_SIZE: u64 = 0x1000;
+ pub const PAGE_SHIFT: u64 = 12;
pub const PAGE_MASK: u64 = 0xfff;
pub const L0_SHIFT: u8 = 39;
pub const L0_MASK: u64 = 0x1ff << Mem::L0_SHIFT;
@@ -20,11 +63,11 @@ impl Mem {
pub const L2_MASK: u64 = 0x1ff << Mem::L2_SHIFT;
pub const L3_SHIFT: u8 = 12;
pub const L3_MASK: u64 = 0x1ff << Mem::L3_SHIFT;
- pub const PHY_PAGES: usize = Mem::PHY_TOP >> Mem::PAGE_SHIFT;
+ pub const PHY_PAGES: u64 = Mem::PHY_TOP >> Mem::PAGE_SHIFT;
// size of frame allocator bitmap: number of physical frames / 8 for 128M
// memory (37268) 4k pages, 37268 bits are needed, hence
// 4096 bytes, exactly one page!
- pub const PHY_BM_SIZE: usize = Mem::PHY_PAGES >> 3;
+ pub const PHY_BM_SIZE: u64 = Mem::PHY_PAGES >> 3;
}
impl VAddr {
diff --git a/src/lib.rs b/src/lib.rs
index cd5cd7c..0eb1c7d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -31,19 +31,27 @@ pub extern "C" fn _entry() -> ! {
assert!(multiboot::check(), "bad multiboot info from grub!");
let mbi = multiboot::get_mb_info().expect("bad multiboot info flags");
let mem = unsafe { mbi.get_mem() }.unwrap();
- let mmap = unsafe { mbi.get_mmap() }.unwrap();
- println!("memory: {:#X?}", mem);
- println!("mmap (start): {:#X?}", mmap);
-
- multiboot::_test_mmap();
+ println!(
+ "available memory: lower {:#X} KiB, upper:{:#X} KiB",
+ mem.lower(),
+ mem.upper()
+ );
+ mm::init();
interrupt::init();
pic_8259::allow(PicDeviceInt::KEYBOARD);
interrupt::interrupt_enable();
- let mut framemap = mm::pma::FMap::new();
- framemap.init();
- println!("Bitmap starting from : {:p}", framemap.bm.as_ptr());
- println!("Skip first {} bytes", framemap.skip_byte);
- println!("system init .. done!");
+
+ println!(
+ "kernel: {:#X} - {:#X}",
+ defs::pmap_kernel_start(),
+ defs::pmap_kernel_end()
+ );
+ println!(
+ " BSS: {:#X} - {:#X}",
+ defs::pmap_bss_start(),
+ defs::pmap_bss_end()
+ );
+
// io::print_welcome();
// busy loop query keyboard
diff --git a/src/machine/multiboot.rs b/src/machine/multiboot.rs
index a8fa4f0..303ed17 100644
--- a/src/machine/multiboot.rs
+++ b/src/machine/multiboot.rs
@@ -1,3 +1,4 @@
+use crate::defs::Range;
use crate::io::*;
use core::fmt;
use core::mem::size_of;
@@ -57,6 +58,15 @@ impl MultibootMmap {
pub const MTYPE_RAM_NVS: u32 = 4;
/// defective RAM
pub const MTYPE_RAM_DEFECT: u32 = 5;
+ pub fn get_range(&self) -> Range {
+ return Range {
+ addr: self.addr,
+ len: self.len,
+ };
+ }
+ pub fn get_end(&self) -> u64 {
+ return self.addr + self.len;
+ }
}
#[repr(C)]
diff --git a/src/mm/heap_allocator.rs b/src/mm/heap_allocator.rs
deleted file mode 100644
index 9eb12a3..0000000
--- a/src/mm/heap_allocator.rs
+++ /dev/null
@@ -1 +0,0 @@
-struct HeapAllocator;
diff --git a/src/mm/mod.rs b/src/mm/mod.rs
index b030dfb..27737e8 100644
--- a/src/mm/mod.rs
+++ b/src/mm/mod.rs
@@ -1,2 +1,51 @@
-pub mod heap_allocator;
+use crate::defs::*;
+use crate::io::*;
+use crate::machine::multiboot;
pub mod pma;
+
+use lazy_static::lazy_static;
+use spin::Mutex;
+lazy_static! {
+ pub static ref GLOBAL_PMA: Mutex<pma::PageStackAllocator> =
+ Mutex::new(pma::PageStackAllocator::new());
+}
+
+pub fn init() {
+ let mbi = multiboot::get_mb_info().unwrap();
+ let mmapinfo = unsafe { mbi.get_mmap() }.unwrap();
+ let buf_start = mmapinfo.mmap_addr;
+ let buf_len = mmapinfo.mmap_length;
+ let buf_end = buf_start + buf_len;
+ let mut curr = buf_start as u64;
+ let mut inserted = 0;
+ loop {
+ if curr >= buf_end as u64 {
+ break;
+ }
+ let mblock = unsafe { &*(curr as *const multiboot::MultibootMmap) };
+ curr += mblock.size as u64;
+ curr += 4;
+ if mblock.mtype != multiboot::MultibootMmap::MTYPE_RAM {
+ continue;
+ }
+ if mblock.get_end() <= pmap_kernel_start() {
+ continue;
+ }
+ // TODO early break if the array is already full
+ if mblock.get_range().contains(pmap_kernel_end()) {
+ let r = Range {
+ addr: pmap_kernel_end(),
+ len: mblock.get_end() - pmap_kernel_end(),
+ };
+ inserted += GLOBAL_PMA.lock().insert_range(r);
+ } else {
+ inserted += GLOBAL_PMA.lock().insert_range(mblock.get_range());
+ }
+ println!(
+ "pma init: {:#X}KiB free memory, {:#X} pages inserted from block {:#X?}",
+ inserted * 0x4,
+ inserted,
+ mblock,
+ );
+ }
+}
diff --git a/src/mm/pma.rs b/src/mm/pma.rs
index f9a6811..a4c27c4 100644
--- a/src/mm/pma.rs
+++ b/src/mm/pma.rs
@@ -1,67 +1,72 @@
-use crate::defs::{self, Mem};
-use core::ffi::c_void;
-use core::{ptr, slice};
-// this is POC code, it will be ugly
+use crate::defs::*;
+use crate::io::*;
+use crate::machine::multiboot::MultibootMmap;
+use core::slice;
extern "C" {
- pub fn ___KERNEL_END__();
+ fn ___FREE_PAGE_STACK__();
}
-type BitU8 = u8;
-/// Bitmap for physical frames
-pub struct FMap {
- pub bm: &'static mut [BitU8],
- // skip over the kernel image and the bitmap itself.
- pub skip_byte: usize,
+/// There should only be one global instance of this.
+pub struct PageStackAllocator {
+ page_stack: &'static mut [u64],
+ size: usize,
+ head: usize,
}
-pub enum PMAError {
- DoubleFree,
-}
+impl PageStackAllocator {
+ // covering 4GiB physical memory of 4K frames
+ const STACK_SIZE: usize = 0x100000;
-impl FMap {
pub fn new() -> Self {
- let map_start = ___KERNEL_END__ as usize;
- let fmap = Self {
- bm: unsafe { slice::from_raw_parts_mut(map_start as *mut u8, Mem::PHY_BM_SIZE) },
- // looks ugly, perhaps FIXME
- // We'll waste several frames for the sake of easy alignment
- skip_byte: 1 + ((map_start >> Mem::PAGE_SHIFT) / 8),
+ let ps = Self {
+ page_stack: unsafe {
+ slice::from_raw_parts_mut(
+ ___FREE_PAGE_STACK__ as usize as *mut u64,
+ Self::STACK_SIZE,
+ )
+ },
+ size: Self::STACK_SIZE,
+ head: 0,
};
- fmap
+ return ps;
}
- /// return : index to the bitmap u8 , bit mask to retrive the bit.
- fn locate_bit(addr: usize) -> Option<(usize, u8)> {
- if addr >= Mem::PHY_TOP {
- return None;
+ /// push an addr into the free page stack
+ /// MUST be atomic or bad things happen...
+ pub fn free_page(&mut self, addr: u64) -> bool {
+ if self.head >= self.size {
+ return false;
}
- let pn = addr >> Mem::PAGE_SHIFT;
- let idx = pn / 8;
- let mask: u8 = 1 << (pn % 8);
- Some((idx, mask))
+ self.page_stack[self.head] = addr;
+ self.head += 1;
+ return true;
}
- pub fn alloc_frame(&mut self) -> usize {
- for i in self.skip_byte..self.bm.len() {
- if self.bm[i] == 0xff {
- continue;
- }
- todo!()
+ pub fn alloc_page(&mut self) -> Option<u64> {
+ if self.head == 0 {
+ return None;
}
- 0
+ self.head -= 1;
+ Some(self.page_stack[self.head])
}
- pub fn dealloc_frame(&mut self) -> Result<(), PMAError> {
- Ok(())
- }
-
- pub fn init(&mut self) {
- for i in 0..self.skip_byte {
- self.bm[i] = 0xff;
- }
- for i in self.skip_byte..self.bm.len() {
- self.bm[i] = 0;
+ /// 4k page only
+ pub fn insert_range(&mut self, r: Range) -> u64 {
+ let mut inserted = 0;
+ let mut page = roundup_4k(r.addr);
+ loop {
+ if !r.contains(page) {
+ break;
+ }
+ if !self.free_page(page) {
+ break;
+ } else {
+ println!("inserted: {:#X}", page);
+ inserted += 1;
+ }
+ page += 0x1000;
}
+ return inserted;
}
}