全局的内存管理器完成

ch4
zhangxinyu 2 years ago
parent c583719ad0
commit c239525dc4

@ -2,6 +2,9 @@ pub const APP_BASE_ADDRESS: usize = 0x80400000; // 载入的app的起始的地
pub const APP_SIZE_LIMIT: usize = 0x20000; // app的最大的二进制文件能够使用的大小
pub const MAX_APP_NUM: usize = 10; // 支持最大的用户应用数量
pub const KERNEL_HEAP_SIZE: usize = 0x30_0000; // 内核的堆大小 3M
pub const PAGE_SIZE_BITS: usize = 0xc; // 页内偏移的位宽(也就是每页的大小)
pub const PAGE_SIZE: usize = 0x1000; // 每个页 的字节大小为 4kb
pub const MEMORY_END: usize = 0x80800000; // 设置我们当前操作系统最大只能用到 0x80800000-0x80000000大小的内存也就是8M
pub const USER_STACK_SIZE: usize = 4096 * 2; // 每个应用用户态的栈大小为8kb
pub const KERNEL_STACK_SIZE: usize = 4096 * 2; // 每个应用的内核栈

@ -0,0 +1,73 @@
use crate::config::{PAGE_SIZE, PAGE_SIZE_BITS};
const PA_WIDTH_SV39: usize = 56; // 真实物理地址 的字节宽度 44(物理页宽) + 12(4kb的宽度)
const PPN_WIDTH_SV39: usize = PA_WIDTH_SV39 - PAGE_SIZE_BITS; // 物理页 的宽度, 也就是 物理地址宽度-每页宽度=物理页宽度
// 物理地址
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct PhysAddr(pub usize);
// 虚拟地址
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct VirtAddr(pub usize);
// 物理页
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct PhysPageNum(pub usize);
// 虚拟页
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct VirtPageNum(pub usize);
// 把usize 转为真实地址(只保留 PA_WIDTH_SV39 位字节)
impl From<usize> for PhysAddr {
fn from(v: usize) -> Self { Self(v & ( (1 << PA_WIDTH_SV39) - 1 )) }
}
// 把usize类型的物理页号 转为物理页结构体 (只保留物理页的宽度)
impl From<usize> for PhysPageNum {
fn from(v: usize) -> Self { Self(v & ( (1 << PPN_WIDTH_SV39) - 1 )) }
}
// 把物理地址转为 usize, 直接返回即可
impl From<PhysAddr> for usize {
fn from(v: PhysAddr) -> Self { v.0 }
}
// 把物理页结构体转为 usize类型的物理页 直接返回即可
impl From<PhysPageNum> for usize {
fn from(v: PhysPageNum) -> Self { v.0 }
}
impl PhysAddr {
// 从当前物理地址得到页内偏移(只保留12个bit即可)
pub fn page_offset(&self) -> usize {
self.0 & (PAGE_SIZE - 1)
}
// 舍去小数位, 把物理地址, 转为 物理页号
pub fn floor(&self) -> PhysPageNum {
PhysPageNum(self.0 / PAGE_SIZE)
}
// 有小数统一 +1, 物理地址转为物理页号
pub fn ceil(&self) -> PhysPageNum {
PhysPageNum((self.0 + PAGE_SIZE - 1) / PAGE_SIZE)
}
}
// 把PhysAddr 转为 PhysPageNum
impl From<PhysAddr> for PhysPageNum {
fn from(v: PhysAddr) -> Self {
assert_eq!(v.page_offset(), 0);
v.floor()
}
}
// 把物理页转为物理地址(左移页宽即可)
impl From<PhysPageNum> for PhysAddr {
fn from(v: PhysPageNum) -> Self { Self(v.0 << PAGE_SIZE_BITS) }
}

@ -0,0 +1,61 @@
use alloc::vec::Vec;
use lazy_static::lazy_static;
use crate::mm::address::{PhysPageNum, PhysAddr};
use crate::config::MEMORY_END;
use crate::sync::UPSafeCell;
extern "C" {
fn ekernel();
}
// 物理页帧管理器, 它管理了 ekernel(操作系统使用的内存结束位置) 到 MEMORY_END(最大的可用的物理内存地址)所有的内存, 这部分内存是给用户用的
// current, end 这个区间表示此前从未被分配过的页
// recycled 表示之前被分配过, 但是已经被回收可以再利用的页
pub struct StackFrameAllocator {
current: usize,
end: usize,
recycled: Vec<usize>,
}
impl StackFrameAllocator {
fn from(l: PhysPageNum, r: PhysPageNum) -> Self {
Self {
current: l.0,
end: r.0,
recycled: Vec::new(),
}
}
}
impl StackFrameAllocator {
// 从分配器中, 找到一个空闲页(它可能之前从未分配过, 或者之前被分配但是已经被回收的完好页)
fn alloc(&mut self) -> Option<PhysPageNum> {
if let Some(ppn) = self.recycled.pop() {
Some(ppn.into())
} else if self.current == self.end {
None
} else {
self.current += 1;
Some((self.current - 1).into())
}
}
// 回收一个页, 为了防止二次回收, 我们这里直接panic
fn dealloc(&mut self, ppn: PhysPageNum) {
let ppn = ppn.0;
// 防止被二次回收
if ppn >= self.current || self.recycled.iter().any(|&v| v == ppn) {
panic!("Frame ppn={:#x} has not been allocated!", ppn);
}
// 校验完毕, 把这个页, 还给管理器
self.recycled.push(ppn);
}
}
lazy_static! {
pub static ref FRAME_ALLOCATOR: UPSafeCell<StackFrameAllocator> = unsafe {
// 这里我们只要完整的页, 舍去开头和结尾一些碎片
UPSafeCell::new(StackFrameAllocator::from(PhysAddr::from(ekernel as usize).ceil(), PhysAddr::from(MEMORY_END).floor()))
};
}

@ -1 +1,3 @@
pub mod heap_allocator;
pub mod heap_allocator;
pub mod address;
pub mod frame_allocator;
Loading…
Cancel
Save