恒等分配
内核采用恒等分配,其实就是虚拟地址等于物理地址。内核还是从 0x80020000 开而不是 0 。这样的原因是一开始没有启用分页的时候我们还是访问物理地址,为了保证内核的内存访问是平滑过度的,恒等分配不用实际分配物理帧,只需要建立映射就可以,因为实际的物理帧就是内核本身。
映射分配
应用采用映射分配,应用的地址空间从 0 开始,映射分配要实际分配物理帧,我们采用简单的栈式分配。
trait FrameAllocator { fn new() -> Self; fn alloc(&mut self) -> Option<PhysPageNum>; fn dealloc(&mut self, ppn: PhysPageNum); } pub struct StackFrameAllocator { current: usize, end: usize, recycled: Vec<usize>, } impl StackFrameAllocator { pub fn init(&mut self, l: PhysPageNum, r: PhysPageNum) { self.current = l.0; self.end = r.0; } } impl FrameAllocator for StackFrameAllocator { fn new() -> Self { Self { current: 0, end: 0, recycled: Vec::new(), } } 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()) } } } fn dealloc(&mut self, ppn: PhysPageNum) { let ppn = ppn.0; // validity check if ppn >= self.current || self.recycled.iter().find(|&v| *v == ppn).is_some() { panic!("Frame ppn={:#x} has not been allocated!", ppn); } // recycle self.recycled.push(ppn); } } type FrameAllocatorImpl = StackFrameAllocator;
还记得逻辑段么?逻辑段包含一系列虚拟地址,分配一个页如下
pub fn map_one(&mut self, page_table: &mut PageTable, vpn: VirtPageNum) { let ppn: PhysPageNum; match self.map_type { MapType::Identical => { ppn = PhysPageNum(vpn.0); } MapType::Framed => { let frame = frame_alloc().unwrap(); ppn = frame.ppn; self.data_frames.insert(vpn, frame); } } let pte_flags = PTEFlags::from_bits(self.map_perm.bits).unwrap(); page_table.map(vpn, ppn, pte_flags); }
用 vpn_range 分配逻辑段的所有页。
pub fn map(&mut self, page_table: &mut PageTable) { for vpn in self.vpn_range { self.map_one(page_table, vpn); } }
具体代码请参考 https://github.com/buhe/bugu/tree/6