diff options
| author | Tianhao Wang <shrik3@mailbox.org> | 2024-05-29 19:53:52 +0200 |
|---|---|---|
| committer | Tianhao Wang <shrik3@mailbox.org> | 2024-06-11 15:17:11 +0200 |
| commit | cd658673a35df8b0da3551e819e26d35c18b89f2 (patch) | |
| tree | 74c209b519290eb43545e800b88ddf9dfa796a7a | |
| parent | 9cf85e88211512b0410f9bb9f2f19ea4ce9a8190 (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.s | 7 | ||||
| -rw-r--r-- | defs/x86_64-linker.ld | 11 | ||||
| -rw-r--r-- | src/defs.rs | 59 | ||||
| -rw-r--r-- | src/lib.rs | 28 | ||||
| -rw-r--r-- | src/machine/multiboot.rs | 10 | ||||
| -rw-r--r-- | src/mm/heap_allocator.rs | 1 | ||||
| -rw-r--r-- | src/mm/mod.rs | 51 | ||||
| -rw-r--r-- | src/mm/pma.rs | 99 |
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 { @@ -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; } } |
