feat: add pmm, add vmm, add allocator, create memory management foundation

This commit is contained in:
Faynot
2026-03-29 19:07:41 +03:00
parent 83117c0a65
commit 7860db3814
9 changed files with 578 additions and 66 deletions

128
kernel/src/mem/pmm.rs Normal file
View File

@@ -0,0 +1,128 @@
use crate::mem::address::{PhysAddr};
pub const PAGE_SIZE: u64 = 4096;
#[allow(dead_code)]
pub struct BitmapPMM {
bitmap: &'static mut [u8],
total_pages: usize,
used_pages: usize,
last_idx: usize,
}
static mut PMM: Option<BitmapPMM> = None;
impl BitmapPMM {
#[allow(dead_code)]
pub fn used_pages(&self) -> usize { self.used_pages }
#[allow(dead_code)]
pub fn total_pages(&self) -> usize { self.total_pages }
pub unsafe fn init(mmap: &limine::response::MemoryMapResponse, hhdm_offset: u64) {
let max_addr = mmap.entries().iter()
.map(|e| e.base + e.length)
.max()
.unwrap_or(0);
let total_pages = (max_addr / PAGE_SIZE) as usize;
let bitmap_size = total_pages.div_ceil(8);
let bitmap_phys_addr = mmap.entries().iter()
.find(|e| e.entry_type == limine::memory_map::EntryType::USABLE && e.length >= bitmap_size as u64)
.map(|e| e.base)
.expect("PMM: Insufficient memory for bitmap");
let bitmap_virt_ptr = (bitmap_phys_addr + hhdm_offset) as *mut u8;
// Оборачиваем небезопасные операции
let bitmap_slice = unsafe { core::slice::from_raw_parts_mut(bitmap_virt_ptr, bitmap_size) };
bitmap_slice.fill(0xFF);
let mut pmm = Self {
bitmap: bitmap_slice,
total_pages,
used_pages: total_pages,
last_idx: 0,
};
for entry in mmap.entries() {
if entry.entry_type == limine::memory_map::EntryType::USABLE {
for addr in (entry.base..entry.base + entry.length).step_by(PAGE_SIZE as usize) {
pmm.free_frame(PhysAddr(addr));
}
}
}
for addr in (bitmap_phys_addr..bitmap_phys_addr + bitmap_size as u64).step_by(PAGE_SIZE as usize) {
pmm.lock_frame(PhysAddr(addr));
}
pmm.lock_frame(PhysAddr(0));
unsafe {
core::ptr::write(core::ptr::addr_of_mut!(PMM), Some(pmm));
}
}
pub fn free_frame(&mut self, phys_addr: PhysAddr) {
let idx = (phys_addr.0 / PAGE_SIZE) as usize;
if idx < self.total_pages {
let byte_idx = idx / 8;
let bit_idx = idx % 8;
if (self.bitmap[byte_idx] & (1 << bit_idx)) != 0 {
self.bitmap[byte_idx] &= !(1 << bit_idx);
self.used_pages -= 1;
}
}
}
pub fn lock_frame(&mut self, phys_addr: PhysAddr) {
let idx = (phys_addr.0 / PAGE_SIZE) as usize;
if idx < self.total_pages {
let byte_idx = idx / 8;
let bit_idx = idx % 8;
if (self.bitmap[byte_idx] & (1 << bit_idx)) == 0 {
self.bitmap[byte_idx] |= 1 << bit_idx;
self.used_pages += 1;
}
}
}
pub fn alloc_frame(&mut self) -> Option<PhysAddr> {
for i in self.last_idx..self.total_pages {
let byte_idx = i / 8;
if self.bitmap[byte_idx] == 0xFF { continue; }
let bit_idx = i % 8;
if (self.bitmap[byte_idx] & (1 << bit_idx)) == 0 {
let addr = PhysAddr(i as u64 * PAGE_SIZE);
self.lock_frame(addr);
self.last_idx = i;
return Some(addr);
}
}
None
}
}
#[allow(dead_code)]
pub unsafe fn get_pmm_unchecked() -> &'static BitmapPMM {
let pmm_ptr = core::ptr::addr_of!(PMM);
unsafe { (*pmm_ptr).as_ref().expect("PMM: Not initialized") }
}
pub fn alloc_page() -> Option<PhysAddr> {
unsafe {
let pmm_ptr = core::ptr::addr_of_mut!(PMM);
(*pmm_ptr).as_mut()?.alloc_frame()
}
}
#[allow(dead_code)]
pub fn free_page(addr: PhysAddr) {
unsafe {
let pmm_ptr = core::ptr::addr_of_mut!(PMM);
if let Some(pmm) = (*pmm_ptr).as_mut() {
pmm.free_frame(addr);
}
}
}