diff --git a/.gitignore b/.gitignore index c4e93345..57118437 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,7 @@ os/target/* os/.idea/* os/src/link_app.S +os/Cargo.lock user/target/* -user/.idea/* \ No newline at end of file +user/.idea/* +user/Cargo.lock diff --git a/os/Cargo.lock b/os/Cargo.lock deleted file mode 100644 index 0f37abff..00000000 --- a/os/Cargo.lock +++ /dev/null @@ -1,148 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "aho-corasick" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" -dependencies = [ - "memchr", -] - -[[package]] -name = "bare-metal" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" -dependencies = [ - "rustc_version", -] - -[[package]] -name = "bit_field" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[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.0", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -dependencies = [ - "spin 0.5.2", -] - -[[package]] -name = "memchr" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" - -[[package]] -name = "os" -version = "0.1.0" -dependencies = [ - "buddy_system_allocator", - "lazy_static", - "riscv", -] - -[[package]] -name = "regex" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", - "thread_local", -] - -[[package]] -name = "regex-syntax" -version = "0.6.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" - -[[package]] -name = "riscv" -version = "0.6.0" -source = "git+https://github.com/rcore-os/riscv#21e32ee1dc786cc0d5006ceee0040ce4f8398575" -dependencies = [ - "bare-metal", - "bit_field", - "bitflags", - "riscv-target", -] - -[[package]] -name = "riscv-target" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88aa938cda42a0cf62a20cfe8d139ff1af20c2e681212b5b34adb5a58333f222" -dependencies = [ - "lazy_static", - "regex", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "spin" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "652ac3743312871a5fb703f0337e68ffa3cdc28c863efad0b8dc858fa10c991b" - -[[package]] -name = "thread_local" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -dependencies = [ - "lazy_static", -] diff --git a/os/Cargo.toml b/os/Cargo.toml index 14b9b69b..24c884a8 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -10,6 +10,7 @@ edition = "2018" riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } lazy_static = { version = "1.4.0", features = ["spin_no_std"] } buddy_system_allocator = "0.6" +spin = "0.7.0" [features] board_qemu = [] diff --git a/os/src/config.rs b/os/src/config.rs index eca451bb..e990dd98 100644 --- a/os/src/config.rs +++ b/os/src/config.rs @@ -4,6 +4,9 @@ pub const MAX_APP_NUM: usize = 4; pub const APP_BASE_ADDRESS: usize = 0x80100000; pub const APP_SIZE_LIMIT: usize = 0x20000; pub const KERNEL_HEAP_SIZE: usize = 0x30_0000; +pub const MEMORY_END: usize = 0x80800000; +pub const PAGE_SIZE: usize = 0x1000; +pub const PAGE_SIZE_BITS: usize = 0xc; #[cfg(feature = "board_k210")] pub const CPU_FREQ: usize = 10000000; diff --git a/os/src/main.rs b/os/src/main.rs index 23891178..9955320f 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -37,8 +37,7 @@ fn clear_bss() { pub fn rust_main() -> ! { clear_bss(); println!("[kernel] Hello, world!"); - mm::init_heap(); - mm::heap_test(); + mm::init(); loop {} trap::init(); loader::load_apps(); diff --git a/os/src/mm/address.rs b/os/src/mm/address.rs new file mode 100644 index 00000000..81af1643 --- /dev/null +++ b/os/src/mm/address.rs @@ -0,0 +1,70 @@ +/// T: {PhysAddr, VirtAddr, PhysPageNum, VirtPageNum} +/// T -> usize: T.0 +/// usize -> T: usize.into() +use crate::config::{PAGE_SIZE, PAGE_SIZE_BITS}; + +/// Definitions +#[derive(Copy, Clone, Debug)] +pub struct PhysAddr(pub usize); + +#[derive(Copy, Clone, Debug)] +pub struct VirtAddr(pub usize); + +#[derive(Copy, Clone, Debug)] +pub struct PhysPageNum(pub usize); + +#[derive(Copy, Clone, Debug)] +pub struct VirtPageNum(pub usize); + +impl From for PhysAddr { + fn from(v: usize) -> Self { Self(v) } +} +impl From for PhysPageNum { + fn from(v: usize) -> Self { Self(v) } +} +impl From for usize { + fn from(v: PhysAddr) -> Self { v.0 } +} +impl From for usize { + fn from(v: PhysPageNum) -> Self { v.0 } +} +impl From for VirtAddr { + fn from(v: usize) -> Self { Self(v) } +} +impl From for VirtPageNum { + fn from(v: usize) -> Self { Self(v) } +} +impl From for usize { + fn from(v: VirtAddr) -> Self { v.0 } +} +impl From for usize { + fn from(v: VirtPageNum) -> Self { v.0 } +} +impl VirtAddr { + pub fn floor(&self) -> VirtPageNum { VirtPageNum(self.0 / PAGE_SIZE) } + pub fn ceil(&self) -> VirtPageNum { VirtPageNum((self.0 + PAGE_SIZE - 1) / PAGE_SIZE) } + pub fn page_offset(&self) -> usize { self.0 & (PAGE_SIZE - 1) } +} +impl From for VirtPageNum { + fn from(v: VirtAddr) -> Self { + assert_eq!(v.page_offset(), 0); + v.floor() + } +} +impl From for VirtAddr { + fn from(v: VirtPageNum) -> Self { Self(v.0 << PAGE_SIZE_BITS) } +} +impl PhysAddr { + pub fn floor(&self) -> PhysPageNum { PhysPageNum(self.0 / PAGE_SIZE) } + pub fn ceil(&self) -> PhysPageNum { PhysPageNum((self.0 + PAGE_SIZE - 1) / PAGE_SIZE) } + pub fn page_offset(&self) -> usize { self.0 & (PAGE_SIZE - 1) } +} +impl From for PhysPageNum { + fn from(v: PhysAddr) -> Self { + assert_eq!(v.page_offset(), 0); + v.floor() + } +} +impl From for PhysAddr { + fn from(v: PhysPageNum) -> Self { Self(v.0 << PAGE_SIZE_BITS) } +} \ No newline at end of file diff --git a/os/src/mm/frame_allocator.rs b/os/src/mm/frame_allocator.rs new file mode 100644 index 00000000..8fe56193 --- /dev/null +++ b/os/src/mm/frame_allocator.rs @@ -0,0 +1,118 @@ +use super::{PhysAddr, PhysPageNum}; +use alloc::vec::Vec; +use spin::Mutex; +use crate::config::MEMORY_END; +use lazy_static::*; +use core::fmt::{self, Debug, Formatter}; +pub struct FrameTracker(PhysPageNum); + +impl Debug for FrameTracker { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_fmt(format_args!("FrameTracker:PPN={:#x}", self.0.0)) + } +} + +impl Drop for FrameTracker { + fn drop(&mut self) { + frame_dealloc(self.0); + } +} + +trait FrameAllocator { + fn new() -> Self; + fn alloc(&mut self) -> Option; + fn dealloc(&mut self, ppn: PhysPageNum); +} + +pub struct StackFrameAllocator { + current: usize, + end: usize, + recycled: Vec, +} + +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 { + 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; + +lazy_static! { + pub static ref FRAME_ALLOCATOR: Mutex = + Mutex::new(FrameAllocatorImpl::new()); +} + +pub fn init_frame_allocator() { + extern "C" { + fn ekernel(); + } + FRAME_ALLOCATOR + .lock() + .init(PhysAddr::from(ekernel as usize).ceil(), PhysAddr::from(MEMORY_END).floor()); +} + +pub fn frame_alloc() -> Option { + FRAME_ALLOCATOR + .lock() + .alloc() + .map(|ppn| FrameTracker(ppn)) +} + +fn frame_dealloc(ppn: PhysPageNum) { + FRAME_ALLOCATOR + .lock() + .dealloc(ppn); +} + +#[allow(unused)] +pub fn frame_allocator_test() { + let mut v: Vec = Vec::new(); + for i in 0..5 { + let frame = frame_alloc().unwrap(); + println!("{:?}", frame); + v.push(frame); + } + v.clear(); + for i in 0..5 { + let frame = frame_alloc().unwrap(); + println!("{:?}", frame); + v.push(frame); + } + drop(v); + println!("frame_allocator_test passed!"); +} \ No newline at end of file diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs index 192e27e9..17890ee2 100644 --- a/os/src/mm/mod.rs +++ b/os/src/mm/mod.rs @@ -1,4 +1,11 @@ mod heap_allocator; +mod address; +mod frame_allocator; -pub use heap_allocator::init_heap; -pub use heap_allocator::heap_test; +pub use address::{PhysAddr, VirtAddr, PhysPageNum, VirtPageNum}; +pub use frame_allocator::{FrameTracker, frame_alloc}; + +pub fn init() { + heap_allocator::init_heap(); + frame_allocator::init_frame_allocator(); +} diff --git a/user/Cargo.lock b/user/Cargo.lock deleted file mode 100644 index e28c9137..00000000 --- a/user/Cargo.lock +++ /dev/null @@ -1,5 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "user_lib" -version = "0.1.0"