diff --git a/os/Cargo.lock b/os/Cargo.lock index 930eae3..683a021 100644 --- a/os/Cargo.lock +++ b/os/Cargo.lock @@ -8,6 +8,21 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "buddy_system_allocator" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4e85e760e105b46ae0bd1236578793c6c147ae7463fe95c8350296b8bfcb830" +dependencies = [ + "spin 0.7.1", +] + [[package]] name = "critical-section" version = "1.1.2" @@ -30,7 +45,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin", + "spin 0.9.8", ] [[package]] @@ -52,6 +67,8 @@ checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" name = "os" version = "0.3.0" dependencies = [ + "bitflags", + "buddy_system_allocator", "lazy_static", "riscv", "sbi-rt", @@ -86,6 +103,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "spin" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13287b4da9d1207a4f4929ac390916d64eacfe236a487e9a9f5b3be392be5162" + [[package]] name = "spin" version = "0.9.8" diff --git a/os/Cargo.toml b/os/Cargo.toml index ca83c2e..0feda23 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -7,3 +7,5 @@ edition = "2021" sbi-rt = { version = "0.0.2", features = ["legacy"] } lazy_static = { version = "1.4.0", features = ["spin_no_std"] } riscv = { version = "0.10.0" } +buddy_system_allocator = {version = "0.6"} +bitflags = {version = "2.6"} diff --git a/os/src/boards/qemu.rs b/os/src/boards/qemu.rs index 7412c84..b90ce14 100644 --- a/os/src/boards/qemu.rs +++ b/os/src/boards/qemu.rs @@ -1 +1,5 @@ pub const CLOCK_FREQUENCY: usize = 10000000; +pub const MEMORY_END: usize = 0x8800_0000; +pub const MMIO: &[(usize, usize)] = &[ + (0x0010_0000, 0x00_2000) +]; diff --git a/os/src/config.rs b/os/src/config.rs index 31c0be9..59efe9e 100644 --- a/os/src/config.rs +++ b/os/src/config.rs @@ -1,8 +1,17 @@ pub const USER_STACK_SIZE: usize = 4096; pub const KERNEL_STACK_SIZE: usize = 4096 * 2; +pub const KERNEL_HEAP_SIZE: usize = 0x30_0000; +pub const PAGE_SIZE: usize = 0x1000; +pub const PAGE_SIZE_BITS: usize = 0xc; -pub const MAX_APP_NUM: usize = 4; -pub const APP_BASE_ADDRESS: usize = 0x80400000; -pub const APP_SIZE_LIMIT: usize = 0x20000; +pub const TRAMPOLINE: usize = usize::MAX - PAGE_SIZE + 1; +pub const TRAP_CONTEXT: usize = TRAMPOLINE - PAGE_SIZE; -pub use crate::boards::qemu::CLOCK_FREQUENCY; +/// Return (bottom, top) of a kernel stack in kernel space +pub fn kernel_stack_position(app_id: usize) -> (usize, usize) { + let top = TRAMPOLINE - app_id * (KERNEL_STACK_SIZE + PAGE_SIZE); + let bottom = top - KERNEL_STACK_SIZE; + (bottom, top) +} + +pub use crate::boards::qemu::{CLOCK_FREQUENCY, MEMORY_END, MMIO}; diff --git a/os/src/loader.rs b/os/src/loader.rs deleted file mode 100644 index 25323f9..0000000 --- a/os/src/loader.rs +++ /dev/null @@ -1,100 +0,0 @@ -use crate::config::{ - APP_BASE_ADDRESS, APP_SIZE_LIMIT, KERNEL_STACK_SIZE, MAX_APP_NUM, USER_STACK_SIZE, -}; -use crate::log_information; -use crate::trap::context::TrapContext; -use core::arch::asm; - -#[repr(align(4096))] -#[derive(Copy, Clone)] -struct KernelStack { - data: [u8; KERNEL_STACK_SIZE], -} - -#[repr(align(4096))] -#[derive(Copy, Clone)] -struct UserStack { - data: [u8; USER_STACK_SIZE], -} - -static KERNEL_STACK: [KernelStack; MAX_APP_NUM] = [KernelStack { - data: [0; KERNEL_STACK_SIZE], -}; MAX_APP_NUM]; - -static USER_STACK: [UserStack; MAX_APP_NUM] = [UserStack { - data: [0; USER_STACK_SIZE], -}; MAX_APP_NUM]; - -impl KernelStack { - fn get_sp(&self) -> usize { - self.data.as_ptr() as usize + KERNEL_STACK_SIZE - } - - pub fn push_context(&self, trap_context: TrapContext) -> usize { - let pointer = (self.get_sp() - size_of::()) as *mut TrapContext; - - unsafe { - *pointer = trap_context; - } - - pointer as usize - } -} - -impl UserStack { - fn get_sp(&self) -> usize { - self.data.as_ptr() as usize + USER_STACK_SIZE - } -} - -pub fn get_app_num() -> usize { - extern "C" { - fn _num_app(); - } - - let app_num_ptr = _num_app as usize as *const usize; - - unsafe { app_num_ptr.read_volatile() } -} - -pub fn load_apps() { - extern "C" { - fn _num_app(); - } - - let app_num_ptr = _num_app as usize as *const usize; - let app_num = unsafe { app_num_ptr.read_volatile() }; - let app_start = unsafe { core::slice::from_raw_parts(app_num_ptr.add(1), app_num + 1) }; - - for i in 0..app_num { - let base_address = APP_BASE_ADDRESS + i * APP_SIZE_LIMIT; - - // 清除目标的内存区域 - for address in base_address..base_address + APP_SIZE_LIMIT { - unsafe { - (address as *mut u8).write_volatile(0); - } - } - - // 将程序从数据段复制过来 - let source = unsafe { - core::slice::from_raw_parts(app_start[i] as *const u8, app_start[i + 1] - app_start[i]) - }; - let destination = - unsafe { core::slice::from_raw_parts_mut(base_address as *mut u8, source.len()) }; - - destination.copy_from_slice(source); - } - - log_information!("Load {} applications in memory.", app_num); - unsafe { - asm!("fence.i"); - } -} - -pub fn initialize_app_context(app_id: usize) -> usize { - KERNEL_STACK[app_id].push_context(TrapContext::init_application_context( - APP_BASE_ADDRESS + app_id * APP_SIZE_LIMIT, - USER_STACK[app_id].get_sp(), - )) -} diff --git a/os/src/main.rs b/os/src/main.rs index 351c8f4..53acdf0 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -1,5 +1,7 @@ #![no_std] #![no_main] +#![feature(alloc_error_handler)] +extern crate alloc; use crate::utils::clear_bss; use core::arch::global_asm; @@ -7,7 +9,6 @@ use core::arch::global_asm; mod boards; mod config; mod console; -mod loader; mod sbi; mod sync; mod syscall; @@ -15,6 +16,7 @@ mod task; mod timer; mod trap; mod utils; +mod memory; global_asm!(include_str!("entry.asm")); global_asm!(include_str!("link_app.asm")); @@ -24,8 +26,6 @@ fn rust_main() -> ! { clear_bss(); log_information!("Hello, rCore!"); trap::init(); - loader::load_apps(); - task::run_first_task(); unreachable!() } diff --git a/os/src/memory.rs b/os/src/memory.rs new file mode 100644 index 0000000..c4d8bc7 --- /dev/null +++ b/os/src/memory.rs @@ -0,0 +1,5 @@ +mod heap_allocator; +mod address; +mod page_table; +mod frame_allocator; +mod memory_set; \ No newline at end of file diff --git a/os/src/memory/address.rs b/os/src/memory/address.rs new file mode 100644 index 0000000..db7d4f2 --- /dev/null +++ b/os/src/memory/address.rs @@ -0,0 +1,256 @@ +use crate::config::{PAGE_SIZE, PAGE_SIZE_BITS}; +use core::fmt::{Debug, Formatter}; +use core::slice::from_raw_parts_mut; +use crate::memory::page_table::PageTableEntry; + +// 在SV39模式下,物理地址的宽度为56,虚拟地址的宽度为39 +pub const PHYSICAL_ADDRESS_WIDTH: usize = 56; +pub const PHYSICAL_PAGE_NUMBER_WIDTH: usize = PHYSICAL_ADDRESS_WIDTH - PAGE_SIZE_BITS; +pub const VIRTUAL_ADDRESS_WIDTH: usize = 39; +pub const VIRTUAL_PAGE_NUMBER_WIDTH: usize = VIRTUAL_ADDRESS_WIDTH - PAGE_SIZE_BITS; + +/// 物理地址 +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +pub struct PhysicalAddress(pub usize); + +impl PhysicalAddress { + pub fn page_offset(&self) -> usize { + self.0 & (PAGE_SIZE - 1) + } + + pub fn floor(&self) -> PhysicalPageNumber { + PhysicalPageNumber(self.0 / PAGE_SIZE) + } + + pub fn ceil(&self) -> PhysicalPageNumber { + if self.0 == 0 { + PhysicalPageNumber(0) + } else { + PhysicalPageNumber((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE) + } + } + + pub fn is_aligned(&self) -> bool { + self.page_offset() == 0 + } +} + +impl Debug for PhysicalAddress { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.write_fmt(format_args!("Physical address: {:#x}.", self.0)) + } +} + +impl From for PhysicalAddress { + fn from(value: usize) -> Self { + Self(value & ((1 << PHYSICAL_ADDRESS_WIDTH) - 1)) + } +} + +impl From for usize { + fn from(value: PhysicalAddress) -> Self { + value.0 + } +} + +impl From for PhysicalPageNumber { + fn from(value: PhysicalAddress) -> Self { + assert_eq!(value.page_offset(), 0); + value.floor() + } +} + +impl From for PhysicalAddress { + fn from(value: PhysicalPageNumber) -> Self { + Self(value.0 << PAGE_SIZE_BITS) + } +} + +/// 物理页号 +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +pub struct PhysicalPageNumber(pub usize); + +// 这里的unsafe只是为了绕过编译器的生命周期检查 +impl PhysicalPageNumber { + pub fn get_page_table_entry_array(&self) -> &'static mut [PageTableEntry] { + let address: PhysicalAddress = (*self).into(); + unsafe { + // 一个页表的大小是2^12 byte + // 页表项的大小是8 byte + // 所有一共有2^9 + from_raw_parts_mut(address.0 as *mut PageTableEntry, 512) + } + } + + pub fn get_bytes_array(&self) -> &'static mut [u8] { + let address: PhysicalAddress = (*self).into(); + unsafe { + from_raw_parts_mut(address.0 as *mut u8, PAGE_SIZE) + } + } + + pub fn get_mut(&self) ->&'static mut T { + let address: PhysicalAddress = (*self).into(); + unsafe { + (address.0 as *mut T).as_mut().unwrap() + } + } +} + +impl Debug for PhysicalPageNumber { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.write_fmt(format_args!("Physical page number: {:#x}.", self.0)) + } +} + +impl From for PhysicalPageNumber { + fn from(value: usize) -> Self { + Self(value & ((1 << PHYSICAL_PAGE_NUMBER_WIDTH) - 1)) + } +} + +impl From for usize { + fn from(value: PhysicalPageNumber) -> Self { + value.0 + } +} + +/// 虚拟地址 +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +pub struct VirtualAddress(pub usize); + +impl VirtualAddress { + pub fn page_offset(&self) -> usize { + self.0 & (PAGE_SIZE - 1) + } + + pub fn is_aligned(&self) -> bool { + self.page_offset() == 0 + } + + pub fn floor(&self) -> VirtualPageNumber { + VirtualPageNumber(self.0 / PAGE_SIZE) + } + + pub fn ceil(&self) -> VirtualPageNumber { + VirtualPageNumber((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE) + } +} + +impl Debug for VirtualAddress { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.write_fmt(format_args!("Virtual address: {:#x}.", self.0)) + } +} + +impl From for VirtualAddress { + fn from(value: usize) -> Self { + Self(value & ((1 << VIRTUAL_ADDRESS_WIDTH) - 1)) + } +} + +impl From for usize { + fn from(value: VirtualAddress) -> Self { + value.0 + } +} + +/// 虚拟页号 +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +pub struct VirtualPageNumber(pub usize); + +impl VirtualPageNumber { + pub fn get_indexes(&self) -> [usize; 3] { + let mut number = self.0; + let mut indexes = [0usize; 3]; + + for i in 0..3 { + indexes[i] = number & (1 << 9 - 1); + number = number >> 9; + } + + indexes + } + + pub fn step(&mut self) { + self.0 += 1; + } +} + +impl Debug for VirtualPageNumber { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.write_fmt(format_args!("Virtual page number: {:#x}.", self.0)) + } +} + +impl From for VirtualPageNumber { + fn from(value: usize) -> Self { + Self(value & ((1 << VIRTUAL_PAGE_NUMBER_WIDTH) - 1)) + } +} + +impl From for usize { + fn from(value: VirtualPageNumber) -> Self { + value.0 + } +} + +#[derive(Copy, Clone)] +pub struct VirtualPageSpan { + left: VirtualPageNumber, + right: VirtualPageNumber +} + +impl VirtualPageSpan { + pub fn new(start: VirtualPageNumber, end: VirtualPageNumber) -> Self { + Self { + left: start, + right: end + } + } + + pub fn get_start(&self) -> VirtualPageNumber { + self.left + } + + pub fn get_end(&self) -> VirtualPageNumber { + self.right + } +} + +impl IntoIterator for VirtualPageSpan { + type Item = VirtualPageNumber; + type IntoIter = VirtualPageSpanIterator; + + fn into_iter(self) -> Self::IntoIter { + VirtualPageSpanIterator::new(&self) + } +} + +pub struct VirtualPageSpanIterator { + current: VirtualPageNumber, + end: VirtualPageNumber +} + +impl VirtualPageSpanIterator { + fn new(span: &VirtualPageSpan) -> Self { + Self { + current: span.left, + end: span.right + } + } +} + +impl Iterator for VirtualPageSpanIterator { + type Item = VirtualPageNumber; + + fn next(&mut self) -> Option { + if self.current == self.end { + None + } else { + let t = self.current; + self.current.step(); + Some(t) + } + } +} diff --git a/os/src/memory/frame_allocator.rs b/os/src/memory/frame_allocator.rs new file mode 100644 index 0000000..f53da5c --- /dev/null +++ b/os/src/memory/frame_allocator.rs @@ -0,0 +1,110 @@ +use crate::config::MEMORY_END; +use crate::memory::address::{PhysicalAddress, PhysicalPageNumber}; +use crate::sync::single_cell::SingleCell; +use alloc::vec; +use alloc::vec::Vec; +use lazy_static::lazy_static; + +trait FrameAllocator { + fn new() -> Self; + + fn alloc(&mut self) -> Option; + + fn dealloc(&mut self, page_number: PhysicalPageNumber); +} + +struct StackedFrameAllocator { + current: usize, + end: usize, + recycled: Vec, +} + +impl FrameAllocator for StackedFrameAllocator { + fn new() -> Self { + Self { + current: 0, + end: 0, + recycled: vec![], + } + } + + fn alloc(&mut self) -> Option { + if let Some(page_num) = self.recycled.pop() { + Some(page_num.into()) + } else { + if self.current == self.end { + None + } else { + self.current += 1; + Some((self.current - 1).into()) + } + } + } + + fn dealloc(&mut self, page_number: PhysicalPageNumber) { + let page_number = page_number.0; + + if page_number >= self.current + || self.recycled.iter().find(|&p| *p == page_number).is_some() + { + panic!( + "Frame physical page number={:#x} has not been allocated.", + page_number + ); + } + + self.recycled.push(page_number); + } +} + +impl StackedFrameAllocator { + pub fn init(&mut self, l: PhysicalPageNumber, r: PhysicalPageNumber) { + self.current = l.0; + self.end = r.0; + } +} + +pub struct FrameTracker { + pub page_number: PhysicalPageNumber +} + +impl FrameTracker { + fn new(page_number: PhysicalPageNumber) -> Self { + // 清空页帧中的内容 + let byte_array = page_number.get_bytes_array(); + for i in byte_array.as_mut() { + *i = 0; + } + + Self { + page_number + } + } +} + +impl Drop for FrameTracker { + fn drop(&mut self) { + FRAME_ALLOCATOR.exclusive_borrow().dealloc(self.page_number); + } +} + +lazy_static! { + static ref FRAME_ALLOCATOR: SingleCell = + SingleCell::new(StackedFrameAllocator::new()); +} + +pub fn initialize_frame_allocator() { + extern "C" { + fn ekernel(); + } + + FRAME_ALLOCATOR.exclusive_borrow().init( + PhysicalAddress::from(ekernel as usize).ceil(), + PhysicalAddress::from(MEMORY_END).floor(), + ) +} + +pub fn allocate_frame() -> Option { + FRAME_ALLOCATOR.exclusive_borrow().alloc().map(|p| FrameTracker::new(p)) +} + diff --git a/os/src/memory/heap_allocator.rs b/os/src/memory/heap_allocator.rs new file mode 100644 index 0000000..2d3f18d --- /dev/null +++ b/os/src/memory/heap_allocator.rs @@ -0,0 +1,20 @@ +use buddy_system_allocator::LockedHeap; +use crate::config::KERNEL_HEAP_SIZE; + +#[global_allocator] +static HEAP_ALLOCATOR: LockedHeap = LockedHeap::empty(); + +static mut HEAP_SPACE: [u8; KERNEL_HEAP_SIZE] = [0; KERNEL_HEAP_SIZE]; + +pub fn init_heap() { + unsafe { + HEAP_ALLOCATOR + .lock() + .init(HEAP_SPACE.as_ptr() as usize, KERNEL_HEAP_SIZE); + } +} + +#[alloc_error_handler] +pub fn handle_alloc_error(layout: core::alloc::Layout) -> ! { + panic!("Heap allocation failed, layout: {:?}", layout); +} \ No newline at end of file diff --git a/os/src/memory/memory_set.rs b/os/src/memory/memory_set.rs new file mode 100644 index 0000000..839e67e --- /dev/null +++ b/os/src/memory/memory_set.rs @@ -0,0 +1,145 @@ +use alloc::collections::BTreeMap; +use alloc::vec; +use alloc::vec::Vec; +use bitflags::bitflags; +use crate::config::PAGE_SIZE; +use crate::memory::address::{PhysicalPageNumber, VirtualAddress, VirtualPageNumber, VirtualPageSpan}; +use crate::memory::frame_allocator::{allocate_frame, FrameTracker}; +use crate::memory::page_table::{PageTable, PageTableEntryFlags}; + +/// 虚拟地址的映射方式 +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum MapType { + /// 恒等映射 + Identical, + /// 新分配物理页帧 + Framed +} + +bitflags! { + /// 逻辑段的权限控制 + /// 只是PageTableEntryFlags的子集 + /// 其他的标志位对于权限控制无用,只和地址转换有关 + pub struct MapPermission: u8 { + const R = 1 << 1; + const W = 1 << 2; + const X = 1 << 3; + const U = 1 << 4; + } +} + +/// 一段地址连续的虚拟内存 +pub struct MapArea { + virtual_page_span: VirtualPageSpan, + data_frames: BTreeMap, + map_type: MapType, + map_permission: MapPermission +} + +impl MapArea { + pub fn new( + start: VirtualAddress, + end: VirtualAddress, + map_type: MapType, + map_permission: MapPermission + ) -> Self { + let start = start.floor(); + let end = end.ceil(); + + Self { + virtual_page_span: VirtualPageSpan::new(start, end), + data_frames: BTreeMap::new(), + map_type, + map_permission + } + } + + pub fn map(&mut self, page_table: &mut PageTable) { + for page_number in self.virtual_page_span { + self.map_one(page_table, page_number); + } + } + + pub fn unmap(&mut self, page_table: &mut PageTable) { + for page_number in self.virtual_page_span { + self.unmap_one(page_table, page_number); + } + } + + /// Copy data into this MapArea + /// The data is start-aligned and shorter than MapArea! + pub fn copy_data(&mut self, page_table: &mut PageTable, data: &[u8]) { + assert_eq!(self.map_type, MapType::Framed); + let mut start = 0; + let mut current_page_number = self.virtual_page_span.get_start(); + let length = data.len(); + + loop { + let source = &data[start..length.min(start + PAGE_SIZE)]; + let destination = &mut page_table + .translate(current_page_number) + .unwrap() + .physical_page_numer() + .get_bytes_array()[..source.len()]; + + destination.copy_from_slice(source); + start += PAGE_SIZE; + if start >= length { + break + } + + // 自增 + current_page_number.step() + } + } + + fn map_one(&mut self, page_table: &mut PageTable, virtual_page_number: VirtualPageNumber) { + let physical_page_number = match self.map_type { + MapType::Identical => { + // 使用和虚拟页号一样的物理页号 + PhysicalPageNumber(virtual_page_number.0) + }, + MapType::Framed => { + // 分配新的物理页帧 + let frame = allocate_frame().unwrap(); + let frame_number = frame.page_number; + self.data_frames.insert(virtual_page_number, frame); + frame_number + } + }; + let flags = PageTableEntryFlags::from_bits(self.map_permission.bits()).unwrap(); + page_table.map(virtual_page_number, physical_page_number, flags); + } + + fn unmap_one(&mut self, page_table: &mut PageTable, virtual_page_number: VirtualPageNumber) { + match self.map_type { + MapType::Framed => { + self.data_frames.remove(&virtual_page_number); + }, + _ => {} + } + page_table.unmap(virtual_page_number); + } +} + +pub struct MemorySet { + page_table: PageTable, + areas: Vec +} + +impl MemorySet { + pub fn new_bare() -> Self { + Self { + page_table: PageTable::new(), + areas: vec![] + } + } + + fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) { + + } +} + + + + diff --git a/os/src/memory/page_table.rs b/os/src/memory/page_table.rs new file mode 100644 index 0000000..be360c6 --- /dev/null +++ b/os/src/memory/page_table.rs @@ -0,0 +1,161 @@ +use crate::memory::address::{PhysicalPageNumber, VirtualPageNumber, PHYSICAL_PAGE_NUMBER_WIDTH}; +use crate::memory::frame_allocator::{allocate_frame, FrameTracker}; +use alloc::vec; +use alloc::vec::Vec; +use bitflags::bitflags; + +bitflags! { + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub struct PageTableEntryFlags: u8 { + /// Valid + const V = 1 << 0; + ///Read + const R = 1 << 1; + /// Write + const W = 1 << 2; + /// Execute + const X = 1 << 3; + /// User + const U = 1 << 4; + /// unknown + const G = 1 << 5; + /// Accessed + const A = 1 << 6; + /// Dirty + const D = 1 << 7; + } +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct PageTableEntry { + pub bits: usize, +} + +impl PageTableEntry { + pub fn new(page_num: PhysicalPageNumber, flags: PageTableEntryFlags) -> Self { + Self { + bits: page_num.0 << 10 | flags.bits() as usize, + } + } + + pub fn empty() -> Self { + Self { bits: 0 } + } + + pub fn physical_page_numer(&self) -> PhysicalPageNumber { + (self.bits >> 10 & (1usize << PHYSICAL_PAGE_NUMBER_WIDTH - 1)).into() + } + + pub fn flags(&self) -> PageTableEntryFlags { + PageTableEntryFlags::from_bits(self.bits as u8).unwrap() + } + + pub fn is_valid(&self) -> bool { + (self.flags() & PageTableEntryFlags::V) != PageTableEntryFlags::empty() + } + + pub fn readable(&self) -> bool { + (self.flags() & PageTableEntryFlags::R) != PageTableEntryFlags::empty() + } + + pub fn writable(&self) -> bool { + (self.flags() & PageTableEntryFlags::W) != PageTableEntryFlags::empty() + } + + pub fn executable(&self) -> bool { + (self.flags() & PageTableEntryFlags::X) != PageTableEntryFlags::empty() + } +} + +pub struct PageTable { + root_page_number: PhysicalPageNumber, + frames: Vec, +} + +impl PageTable { + pub fn new() -> Self { + let frame = allocate_frame().unwrap(); + Self { + root_page_number: frame.page_number, + frames: vec![frame], + } + } + + pub fn map( + &mut self, + virtual_page_number: VirtualPageNumber, + physical_page_number: PhysicalPageNumber, + flags: PageTableEntryFlags, + ) { + let entry = self.find_entry_or_create(virtual_page_number); + assert!( + !entry.is_valid(), + "Virtual page number {:?} is mapped before mapping.", + virtual_page_number + ); + *entry = PageTableEntry::new(physical_page_number, flags | PageTableEntryFlags::V); + } + + pub fn unmap(&mut self, virtual_page_number: VirtualPageNumber) { + let entry = self.find_entry(virtual_page_number).unwrap(); + assert!( + entry.is_valid(), + "Virtual page number {:?} is invalid before unmapping", + virtual_page_number + ); + *entry = PageTableEntry::empty(); + } + + /// 从satp寄存器创建临时的页表 + /// 方便在用户空间时手动查看页表 + pub fn from_token(satp: usize) -> Self { + Self { + root_page_number: PhysicalPageNumber::from( + satp & ((1usize << PHYSICAL_PAGE_NUMBER_WIDTH) - 1), + ), + frames: vec![], + } + } + + pub fn translate(&self, virtual_page_number: VirtualPageNumber) -> Option { + self.find_entry(virtual_page_number).map(|e| e.clone()) + } + + fn find_entry_or_create(&mut self, page_number: VirtualPageNumber) -> &mut PageTableEntry { + let indexes = page_number.get_indexes(); + let mut physical_page_number = self.root_page_number; + + for i in 0..2 { + let entry = &mut physical_page_number.get_page_table_entry_array()[indexes[i]]; + + // 当V是1,其他都是0的页帧就是页表 + if !entry.is_valid() { + let frame = allocate_frame().unwrap(); + *entry = PageTableEntry::new(frame.page_number, PageTableEntryFlags::V); + self.frames.push(frame); + } + + physical_page_number = entry.physical_page_numer(); + } + + &mut physical_page_number.get_page_table_entry_array()[indexes[2]] + } + + fn find_entry(&self, page_number: VirtualPageNumber) -> Option<&mut PageTableEntry> { + let indexes = page_number.get_indexes(); + let mut physical_page_number = self.root_page_number; + + for i in 0..2 { + let entry = &mut physical_page_number.get_page_table_entry_array()[indexes[i]]; + + if !entry.is_valid() { + return None; + } + + physical_page_number = entry.physical_page_numer(); + } + + Some(&mut physical_page_number.get_page_table_entry_array()[indexes[2]]) + } +} diff --git a/os/src/task.rs b/os/src/task.rs index 7a97b46..ddd104e 100644 --- a/os/src/task.rs +++ b/os/src/task.rs @@ -1,7 +1,5 @@ use lazy_static::lazy_static; -use crate::config::MAX_APP_NUM; -use crate::loader::{get_app_num, initialize_app_context}; use crate::log_information; use crate::sbi::shutdown; use crate::sync::single_cell::SingleCell;