diff --git a/.github/workflows/doc-and-test.yml b/.github/workflows/doc-and-test.yml index f4027c2..9fee30e 100644 --- a/.github/workflows/doc-and-test.yml +++ b/.github/workflows/doc-and-test.yml @@ -4,7 +4,7 @@ on: [push] env: CARGO_TERM_COLOR: always - rust_toolchain: nightly-2024-01-18 + rust_toolchain: nightly-2025-02-18 jobs: build-doc: @@ -49,7 +49,10 @@ jobs: - name: Install QEMU run: | sudo apt-get update - sudo apt-get install ninja-build -y + sudo apt-get install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev \ + gawk build-essential bison flex texinfo gperf libtool patchutils bc \ + zlib1g-dev libexpat-dev pkg-config libglib2.0-dev libpixman-1-dev libsdl2-dev libslirp-dev \ + python3 python3-pip ninja-build -y if [ ! -d qemu-7.0.0 ]; then wget https://download.qemu.org/qemu-7.0.0.tar.xz tar -xf qemu-7.0.0.tar.xz @@ -65,4 +68,4 @@ jobs: - name: Run usertests run: cd os && make run TEST=1 timeout-minutes: 10 - + diff --git a/.gitignore b/.gitignore index 45fffb0..7e20e83 100644 --- a/.gitignore +++ b/.gitignore @@ -3,14 +3,22 @@ !.vscode/settings.json !.devcontainer/devcontainer.json -**/target/ +.idea **/Cargo.lock +**/target/ os/src/link_app.S os/src/linker.ld os/last-* +os/Cargo.lock os/.gdb_history -os/virt.out +user/build +user/target/* +user/.idea/* +user/Cargo.lock +easy-fs/Cargo.lock +easy-fs/target/* +easy-fs-fuse/Cargo.lock +easy-fs-fuse/target/* tools/ pushall.sh -.vscode/*.log diff --git a/README.md b/README.md index 2df01b0..767cb14 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Here we manually compile and install Qemu 7.0.0. For example, on Ubuntu 18.04: # install dependency packages $ sudo apt install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev \ gawk build-essential bison flex texinfo gperf libtool patchutils bc \ - zlib1g-dev libexpat-dev pkg-config libglib2.0-dev libpixman-1-dev git tmux python3 python3-pip ninja-build + zlib1g-dev libexpat-dev pkg-config libglib2.0-dev libpixman-1-dev git tmux python3 python3-pip # download Qemu source code $ wget https://download.qemu.org/qemu-7.0.0.tar.xz # extract to qemu-7.0.0/ @@ -64,7 +64,9 @@ $ make -j$(nproc) Then, add following contents to `~/.bashrc`(please adjust these paths according to your environment): ``` -export PATH=$PATH:/path/to/qemu-7.0.0/build +export PATH=$PATH:/home/shinbokuow/Downloads/built/qemu-7.0.0 +export PATH=$PATH:/home/shinbokuow/Downloads/built/qemu-7.0.0/riscv64-softmmu +export PATH=$PATH:/home/shinbokuow/Downloads/built/qemu-7.0.0/riscv64-linux-user ``` Finally, update the current shell: diff --git a/easy-fs-fuse/.gitignore b/easy-fs-fuse/.gitignore new file mode 100644 index 0000000..79f5db6 --- /dev/null +++ b/easy-fs-fuse/.gitignore @@ -0,0 +1,3 @@ +.idea/ +target/ +Cargo.lock diff --git a/easy-fs-fuse/Cargo.toml b/easy-fs-fuse/Cargo.toml index d8d4e7f..5c5e68d 100644 --- a/easy-fs-fuse/Cargo.toml +++ b/easy-fs-fuse/Cargo.toml @@ -13,4 +13,4 @@ rand = "0.8.0" # [features] # board_qemu = [] -# board_k210 = [] +# board_k210 = [] \ No newline at end of file diff --git a/easy-fs-fuse/src/main.rs b/easy-fs-fuse/src/main.rs index dceec15..39b9eaf 100644 --- a/easy-fs-fuse/src/main.rs +++ b/easy-fs-fuse/src/main.rs @@ -23,10 +23,6 @@ impl BlockDevice for BlockFile { .expect("Error when seeking!"); assert_eq!(file.write(buf).unwrap(), BLOCK_SZ, "Not a complete block!"); } - - fn handle_irq(&self) { - unimplemented!(); - } } fn main() { @@ -59,11 +55,11 @@ fn easy_fs_pack() -> std::io::Result<()> { .write(true) .create(true) .open(format!("{}{}", target_path, "fs.img"))?; - f.set_len(32 * 2048 * 512).unwrap(); + f.set_len(16 * 2048 * 512).unwrap(); f }))); - // 32MiB, at most 4095 files - let efs = EasyFileSystem::create(block_file, 32 * 2048, 1); + // 16MiB, at most 4095 files + let efs = EasyFileSystem::create(block_file, 16 * 2048, 1); let root_inode = Arc::new(EasyFileSystem::root_inode(&efs)); let apps: Vec<_> = read_dir(src_path) .unwrap() @@ -153,3 +149,59 @@ fn efs_test() -> std::io::Result<()> { Ok(()) } + +#[test] +fn mac_test() -> std::io::Result<()> { + const BLOCK_SZ: usize = 512; + + let block_file = Arc::new(BlockFile(Mutex::new({ + let f = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open("target/fs_mac.img")?; + f.set_len(8192 * BLOCK_SZ).unwrap(); + f + }))); + + EasyFileSystem::create(block_file.clone(), 4096, 1); + let efs = EasyFileSystem::open(block_file.clone()); + let root_inode = EasyFileSystem::root_inode(&efs); + + root_inode.create("root_file"); + root_inode.create("public_file"); + + let secret_inode = root_inode.find("root_file").unwrap(); + secret_inode.write_at(0, b"TOP SECRET: root only!"); + let public_inode = root_inode.find("public_file").unwrap(); + public_inode.write_at(0, b"This file is public."); + + let check_permission = |user: &str, filename: &str| -> bool { + if filename == "root_file" && user != "root" { + false + } else { + true + } + }; + + let users = ["root", "nonroot"]; + for user in users.iter() { + println!("{} task:", user); + + for filename in ["root_file", "public_file"].iter() { + if check_permission(user, filename) { + let inode = root_inode.find(filename).unwrap(); + let mut buf = [0u8; 128]; + let len = inode.read_at(0, &mut buf); + let content = core::str::from_utf8(&buf[..len]).unwrap(); + println!("{}: Opened successfully"); + } else { + println!("{}: Permission denied"); + } + } + + println!(); + } + + Ok(()) +} diff --git a/easy-fs/src/bitmap.rs b/easy-fs/src/bitmap.rs index 2cea613..287e848 100644 --- a/easy-fs/src/bitmap.rs +++ b/easy-fs/src/bitmap.rs @@ -1,16 +1,16 @@ use super::{get_block_cache, BlockDevice, BLOCK_SZ}; use alloc::sync::Arc; - +/// A bitmap block type BitmapBlock = [u64; 64]; - +/// Number of bits in a block const BLOCK_BITS: usize = BLOCK_SZ * 8; - +/// A bitmap pub struct Bitmap { start_block_id: usize, blocks: usize, } -/// Return (block_pos, bits64_pos, inner_pos) +/// Decompose bits into (block_pos, bits64_pos, inner_pos) fn decomposition(mut bit: usize) -> (usize, usize, usize) { let block_pos = bit / BLOCK_BITS; bit %= BLOCK_BITS; @@ -18,13 +18,14 @@ fn decomposition(mut bit: usize) -> (usize, usize, usize) { } impl Bitmap { + /// A new bitmap from start block id and number of blocks pub fn new(start_block_id: usize, blocks: usize) -> Self { Self { start_block_id, blocks, } } - + /// Allocate a new block from a block device pub fn alloc(&self, block_device: &Arc) -> Option { for block_id in 0..self.blocks { let pos = get_block_cache( @@ -52,7 +53,7 @@ impl Bitmap { } None } - + /// Deallocate a block pub fn dealloc(&self, block_device: &Arc, bit: usize) { let (block_pos, bits64_pos, inner_pos) = decomposition(bit); get_block_cache(block_pos + self.start_block_id, Arc::clone(block_device)) @@ -62,7 +63,7 @@ impl Bitmap { bitmap_block[bits64_pos] -= 1u64 << inner_pos; }); } - + /// Get the max number of allocatable blocks pub fn maximum(&self) -> usize { self.blocks * BLOCK_BITS } diff --git a/easy-fs/src/block_cache.rs b/easy-fs/src/block_cache.rs index 1b3b969..786f9e0 100644 --- a/easy-fs/src/block_cache.rs +++ b/easy-fs/src/block_cache.rs @@ -1,15 +1,61 @@ use super::{BlockDevice, BLOCK_SZ}; +use alloc::boxed::Box; use alloc::collections::VecDeque; use alloc::sync::Arc; -use alloc::vec; -use alloc::vec::Vec; +use core::alloc::Layout; +use core::mem::ManuallyDrop; +use core::ptr::{addr_of, addr_of_mut}; +use core::slice; use lazy_static::*; use spin::Mutex; +/// Use `ManuallyDrop` to ensure data is deallocated with an alignment of `BLOCK_SZ` +struct CacheData(ManuallyDrop>); + +impl CacheData { + pub fn new() -> Self { + let data = unsafe { + let raw = alloc::alloc::alloc(Self::layout()); + Box::from_raw(raw as *mut [u8; BLOCK_SZ]) + }; + Self(ManuallyDrop::new(data)) + } + + fn layout() -> Layout { + Layout::from_size_align(BLOCK_SZ, BLOCK_SZ).unwrap() + } +} + +impl Drop for CacheData { + fn drop(&mut self) { + let ptr = self.0.as_mut_ptr(); + unsafe { alloc::alloc::dealloc(ptr, Self::layout()) }; + } +} + +impl AsRef<[u8]> for CacheData { + fn as_ref(&self) -> &[u8] { + let ptr = self.0.as_ptr() as *const u8; + unsafe { slice::from_raw_parts(ptr, BLOCK_SZ) } + } +} + +impl AsMut<[u8]> for CacheData { + fn as_mut(&mut self) -> &mut [u8] { + let ptr = self.0.as_mut_ptr() as *mut u8; + unsafe { slice::from_raw_parts_mut(ptr, BLOCK_SZ) } + } +} + +/// Cached block inside memory pub struct BlockCache { - cache: Vec, + /// cached block data + cache: CacheData, + /// underlying block id block_id: usize, + /// underlying block device block_device: Arc, + /// whether the block is dirty modified: bool, } @@ -17,8 +63,8 @@ impl BlockCache { /// Load a new BlockCache from disk. pub fn new(block_id: usize, block_device: Arc) -> Self { // for alignment and move effciency - let mut cache = vec![0u8; BLOCK_SZ]; - block_device.read_block(block_id, &mut cache); + let mut cache = CacheData::new(); + block_device.read_block(block_id, cache.as_mut()); Self { cache, block_id, @@ -26,9 +72,13 @@ impl BlockCache { modified: false, } } + /// Get the address of an offset inside the cached block data + fn addr_of_offset(&self, offset: usize) -> *const u8 { + addr_of!(self.cache.as_ref()[offset]) + } - fn addr_of_offset(&self, offset: usize) -> usize { - &self.cache[offset] as *const _ as usize + fn addr_of_offset_mut(&mut self, offset: usize) -> *mut u8 { + addr_of_mut!(self.cache.as_mut()[offset]) } pub fn get_ref(&self, offset: usize) -> &T @@ -37,8 +87,8 @@ impl BlockCache { { let type_size = core::mem::size_of::(); assert!(offset + type_size <= BLOCK_SZ); - let addr = self.addr_of_offset(offset); - unsafe { &*(addr as *const T) } + let addr = self.addr_of_offset(offset) as *const T; + unsafe { &*addr } } pub fn get_mut(&mut self, offset: usize) -> &mut T @@ -48,8 +98,8 @@ impl BlockCache { let type_size = core::mem::size_of::(); assert!(offset + type_size <= BLOCK_SZ); self.modified = true; - let addr = self.addr_of_offset(offset); - unsafe { &mut *(addr as *mut T) } + let addr = self.addr_of_offset_mut(offset) as *mut T; + unsafe { &mut *addr } } pub fn read(&self, offset: usize, f: impl FnOnce(&T) -> V) -> V { @@ -63,7 +113,8 @@ impl BlockCache { pub fn sync(&mut self) { if self.modified { self.modified = false; - self.block_device.write_block(self.block_id, &self.cache); + self.block_device + .write_block(self.block_id, self.cache.as_ref()); } } } @@ -73,7 +124,7 @@ impl Drop for BlockCache { self.sync() } } - +/// Use a block cache of 16 blocks const BLOCK_CACHE_SIZE: usize = 16; pub struct BlockCacheManager { @@ -121,10 +172,11 @@ impl BlockCacheManager { } lazy_static! { + /// The global block cache manager pub static ref BLOCK_CACHE_MANAGER: Mutex = Mutex::new(BlockCacheManager::new()); } - +/// Get the block cache corresponding to the given block id and block device pub fn get_block_cache( block_id: usize, block_device: Arc, @@ -133,7 +185,7 @@ pub fn get_block_cache( .lock() .get_block_cache(block_id, block_device) } - +/// Sync all block cache to block device pub fn block_cache_sync_all() { let manager = BLOCK_CACHE_MANAGER.lock(); for (_, cache) in manager.queue.iter() { diff --git a/easy-fs/src/block_dev.rs b/easy-fs/src/block_dev.rs index eb39fbd..555954a 100644 --- a/easy-fs/src/block_dev.rs +++ b/easy-fs/src/block_dev.rs @@ -1,7 +1,9 @@ use core::any::Any; - +/// Trait for block devices +/// which reads and writes data in the unit of blocks pub trait BlockDevice: Send + Sync + Any { + ///Read data form block to buffer fn read_block(&self, block_id: usize, buf: &mut [u8]); + ///Write data from buffer to block fn write_block(&self, block_id: usize, buf: &[u8]); - fn handle_irq(&self); } diff --git a/easy-fs/src/efs.rs b/easy-fs/src/efs.rs index 82e95ae..e28f6b2 100644 --- a/easy-fs/src/efs.rs +++ b/easy-fs/src/efs.rs @@ -5,18 +5,22 @@ use super::{ use crate::BLOCK_SZ; use alloc::sync::Arc; use spin::Mutex; - +///An easy file system on block pub struct EasyFileSystem { + ///Real device pub block_device: Arc, + ///Inode bitmap pub inode_bitmap: Bitmap, + ///Data bitmap pub data_bitmap: Bitmap, inode_area_start_block: u32, data_area_start_block: u32, } type DataBlock = [u8; BLOCK_SZ]; - +/// An easy fs over a block device impl EasyFileSystem { + /// A data block of block size pub fn create( block_device: Arc, total_blocks: u32, @@ -32,7 +36,7 @@ impl EasyFileSystem { let data_bitmap_blocks = (data_total_blocks + 4096) / 4097; let data_area_blocks = data_total_blocks - data_bitmap_blocks; let data_bitmap = Bitmap::new( - (1 + inode_bitmap_blocks + inode_area_blocks) as usize, + (1 + inode_total_blocks) as usize, data_bitmap_blocks as usize, ); let mut efs = Self { @@ -77,7 +81,7 @@ impl EasyFileSystem { block_cache_sync_all(); Arc::new(Mutex::new(efs)) } - + /// Open a block device as a filesystem pub fn open(block_device: Arc) -> Arc> { // read SuperBlock get_block_cache(0, Arc::clone(&block_device)) @@ -99,7 +103,7 @@ impl EasyFileSystem { Arc::new(Mutex::new(efs)) }) } - + /// Get the root inode of the filesystem pub fn root_inode(efs: &Arc>) -> Inode { let block_device = Arc::clone(&efs.lock().block_device); // acquire efs lock temporarily @@ -107,7 +111,7 @@ impl EasyFileSystem { // release efs lock Inode::new(block_id, block_offset, Arc::clone(efs), block_device) } - + /// Get inode by id pub fn get_disk_inode_pos(&self, inode_id: u32) -> (u32, usize) { let inode_size = core::mem::size_of::(); let inodes_per_block = (BLOCK_SZ / inode_size) as u32; @@ -117,20 +121,20 @@ impl EasyFileSystem { (inode_id % inodes_per_block) as usize * inode_size, ) } - + /// Get data block by id pub fn get_data_block_id(&self, data_block_id: u32) -> u32 { self.data_area_start_block + data_block_id } - + /// Allocate a new inode pub fn alloc_inode(&mut self) -> u32 { self.inode_bitmap.alloc(&self.block_device).unwrap() as u32 } - /// Return a block ID not ID in the data area. + /// Allocate a data block pub fn alloc_data(&mut self) -> u32 { self.data_bitmap.alloc(&self.block_device).unwrap() as u32 + self.data_area_start_block } - + /// Deallocate a data block pub fn dealloc_data(&mut self, block_id: u32) { get_block_cache(block_id as usize, Arc::clone(&self.block_device)) .lock() diff --git a/easy-fs/src/layout.rs b/easy-fs/src/layout.rs index 618484c..6daccaf 100644 --- a/easy-fs/src/layout.rs +++ b/easy-fs/src/layout.rs @@ -3,16 +3,24 @@ use alloc::sync::Arc; use alloc::vec::Vec; use core::fmt::{Debug, Formatter, Result}; +/// Magic number for sanity check const EFS_MAGIC: u32 = 0x3b800001; +/// The max number of direct inodes const INODE_DIRECT_COUNT: usize = 28; +/// The max length of inode name const NAME_LENGTH_LIMIT: usize = 27; +/// The max number of indirect1 inodes const INODE_INDIRECT1_COUNT: usize = BLOCK_SZ / 4; +/// The max number of indirect2 inodes const INODE_INDIRECT2_COUNT: usize = INODE_INDIRECT1_COUNT * INODE_INDIRECT1_COUNT; +/// The upper bound of direct inode index const DIRECT_BOUND: usize = INODE_DIRECT_COUNT; +/// The upper bound of indirect1 inode index const INDIRECT1_BOUND: usize = DIRECT_BOUND + INODE_INDIRECT1_COUNT; +/// The upper bound of indirect2 inode indexs #[allow(unused)] const INDIRECT2_BOUND: usize = INDIRECT1_BOUND + INODE_INDIRECT2_COUNT; - +/// Super block of a filesystem #[repr(C)] pub struct SuperBlock { magic: u32, @@ -36,6 +44,7 @@ impl Debug for SuperBlock { } impl SuperBlock { + /// Initialize a super block pub fn initialize( &mut self, total_blocks: u32, @@ -53,20 +62,23 @@ impl SuperBlock { data_area_blocks, } } + /// Check if a super block is valid using efs magic pub fn is_valid(&self) -> bool { self.magic == EFS_MAGIC } } - +/// Type of a disk inode #[derive(PartialEq)] pub enum DiskInodeType { File, Directory, } +/// A indirect block type IndirectBlock = [u32; BLOCK_SZ / 4]; +/// A data block type DataBlock = [u8; BLOCK_SZ]; - +/// A disk inode #[repr(C)] pub struct DiskInode { pub size: u32, @@ -77,7 +89,8 @@ pub struct DiskInode { } impl DiskInode { - /// indirect1 and indirect2 block are allocated only when they are needed. + /// Initialize a disk inode, as well as all direct inodes under it + /// indirect1 and indirect2 block are allocated only when they are needed pub fn initialize(&mut self, type_: DiskInodeType) { self.size = 0; self.direct.iter_mut().for_each(|v| *v = 0); @@ -85,9 +98,11 @@ impl DiskInode { self.indirect2 = 0; self.type_ = type_; } + /// Whether this inode is a directory pub fn is_dir(&self) -> bool { self.type_ == DiskInodeType::Directory } + /// Whether this inode is a file #[allow(unused)] pub fn is_file(&self) -> bool { self.type_ == DiskInodeType::File @@ -116,10 +131,12 @@ impl DiskInode { } total as u32 } + /// Get the number of data blocks that have to be allocated given the new size of data pub fn blocks_num_needed(&self, new_size: u32) -> u32 { assert!(new_size >= self.size); Self::total_blocks(new_size) - Self::total_blocks(self.size) } + /// Get id of block given inner id pub fn get_block_id(&self, inner_id: u32, block_device: &Arc) -> u32 { let inner_id = inner_id as usize; if inner_id < INODE_DIRECT_COUNT { @@ -144,6 +161,7 @@ impl DiskInode { }) } } + /// Inncrease the size of current disk inode pub fn increase_size( &mut self, new_size: u32, @@ -218,7 +236,6 @@ impl DiskInode { } /// Clear size to zero and return blocks that should be deallocated. - /// /// We will clear the block contents to zero later. pub fn clear_size(&mut self, block_device: &Arc) -> Vec { let mut v: Vec = Vec::new(); @@ -291,6 +308,7 @@ impl DiskInode { self.indirect2 = 0; v } + /// Read data from current disk inode pub fn read_at( &self, offset: usize, @@ -330,7 +348,8 @@ impl DiskInode { } read_size } - /// File size must be adjusted before. + /// Write data into current disk inode + /// size must be adjusted properly beforehand pub fn write_at( &mut self, offset: usize, @@ -369,22 +388,24 @@ impl DiskInode { write_size } } - +/// A directory entry #[repr(C)] pub struct DirEntry { name: [u8; NAME_LENGTH_LIMIT + 1], inode_number: u32, } - +/// Size of a directory entry pub const DIRENT_SZ: usize = 32; impl DirEntry { + /// Create an empty directory entry pub fn empty() -> Self { Self { name: [0u8; NAME_LENGTH_LIMIT + 1], inode_number: 0, } } + /// Crate a directory entry from name and inode number pub fn new(name: &str, inode_number: u32) -> Self { let mut bytes = [0u8; NAME_LENGTH_LIMIT + 1]; bytes[..name.len()].copy_from_slice(name.as_bytes()); @@ -393,16 +414,20 @@ impl DirEntry { inode_number, } } + /// Serialize into bytes pub fn as_bytes(&self) -> &[u8] { unsafe { core::slice::from_raw_parts(self as *const _ as usize as *const u8, DIRENT_SZ) } } + /// Serialize into mutable bytes pub fn as_bytes_mut(&mut self) -> &mut [u8] { unsafe { core::slice::from_raw_parts_mut(self as *mut _ as usize as *mut u8, DIRENT_SZ) } } + /// Get name of the entry pub fn name(&self) -> &str { let len = (0usize..).find(|i| self.name[*i] == 0).unwrap(); core::str::from_utf8(&self.name[..len]).unwrap() } + /// Get inode number of the entry pub fn inode_number(&self) -> u32 { self.inode_number } diff --git a/easy-fs/src/lib.rs b/easy-fs/src/lib.rs index fa36e6b..822c237 100644 --- a/easy-fs/src/lib.rs +++ b/easy-fs/src/lib.rs @@ -1,14 +1,14 @@ +//!An easy file system isolated from the kernel #![no_std] - +#![deny(missing_docs)] extern crate alloc; - mod bitmap; mod block_cache; mod block_dev; mod efs; mod layout; mod vfs; - +/// Use a block size of 512 bytes pub const BLOCK_SZ: usize = 512; use bitmap::Bitmap; use block_cache::{block_cache_sync_all, get_block_cache}; diff --git a/easy-fs/src/vfs.rs b/easy-fs/src/vfs.rs index 7290fa4..9f90c50 100644 --- a/easy-fs/src/vfs.rs +++ b/easy-fs/src/vfs.rs @@ -6,7 +6,7 @@ use alloc::string::String; use alloc::sync::Arc; use alloc::vec::Vec; use spin::{Mutex, MutexGuard}; - +/// Virtual filesystem layer over easy-fs pub struct Inode { block_id: usize, block_offset: usize, @@ -15,7 +15,7 @@ pub struct Inode { } impl Inode { - /// We should not acquire efs lock here. + /// Create a vfs inode pub fn new( block_id: u32, block_offset: usize, @@ -29,19 +29,19 @@ impl Inode { block_device, } } - + /// Call a function over a disk inode to read it fn read_disk_inode(&self, f: impl FnOnce(&DiskInode) -> V) -> V { get_block_cache(self.block_id, Arc::clone(&self.block_device)) .lock() .read(self.block_offset, f) } - + /// Call a function over a disk inode to modify it fn modify_disk_inode(&self, f: impl FnOnce(&mut DiskInode) -> V) -> V { get_block_cache(self.block_id, Arc::clone(&self.block_device)) .lock() .modify(self.block_offset, f) } - + /// Find inode under a disk inode by name fn find_inode_id(&self, name: &str, disk_inode: &DiskInode) -> Option { // assert it is a directory assert!(disk_inode.is_dir()); @@ -58,7 +58,7 @@ impl Inode { } None } - + /// Find inode under current inode by name pub fn find(&self, name: &str) -> Option> { let fs = self.fs.lock(); self.read_disk_inode(|disk_inode| { @@ -73,7 +73,7 @@ impl Inode { }) }) } - + /// Increase the size of a disk inode fn increase_size( &self, new_size: u32, @@ -90,16 +90,16 @@ impl Inode { } disk_inode.increase_size(new_size, v, &self.block_device); } - + /// Create inode under current inode by name pub fn create(&self, name: &str) -> Option> { let mut fs = self.fs.lock(); - let op = |root_inode: &mut DiskInode| { + let op = |root_inode: &DiskInode| { // assert it is a directory assert!(root_inode.is_dir()); // has the file been created? self.find_inode_id(name, root_inode) }; - if self.modify_disk_inode(op).is_some() { + if self.read_disk_inode(op).is_some() { return None; } // create a new file @@ -138,7 +138,7 @@ impl Inode { ))) // release efs lock automatically by compiler } - + /// List inodes under current inode pub fn ls(&self) -> Vec { let _fs = self.fs.lock(); self.read_disk_inode(|disk_inode| { @@ -155,12 +155,12 @@ impl Inode { v }) } - + /// Read data from current inode pub fn read_at(&self, offset: usize, buf: &mut [u8]) -> usize { let _fs = self.fs.lock(); self.read_disk_inode(|disk_inode| disk_inode.read_at(offset, buf, &self.block_device)) } - + /// Write data to current inode pub fn write_at(&self, offset: usize, buf: &[u8]) -> usize { let mut fs = self.fs.lock(); let size = self.modify_disk_inode(|disk_inode| { @@ -170,7 +170,7 @@ impl Inode { block_cache_sync_all(); size } - + /// Clear the data in current inode pub fn clear(&self) { let mut fs = self.fs.lock(); self.modify_disk_inode(|disk_inode| { diff --git a/figures/logo.png b/figures/logo.png deleted file mode 100644 index 84af081..0000000 Binary files a/figures/logo.png and /dev/null differ diff --git a/os/Cargo.toml b/os/Cargo.toml index fde4b6c..d621557 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -2,7 +2,7 @@ name = "os" version = "0.1.0" authors = ["Yifan Wu "] -edition = "2021" +edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -12,12 +12,8 @@ lazy_static = { version = "1.4.0", features = ["spin_no_std"] } buddy_system_allocator = "0.6" bitflags = "1.2.1" xmas-elf = "0.7.0" -volatile = "0.3" virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" } -lose-net-stack = { git = "https://github.com/yfblock/lose-net-stack", rev = "db42380" } easy-fs = { path = "../easy-fs" } -embedded-graphics = "0.7.1" -tinybmp = "0.3.1" log = "0.4" sbi-rt = { version = "0.0.2", features = ["legacy"] } diff --git a/os/Makefile b/os/Makefile index b0c3463..ff109f0 100644 --- a/os/Makefile +++ b/os/Makefile @@ -12,12 +12,6 @@ BOARD := qemu SBI ?= rustsbi BOOTLOADER := ../bootloader/$(SBI)-$(BOARD).bin -# GUI -GUI ?= off -ifeq ($(GUI), off) - GUI_OPTION := -display none -endif - # Building mode argument ifeq ($(MODE), release) MODE_ARG := --release @@ -68,27 +62,17 @@ disasm: kernel disasm-vim: kernel @$(OBJDUMP) $(DISASM) $(KERNEL_ELF) > $(DISASM_TMP) - @nvim $(DISASM_TMP) + @vim $(DISASM_TMP) @rm $(DISASM_TMP) run: run-inner QEMU_ARGS := -machine virt \ + -nographic \ -bios $(BOOTLOADER) \ - -serial stdio \ - $(GUI_OPTION) \ -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) \ -drive file=$(FS_IMG),if=none,format=raw,id=x0 \ - -device virtio-blk-device,drive=x0 \ - -device virtio-gpu-device \ - -device virtio-keyboard-device \ - -device virtio-mouse-device \ - -device virtio-net-device,netdev=net0 \ - -netdev user,id=net0,hostfwd=udp::6200-:2000,hostfwd=tcp::6201-:80 - -fdt: - @qemu-system-riscv64 -M 128m -machine virt,dumpdtb=virt.out - fdtdump virt.out + -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0 QEMU_NAME := qemu-system-riscv64 qemu-version-check: @@ -109,4 +93,4 @@ gdbserver: qemu-version-check build gdbclient: @riscv64-unknown-elf-gdb -ex 'file $(KERNEL_ELF)' -ex 'set arch riscv:rv64' -ex 'target remote localhost:1234' -.PHONY: build env kernel clean disasm disasm-vim run-inner fs-img gdbserver gdbclient fdt qemu-version-check +.PHONY: build env kernel clean disasm disasm-vim run-inner fs-img gdbserver gdbclient qemu-version-check diff --git a/os/scripts/qemu-ver-check.sh b/os/scripts/qemu-ver-check.sh old mode 100644 new mode 100755 index 8c20456..40ef766 --- a/os/scripts/qemu-ver-check.sh +++ b/os/scripts/qemu-ver-check.sh @@ -13,7 +13,7 @@ then exit 1 else QEMU_VERSION=$($1 --version|head -n 1|awk '{print $4}') - MAJOR_VERSION=$(echo $QEMU_VERSION|cut -c1-1) + MAJOR_VERSION=$(echo $QEMU_VERSION | awk -F '.' '{print $1}') if [ $MAJOR_VERSION -lt $MINIMUM_MAJOR_VERSION ] then echo "${RED}Error: Required major version of QEMU is ${MINIMUM_MAJOR_VERSION}, " \ diff --git a/os/src/assert/desktop.bmp b/os/src/assert/desktop.bmp deleted file mode 100644 index a754f7a..0000000 Binary files a/os/src/assert/desktop.bmp and /dev/null differ diff --git a/os/src/assert/file.bmp b/os/src/assert/file.bmp deleted file mode 100644 index 4a4e83b..0000000 Binary files a/os/src/assert/file.bmp and /dev/null differ diff --git a/os/src/assert/folder.bmp b/os/src/assert/folder.bmp deleted file mode 100644 index c8384cb..0000000 Binary files a/os/src/assert/folder.bmp and /dev/null differ diff --git a/os/src/assert/mouse.bmp b/os/src/assert/mouse.bmp deleted file mode 100644 index 22a4613..0000000 Binary files a/os/src/assert/mouse.bmp and /dev/null differ diff --git a/os/src/boards/qemu.rs b/os/src/boards/qemu.rs index 5daf541..275de4d 100644 --- a/os/src/boards/qemu.rs +++ b/os/src/boards/qemu.rs @@ -3,53 +3,7 @@ pub const MEMORY_END: usize = 0x8800_0000; pub const MMIO: &[(usize, usize)] = &[ (0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine - (0x2000000, 0x10000), // core local interrupter (CLINT) - (0xc000000, 0x210000), // VIRT_PLIC in virt machine - (0x10000000, 0x9000), // VIRT_UART0 with GPU in virt machine + (0x1000_1000, 0x00_1000), // Virtio Block in virt machine ]; pub type BlockDeviceImpl = crate::drivers::block::VirtIOBlock; -pub type CharDeviceImpl = crate::drivers::chardev::NS16550a; - -pub const VIRT_PLIC: usize = 0xC00_0000; -pub const VIRT_UART: usize = 0x1000_0000; -#[allow(unused)] -pub const VIRTGPU_XRES: u32 = 1280; -#[allow(unused)] -pub const VIRTGPU_YRES: u32 = 800; - -use crate::drivers::block::BLOCK_DEVICE; -use crate::drivers::chardev::{CharDevice, UART}; -use crate::drivers::plic::{IntrTargetPriority, PLIC}; -use crate::drivers::{KEYBOARD_DEVICE, MOUSE_DEVICE}; - -pub fn device_init() { - use riscv::register::sie; - let mut plic = unsafe { PLIC::new(VIRT_PLIC) }; - let hart_id: usize = 0; - let supervisor = IntrTargetPriority::Supervisor; - let machine = IntrTargetPriority::Machine; - plic.set_threshold(hart_id, supervisor, 0); - plic.set_threshold(hart_id, machine, 1); - //irq nums: 5 keyboard, 6 mouse, 8 block, 10 uart - for intr_src_id in [5usize, 6, 8, 10] { - plic.enable(hart_id, supervisor, intr_src_id); - plic.set_priority(intr_src_id, 1); - } - unsafe { - sie::set_sext(); - } -} - -pub fn irq_handler() { - let mut plic = unsafe { PLIC::new(VIRT_PLIC) }; - let intr_src_id = plic.claim(0, IntrTargetPriority::Supervisor); - match intr_src_id { - 5 => KEYBOARD_DEVICE.handle_irq(), - 6 => MOUSE_DEVICE.handle_irq(), - 8 => BLOCK_DEVICE.handle_irq(), - 10 => UART.handle_irq(), - _ => panic!("unsupported IRQ {}", intr_src_id), - } - plic.complete(0, IntrTargetPriority::Supervisor, intr_src_id); -} diff --git a/os/src/config.rs b/os/src/config.rs index d9b9b71..f9a2b7f 100644 --- a/os/src/config.rs +++ b/os/src/config.rs @@ -1,12 +1,14 @@ +//! Constants used in rCore #[allow(unused)] pub const USER_STACK_SIZE: usize = 4096 * 2; pub const KERNEL_STACK_SIZE: usize = 4096 * 2; -pub const KERNEL_HEAP_SIZE: usize = 0x100_0000; +pub const KERNEL_HEAP_SIZE: usize = 0x20_0000; + pub const PAGE_SIZE: usize = 0x1000; pub const PAGE_SIZE_BITS: usize = 0xc; pub const TRAMPOLINE: usize = usize::MAX - PAGE_SIZE + 1; -pub const TRAP_CONTEXT_BASE: usize = TRAMPOLINE - PAGE_SIZE; +pub const TRAP_CONTEXT: usize = TRAMPOLINE - PAGE_SIZE; pub use crate::board::{CLOCK_FREQ, MEMORY_END, MMIO}; diff --git a/os/src/console.rs b/os/src/console.rs index 085637b..5435310 100644 --- a/os/src/console.rs +++ b/os/src/console.rs @@ -1,5 +1,5 @@ -use crate::drivers::chardev::CharDevice; -use crate::drivers::chardev::UART; +//! SBI console driver, for text output +use crate::sbi::console_putchar; use core::fmt::{self, Write}; struct Stdout; @@ -7,7 +7,7 @@ struct Stdout; impl Write for Stdout { fn write_str(&mut self, s: &str) -> fmt::Result { for c in s.chars() { - UART.write(c as u8); + console_putchar(c as usize); } Ok(()) } @@ -18,15 +18,17 @@ pub fn print(args: fmt::Arguments) { } #[macro_export] +/// print string macro macro_rules! print { ($fmt: literal $(, $($arg: tt)+)?) => { - $crate::console::print(format_args!($fmt $(, $($arg)+)?)) + $crate::console::print(format_args!($fmt $(, $($arg)+)?)); } } #[macro_export] +/// println string macro macro_rules! println { ($fmt: literal $(, $($arg: tt)+)?) => { - $crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?)) + $crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?)); } } diff --git a/os/src/drivers/block/virtio_blk.rs b/os/src/drivers/block/virtio_blk.rs index fb89084..5097831 100644 --- a/os/src/drivers/block/virtio_blk.rs +++ b/os/src/drivers/block/virtio_blk.rs @@ -1,87 +1,83 @@ use super::BlockDevice; -use crate::drivers::bus::virtio::VirtioHal; -use crate::sync::{Condvar, UPIntrFreeCell}; -use crate::task::schedule; -use crate::DEV_NON_BLOCKING_ACCESS; -use alloc::collections::BTreeMap; -use virtio_drivers::{BlkResp, RespStatus, VirtIOBlk, VirtIOHeader}; +use crate::mm::{ + FrameTracker, PageTable, PhysAddr, PhysPageNum, StepByOne, VirtAddr, frame_alloc, + frame_dealloc, kernel_token, +}; +use crate::sync::UPSafeCell; +use alloc::vec::Vec; +use lazy_static::*; +use virtio_drivers::{Hal, VirtIOBlk, VirtIOHeader}; #[allow(unused)] -const VIRTIO0: usize = 0x10008000; +const VIRTIO0: usize = 0x10001000; -pub struct VirtIOBlock { - virtio_blk: UPIntrFreeCell>, - condvars: BTreeMap, +pub struct VirtIOBlock(UPSafeCell>); + +lazy_static! { + static ref QUEUE_FRAMES: UPSafeCell> = unsafe { UPSafeCell::new(Vec::new()) }; } impl BlockDevice for VirtIOBlock { fn read_block(&self, block_id: usize, buf: &mut [u8]) { - let nb = *DEV_NON_BLOCKING_ACCESS.exclusive_access(); - if nb { - let mut resp = BlkResp::default(); - let task_cx_ptr = self.virtio_blk.exclusive_session(|blk| { - let token = unsafe { blk.read_block_nb(block_id, buf, &mut resp).unwrap() }; - self.condvars.get(&token).unwrap().wait_no_sched() - }); - schedule(task_cx_ptr); - assert_eq!( - resp.status(), - RespStatus::Ok, - "Error when reading VirtIOBlk" - ); - } else { - self.virtio_blk - .exclusive_access() - .read_block(block_id, buf) - .expect("Error when reading VirtIOBlk"); - } + self.0 + .exclusive_access() + .read_block(block_id, buf) + .expect("Error when reading VirtIOBlk"); } fn write_block(&self, block_id: usize, buf: &[u8]) { - let nb = *DEV_NON_BLOCKING_ACCESS.exclusive_access(); - if nb { - let mut resp = BlkResp::default(); - let task_cx_ptr = self.virtio_blk.exclusive_session(|blk| { - let token = unsafe { blk.write_block_nb(block_id, buf, &mut resp).unwrap() }; - self.condvars.get(&token).unwrap().wait_no_sched() - }); - schedule(task_cx_ptr); - assert_eq!( - resp.status(), - RespStatus::Ok, - "Error when writing VirtIOBlk" - ); - } else { - self.virtio_blk - .exclusive_access() - .write_block(block_id, buf) - .expect("Error when writing VirtIOBlk"); - } - } - fn handle_irq(&self) { - self.virtio_blk.exclusive_session(|blk| { - while let Ok(token) = blk.pop_used() { - self.condvars.get(&token).unwrap().signal(); - } - }); + self.0 + .exclusive_access() + .write_block(block_id, buf) + .expect("Error when writing VirtIOBlk"); } } impl VirtIOBlock { + #[allow(unused)] pub fn new() -> Self { - let virtio_blk = unsafe { - UPIntrFreeCell::new( + unsafe { + Self(UPSafeCell::new( VirtIOBlk::::new(&mut *(VIRTIO0 as *mut VirtIOHeader)).unwrap(), - ) - }; - let mut condvars = BTreeMap::new(); - let channels = virtio_blk.exclusive_access().virt_queue_size(); - for i in 0..channels { - let condvar = Condvar::new(); - condvars.insert(i, condvar); - } - Self { - virtio_blk, - condvars, + )) } } } + +pub struct VirtioHal; + +impl Hal for VirtioHal { + fn dma_alloc(pages: usize) -> usize { + let mut ppn_base = PhysPageNum(0); + for i in 0..pages { + let frame = frame_alloc().unwrap(); + if i == 0 { + ppn_base = frame.ppn; + } + assert_eq!(frame.ppn.0, ppn_base.0 + i); + QUEUE_FRAMES.exclusive_access().push(frame); + } + let pa: PhysAddr = ppn_base.into(); + pa.0 + } + + fn dma_dealloc(pa: usize, pages: usize) -> i32 { + let pa = PhysAddr::from(pa); + let mut ppn_base: PhysPageNum = pa.into(); + for _ in 0..pages { + frame_dealloc(ppn_base); + ppn_base.step(); + } + 0 + } + + fn phys_to_virt(addr: usize) -> usize { + addr + } + + fn virt_to_phys(vaddr: usize) -> usize { + PageTable::from_token(kernel_token()) + .translate_va(VirtAddr::from(vaddr)) + .unwrap() + .0 + } +} diff --git a/os/src/drivers/bus/mod.rs b/os/src/drivers/bus/mod.rs deleted file mode 100644 index d43f304..0000000 --- a/os/src/drivers/bus/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod virtio; diff --git a/os/src/drivers/bus/virtio.rs b/os/src/drivers/bus/virtio.rs deleted file mode 100644 index 069d478..0000000 --- a/os/src/drivers/bus/virtio.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::mm::{ - frame_alloc_more, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum, - StepByOne, VirtAddr, -}; -use crate::sync::UPIntrFreeCell; -use alloc::vec::Vec; -use lazy_static::*; -use virtio_drivers::Hal; - -lazy_static! { - static ref QUEUE_FRAMES: UPIntrFreeCell> = - unsafe { UPIntrFreeCell::new(Vec::new()) }; -} - -pub struct VirtioHal; - -impl Hal for VirtioHal { - fn dma_alloc(pages: usize) -> usize { - let trakcers = frame_alloc_more(pages); - let ppn_base = trakcers.as_ref().unwrap().last().unwrap().ppn; - QUEUE_FRAMES - .exclusive_access() - .append(&mut trakcers.unwrap()); - let pa: PhysAddr = ppn_base.into(); - pa.0 - } - - fn dma_dealloc(pa: usize, pages: usize) -> i32 { - let pa = PhysAddr::from(pa); - let mut ppn_base: PhysPageNum = pa.into(); - for _ in 0..pages { - frame_dealloc(ppn_base); - ppn_base.step(); - } - 0 - } - - fn phys_to_virt(addr: usize) -> usize { - addr - } - - fn virt_to_phys(vaddr: usize) -> usize { - PageTable::from_token(kernel_token()) - .translate_va(VirtAddr::from(vaddr)) - .unwrap() - .0 - } -} diff --git a/os/src/drivers/chardev/mod.rs b/os/src/drivers/chardev/mod.rs deleted file mode 100644 index 64c168f..0000000 --- a/os/src/drivers/chardev/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -mod ns16550a; - -use crate::board::CharDeviceImpl; -use alloc::sync::Arc; -use lazy_static::*; -pub use ns16550a::NS16550a; - -pub trait CharDevice { - fn init(&self); - fn read(&self) -> u8; - fn write(&self, ch: u8); - fn handle_irq(&self); -} - -lazy_static! { - pub static ref UART: Arc = Arc::new(CharDeviceImpl::new()); -} diff --git a/os/src/drivers/chardev/ns16550a.rs b/os/src/drivers/chardev/ns16550a.rs deleted file mode 100644 index 7122cec..0000000 --- a/os/src/drivers/chardev/ns16550a.rs +++ /dev/null @@ -1,186 +0,0 @@ -///! Ref: https://www.lammertbies.nl/comm/info/serial-uart -///! Ref: ns16550a datasheet: https://datasheetspdf.com/pdf-file/605590/NationalSemiconductor/NS16550A/1 -///! Ref: ns16450 datasheet: https://datasheetspdf.com/pdf-file/1311818/NationalSemiconductor/NS16450/1 -use super::CharDevice; -use crate::sync::{Condvar, UPIntrFreeCell}; -use crate::task::schedule; -use alloc::collections::VecDeque; -use bitflags::*; -use volatile::{ReadOnly, Volatile, WriteOnly}; - -bitflags! { - /// InterruptEnableRegister - pub struct IER: u8 { - const RX_AVAILABLE = 1 << 0; - const TX_EMPTY = 1 << 1; - } - - /// LineStatusRegister - pub struct LSR: u8 { - const DATA_AVAILABLE = 1 << 0; - const THR_EMPTY = 1 << 5; - } - - /// Model Control Register - pub struct MCR: u8 { - const DATA_TERMINAL_READY = 1 << 0; - const REQUEST_TO_SEND = 1 << 1; - const AUX_OUTPUT1 = 1 << 2; - const AUX_OUTPUT2 = 1 << 3; - } -} - -#[repr(C)] -#[allow(dead_code)] -struct ReadWithoutDLAB { - /// receiver buffer register - pub rbr: ReadOnly, - /// interrupt enable register - pub ier: Volatile, - /// interrupt identification register - pub iir: ReadOnly, - /// line control register - pub lcr: Volatile, - /// model control register - pub mcr: Volatile, - /// line status register - pub lsr: ReadOnly, - /// ignore MSR - _padding1: ReadOnly, - /// ignore SCR - _padding2: ReadOnly, -} - -#[repr(C)] -#[allow(dead_code)] -struct WriteWithoutDLAB { - /// transmitter holding register - pub thr: WriteOnly, - /// interrupt enable register - pub ier: Volatile, - /// ignore FCR - _padding0: ReadOnly, - /// line control register - pub lcr: Volatile, - /// modem control register - pub mcr: Volatile, - /// line status register - pub lsr: ReadOnly, - /// ignore other registers - _padding1: ReadOnly, -} - -pub struct NS16550aRaw { - base_addr: usize, -} - -impl NS16550aRaw { - fn read_end(&mut self) -> &mut ReadWithoutDLAB { - unsafe { &mut *(self.base_addr as *mut ReadWithoutDLAB) } - } - - fn write_end(&mut self) -> &mut WriteWithoutDLAB { - unsafe { &mut *(self.base_addr as *mut WriteWithoutDLAB) } - } - - pub fn new(base_addr: usize) -> Self { - Self { base_addr } - } - - pub fn init(&mut self) { - let read_end = self.read_end(); - let mut mcr = MCR::empty(); - mcr |= MCR::DATA_TERMINAL_READY; - mcr |= MCR::REQUEST_TO_SEND; - mcr |= MCR::AUX_OUTPUT2; - read_end.mcr.write(mcr); - let ier = IER::RX_AVAILABLE; - read_end.ier.write(ier); - } - - pub fn read(&mut self) -> Option { - let read_end = self.read_end(); - let lsr = read_end.lsr.read(); - if lsr.contains(LSR::DATA_AVAILABLE) { - Some(read_end.rbr.read()) - } else { - None - } - } - - pub fn write(&mut self, ch: u8) { - let write_end = self.write_end(); - loop { - if write_end.lsr.read().contains(LSR::THR_EMPTY) { - write_end.thr.write(ch); - break; - } - } - } -} - -struct NS16550aInner { - ns16550a: NS16550aRaw, - read_buffer: VecDeque, -} - -pub struct NS16550a { - inner: UPIntrFreeCell, - condvar: Condvar, -} - -impl NS16550a { - pub fn new() -> Self { - let inner = NS16550aInner { - ns16550a: NS16550aRaw::new(BASE_ADDR), - read_buffer: VecDeque::new(), - }; - //inner.ns16550a.init(); - Self { - inner: unsafe { UPIntrFreeCell::new(inner) }, - condvar: Condvar::new(), - } - } - - pub fn read_buffer_is_empty(&self) -> bool { - self.inner - .exclusive_session(|inner| inner.read_buffer.is_empty()) - } -} - -impl CharDevice for NS16550a { - fn init(&self) { - let mut inner = self.inner.exclusive_access(); - inner.ns16550a.init(); - drop(inner); - } - - fn read(&self) -> u8 { - loop { - let mut inner = self.inner.exclusive_access(); - if let Some(ch) = inner.read_buffer.pop_front() { - return ch; - } else { - let task_cx_ptr = self.condvar.wait_no_sched(); - drop(inner); - schedule(task_cx_ptr); - } - } - } - fn write(&self, ch: u8) { - let mut inner = self.inner.exclusive_access(); - inner.ns16550a.write(ch); - } - fn handle_irq(&self) { - let mut count = 0; - self.inner.exclusive_session(|inner| { - while let Some(ch) = inner.ns16550a.read() { - count += 1; - inner.read_buffer.push_back(ch); - } - }); - if count > 0 { - self.condvar.signal(); - } - } -} diff --git a/os/src/drivers/gpu/mod.rs b/os/src/drivers/gpu/mod.rs deleted file mode 100644 index 759633f..0000000 --- a/os/src/drivers/gpu/mod.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::drivers::bus::virtio::VirtioHal; -use crate::sync::UPIntrFreeCell; -use alloc::{sync::Arc, vec::Vec}; -use core::any::Any; -use embedded_graphics::pixelcolor::Rgb888; -use tinybmp::Bmp; -use virtio_drivers::{VirtIOGpu, VirtIOHeader}; -const VIRTIO7: usize = 0x10007000; -pub trait GpuDevice: Send + Sync + Any { - fn update_cursor(&self); - fn get_framebuffer(&self) -> &mut [u8]; - fn flush(&self); -} - -lazy_static::lazy_static!( - pub static ref GPU_DEVICE: Arc = Arc::new(VirtIOGpuWrapper::new()); -); - -pub struct VirtIOGpuWrapper { - gpu: UPIntrFreeCell>, - fb: &'static [u8], -} -static BMP_DATA: &[u8] = include_bytes!("../../assert/mouse.bmp"); -impl VirtIOGpuWrapper { - pub fn new() -> Self { - unsafe { - let mut virtio = - VirtIOGpu::::new(&mut *(VIRTIO7 as *mut VirtIOHeader)).unwrap(); - - let fbuffer = virtio.setup_framebuffer().unwrap(); - let len = fbuffer.len(); - let ptr = fbuffer.as_mut_ptr(); - let fb = core::slice::from_raw_parts_mut(ptr, len); - - let bmp = Bmp::::from_slice(BMP_DATA).unwrap(); - let raw = bmp.as_raw(); - let mut b = Vec::new(); - for i in raw.image_data().chunks(3) { - let mut v = i.to_vec(); - b.append(&mut v); - if i == [255, 255, 255] { - b.push(0x0) - } else { - b.push(0xff) - } - } - virtio.setup_cursor(b.as_slice(), 50, 50, 50, 50).unwrap(); - - Self { - gpu: UPIntrFreeCell::new(virtio), - fb, - } - } - } -} - -impl GpuDevice for VirtIOGpuWrapper { - fn flush(&self) { - self.gpu.exclusive_access().flush().unwrap(); - } - fn get_framebuffer(&self) -> &mut [u8] { - unsafe { - let ptr = self.fb.as_ptr() as *const _ as *mut u8; - core::slice::from_raw_parts_mut(ptr, self.fb.len()) - } - } - fn update_cursor(&self) {} -} diff --git a/os/src/drivers/input/mod.rs b/os/src/drivers/input/mod.rs deleted file mode 100644 index a9f5f0b..0000000 --- a/os/src/drivers/input/mod.rs +++ /dev/null @@ -1,83 +0,0 @@ -use crate::drivers::bus::virtio::VirtioHal; -use crate::sync::{Condvar, UPIntrFreeCell}; -use crate::task::schedule; -use alloc::collections::VecDeque; -use alloc::sync::Arc; -use core::any::Any; -use virtio_drivers::{VirtIOHeader, VirtIOInput}; - -const VIRTIO5: usize = 0x10005000; -const VIRTIO6: usize = 0x10006000; - -struct VirtIOInputInner { - virtio_input: VirtIOInput<'static, VirtioHal>, - events: VecDeque, -} - -struct VirtIOInputWrapper { - inner: UPIntrFreeCell, - condvar: Condvar, -} - -pub trait InputDevice: Send + Sync + Any { - fn read_event(&self) -> u64; - fn handle_irq(&self); - fn is_empty(&self) -> bool; -} - -lazy_static::lazy_static!( - pub static ref KEYBOARD_DEVICE: Arc = Arc::new(VirtIOInputWrapper::new(VIRTIO5)); - pub static ref MOUSE_DEVICE: Arc = Arc::new(VirtIOInputWrapper::new(VIRTIO6)); -); - -impl VirtIOInputWrapper { - pub fn new(addr: usize) -> Self { - let inner = VirtIOInputInner { - virtio_input: unsafe { - VirtIOInput::::new(&mut *(addr as *mut VirtIOHeader)).unwrap() - }, - events: VecDeque::new(), - }; - Self { - inner: unsafe { UPIntrFreeCell::new(inner) }, - condvar: Condvar::new(), - } - } -} - -impl InputDevice for VirtIOInputWrapper { - fn is_empty(&self) -> bool { - self.inner.exclusive_access().events.is_empty() - } - - fn read_event(&self) -> u64 { - loop { - let mut inner = self.inner.exclusive_access(); - if let Some(event) = inner.events.pop_front() { - return event; - } else { - let task_cx_ptr = self.condvar.wait_no_sched(); - drop(inner); - schedule(task_cx_ptr); - } - } - } - - fn handle_irq(&self) { - let mut count = 0; - let mut result = 0; - self.inner.exclusive_session(|inner| { - inner.virtio_input.ack_interrupt(); - while let Some(event) = inner.virtio_input.pop_pending_event() { - count += 1; - result = (event.event_type as u64) << 48 - | (event.code as u64) << 32 - | (event.value) as u64; - inner.events.push_back(result); - } - }); - if count > 0 { - self.condvar.signal(); - }; - } -} diff --git a/os/src/drivers/mod.rs b/os/src/drivers/mod.rs index 605397d..c2dea36 100644 --- a/os/src/drivers/mod.rs +++ b/os/src/drivers/mod.rs @@ -1,13 +1,3 @@ pub mod block; -pub mod bus; -pub mod chardev; -pub mod gpu; -pub mod input; -pub mod net; -pub mod plic; pub use block::BLOCK_DEVICE; -pub use bus::*; -pub use gpu::*; -pub use input::*; -pub use net::*; diff --git a/os/src/drivers/net/mod.rs b/os/src/drivers/net/mod.rs deleted file mode 100644 index 7a70587..0000000 --- a/os/src/drivers/net/mod.rs +++ /dev/null @@ -1,46 +0,0 @@ -use core::any::Any; - -use crate::drivers::virtio::VirtioHal; -use crate::sync::UPIntrFreeCell; -use alloc::sync::Arc; -use lazy_static::*; -use virtio_drivers::{VirtIOHeader, VirtIONet}; - -const VIRTIO8: usize = 0x10004000; - -lazy_static! { - pub static ref NET_DEVICE: Arc = Arc::new(VirtIONetWrapper::new()); -} - -pub trait NetDevice: Send + Sync + Any { - fn transmit(&self, data: &[u8]); - fn receive(&self, data: &mut [u8]) -> usize; -} - -pub struct VirtIONetWrapper(UPIntrFreeCell>); - -impl NetDevice for VirtIONetWrapper { - fn transmit(&self, data: &[u8]) { - self.0 - .exclusive_access() - .send(data) - .expect("can't send data") - } - - fn receive(&self, data: &mut [u8]) -> usize { - self.0 - .exclusive_access() - .recv(data) - .expect("can't receive data") - } -} - -impl VirtIONetWrapper { - pub fn new() -> Self { - unsafe { - let virtio = VirtIONet::::new(&mut *(VIRTIO8 as *mut VirtIOHeader)) - .expect("can't create net device by virtio"); - VirtIONetWrapper(UPIntrFreeCell::new(virtio)) - } - } -} diff --git a/os/src/drivers/plic.rs b/os/src/drivers/plic.rs deleted file mode 100644 index 77bad5f..0000000 --- a/os/src/drivers/plic.rs +++ /dev/null @@ -1,124 +0,0 @@ -#[allow(clippy::upper_case_acronyms)] -pub struct PLIC { - base_addr: usize, -} - -#[derive(Copy, Clone)] -pub enum IntrTargetPriority { - Machine = 0, - Supervisor = 1, -} - -impl IntrTargetPriority { - pub fn supported_number() -> usize { - 2 - } -} - -impl PLIC { - fn priority_ptr(&self, intr_source_id: usize) -> *mut u32 { - assert!(intr_source_id > 0 && intr_source_id <= 132); - (self.base_addr + intr_source_id * 4) as *mut u32 - } - fn hart_id_with_priority(hart_id: usize, target_priority: IntrTargetPriority) -> usize { - let priority_num = IntrTargetPriority::supported_number(); - hart_id * priority_num + target_priority as usize - } - fn enable_ptr( - &self, - hart_id: usize, - target_priority: IntrTargetPriority, - intr_source_id: usize, - ) -> (*mut u32, usize) { - let id = Self::hart_id_with_priority(hart_id, target_priority); - let (reg_id, reg_shift) = (intr_source_id / 32, intr_source_id % 32); - ( - (self.base_addr + 0x2000 + 0x80 * id + 0x4 * reg_id) as *mut u32, - reg_shift, - ) - } - fn threshold_ptr_of_hart_with_priority( - &self, - hart_id: usize, - target_priority: IntrTargetPriority, - ) -> *mut u32 { - let id = Self::hart_id_with_priority(hart_id, target_priority); - (self.base_addr + 0x20_0000 + 0x1000 * id) as *mut u32 - } - fn claim_comp_ptr_of_hart_with_priority( - &self, - hart_id: usize, - target_priority: IntrTargetPriority, - ) -> *mut u32 { - let id = Self::hart_id_with_priority(hart_id, target_priority); - (self.base_addr + 0x20_0004 + 0x1000 * id) as *mut u32 - } - pub unsafe fn new(base_addr: usize) -> Self { - Self { base_addr } - } - pub fn set_priority(&mut self, intr_source_id: usize, priority: u32) { - assert!(priority < 8); - unsafe { - self.priority_ptr(intr_source_id).write_volatile(priority); - } - } - #[allow(unused)] - pub fn get_priority(&mut self, intr_source_id: usize) -> u32 { - unsafe { self.priority_ptr(intr_source_id).read_volatile() & 7 } - } - pub fn enable( - &mut self, - hart_id: usize, - target_priority: IntrTargetPriority, - intr_source_id: usize, - ) { - let (reg_ptr, shift) = self.enable_ptr(hart_id, target_priority, intr_source_id); - unsafe { - reg_ptr.write_volatile(reg_ptr.read_volatile() | 1 << shift); - } - } - #[allow(unused)] - pub fn disable( - &mut self, - hart_id: usize, - target_priority: IntrTargetPriority, - intr_source_id: usize, - ) { - let (reg_ptr, shift) = self.enable_ptr(hart_id, target_priority, intr_source_id); - unsafe { - reg_ptr.write_volatile(reg_ptr.read_volatile() & (!(1u32 << shift))); - } - } - pub fn set_threshold( - &mut self, - hart_id: usize, - target_priority: IntrTargetPriority, - threshold: u32, - ) { - assert!(threshold < 8); - let threshold_ptr = self.threshold_ptr_of_hart_with_priority(hart_id, target_priority); - unsafe { - threshold_ptr.write_volatile(threshold); - } - } - #[allow(unused)] - pub fn get_threshold(&mut self, hart_id: usize, target_priority: IntrTargetPriority) -> u32 { - let threshold_ptr = self.threshold_ptr_of_hart_with_priority(hart_id, target_priority); - unsafe { threshold_ptr.read_volatile() & 7 } - } - pub fn claim(&mut self, hart_id: usize, target_priority: IntrTargetPriority) -> u32 { - let claim_comp_ptr = self.claim_comp_ptr_of_hart_with_priority(hart_id, target_priority); - unsafe { claim_comp_ptr.read_volatile() } - } - pub fn complete( - &mut self, - hart_id: usize, - target_priority: IntrTargetPriority, - completion: u32, - ) { - let claim_comp_ptr = self.claim_comp_ptr_of_hart_with_priority(hart_id, target_priority); - unsafe { - claim_comp_ptr.write_volatile(completion); - } - } -} diff --git a/os/src/entry.asm b/os/src/entry.asm index c32d68f..3a9990f 100644 --- a/os/src/entry.asm +++ b/os/src/entry.asm @@ -9,4 +9,4 @@ _start: boot_stack_lower_bound: .space 4096 * 16 .globl boot_stack_top -boot_stack_top: +boot_stack_top: \ No newline at end of file diff --git a/os/src/fs/inode.rs b/os/src/fs/inode.rs index 321338d..2490d6a 100644 --- a/os/src/fs/inode.rs +++ b/os/src/fs/inode.rs @@ -1,32 +1,41 @@ +//! `Arc` -> `OSInodeInner`: In order to open files concurrently +//! we need to wrap `Inode` into `Arc`,but `Mutex` in `Inode` prevents +//! file systems from being accessed simultaneously +//! +//! `UPSafeCell` -> `OSInode`: for static `ROOT_INODE`,we +//! need to wrap `OSInodeInner` into `UPSafeCell` use super::File; use crate::drivers::BLOCK_DEVICE; use crate::mm::UserBuffer; -use crate::sync::UPIntrFreeCell; +use crate::sync::UPSafeCell; use alloc::sync::Arc; use alloc::vec::Vec; use bitflags::*; use easy_fs::{EasyFileSystem, Inode}; use lazy_static::*; - +/// A wrapper around a filesystem inode +/// to implement File trait atop pub struct OSInode { readable: bool, writable: bool, - inner: UPIntrFreeCell, + inner: UPSafeCell, } - +/// The OS inode inner in 'UPSafeCell' pub struct OSInodeInner { offset: usize, inode: Arc, } impl OSInode { + /// Construct an OS inode from a inode pub fn new(readable: bool, writable: bool, inode: Arc) -> Self { Self { readable, writable, - inner: unsafe { UPIntrFreeCell::new(OSInodeInner { offset: 0, inode }) }, + inner: unsafe { UPSafeCell::new(OSInodeInner { offset: 0, inode }) }, } } + /// Read all data inside a inode into vector pub fn read_all(&self) -> Vec { let mut inner = self.inner.exclusive_access(); let mut buffer = [0u8; 512]; @@ -49,21 +58,27 @@ lazy_static! { Arc::new(EasyFileSystem::root_inode(&efs)) }; } - +/// List all files in the filesystems pub fn list_apps() { println!("/**** APPS ****"); for app in ROOT_INODE.ls() { println!("{}", app); } - println!("**************/") + println!("**************/"); } bitflags! { + ///Open file flags pub struct OpenFlags: u32 { + ///Read only const RDONLY = 0; + ///Write only const WRONLY = 1 << 0; + ///Read & Write const RDWR = 1 << 1; + ///Allow create const CREATE = 1 << 9; + ///Clear file and return an empty one const TRUNC = 1 << 10; } } @@ -81,7 +96,7 @@ impl OpenFlags { } } } - +///Open file with flags pub fn open_file(name: &str, flags: OpenFlags) -> Option> { let (readable, writable) = flags.read_write(); if flags.contains(OpenFlags::CREATE) { diff --git a/os/src/fs/mod.rs b/os/src/fs/mod.rs index cbde739..c3cc1e7 100644 --- a/os/src/fs/mod.rs +++ b/os/src/fs/mod.rs @@ -1,16 +1,19 @@ +//! File system in os mod inode; -mod pipe; mod stdio; use crate::mm::UserBuffer; - +/// File trait pub trait File: Send + Sync { + /// If readable fn readable(&self) -> bool; + /// If writable fn writable(&self) -> bool; + /// Read file to `UserBuffer` fn read(&self, buf: UserBuffer) -> usize; + /// Write `UserBuffer` to file fn write(&self, buf: UserBuffer) -> usize; } -pub use inode::{list_apps, open_file, OpenFlags}; -pub use pipe::make_pipe; +pub use inode::{OSInode, OpenFlags, list_apps, open_file}; pub use stdio::{Stdin, Stdout}; diff --git a/os/src/fs/pipe.rs b/os/src/fs/pipe.rs deleted file mode 100644 index d10dc33..0000000 --- a/os/src/fs/pipe.rs +++ /dev/null @@ -1,173 +0,0 @@ -use super::File; -use crate::mm::UserBuffer; -use crate::sync::UPIntrFreeCell; -use alloc::sync::{Arc, Weak}; - -use crate::task::suspend_current_and_run_next; - -pub struct Pipe { - readable: bool, - writable: bool, - buffer: Arc>, -} - -impl Pipe { - pub fn read_end_with_buffer(buffer: Arc>) -> Self { - Self { - readable: true, - writable: false, - buffer, - } - } - pub fn write_end_with_buffer(buffer: Arc>) -> Self { - Self { - readable: false, - writable: true, - buffer, - } - } -} - -const RING_BUFFER_SIZE: usize = 32; - -#[derive(Copy, Clone, PartialEq)] -enum RingBufferStatus { - Full, - Empty, - Normal, -} - -pub struct PipeRingBuffer { - arr: [u8; RING_BUFFER_SIZE], - head: usize, - tail: usize, - status: RingBufferStatus, - write_end: Option>, -} - -impl PipeRingBuffer { - pub fn new() -> Self { - Self { - arr: [0; RING_BUFFER_SIZE], - head: 0, - tail: 0, - status: RingBufferStatus::Empty, - write_end: None, - } - } - pub fn set_write_end(&mut self, write_end: &Arc) { - self.write_end = Some(Arc::downgrade(write_end)); - } - pub fn write_byte(&mut self, byte: u8) { - self.status = RingBufferStatus::Normal; - self.arr[self.tail] = byte; - self.tail = (self.tail + 1) % RING_BUFFER_SIZE; - if self.tail == self.head { - self.status = RingBufferStatus::Full; - } - } - pub fn read_byte(&mut self) -> u8 { - self.status = RingBufferStatus::Normal; - let c = self.arr[self.head]; - self.head = (self.head + 1) % RING_BUFFER_SIZE; - if self.head == self.tail { - self.status = RingBufferStatus::Empty; - } - c - } - pub fn available_read(&self) -> usize { - if self.status == RingBufferStatus::Empty { - 0 - } else if self.tail > self.head { - self.tail - self.head - } else { - self.tail + RING_BUFFER_SIZE - self.head - } - } - pub fn available_write(&self) -> usize { - if self.status == RingBufferStatus::Full { - 0 - } else { - RING_BUFFER_SIZE - self.available_read() - } - } - pub fn all_write_ends_closed(&self) -> bool { - self.write_end.as_ref().unwrap().upgrade().is_none() - } -} - -/// Return (read_end, write_end) -pub fn make_pipe() -> (Arc, Arc) { - let buffer = Arc::new(unsafe { UPIntrFreeCell::new(PipeRingBuffer::new()) }); - let read_end = Arc::new(Pipe::read_end_with_buffer(buffer.clone())); - let write_end = Arc::new(Pipe::write_end_with_buffer(buffer.clone())); - buffer.exclusive_access().set_write_end(&write_end); - (read_end, write_end) -} - -impl File for Pipe { - fn readable(&self) -> bool { - self.readable - } - fn writable(&self) -> bool { - self.writable - } - fn read(&self, buf: UserBuffer) -> usize { - assert!(self.readable()); - let want_to_read = buf.len(); - let mut buf_iter = buf.into_iter(); - let mut already_read = 0usize; - loop { - let mut ring_buffer = self.buffer.exclusive_access(); - let loop_read = ring_buffer.available_read(); - if loop_read == 0 { - if ring_buffer.all_write_ends_closed() { - return already_read; - } - drop(ring_buffer); - suspend_current_and_run_next(); - continue; - } - for _ in 0..loop_read { - if let Some(byte_ref) = buf_iter.next() { - unsafe { - *byte_ref = ring_buffer.read_byte(); - } - already_read += 1; - if already_read == want_to_read { - return want_to_read; - } - } else { - return already_read; - } - } - } - } - fn write(&self, buf: UserBuffer) -> usize { - assert!(self.writable()); - let want_to_write = buf.len(); - let mut buf_iter = buf.into_iter(); - let mut already_write = 0usize; - loop { - let mut ring_buffer = self.buffer.exclusive_access(); - let loop_write = ring_buffer.available_write(); - if loop_write == 0 { - drop(ring_buffer); - suspend_current_and_run_next(); - continue; - } - // write at most loop_write bytes - for _ in 0..loop_write { - if let Some(byte_ref) = buf_iter.next() { - ring_buffer.write_byte(unsafe { *byte_ref }); - already_write += 1; - if already_write == want_to_write { - return want_to_write; - } - } else { - return already_write; - } - } - } - } -} diff --git a/os/src/fs/stdio.rs b/os/src/fs/stdio.rs index 66f4c5a..8375ac9 100644 --- a/os/src/fs/stdio.rs +++ b/os/src/fs/stdio.rs @@ -1,9 +1,11 @@ +//!Stdin & Stdout use super::File; -use crate::drivers::chardev::CharDevice; -use crate::drivers::chardev::UART; use crate::mm::UserBuffer; - +use crate::sbi::console_getchar; +use crate::task::suspend_current_and_run_next; +///Standard input pub struct Stdin; +///Standard output pub struct Stdout; impl File for Stdin { @@ -15,8 +17,18 @@ impl File for Stdin { } fn read(&self, mut user_buf: UserBuffer) -> usize { assert_eq!(user_buf.len(), 1); - //println!("before UART.read() in Stdin::read()"); - let ch = UART.read(); + // busy loop + let mut c: usize; + loop { + c = console_getchar(); + if c == 0 { + suspend_current_and_run_next(); + continue; + } else { + break; + } + } + let ch = c as u8; unsafe { user_buf.buffers[0].as_mut_ptr().write_volatile(ch); } diff --git a/os/src/lang_items.rs b/os/src/lang_items.rs index 021f16f..79cd51e 100644 --- a/os/src/lang_items.rs +++ b/os/src/lang_items.rs @@ -1,6 +1,5 @@ +//! The panic handler use crate::sbi::shutdown; -use crate::task::current_kstack_top; -use core::arch::asm; use core::panic::PanicInfo; use log::*; @@ -11,28 +10,10 @@ fn panic(info: &PanicInfo) -> ! { "[kernel] Panicked at {}:{} {}", location.file(), location.line(), - info.message().unwrap() + info.message() ); } else { - error!("[kernel] Panicked: {}", info.message().unwrap()); - } - unsafe { - backtrace(); + error!("[kernel] Panicked: {}", info.message()); } shutdown(true) } - -unsafe fn backtrace() { - let mut fp: usize; - let stop = current_kstack_top(); - asm!("mv {}, s0", out(reg) fp); - println!("---START BACKTRACE---"); - for i in 0..10 { - if fp == stop { - break; - } - println!("#{}:ra={:#x}", i, *((fp - 8) as *const usize)); - fp = *((fp - 16) as *const usize); - } - println!("---END BACKTRACE---"); -} diff --git a/os/src/logging.rs b/os/src/logging.rs new file mode 100644 index 0000000..b5421f1 --- /dev/null +++ b/os/src/logging.rs @@ -0,0 +1,47 @@ +/*! + +本模块利用 log crate 为你提供了日志功能,使用方式见 main.rs. + +*/ + +use log::{self, Level, LevelFilter, Log, Metadata, Record}; + +struct SimpleLogger; + +impl Log for SimpleLogger { + fn enabled(&self, _metadata: &Metadata) -> bool { + true + } + fn log(&self, record: &Record) { + if !self.enabled(record.metadata()) { + return; + } + let color = match record.level() { + Level::Error => 31, // Red + Level::Warn => 93, // BrightYellow + Level::Info => 34, // Blue + Level::Debug => 32, // Green + Level::Trace => 90, // BrightBlack + }; + println!( + "\u{1B}[{}m[{:>5}] {}\u{1B}[0m", + color, + record.level(), + record.args(), + ); + } + fn flush(&self) {} +} + +pub fn init() { + static LOGGER: SimpleLogger = SimpleLogger; + log::set_logger(&LOGGER).unwrap(); + log::set_max_level(match option_env!("LOG") { + Some("ERROR") => LevelFilter::Error, + Some("WARN") => LevelFilter::Warn, + Some("INFO") => LevelFilter::Info, + Some("DEBUG") => LevelFilter::Debug, + Some("TRACE") => LevelFilter::Trace, + _ => LevelFilter::Info, + }); +} diff --git a/os/src/main.rs b/os/src/main.rs index 276aaf5..46161de 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -1,15 +1,37 @@ +//! The main module and entrypoint +//! +//! Various facilities of the kernels are implemented as submodules. The most +//! important ones are: +//! +//! - [`trap`]: Handles all cases of switching from userspace to the kernel +//! - [`task`]: Task management +//! - [`syscall`]: System call handling and implementation +//! - [`mm`]: Address map using SV39 +//! - [`sync`]: Wrap a static data structure inside it so that we are able to access it without any `unsafe`. +//! - [`fs`]: Separate user from file system with some structures +//! +//! The operating system also starts in this module. Kernel code starts +//! executing from `entry.asm`, after which [`rust_main()`] is called to +//! initialize various pieces of functionality. (See its source code for +//! details.) +//! +//! We then call [`task::run_tasks()`] and for the first time go to +//! userspace. + +#![deny(missing_docs)] +#![deny(warnings)] +#![allow(unused_imports)] #![no_std] #![no_main] -#![feature(panic_info_message)] #![feature(alloc_error_handler)] -//use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE, INPUT_CONDVAR}; -use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE}; extern crate alloc; #[macro_use] extern crate bitflags; +use log::*; + #[path = "boards/qemu.rs"] mod board; @@ -17,26 +39,25 @@ mod board; mod console; mod config; mod drivers; -mod fs; -mod lang_items; -mod mm; -mod net; -mod sbi; -mod sync; -mod syscall; -mod task; -mod timer; -mod trap; +pub mod fs; +pub mod lang_items; +mod logging; +pub mod mm; +pub mod sbi; +pub mod sync; +pub mod syscall; +pub mod task; +pub mod timer; +pub mod trap; -use crate::drivers::chardev::CharDevice; -use crate::drivers::chardev::UART; - -core::arch::global_asm!(include_str!("entry.asm")); +use core::arch::global_asm; +global_asm!(include_str!("entry.asm")); +/// clear BSS segment fn clear_bss() { - extern "C" { - fn sbss(); - fn ebss(); + unsafe extern "C" { + safe fn sbss(); + safe fn ebss(); } unsafe { core::slice::from_raw_parts_mut(sbss as usize as *mut u8, ebss as usize - sbss as usize) @@ -44,33 +65,19 @@ fn clear_bss() { } } -use lazy_static::*; -use sync::UPIntrFreeCell; - -lazy_static! { - pub static ref DEV_NON_BLOCKING_ACCESS: UPIntrFreeCell = - unsafe { UPIntrFreeCell::new(false) }; -} - -#[no_mangle] +/// the rust entry-point of os +#[unsafe(no_mangle)] pub fn rust_main() -> ! { clear_bss(); + logging::init(); + info!("[kernel] Hello, world!"); mm::init(); - UART.init(); - println!("KERN: init gpu"); - let _gpu = GPU_DEVICE.clone(); - println!("KERN: init keyboard"); - let _keyboard = KEYBOARD_DEVICE.clone(); - println!("KERN: init mouse"); - let _mouse = MOUSE_DEVICE.clone(); - println!("KERN: init trap"); + mm::remap_test(); trap::init(); trap::enable_timer_interrupt(); timer::set_next_trigger(); - board::device_init(); fs::list_apps(); task::add_initproc(); - *DEV_NON_BLOCKING_ACCESS.exclusive_access() = true; task::run_tasks(); panic!("Unreachable in rust_main!"); } diff --git a/os/src/mm/address.rs b/os/src/mm/address.rs index df3e130..f0ee691 100644 --- a/os/src/mm/address.rs +++ b/os/src/mm/address.rs @@ -1,3 +1,4 @@ +//! Implementation of physical and virtual address and page number. use super::PageTableEntry; use crate::config::{PAGE_SIZE, PAGE_SIZE_BITS}; use core::fmt::{self, Debug, Formatter}; @@ -14,14 +15,17 @@ pub struct PhysAddr(pub usize); #[repr(C)] #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +///virtual address pub struct VirtAddr(pub usize); #[repr(C)] #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +///phiscal page number pub struct PhysPageNum(pub usize); #[repr(C)] #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +///virtual page number pub struct VirtPageNum(pub usize); /// Debugging @@ -95,11 +99,13 @@ impl From for usize { v.0 } } - +/// impl VirtAddr { + ///`VirtAddr`->`VirtPageNum` pub fn floor(&self) -> VirtPageNum { VirtPageNum(self.0 / PAGE_SIZE) } + ///`VirtAddr`->`VirtPageNum` pub fn ceil(&self) -> VirtPageNum { if self.0 == 0 { VirtPageNum(0) @@ -107,9 +113,11 @@ impl VirtAddr { VirtPageNum((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE) } } + ///Get page offset pub fn page_offset(&self) -> usize { self.0 & (PAGE_SIZE - 1) } + ///Check page aligned pub fn aligned(&self) -> bool { self.page_offset() == 0 } @@ -126,9 +134,11 @@ impl From for VirtAddr { } } impl PhysAddr { + ///`PhysAddr`->`PhysPageNum` pub fn floor(&self) -> PhysPageNum { PhysPageNum(self.0 / PAGE_SIZE) } + ///`PhysAddr`->`PhysPageNum` pub fn ceil(&self) -> PhysPageNum { if self.0 == 0 { PhysPageNum(0) @@ -136,9 +146,11 @@ impl PhysAddr { PhysPageNum((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE) } } + ///Get page offset pub fn page_offset(&self) -> usize { self.0 & (PAGE_SIZE - 1) } + ///Check page aligned pub fn aligned(&self) -> bool { self.page_offset() == 0 } @@ -156,6 +168,7 @@ impl From for PhysAddr { } impl VirtPageNum { + ///Return VPN 3 level index pub fn indexes(&self) -> [usize; 3] { let mut vpn = self.0; let mut idx = [0usize; 3]; @@ -168,29 +181,35 @@ impl VirtPageNum { } impl PhysAddr { + ///Get reference to `PhysAddr` value pub fn get_ref(&self) -> &'static T { unsafe { (self.0 as *const T).as_ref().unwrap() } } + ///Get mutable reference to `PhysAddr` value pub fn get_mut(&self) -> &'static mut T { unsafe { (self.0 as *mut T).as_mut().unwrap() } } } impl PhysPageNum { + ///Get `PageTableEntry` on `PhysPageNum` pub fn get_pte_array(&self) -> &'static mut [PageTableEntry] { let pa: PhysAddr = (*self).into(); unsafe { core::slice::from_raw_parts_mut(pa.0 as *mut PageTableEntry, 512) } } + ///Get u8 array on `PhysPageNum` pub fn get_bytes_array(&self) -> &'static mut [u8] { let pa: PhysAddr = (*self).into(); unsafe { core::slice::from_raw_parts_mut(pa.0 as *mut u8, 4096) } } + ///Get Get mutable reference to `PhysAddr` value on `PhysPageNum` pub fn get_mut(&self) -> &'static mut T { let pa: PhysAddr = (*self).into(); pa.get_mut() } } - +///Add value by one pub trait StepByOne { + ///Add value by one fn step(&mut self); } impl StepByOne for VirtPageNum { @@ -205,6 +224,7 @@ impl StepByOne for PhysPageNum { } #[derive(Copy, Clone)] +/// a simple range structure for type T pub struct SimpleRange where T: StepByOne + Copy + PartialEq + PartialOrd + Debug, @@ -237,6 +257,7 @@ where SimpleRangeIterator::new(self.l, self.r) } } +/// iterator for the simple range structure pub struct SimpleRangeIterator where T: StepByOne + Copy + PartialEq + PartialOrd + Debug, @@ -267,4 +288,5 @@ where } } } +/// a simple range structure for virtual page number pub type VPNRange = SimpleRange; diff --git a/os/src/mm/frame_allocator.rs b/os/src/mm/frame_allocator.rs index 163bb57..28b519c 100644 --- a/os/src/mm/frame_allocator.rs +++ b/os/src/mm/frame_allocator.rs @@ -1,15 +1,20 @@ +//! Implementation of [`FrameAllocator`] which +//! controls all the frames in the operating system. use super::{PhysAddr, PhysPageNum}; use crate::config::MEMORY_END; -use crate::sync::UPIntrFreeCell; +use crate::sync::UPSafeCell; use alloc::vec::Vec; use core::fmt::{self, Debug, Formatter}; use lazy_static::*; +/// manage a frame which has the same lifecycle as the tracker pub struct FrameTracker { + /// pub ppn: PhysPageNum, } impl FrameTracker { + ///Create an empty `FrameTracker` pub fn new(ppn: PhysPageNum) -> Self { // page cleaning let bytes_array = ppn.get_bytes_array(); @@ -35,10 +40,9 @@ impl Drop for FrameTracker { trait FrameAllocator { fn new() -> Self; fn alloc(&mut self) -> Option; - fn alloc_more(&mut self, pages: usize) -> Option>; fn dealloc(&mut self, ppn: PhysPageNum); } - +/// an implementation for frame allocator pub struct StackFrameAllocator { current: usize, end: usize, @@ -49,7 +53,7 @@ impl StackFrameAllocator { pub fn init(&mut self, l: PhysPageNum, r: PhysPageNum) { self.current = l.0; self.end = r.0; - // println!("last {} Physical Frames.", self.end - self.current); + println!("last {} Physical Frames.", self.end - self.current); } } impl FrameAllocator for StackFrameAllocator { @@ -70,16 +74,6 @@ impl FrameAllocator for StackFrameAllocator { Some((self.current - 1).into()) } } - fn alloc_more(&mut self, pages: usize) -> Option> { - if self.current + pages >= self.end { - None - } else { - self.current += pages; - let arr: Vec = (1..pages + 1).collect(); - let v = arr.iter().map(|x| (self.current - x).into()).collect(); - Some(v) - } - } fn dealloc(&mut self, ppn: PhysPageNum) { let ppn = ppn.0; // validity check @@ -94,39 +88,34 @@ impl FrameAllocator for StackFrameAllocator { type FrameAllocatorImpl = StackFrameAllocator; lazy_static! { - pub static ref FRAME_ALLOCATOR: UPIntrFreeCell = - unsafe { UPIntrFreeCell::new(FrameAllocatorImpl::new()) }; + /// frame allocator instance through lazy_static! + pub static ref FRAME_ALLOCATOR: UPSafeCell = + unsafe { UPSafeCell::new(FrameAllocatorImpl::new()) }; } - +/// initiate the frame allocator using `ekernel` and `MEMORY_END` pub fn init_frame_allocator() { - extern "C" { - fn ekernel(); + unsafe extern "C" { + safe fn ekernel(); } FRAME_ALLOCATOR.exclusive_access().init( PhysAddr::from(ekernel as usize).ceil(), PhysAddr::from(MEMORY_END).floor(), ); } - +/// allocate a frame pub fn frame_alloc() -> Option { FRAME_ALLOCATOR .exclusive_access() .alloc() .map(FrameTracker::new) } - -pub fn frame_alloc_more(num: usize) -> Option> { - FRAME_ALLOCATOR - .exclusive_access() - .alloc_more(num) - .map(|x| x.iter().map(|&t| FrameTracker::new(t)).collect()) -} - +/// deallocate a frame pub fn frame_dealloc(ppn: PhysPageNum) { FRAME_ALLOCATOR.exclusive_access().dealloc(ppn); } #[allow(unused)] +/// a simple test for frame allocator pub fn frame_allocator_test() { let mut v: Vec = Vec::new(); for i in 0..5 { @@ -143,20 +132,3 @@ pub fn frame_allocator_test() { drop(v); println!("frame_allocator_test passed!"); } - -#[allow(unused)] -pub fn frame_allocator_alloc_more_test() { - let mut v: Vec = Vec::new(); - let frames = frame_alloc_more(5).unwrap(); - for frame in &frames { - println!("{:?}", frame); - } - v.extend(frames); - v.clear(); - let frames = frame_alloc_more(5).unwrap(); - for frame in &frames { - println!("{:?}", frame); - } - drop(v); - println!("frame_allocator_test passed!"); -} diff --git a/os/src/mm/heap_allocator.rs b/os/src/mm/heap_allocator.rs index 42a6d76..a6b413b 100644 --- a/os/src/mm/heap_allocator.rs +++ b/os/src/mm/heap_allocator.rs @@ -1,21 +1,25 @@ +//! The global allocator use crate::config::KERNEL_HEAP_SIZE; use buddy_system_allocator::LockedHeap; +use core::ptr::addr_of_mut; #[global_allocator] +/// heap allocator instance static HEAP_ALLOCATOR: LockedHeap = LockedHeap::empty(); #[alloc_error_handler] +/// panic when heap allocation error occurs pub fn handle_alloc_error(layout: core::alloc::Layout) -> ! { panic!("Heap allocation error, layout = {:?}", layout); } - +/// heap space ([u8; KERNEL_HEAP_SIZE]) static mut HEAP_SPACE: [u8; KERNEL_HEAP_SIZE] = [0; KERNEL_HEAP_SIZE]; - +/// initiate heap allocator pub fn init_heap() { unsafe { HEAP_ALLOCATOR .lock() - .init(HEAP_SPACE.as_ptr() as usize, KERNEL_HEAP_SIZE); + .init(addr_of_mut!(HEAP_SPACE) as usize, KERNEL_HEAP_SIZE); } } @@ -23,9 +27,9 @@ pub fn init_heap() { pub fn heap_test() { use alloc::boxed::Box; use alloc::vec::Vec; - extern "C" { - fn sbss(); - fn ebss(); + unsafe extern "C" { + safe fn sbss(); + safe fn ebss(); } let bss_range = sbss as usize..ebss as usize; let a = Box::new(5); diff --git a/os/src/mm/memory_set.rs b/os/src/mm/memory_set.rs index d607c88..b1e5072 100644 --- a/os/src/mm/memory_set.rs +++ b/os/src/mm/memory_set.rs @@ -1,9 +1,11 @@ -use super::{frame_alloc, FrameTracker}; +//! Implementation of [`MapArea`] and [`MemorySet`]. + +use super::{FrameTracker, frame_alloc}; use super::{PTEFlags, PageTable, PageTableEntry}; use super::{PhysAddr, PhysPageNum, VirtAddr, VirtPageNum}; use super::{StepByOne, VPNRange}; -use crate::config::{MEMORY_END, MMIO, PAGE_SIZE, TRAMPOLINE}; -use crate::sync::UPIntrFreeCell; +use crate::config::{MEMORY_END, MMIO, PAGE_SIZE, TRAMPOLINE, TRAP_CONTEXT, USER_STACK_SIZE}; +use crate::sync::UPSafeCell; use alloc::collections::BTreeMap; use alloc::sync::Arc; use alloc::vec::Vec; @@ -11,40 +13,43 @@ use core::arch::asm; use lazy_static::*; use riscv::register::satp; -extern "C" { - fn stext(); - fn etext(); - fn srodata(); - fn erodata(); - fn sdata(); - fn edata(); - fn sbss_with_stack(); - fn ebss(); - fn ekernel(); - fn strampoline(); +unsafe extern "C" { + safe fn stext(); + safe fn etext(); + safe fn srodata(); + safe fn erodata(); + safe fn sdata(); + safe fn edata(); + safe fn sbss_with_stack(); + safe fn ebss(); + safe fn ekernel(); + safe fn strampoline(); } lazy_static! { - pub static ref KERNEL_SPACE: Arc> = - Arc::new(unsafe { UPIntrFreeCell::new(MemorySet::new_kernel()) }); + /// a memory set instance through lazy_static! managing kernel space + pub static ref KERNEL_SPACE: Arc> = + Arc::new(unsafe { UPSafeCell::new(MemorySet::new_kernel()) }); } - +///Get kernelspace root ppn pub fn kernel_token() -> usize { KERNEL_SPACE.exclusive_access().token() } - +/// memory set structure, controls virtual-memory space pub struct MemorySet { page_table: PageTable, areas: Vec, } impl MemorySet { + ///Create an empty `MemorySet` pub fn new_bare() -> Self { Self { page_table: PageTable::new(), areas: Vec::new(), } } + ///Get pagetable `root_ppn` pub fn token(&self) -> usize { self.page_table.token() } @@ -60,6 +65,7 @@ impl MemorySet { None, ); } + ///Remove `MapArea` that starts with `start_vpn` pub fn remove_area_with_start_vpn(&mut self, start_vpn: VirtPageNum) { if let Some((idx, area)) = self .areas @@ -71,10 +77,7 @@ impl MemorySet { self.areas.remove(idx); } } - /// Add a new MapArea into this MemorySet. - /// Assuming that there are no conflicts in the virtual address - /// space. - pub fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) { + fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) { map_area.map(&mut self.page_table); if let Some(data) = data { map_area.copy_data(&self.page_table, data); @@ -95,14 +98,14 @@ impl MemorySet { // map trampoline memory_set.map_trampoline(); // map kernel sections - // println!(".text [{:#x}, {:#x})", stext as usize, etext as usize); - // println!(".rodata [{:#x}, {:#x})", srodata as usize, erodata as usize); - // println!(".data [{:#x}, {:#x})", sdata as usize, edata as usize); - // println!( - // ".bss [{:#x}, {:#x})", - // sbss_with_stack as usize, ebss as usize - // ); - // println!("mapping .text section"); + println!(".text [{:#x}, {:#x})", stext as usize, etext as usize); + println!(".rodata [{:#x}, {:#x})", srodata as usize, erodata as usize); + println!(".data [{:#x}, {:#x})", sdata as usize, edata as usize); + println!( + ".bss [{:#x}, {:#x})", + sbss_with_stack as usize, ebss as usize + ); + println!("mapping .text section"); memory_set.push( MapArea::new( (stext as usize).into(), @@ -112,7 +115,7 @@ impl MemorySet { ), None, ); - // println!("mapping .rodata section"); + println!("mapping .rodata section"); memory_set.push( MapArea::new( (srodata as usize).into(), @@ -122,7 +125,7 @@ impl MemorySet { ), None, ); - // println!("mapping .data section"); + println!("mapping .data section"); memory_set.push( MapArea::new( (sdata as usize).into(), @@ -132,7 +135,7 @@ impl MemorySet { ), None, ); - // println!("mapping .bss section"); + println!("mapping .bss section"); memory_set.push( MapArea::new( (sbss_with_stack as usize).into(), @@ -142,7 +145,7 @@ impl MemorySet { ), None, ); - // println!("mapping physical memory"); + println!("mapping physical memory"); memory_set.push( MapArea::new( (ekernel as usize).into(), @@ -152,7 +155,7 @@ impl MemorySet { ), None, ); - //println!("mapping memory-mapped registers"); + println!("mapping memory-mapped registers"); for pair in MMIO { memory_set.push( MapArea::new( @@ -166,8 +169,8 @@ impl MemorySet { } memory_set } - /// Include sections in elf and trampoline, - /// also returns user_sp_base and entry point. + /// Include sections in elf and trampoline and TrapContext and user stack, + /// also returns user_sp and entry point. pub fn from_elf(elf_data: &[u8]) -> (Self, usize, usize) { let mut memory_set = Self::new_bare(); // map trampoline @@ -203,15 +206,38 @@ impl MemorySet { ); } } + // map user stack with U flags let max_end_va: VirtAddr = max_end_vpn.into(); - let mut user_stack_base: usize = max_end_va.into(); - user_stack_base += PAGE_SIZE; + let mut user_stack_bottom: usize = max_end_va.into(); + // guard page + user_stack_bottom += PAGE_SIZE; + let user_stack_top = user_stack_bottom + USER_STACK_SIZE; + memory_set.push( + MapArea::new( + user_stack_bottom.into(), + user_stack_top.into(), + MapType::Framed, + MapPermission::R | MapPermission::W | MapPermission::U, + ), + None, + ); + // map TrapContext + memory_set.push( + MapArea::new( + TRAP_CONTEXT.into(), + TRAMPOLINE.into(), + MapType::Framed, + MapPermission::R | MapPermission::W, + ), + None, + ); ( memory_set, - user_stack_base, + user_stack_top, elf.header.pt2.entry_point() as usize, ) } + ///Clone a same `MemorySet` pub fn from_existed_user(user_space: &MemorySet) -> MemorySet { let mut memory_set = Self::new_bare(); // map trampoline @@ -231,6 +257,7 @@ impl MemorySet { } memory_set } + ///Refresh TLB with `sfence.vma` pub fn activate(&self) { let satp = self.page_table.token(); unsafe { @@ -238,15 +265,17 @@ impl MemorySet { asm!("sfence.vma"); } } + ///Translate throuth pagetable pub fn translate(&self, vpn: VirtPageNum) -> Option { self.page_table.translate(vpn) } + ///Remove all `MapArea` pub fn recycle_data_pages(&mut self) { //*self = Self::new_bare(); self.areas.clear(); } } - +/// map area structure, controls a contiguous piece of virtual memory pub struct MapArea { vpn_range: VPNRange, data_frames: BTreeMap, @@ -289,11 +318,6 @@ impl MapArea { ppn = frame.ppn; self.data_frames.insert(vpn, frame); } - MapType::Linear(pn_offset) => { - // check for sv39 - assert!(vpn.0 < (1usize << 27)); - ppn = PhysPageNum((vpn.0 as isize + pn_offset) as usize); - } } let pte_flags = PTEFlags::from_bits(self.map_perm.bits).unwrap(); page_table.map(vpn, ppn, pte_flags); @@ -339,42 +363,53 @@ impl MapArea { } #[derive(Copy, Clone, PartialEq, Debug)] +/// map type for memory set: identical or framed pub enum MapType { Identical, Framed, - /// offset of page num - Linear(isize), } bitflags! { + /// map permission corresponding to that in pte: `R W X U` pub struct MapPermission: u8 { + ///Readable const R = 1 << 1; + ///Writable const W = 1 << 2; + ///Excutable const X = 1 << 3; + ///Accessible in U mode const U = 1 << 4; } } #[allow(unused)] +///Check PageTable running correctly pub fn remap_test() { let mut kernel_space = KERNEL_SPACE.exclusive_access(); let mid_text: VirtAddr = ((stext as usize + etext as usize) / 2).into(); let mid_rodata: VirtAddr = ((srodata as usize + erodata as usize) / 2).into(); let mid_data: VirtAddr = ((sdata as usize + edata as usize) / 2).into(); - assert!(!kernel_space - .page_table - .translate(mid_text.floor()) - .unwrap() - .writable(),); - assert!(!kernel_space - .page_table - .translate(mid_rodata.floor()) - .unwrap() - .writable(),); - assert!(!kernel_space - .page_table - .translate(mid_data.floor()) - .unwrap() - .executable(),); + assert!( + !kernel_space + .page_table + .translate(mid_text.floor()) + .unwrap() + .writable(), + ); + assert!( + !kernel_space + .page_table + .translate(mid_rodata.floor()) + .unwrap() + .writable(), + ); + assert!( + !kernel_space + .page_table + .translate(mid_data.floor()) + .unwrap() + .executable(), + ); println!("remap_test passed!"); } diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs index 642d0b7..3255725 100644 --- a/os/src/mm/mod.rs +++ b/os/src/mm/mod.rs @@ -1,19 +1,27 @@ +//! Memory management implementation +//! +//! SV39 page-based virtual-memory architecture for RV64 systems, and +//! everything about memory management, like frame allocator, page table, +//! map area and memory set, is implemented here. +//! +//! Every task or process has a memory_set to control its virtual memory. mod address; mod frame_allocator; mod heap_allocator; mod memory_set; mod page_table; -pub use address::VPNRange; +use address::VPNRange; pub use address::{PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum}; -pub use frame_allocator::{frame_alloc, frame_alloc_more, frame_dealloc, FrameTracker}; -pub use memory_set::{kernel_token, MapArea, MapPermission, MapType, MemorySet, KERNEL_SPACE}; +pub use frame_allocator::{FrameTracker, frame_alloc, frame_dealloc}; +pub use memory_set::remap_test; +pub use memory_set::{KERNEL_SPACE, MapPermission, MemorySet, kernel_token}; use page_table::PTEFlags; pub use page_table::{ - translated_byte_buffer, translated_ref, translated_refmut, translated_str, PageTable, - PageTableEntry, UserBuffer, + PageTable, PageTableEntry, UserBuffer, UserBufferIterator, translated_byte_buffer, + translated_ref, translated_refmut, translated_str, }; - +/// initiate heap allocator, frame allocator and kernel space pub fn init() { heap_allocator::init_heap(); frame_allocator::init_frame_allocator(); diff --git a/os/src/mm/page_table.rs b/os/src/mm/page_table.rs index dfaf4b6..f5fdf2b 100644 --- a/os/src/mm/page_table.rs +++ b/os/src/mm/page_table.rs @@ -1,4 +1,6 @@ -use super::{frame_alloc, FrameTracker, PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum}; +//! Implementation of [`PageTableEntry`] and [`PageTable`]. + +use super::{FrameTracker, PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum, frame_alloc}; use alloc::string::String; use alloc::vec; use alloc::vec::Vec; @@ -19,39 +21,49 @@ bitflags! { #[derive(Copy, Clone)] #[repr(C)] +/// page table entry structure pub struct PageTableEntry { + ///PTE pub bits: usize, } impl PageTableEntry { + ///Create a PTE from ppn pub fn new(ppn: PhysPageNum, flags: PTEFlags) -> Self { PageTableEntry { bits: ppn.0 << 10 | flags.bits as usize, } } + ///Return an empty PTE pub fn empty() -> Self { PageTableEntry { bits: 0 } } + ///Return 44bit ppn pub fn ppn(&self) -> PhysPageNum { (self.bits >> 10 & ((1usize << 44) - 1)).into() } + ///Return 10bit flag pub fn flags(&self) -> PTEFlags { PTEFlags::from_bits(self.bits as u8).unwrap() } + ///Check PTE valid pub fn is_valid(&self) -> bool { (self.flags() & PTEFlags::V) != PTEFlags::empty() } + ///Check PTE readable pub fn readable(&self) -> bool { (self.flags() & PTEFlags::R) != PTEFlags::empty() } + ///Check PTE writable pub fn writable(&self) -> bool { (self.flags() & PTEFlags::W) != PTEFlags::empty() } + ///Check PTE executable pub fn executable(&self) -> bool { (self.flags() & PTEFlags::X) != PTEFlags::empty() } } - +///Record root ppn and has the same lifetime as 1 and 2 level `PageTableEntry` pub struct PageTable { root_ppn: PhysPageNum, frames: Vec, @@ -59,6 +71,7 @@ pub struct PageTable { /// Assume that it won't oom when creating/mapping. impl PageTable { + /// Create an empty `PageTable` pub fn new() -> Self { let frame = frame_alloc().unwrap(); PageTable { @@ -73,6 +86,7 @@ impl PageTable { frames: Vec::new(), } } + /// Find phsical address by virtual address, create a frame if not exist fn find_pte_create(&mut self, vpn: VirtPageNum) -> Option<&mut PageTableEntry> { let idxs = vpn.indexes(); let mut ppn = self.root_ppn; @@ -92,6 +106,7 @@ impl PageTable { } result } + /// Find phsical address by virtual address fn find_pte(&self, vpn: VirtPageNum) -> Option<&mut PageTableEntry> { let idxs = vpn.indexes(); let mut ppn = self.root_ppn; @@ -110,20 +125,24 @@ impl PageTable { result } #[allow(unused)] + /// Create a mapping form `vpn` to `ppn` pub fn map(&mut self, vpn: VirtPageNum, ppn: PhysPageNum, flags: PTEFlags) { let pte = self.find_pte_create(vpn).unwrap(); assert!(!pte.is_valid(), "vpn {:?} is mapped before mapping", vpn); *pte = PageTableEntry::new(ppn, flags | PTEFlags::V); } #[allow(unused)] + /// Delete a mapping form `vpn` pub fn unmap(&mut self, vpn: VirtPageNum) { let pte = self.find_pte(vpn).unwrap(); assert!(pte.is_valid(), "vpn {:?} is invalid before unmapping", vpn); *pte = PageTableEntry::empty(); } + /// Translate `VirtPageNum` to `PageTableEntry` pub fn translate(&self, vpn: VirtPageNum) -> Option { self.find_pte(vpn).map(|pte| *pte) } + /// Translate `VirtAddr` to `PhysAddr` pub fn translate_va(&self, va: VirtAddr) -> Option { self.find_pte(va.clone().floor()).map(|pte| { let aligned_pa: PhysAddr = pte.ppn().into(); @@ -132,11 +151,12 @@ impl PageTable { (aligned_pa_usize + offset).into() }) } + /// Get root ppn pub fn token(&self) -> usize { 8usize << 60 | self.root_ppn.0 } } - +/// Translate a pointer to a mutable u8 Vec through page table pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<&'static mut [u8]> { let page_table = PageTable::from_token(token); let mut start = ptr as usize; @@ -159,7 +179,7 @@ pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<& v } -/// Load a string from other address spaces into kernel space without an end `\0`. +/// Translate a pointer to a mutable u8 Vec end with `\0` through page table to a `String` pub fn translated_str(token: usize, ptr: *const u8) -> String { let page_table = PageTable::from_token(token); let mut string = String::new(); @@ -178,6 +198,8 @@ pub fn translated_str(token: usize, ptr: *const u8) -> String { string } +#[allow(unused)] +///Translate a generic through page table and return a reference pub fn translated_ref(token: usize, ptr: *const T) -> &'static T { let page_table = PageTable::from_token(token); page_table @@ -185,7 +207,7 @@ pub fn translated_ref(token: usize, ptr: *const T) -> &'static T { .unwrap() .get_ref() } - +///Translate a generic through page table and return a mutable reference pub fn translated_refmut(token: usize, ptr: *mut T) -> &'static mut T { let page_table = PageTable::from_token(token); let va = ptr as usize; @@ -194,15 +216,18 @@ pub fn translated_refmut(token: usize, ptr: *mut T) -> &'static mut T { .unwrap() .get_mut() } - +///Array of u8 slice that user communicate with os pub struct UserBuffer { + ///U8 vec pub buffers: Vec<&'static mut [u8]>, } impl UserBuffer { + ///Create a `UserBuffer` by parameter pub fn new(buffers: Vec<&'static mut [u8]>) -> Self { Self { buffers } } + ///Length of `UserBuffer` pub fn len(&self) -> usize { let mut total: usize = 0; for b in self.buffers.iter() { @@ -223,7 +248,7 @@ impl IntoIterator for UserBuffer { } } } - +/// Iterator of `UserBuffer` pub struct UserBufferIterator { buffers: Vec<&'static mut [u8]>, current_buffer: usize, diff --git a/os/src/net/mod.rs b/os/src/net/mod.rs deleted file mode 100644 index 469a365..0000000 --- a/os/src/net/mod.rs +++ /dev/null @@ -1,136 +0,0 @@ -pub mod port_table; -pub mod socket; -pub mod tcp; -pub mod udp; - -pub use lose_net_stack::IPv4; - -use alloc::{sync::Arc, vec}; -use lose_net_stack::{results::Packet, LoseStack, MacAddress, TcpFlags}; - -use crate::{ - drivers::NET_DEVICE, - net::socket::{get_socket, push_data}, - sync::UPIntrFreeCell, -}; - -use self::{port_table::check_accept, socket::set_s_a_by_index}; - -pub struct NetStack(UPIntrFreeCell); - -impl NetStack { - pub fn new() -> Self { - unsafe { - NetStack(UPIntrFreeCell::new(LoseStack::new( - IPv4::new(10, 0, 2, 15), - MacAddress::new([0x52, 0x54, 0x00, 0x12, 0x34, 0x56]), - ))) - } - } -} - -lazy_static::lazy_static! { - static ref LOSE_NET_STACK: Arc = Arc::new(NetStack::new()); -} - -pub fn net_interrupt_handler() { - let mut recv_buf = vec![0u8; 1024]; - - let len = NET_DEVICE.receive(&mut recv_buf); - - let packet = LOSE_NET_STACK - .0 - .exclusive_access() - .analysis(&recv_buf[..len]); - - // println!("[kernel] receive a packet"); - // hexdump(&recv_buf[..len]); - - match packet { - Packet::ARP(arp_packet) => { - let lose_stack = LOSE_NET_STACK.0.exclusive_access(); - let reply_packet = arp_packet - .reply_packet(lose_stack.ip, lose_stack.mac) - .expect("can't build reply"); - let reply_data = reply_packet.build_data(); - NET_DEVICE.transmit(&reply_data) - } - - Packet::UDP(udp_packet) => { - let target = udp_packet.source_ip; - let lport = udp_packet.dest_port; - let rport = udp_packet.source_port; - - if let Some(socket_index) = get_socket(target, lport, rport) { - push_data(socket_index, udp_packet.data.to_vec()); - } - } - - Packet::TCP(tcp_packet) => { - let target = tcp_packet.source_ip; - let lport = tcp_packet.dest_port; - let rport = tcp_packet.source_port; - let flags = tcp_packet.flags; - - if flags.contains(TcpFlags::S) { - // if it has a port to accept, then response the request - if check_accept(lport, &tcp_packet).is_some() { - let mut reply_packet = tcp_packet.ack(); - reply_packet.flags = TcpFlags::S | TcpFlags::A; - NET_DEVICE.transmit(&reply_packet.build_data()); - } - return; - } else if tcp_packet.flags.contains(TcpFlags::F) { - // tcp disconnected - let reply_packet = tcp_packet.ack(); - NET_DEVICE.transmit(&reply_packet.build_data()); - - let mut end_packet = reply_packet.ack(); - end_packet.flags |= TcpFlags::F; - NET_DEVICE.transmit(&end_packet.build_data()); - } else if tcp_packet.flags.contains(TcpFlags::A) && tcp_packet.data_len == 0 { - return; - } - - if let Some(socket_index) = get_socket(target, lport, rport) { - push_data(socket_index, tcp_packet.data.to_vec()); - set_s_a_by_index(socket_index, tcp_packet.seq, tcp_packet.ack); - } - } - _ => {} - } -} - -#[allow(unused)] -pub fn hexdump(data: &[u8]) { - const PRELAND_WIDTH: usize = 70; - println!("[kernel] {:-^1$}", " hexdump ", PRELAND_WIDTH); - for offset in (0..data.len()).step_by(16) { - print!("[kernel] "); - for i in 0..16 { - if offset + i < data.len() { - print!("{:02x} ", data[offset + i]); - } else { - print!("{:02} ", ""); - } - } - - print!("{:>6}", ' '); - - for i in 0..16 { - if offset + i < data.len() { - let c = data[offset + i]; - if c >= 0x20 && c <= 0x7e { - print!("{}", c as char); - } else { - print!("."); - } - } else { - print!("{:02} ", ""); - } - } - - println!(""); - } - println!("[kernel] {:-^1$}", " hexdump end ", PRELAND_WIDTH); -} diff --git a/os/src/net/port_table.rs b/os/src/net/port_table.rs deleted file mode 100644 index bcda046..0000000 --- a/os/src/net/port_table.rs +++ /dev/null @@ -1,141 +0,0 @@ -use alloc::{sync::Arc, vec::Vec}; -use lazy_static::lazy_static; -use lose_net_stack::packets::tcp::TCPPacket; - -use crate::fs::File; -use crate::sync::UPIntrFreeCell; -use crate::task::TaskControlBlock; - -use super::tcp::TCP; - -pub struct Port { - pub port: u16, - pub receivable: bool, - pub schedule: Option>, -} - -lazy_static! { - static ref LISTEN_TABLE: UPIntrFreeCell>> = - unsafe { UPIntrFreeCell::new(Vec::new()) }; -} - -pub fn listen(port: u16) -> Option { - let mut listen_table = LISTEN_TABLE.exclusive_access(); - let mut index = usize::MAX; - for i in 0..listen_table.len() { - if listen_table[i].is_none() { - index = i; - break; - } - } - - let listen_port = Port { - port, - receivable: false, - schedule: None, - }; - - if index == usize::MAX { - listen_table.push(Some(listen_port)); - Some(listen_table.len() - 1) - } else { - listen_table[index] = Some(listen_port); - Some(index) - } -} - -// can accept request -pub fn accept(listen_index: usize, task: Arc) { - let mut listen_table = LISTEN_TABLE.exclusive_access(); - assert!(listen_index < listen_table.len()); - let listen_port = listen_table[listen_index].as_mut(); - assert!(listen_port.is_some()); - let listen_port = listen_port.unwrap(); - listen_port.receivable = true; - listen_port.schedule = Some(task); -} - -pub fn port_acceptable(listen_index: usize) -> bool { - let mut listen_table = LISTEN_TABLE.exclusive_access(); - assert!(listen_index < listen_table.len()); - - let listen_port = listen_table[listen_index].as_mut(); - listen_port.map_or(false, |x| x.receivable) -} - -// check whether it can accept request -pub fn check_accept(port: u16, tcp_packet: &TCPPacket) -> Option<()> { - LISTEN_TABLE.exclusive_session(|listen_table| { - let mut listen_ports: Vec<&mut Option> = listen_table - .iter_mut() - .filter(|x| match x { - Some(t) => t.port == port && t.receivable == true, - None => false, - }) - .collect(); - if listen_ports.len() == 0 { - None - } else { - let listen_port = listen_ports[0].as_mut().unwrap(); - let task = listen_port.schedule.clone().unwrap(); - // wakeup_task(Arc::clone(&listen_port.schedule.clone().unwrap())); - listen_port.schedule = None; - listen_port.receivable = false; - - accept_connection(port, tcp_packet, task); - Some(()) - } - }) -} - -pub fn accept_connection(_port: u16, tcp_packet: &TCPPacket, task: Arc) { - let process = task.process.upgrade().unwrap(); - let mut inner = process.inner_exclusive_access(); - let fd = inner.alloc_fd(); - - let tcp_socket = TCP::new( - tcp_packet.source_ip, - tcp_packet.dest_port, - tcp_packet.source_port, - tcp_packet.seq, - tcp_packet.ack, - ); - - inner.fd_table[fd] = Some(Arc::new(tcp_socket)); - - let cx = task.inner_exclusive_access().get_trap_cx(); - cx.x[10] = fd; -} - -// store in the fd_table, delete the listen table when close the application. -pub struct PortFd(usize); - -impl PortFd { - pub fn new(port_index: usize) -> Self { - PortFd(port_index) - } -} - -impl Drop for PortFd { - fn drop(&mut self) { - LISTEN_TABLE.exclusive_access()[self.0] = None - } -} - -impl File for PortFd { - fn readable(&self) -> bool { - false - } - - fn writable(&self) -> bool { - false - } - - fn read(&self, _buf: crate::mm::UserBuffer) -> usize { - 0 - } - - fn write(&self, _buf: crate::mm::UserBuffer) -> usize { - 0 - } -} diff --git a/os/src/net/socket.rs b/os/src/net/socket.rs deleted file mode 100644 index a37ba82..0000000 --- a/os/src/net/socket.rs +++ /dev/null @@ -1,123 +0,0 @@ -use alloc::collections::VecDeque; -use alloc::vec::Vec; -use lazy_static::lazy_static; -use lose_net_stack::IPv4; - -use crate::sync::UPIntrFreeCell; - -// TODO: specify the protocol, TCP or UDP -pub struct Socket { - pub raddr: IPv4, // remote address - pub lport: u16, // local port - pub rport: u16, // rempote port - pub buffers: VecDeque>, // datas - pub seq: u32, - pub ack: u32, -} - -lazy_static! { - static ref SOCKET_TABLE: UPIntrFreeCell>> = - unsafe { UPIntrFreeCell::new(Vec::new()) }; -} - -/// get the seq and ack by socket index -pub fn get_s_a_by_index(index: usize) -> Option<(u32, u32)> { - let socket_table = SOCKET_TABLE.exclusive_access(); - - assert!(index < socket_table.len()); - - socket_table.get(index).map_or(None, |x| match x { - Some(x) => Some((x.seq, x.ack)), - None => None, - }) -} - -pub fn set_s_a_by_index(index: usize, seq: u32, ack: u32) { - let mut socket_table = SOCKET_TABLE.exclusive_access(); - - assert!(socket_table.len() > index); - assert!(socket_table[index].is_some()); - - let sock = socket_table[index].as_mut().unwrap(); - - sock.ack = ack; - sock.seq = seq; -} - -pub fn get_socket(raddr: IPv4, lport: u16, rport: u16) -> Option { - let socket_table = SOCKET_TABLE.exclusive_access(); - for i in 0..socket_table.len() { - let sock = &socket_table[i]; - if sock.is_none() { - continue; - } - - let sock = sock.as_ref().unwrap(); - if sock.raddr == raddr && sock.lport == lport && sock.rport == rport { - return Some(i); - } - } - None -} - -pub fn add_socket(raddr: IPv4, lport: u16, rport: u16) -> Option { - if get_socket(raddr, lport, rport).is_some() { - return None; - } - - let mut socket_table = SOCKET_TABLE.exclusive_access(); - let mut index = usize::MAX; - for i in 0..socket_table.len() { - if socket_table[i].is_none() { - index = i; - break; - } - } - - let socket = Socket { - raddr, - lport, - rport, - buffers: VecDeque::new(), - seq: 0, - ack: 0, - }; - - if index == usize::MAX { - socket_table.push(Some(socket)); - Some(socket_table.len() - 1) - } else { - socket_table[index] = Some(socket); - Some(index) - } -} - -pub fn remove_socket(index: usize) { - let mut socket_table = SOCKET_TABLE.exclusive_access(); - - assert!(socket_table.len() > index); - - socket_table[index] = None; -} - -pub fn push_data(index: usize, data: Vec) { - let mut socket_table = SOCKET_TABLE.exclusive_access(); - - assert!(socket_table.len() > index); - assert!(socket_table[index].is_some()); - - socket_table[index] - .as_mut() - .unwrap() - .buffers - .push_back(data); -} - -pub fn pop_data(index: usize) -> Option> { - let mut socket_table = SOCKET_TABLE.exclusive_access(); - - assert!(socket_table.len() > index); - assert!(socket_table[index].is_some()); - - socket_table[index].as_mut().unwrap().buffers.pop_front() -} diff --git a/os/src/net/tcp.rs b/os/src/net/tcp.rs deleted file mode 100644 index d1f7bd2..0000000 --- a/os/src/net/tcp.rs +++ /dev/null @@ -1,113 +0,0 @@ -use alloc::vec; -use lose_net_stack::packets::tcp::TCPPacket; -use lose_net_stack::IPv4; -use lose_net_stack::MacAddress; -use lose_net_stack::TcpFlags; - -use crate::{drivers::NET_DEVICE, fs::File}; - -use super::socket::get_s_a_by_index; -use super::{ - net_interrupt_handler, - socket::{add_socket, pop_data, remove_socket}, - LOSE_NET_STACK, -}; - -// add tcp packet info to this structure -pub struct TCP { - pub target: IPv4, - pub sport: u16, - pub dport: u16, - pub seq: u32, - pub ack: u32, - pub socket_index: usize, -} - -impl TCP { - pub fn new(target: IPv4, sport: u16, dport: u16, seq: u32, ack: u32) -> Self { - let index = add_socket(target, sport, dport).expect("can't add socket"); - - Self { - target, - sport, - dport, - seq, - ack, - socket_index: index, - } - } -} - -impl File for TCP { - fn readable(&self) -> bool { - true - } - - fn writable(&self) -> bool { - true - } - - fn read(&self, mut buf: crate::mm::UserBuffer) -> usize { - loop { - if let Some(data) = pop_data(self.socket_index) { - let data_len = data.len(); - let mut left = 0; - for i in 0..buf.buffers.len() { - let buffer_i_len = buf.buffers[i].len().min(data_len - left); - - buf.buffers[i][..buffer_i_len] - .copy_from_slice(&data[left..(left + buffer_i_len)]); - - left += buffer_i_len; - if left == data_len { - break; - } - } - return left; - } else { - net_interrupt_handler(); - } - } - } - - fn write(&self, buf: crate::mm::UserBuffer) -> usize { - let lose_net_stack = LOSE_NET_STACK.0.exclusive_access(); - - let mut data = vec![0u8; buf.len()]; - - let mut left = 0; - for i in 0..buf.buffers.len() { - data[left..(left + buf.buffers[i].len())].copy_from_slice(buf.buffers[i]); - left += buf.buffers[i].len(); - } - - let len = data.len(); - - // get sock and sequence - let (ack, seq) = get_s_a_by_index(self.socket_index).map_or((0, 0), |x| x); - - let tcp_packet = TCPPacket { - source_ip: lose_net_stack.ip, - source_mac: lose_net_stack.mac, - source_port: self.sport, - dest_ip: self.target, - dest_mac: MacAddress::new([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), - dest_port: self.dport, - data_len: len, - seq, - ack, - flags: TcpFlags::A, - win: 65535, - urg: 0, - data: data.as_ref(), - }; - NET_DEVICE.transmit(&tcp_packet.build_data()); - len - } -} - -impl Drop for TCP { - fn drop(&mut self) { - remove_socket(self.socket_index) - } -} diff --git a/os/src/net/udp.rs b/os/src/net/udp.rs deleted file mode 100644 index f343ed4..0000000 --- a/os/src/net/udp.rs +++ /dev/null @@ -1,95 +0,0 @@ -use super::net_interrupt_handler; -use super::socket::{add_socket, pop_data, remove_socket}; -use super::LOSE_NET_STACK; -use super::NET_DEVICE; -use crate::fs::File; -use alloc::vec; -use lose_net_stack::packets::udp::UDPPacket; -use lose_net_stack::IPv4; -use lose_net_stack::MacAddress; - -pub struct UDP { - pub target: IPv4, - pub sport: u16, - pub dport: u16, - pub socket_index: usize, -} - -impl UDP { - pub fn new(target: IPv4, sport: u16, dport: u16) -> Self { - let index = add_socket(target, sport, dport).expect("can't add socket"); - - Self { - target, - sport, - dport, - socket_index: index, - } - } -} - -impl File for UDP { - fn readable(&self) -> bool { - true - } - - fn writable(&self) -> bool { - true - } - - fn read(&self, mut buf: crate::mm::UserBuffer) -> usize { - loop { - if let Some(data) = pop_data(self.socket_index) { - let data_len = data.len(); - let mut left = 0; - for i in 0..buf.buffers.len() { - let buffer_i_len = buf.buffers[i].len().min(data_len - left); - - buf.buffers[i][..buffer_i_len] - .copy_from_slice(&data[left..(left + buffer_i_len)]); - - left += buffer_i_len; - if left == data_len { - break; - } - } - return left; - } else { - net_interrupt_handler(); - } - } - } - - fn write(&self, buf: crate::mm::UserBuffer) -> usize { - let lose_net_stack = LOSE_NET_STACK.0.exclusive_access(); - - let mut data = vec![0u8; buf.len()]; - - let mut left = 0; - for i in 0..buf.buffers.len() { - data[left..(left + buf.buffers[i].len())].copy_from_slice(buf.buffers[i]); - left += buf.buffers[i].len(); - } - - let len = data.len(); - - let udp_packet = UDPPacket::new( - lose_net_stack.ip, - lose_net_stack.mac, - self.sport, - self.target, - MacAddress::new([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), - self.dport, - len, - data.as_ref(), - ); - NET_DEVICE.transmit(&udp_packet.build_data()); - len - } -} - -impl Drop for UDP { - fn drop(&mut self) { - remove_socket(self.socket_index) - } -} diff --git a/os/src/sbi.rs b/os/src/sbi.rs index 2c0aaa5..a73476f 100644 --- a/os/src/sbi.rs +++ b/os/src/sbi.rs @@ -1,3 +1,18 @@ +//! SBI call wrappers +#![allow(unused)] + +/// use sbi call to putchar in console (qemu uart handler) +pub fn console_putchar(c: usize) { + #[allow(deprecated)] + sbi_rt::legacy::console_putchar(c); +} + +/// use sbi call to getchar from console (qemu uart handler) +pub fn console_getchar() -> usize { + #[allow(deprecated)] + sbi_rt::legacy::console_getchar() +} + /// use sbi call to set timer pub fn set_timer(timer: usize) { sbi_rt::set_timer(timer as _); @@ -5,7 +20,7 @@ pub fn set_timer(timer: usize) { /// use sbi call to shutdown the kernel pub fn shutdown(failure: bool) -> ! { - use sbi_rt::{system_reset, NoReason, Shutdown, SystemFailure}; + use sbi_rt::{NoReason, Shutdown, SystemFailure, system_reset}; if !failure { system_reset(Shutdown, NoReason); } else { diff --git a/os/src/sync/condvar.rs b/os/src/sync/condvar.rs deleted file mode 100644 index d13652f..0000000 --- a/os/src/sync/condvar.rs +++ /dev/null @@ -1,58 +0,0 @@ -use crate::sync::{Mutex, UPIntrFreeCell}; -use crate::task::{ - block_current_and_run_next, block_current_task, current_task, wakeup_task, TaskContext, - TaskControlBlock, -}; -use alloc::{collections::VecDeque, sync::Arc}; - -pub struct Condvar { - pub inner: UPIntrFreeCell, -} - -pub struct CondvarInner { - pub wait_queue: VecDeque>, -} - -impl Condvar { - pub fn new() -> Self { - Self { - inner: unsafe { - UPIntrFreeCell::new(CondvarInner { - wait_queue: VecDeque::new(), - }) - }, - } - } - - pub fn signal(&self) { - let mut inner = self.inner.exclusive_access(); - if let Some(task) = inner.wait_queue.pop_front() { - wakeup_task(task); - } - } - - /* - pub fn wait(&self) { - let mut inner = self.inner.exclusive_access(); - inner.wait_queue.push_back(current_task().unwrap()); - drop(inner); - block_current_and_run_next(); - } - */ - - pub fn wait_no_sched(&self) -> *mut TaskContext { - self.inner.exclusive_session(|inner| { - inner.wait_queue.push_back(current_task().unwrap()); - }); - block_current_task() - } - - pub fn wait_with_mutex(&self, mutex: Arc) { - mutex.unlock(); - self.inner.exclusive_session(|inner| { - inner.wait_queue.push_back(current_task().unwrap()); - }); - block_current_and_run_next(); - mutex.lock(); - } -} diff --git a/os/src/sync/mod.rs b/os/src/sync/mod.rs index d9a00b5..aa04db3 100644 --- a/os/src/sync/mod.rs +++ b/os/src/sync/mod.rs @@ -1,9 +1,4 @@ -mod condvar; -mod mutex; -mod semaphore; +//! Synchronization and interior mutability primitives mod up; -pub use condvar::Condvar; -pub use mutex::{Mutex, MutexBlocking, MutexSpin}; -pub use semaphore::Semaphore; -pub use up::{UPIntrFreeCell, UPIntrRefMut}; +pub use up::UPSafeCell; diff --git a/os/src/sync/mutex.rs b/os/src/sync/mutex.rs deleted file mode 100644 index aaf1571..0000000 --- a/os/src/sync/mutex.rs +++ /dev/null @@ -1,88 +0,0 @@ -use super::UPIntrFreeCell; -use crate::task::TaskControlBlock; -use crate::task::{block_current_and_run_next, suspend_current_and_run_next}; -use crate::task::{current_task, wakeup_task}; -use alloc::{collections::VecDeque, sync::Arc}; - -pub trait Mutex: Sync + Send { - fn lock(&self); - fn unlock(&self); -} - -pub struct MutexSpin { - locked: UPIntrFreeCell, -} - -impl MutexSpin { - pub fn new() -> Self { - Self { - locked: unsafe { UPIntrFreeCell::new(false) }, - } - } -} - -impl Mutex for MutexSpin { - fn lock(&self) { - loop { - let mut locked = self.locked.exclusive_access(); - if *locked { - drop(locked); - suspend_current_and_run_next(); - continue; - } else { - *locked = true; - return; - } - } - } - - fn unlock(&self) { - let mut locked = self.locked.exclusive_access(); - *locked = false; - } -} - -pub struct MutexBlocking { - inner: UPIntrFreeCell, -} - -pub struct MutexBlockingInner { - locked: bool, - wait_queue: VecDeque>, -} - -impl MutexBlocking { - pub fn new() -> Self { - Self { - inner: unsafe { - UPIntrFreeCell::new(MutexBlockingInner { - locked: false, - wait_queue: VecDeque::new(), - }) - }, - } - } -} - -impl Mutex for MutexBlocking { - fn lock(&self) { - let mut mutex_inner = self.inner.exclusive_access(); - if mutex_inner.locked { - mutex_inner.wait_queue.push_back(current_task().unwrap()); - drop(mutex_inner); - block_current_and_run_next(); - } else { - mutex_inner.locked = true; - } - } - - fn unlock(&self) { - let mut mutex_inner = self.inner.exclusive_access(); - assert!(mutex_inner.locked); - if let Some(waking_task) = mutex_inner.wait_queue.pop_front() { - wakeup_task(waking_task); - } else { - mutex_inner.locked = false; - } - } -} diff --git a/os/src/sync/semaphore.rs b/os/src/sync/semaphore.rs deleted file mode 100644 index bdad319..0000000 --- a/os/src/sync/semaphore.rs +++ /dev/null @@ -1,45 +0,0 @@ -use crate::sync::UPIntrFreeCell; -use crate::task::{block_current_and_run_next, current_task, wakeup_task, TaskControlBlock}; -use alloc::{collections::VecDeque, sync::Arc}; - -pub struct Semaphore { - pub inner: UPIntrFreeCell, -} - -pub struct SemaphoreInner { - pub count: isize, - pub wait_queue: VecDeque>, -} - -impl Semaphore { - pub fn new(res_count: usize) -> Self { - Self { - inner: unsafe { - UPIntrFreeCell::new(SemaphoreInner { - count: res_count as isize, - wait_queue: VecDeque::new(), - }) - }, - } - } - - pub fn up(&self) { - let mut inner = self.inner.exclusive_access(); - inner.count += 1; - if inner.count <= 0 { - if let Some(task) = inner.wait_queue.pop_front() { - wakeup_task(task); - } - } - } - - pub fn down(&self) { - let mut inner = self.inner.exclusive_access(); - inner.count -= 1; - if inner.count < 0 { - inner.wait_queue.push_back(current_task().unwrap()); - drop(inner); - block_current_and_run_next(); - } - } -} diff --git a/os/src/sync/up.rs b/os/src/sync/up.rs index 6c7a0f4..955b9dc 100644 --- a/os/src/sync/up.rs +++ b/os/src/sync/up.rs @@ -1,9 +1,6 @@ -use core::cell::{RefCell, RefMut, UnsafeCell}; -use core::ops::{Deref, DerefMut}; -use lazy_static::*; -use riscv::register::sstatus; +//! Uniprocessor interior mutability primitives +use core::cell::{RefCell, RefMut}; -/* /// Wrap a static data structure inside it so that we are /// able to access it without any `unsafe`. /// @@ -26,115 +23,8 @@ impl UPSafeCell { inner: RefCell::new(value), } } - /// Panic if the data has been borrowed. + /// Exclusive access inner data in UPSafeCell. Panic if the data has been borrowed. pub fn exclusive_access(&self) -> RefMut<'_, T> { self.inner.borrow_mut() } } -*/ - -pub struct UPSafeCellRaw { - inner: UnsafeCell, -} - -unsafe impl Sync for UPSafeCellRaw {} - -impl UPSafeCellRaw { - pub unsafe fn new(value: T) -> Self { - Self { - inner: UnsafeCell::new(value), - } - } - pub fn get_mut(&self) -> &mut T { - unsafe { &mut (*self.inner.get()) } - } -} - -pub struct IntrMaskingInfo { - nested_level: usize, - sie_before_masking: bool, -} - -lazy_static! { - static ref INTR_MASKING_INFO: UPSafeCellRaw = - unsafe { UPSafeCellRaw::new(IntrMaskingInfo::new()) }; -} - -impl IntrMaskingInfo { - pub fn new() -> Self { - Self { - nested_level: 0, - sie_before_masking: false, - } - } - - pub fn enter(&mut self) { - let sie = sstatus::read().sie(); - unsafe { - sstatus::clear_sie(); - } - if self.nested_level == 0 { - self.sie_before_masking = sie; - } - self.nested_level += 1; - } - - pub fn exit(&mut self) { - self.nested_level -= 1; - if self.nested_level == 0 && self.sie_before_masking { - unsafe { - sstatus::set_sie(); - } - } - } -} - -pub struct UPIntrFreeCell { - /// inner data - inner: RefCell, -} - -unsafe impl Sync for UPIntrFreeCell {} - -pub struct UPIntrRefMut<'a, T>(Option>); - -impl UPIntrFreeCell { - pub unsafe fn new(value: T) -> Self { - Self { - inner: RefCell::new(value), - } - } - - /// Panic if the data has been borrowed. - pub fn exclusive_access(&self) -> UPIntrRefMut<'_, T> { - INTR_MASKING_INFO.get_mut().enter(); - UPIntrRefMut(Some(self.inner.borrow_mut())) - } - - pub fn exclusive_session(&self, f: F) -> V - where - F: FnOnce(&mut T) -> V, - { - let mut inner = self.exclusive_access(); - f(inner.deref_mut()) - } -} - -impl<'a, T> Drop for UPIntrRefMut<'a, T> { - fn drop(&mut self) { - self.0 = None; - INTR_MASKING_INFO.get_mut().exit(); - } -} - -impl<'a, T> Deref for UPIntrRefMut<'a, T> { - type Target = T; - fn deref(&self) -> &Self::Target { - self.0.as_ref().unwrap().deref() - } -} -impl<'a, T> DerefMut for UPIntrRefMut<'a, T> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.0.as_mut().unwrap().deref_mut() - } -} diff --git a/os/src/syscall/fs.rs b/os/src/syscall/fs.rs index 2758825..8d46fad 100644 --- a/os/src/syscall/fs.rs +++ b/os/src/syscall/fs.rs @@ -1,12 +1,12 @@ -use crate::fs::{make_pipe, open_file, OpenFlags}; -use crate::mm::{translated_byte_buffer, translated_refmut, translated_str, UserBuffer}; -use crate::task::{current_process, current_user_token}; -use alloc::sync::Arc; +//! File and filesystem-related syscalls +use crate::fs::{OpenFlags, open_file}; +use crate::mm::{UserBuffer, translated_byte_buffer, translated_str}; +use crate::task::{current_task, current_user_token}; pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize { let token = current_user_token(); - let process = current_process(); - let inner = process.inner_exclusive_access(); + let task = current_task().unwrap(); + let inner = task.inner_exclusive_access(); if fd >= inner.fd_table.len() { return -1; } @@ -25,8 +25,8 @@ pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize { pub fn sys_read(fd: usize, buf: *const u8, len: usize) -> isize { let token = current_user_token(); - let process = current_process(); - let inner = process.inner_exclusive_access(); + let task = current_task().unwrap(); + let inner = task.inner_exclusive_access(); if fd >= inner.fd_table.len() { return -1; } @@ -44,11 +44,18 @@ pub fn sys_read(fd: usize, buf: *const u8, len: usize) -> isize { } pub fn sys_open(path: *const u8, flags: u32) -> isize { - let process = current_process(); + let task = current_task().unwrap(); let token = current_user_token(); let path = translated_str(token, path); + + // 简单用户检查示例:非 root 用户不能打开 /root 下文件 + let username = task.inner_exclusive_access().user.clone(); + if path.starts_with("/root") && username != "root" { + return -1; // Permission denied + } + if let Some(inode) = open_file(path.as_str(), OpenFlags::from_bits(flags).unwrap()) { - let mut inner = process.inner_exclusive_access(); + let mut inner = task.inner_exclusive_access(); let fd = inner.alloc_fd(); inner.fd_table[fd] = Some(inode); fd as isize @@ -57,9 +64,10 @@ pub fn sys_open(path: *const u8, flags: u32) -> isize { } } + pub fn sys_close(fd: usize) -> isize { - let process = current_process(); - let mut inner = process.inner_exclusive_access(); + let task = current_task().unwrap(); + let mut inner = task.inner_exclusive_access(); if fd >= inner.fd_table.len() { return -1; } @@ -69,31 +77,3 @@ pub fn sys_close(fd: usize) -> isize { inner.fd_table[fd].take(); 0 } - -pub fn sys_pipe(pipe: *mut usize) -> isize { - let process = current_process(); - let token = current_user_token(); - let mut inner = process.inner_exclusive_access(); - let (pipe_read, pipe_write) = make_pipe(); - let read_fd = inner.alloc_fd(); - inner.fd_table[read_fd] = Some(pipe_read); - let write_fd = inner.alloc_fd(); - inner.fd_table[write_fd] = Some(pipe_write); - *translated_refmut(token, pipe) = read_fd; - *translated_refmut(token, unsafe { pipe.add(1) }) = write_fd; - 0 -} - -pub fn sys_dup(fd: usize) -> isize { - let process = current_process(); - let mut inner = process.inner_exclusive_access(); - if fd >= inner.fd_table.len() { - return -1; - } - if inner.fd_table[fd].is_none() { - return -1; - } - let new_fd = inner.alloc_fd(); - inner.fd_table[new_fd] = Some(Arc::clone(inner.fd_table[fd].as_ref().unwrap())); - new_fd as isize -} diff --git a/os/src/syscall/gui.rs b/os/src/syscall/gui.rs deleted file mode 100644 index c5ba8a4..0000000 --- a/os/src/syscall/gui.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::drivers::GPU_DEVICE; -use crate::mm::{MapArea, MapPermission, MapType, PhysAddr, VirtAddr}; -use crate::task::current_process; - -const FB_VADDR: usize = 0x10000000; - -pub fn sys_framebuffer() -> isize { - let fb = GPU_DEVICE.get_framebuffer(); - let len = fb.len(); - // println!("[kernel] FrameBuffer: addr 0x{:X}, len {}", fb.as_ptr() as usize , len); - let fb_start_pa = PhysAddr::from(fb.as_ptr() as usize); - assert!(fb_start_pa.aligned()); - let fb_start_ppn = fb_start_pa.floor(); - let fb_start_vpn = VirtAddr::from(FB_VADDR).floor(); - let pn_offset = fb_start_ppn.0 as isize - fb_start_vpn.0 as isize; - - let current_process = current_process(); - let mut inner = current_process.inner_exclusive_access(); - inner.memory_set.push( - MapArea::new( - (FB_VADDR as usize).into(), - (FB_VADDR + len as usize).into(), - MapType::Linear(pn_offset), - MapPermission::R | MapPermission::W | MapPermission::U, - ), - None, - ); - FB_VADDR as isize -} - -pub fn sys_framebuffer_flush() -> isize { - GPU_DEVICE.flush(); - 0 -} diff --git a/os/src/syscall/input.rs b/os/src/syscall/input.rs deleted file mode 100644 index ee86bd3..0000000 --- a/os/src/syscall/input.rs +++ /dev/null @@ -1,28 +0,0 @@ -//use crate::drivers::{KEYBOARD_DEVICE,MOUSE_DEVICE,INPUT_CONDVAR,read_input_event}; -use crate::drivers::{KEYBOARD_DEVICE, MOUSE_DEVICE}; - -pub fn sys_event_get() -> isize { - let kb = KEYBOARD_DEVICE.clone(); - let mouse = MOUSE_DEVICE.clone(); - //let input=INPUT_CONDVAR.clone(); - //read_input_event() as isize - if !kb.is_empty() { - kb.read_event() as isize - } else if !mouse.is_empty() { - mouse.read_event() as isize - } else { - 0 - } -} - -use crate::drivers::chardev::UART; - -/// check UART's read-buffer is empty or not -pub fn sys_key_pressed() -> isize { - let res = !UART.read_buffer_is_empty(); - if res { - 1 - } else { - 0 - } -} diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index cd12de0..8bcb326 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -1,90 +1,45 @@ -const SYSCALL_DUP: usize = 24; -const SYSCALL_CONNECT: usize = 29; -const SYSCALL_LISTEN: usize = 30; -const SYSCALL_ACCEPT: usize = 31; +//! Implementation of syscalls +//! +//! The single entry point to all system calls, [`syscall()`], is called +//! whenever userspace wishes to perform a system call using the `ecall` +//! instruction. In this case, the processor raises an 'Environment call from +//! U-mode' exception, which is handled as one of the cases in +//! [`crate::trap::trap_handler`]. +//! +//! For clarity, each single syscall is implemented as its own function, named +//! `sys_` then the name of the syscall. You can find functions like this in +//! submodules, and you should also implement syscalls this way. const SYSCALL_OPEN: usize = 56; const SYSCALL_CLOSE: usize = 57; -const SYSCALL_PIPE: usize = 59; const SYSCALL_READ: usize = 63; const SYSCALL_WRITE: usize = 64; const SYSCALL_EXIT: usize = 93; -const SYSCALL_SLEEP: usize = 101; const SYSCALL_YIELD: usize = 124; -const SYSCALL_KILL: usize = 129; const SYSCALL_GET_TIME: usize = 169; const SYSCALL_GETPID: usize = 172; const SYSCALL_FORK: usize = 220; const SYSCALL_EXEC: usize = 221; const SYSCALL_WAITPID: usize = 260; -const SYSCALL_THREAD_CREATE: usize = 1000; -const SYSCALL_GETTID: usize = 1001; -const SYSCALL_WAITTID: usize = 1002; -const SYSCALL_MUTEX_CREATE: usize = 1010; -const SYSCALL_MUTEX_LOCK: usize = 1011; -const SYSCALL_MUTEX_UNLOCK: usize = 1012; -const SYSCALL_SEMAPHORE_CREATE: usize = 1020; -const SYSCALL_SEMAPHORE_UP: usize = 1021; -const SYSCALL_SEMAPHORE_DOWN: usize = 1022; -const SYSCALL_CONDVAR_CREATE: usize = 1030; -const SYSCALL_CONDVAR_SIGNAL: usize = 1031; -const SYSCALL_CONDVAR_WAIT: usize = 1032; -const SYSCALL_FRAMEBUFFER: usize = 2000; -const SYSCALL_FRAMEBUFFER_FLUSH: usize = 2001; -const SYSCALL_EVENT_GET: usize = 3000; -const SYSCALL_KEY_PRESSED: usize = 3001; mod fs; -mod gui; -mod input; -mod net; mod process; -mod sync; -mod thread; use fs::*; -use gui::*; -use input::*; -use net::*; use process::*; -use sync::*; -use thread::*; - +/// handle syscall exception with `syscall_id` and other arguments pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { - SYSCALL_DUP => sys_dup(args[0]), - SYSCALL_CONNECT => sys_connect(args[0] as _, args[1] as _, args[2] as _), - SYSCALL_LISTEN => sys_listen(args[0] as _), - SYSCALL_ACCEPT => sys_accept(args[0] as _), SYSCALL_OPEN => sys_open(args[0] as *const u8, args[1] as u32), SYSCALL_CLOSE => sys_close(args[0]), - SYSCALL_PIPE => sys_pipe(args[0] as *mut usize), SYSCALL_READ => sys_read(args[0], args[1] as *const u8, args[2]), SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]), SYSCALL_EXIT => sys_exit(args[0] as i32), - SYSCALL_SLEEP => sys_sleep(args[0]), SYSCALL_YIELD => sys_yield(), - SYSCALL_KILL => sys_kill(args[0], args[1] as u32), SYSCALL_GET_TIME => sys_get_time(), SYSCALL_GETPID => sys_getpid(), SYSCALL_FORK => sys_fork(), - SYSCALL_EXEC => sys_exec(args[0] as *const u8, args[1] as *const usize), + SYSCALL_EXEC => sys_exec(args[0] as *const u8), SYSCALL_WAITPID => sys_waitpid(args[0] as isize, args[1] as *mut i32), - SYSCALL_THREAD_CREATE => sys_thread_create(args[0], args[1]), - SYSCALL_GETTID => sys_gettid(), - SYSCALL_WAITTID => sys_waittid(args[0]) as isize, - SYSCALL_MUTEX_CREATE => sys_mutex_create(args[0] == 1), - SYSCALL_MUTEX_LOCK => sys_mutex_lock(args[0]), - SYSCALL_MUTEX_UNLOCK => sys_mutex_unlock(args[0]), - SYSCALL_SEMAPHORE_CREATE => sys_semaphore_create(args[0]), - SYSCALL_SEMAPHORE_UP => sys_semaphore_up(args[0]), - SYSCALL_SEMAPHORE_DOWN => sys_semaphore_down(args[0]), - SYSCALL_CONDVAR_CREATE => sys_condvar_create(), - SYSCALL_CONDVAR_SIGNAL => sys_condvar_signal(args[0]), - SYSCALL_CONDVAR_WAIT => sys_condvar_wait(args[0], args[1]), - SYSCALL_FRAMEBUFFER => sys_framebuffer(), - SYSCALL_FRAMEBUFFER_FLUSH => sys_framebuffer_flush(), - SYSCALL_EVENT_GET => sys_event_get(), - SYSCALL_KEY_PRESSED => sys_key_pressed(), _ => panic!("Unsupported syscall_id: {}", syscall_id), } } diff --git a/os/src/syscall/net.rs b/os/src/syscall/net.rs deleted file mode 100644 index c16b9ce..0000000 --- a/os/src/syscall/net.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::net::port_table::{accept, listen, port_acceptable, PortFd}; -use crate::net::udp::UDP; -use crate::net::{net_interrupt_handler, IPv4}; -use crate::task::{current_process, current_task, current_trap_cx}; -use alloc::sync::Arc; - -// just support udp -pub fn sys_connect(raddr: u32, lport: u16, rport: u16) -> isize { - let process = current_process(); - let mut inner = process.inner_exclusive_access(); - let fd = inner.alloc_fd(); - let udp_node = UDP::new(IPv4::from_u32(raddr), lport, rport); - inner.fd_table[fd] = Some(Arc::new(udp_node)); - fd as isize -} - -// listen a port -pub fn sys_listen(port: u16) -> isize { - match listen(port) { - Some(port_index) => { - let process = current_process(); - let mut inner = process.inner_exclusive_access(); - let fd = inner.alloc_fd(); - let port_fd = PortFd::new(port_index); - inner.fd_table[fd] = Some(Arc::new(port_fd)); - - // NOTICE: this return the port index, not the fd - port_index as isize - } - None => -1, - } -} - -// accept a tcp connection -pub fn sys_accept(port_index: usize) -> isize { - println!("accepting port {}", port_index); - - let task = current_task().unwrap(); - accept(port_index, task); - // block_current_and_run_next(); - - // NOTICE: There does not have interrupt handler, just call it munually. - loop { - net_interrupt_handler(); - - if !port_acceptable(port_index) { - break; - } - } - - let cx = current_trap_cx(); - cx.x[10] as isize -} diff --git a/os/src/syscall/process.rs b/os/src/syscall/process.rs index 7d5b67a..61e78d6 100644 --- a/os/src/syscall/process.rs +++ b/os/src/syscall/process.rs @@ -1,13 +1,11 @@ -use crate::fs::{open_file, OpenFlags}; -use crate::mm::{translated_ref, translated_refmut, translated_str}; +use crate::fs::{OpenFlags, open_file}; +use crate::mm::{translated_refmut, translated_str}; use crate::task::{ - current_process, current_task, current_user_token, exit_current_and_run_next, pid2process, - suspend_current_and_run_next, SignalFlags, + add_task, current_task, current_user_token, exit_current_and_run_next, + suspend_current_and_run_next, }; use crate::timer::get_time_ms; -use alloc::string::String; use alloc::sync::Arc; -use alloc::vec::Vec; pub fn sys_exit(exit_code: i32) -> ! { exit_current_and_run_next(exit_code); @@ -24,44 +22,31 @@ pub fn sys_get_time() -> isize { } pub fn sys_getpid() -> isize { - current_task().unwrap().process.upgrade().unwrap().getpid() as isize + current_task().unwrap().pid.0 as isize } pub fn sys_fork() -> isize { - let current_process = current_process(); - let new_process = current_process.fork(); - let new_pid = new_process.getpid(); + let current_task = current_task().unwrap(); + let new_task = current_task.fork(); + let new_pid = new_task.pid.0; // modify trap context of new_task, because it returns immediately after switching - let new_process_inner = new_process.inner_exclusive_access(); - let task = new_process_inner.tasks[0].as_ref().unwrap(); - let trap_cx = task.inner_exclusive_access().get_trap_cx(); + let trap_cx = new_task.inner_exclusive_access().get_trap_cx(); // we do not have to move to next instruction since we have done it before // for child process, fork returns 0 trap_cx.x[10] = 0; + // add new task to scheduler + add_task(new_task); new_pid as isize } -pub fn sys_exec(path: *const u8, mut args: *const usize) -> isize { +pub fn sys_exec(path: *const u8) -> isize { let token = current_user_token(); let path = translated_str(token, path); - let mut args_vec: Vec = Vec::new(); - loop { - let arg_str_ptr = *translated_ref(token, args); - if arg_str_ptr == 0 { - break; - } - args_vec.push(translated_str(token, arg_str_ptr as *const u8)); - unsafe { - args = args.add(1); - } - } if let Some(app_inode) = open_file(path.as_str(), OpenFlags::RDONLY) { let all_data = app_inode.read_all(); - let process = current_process(); - let argc = args_vec.len(); - process.exec(all_data.as_slice(), args_vec); - // return argc because cx.x[10] will be covered with it later - argc as isize + let task = current_task().unwrap(); + task.exec(all_data.as_slice()); + 0 } else { -1 } @@ -70,10 +55,11 @@ pub fn sys_exec(path: *const u8, mut args: *const usize) -> isize { /// If there is not a child process whose pid is same as given, return -1. /// Else if there is a child process but it is still running, return -2. pub fn sys_waitpid(pid: isize, exit_code_ptr: *mut i32) -> isize { - let process = current_process(); + let task = current_task().unwrap(); // find a child process - let mut inner = process.inner_exclusive_access(); + // ---- access current PCB exclusively + let mut inner = task.inner_exclusive_access(); if !inner .children .iter() @@ -84,7 +70,7 @@ pub fn sys_waitpid(pid: isize, exit_code_ptr: *mut i32) -> isize { } let pair = inner.children.iter().enumerate().find(|(_, p)| { // ++++ temporarily access child PCB exclusively - p.inner_exclusive_access().is_zombie && (pid == -1 || pid as usize == p.getpid()) + p.inner_exclusive_access().is_zombie() && (pid == -1 || pid as usize == p.getpid()) // ++++ release child PCB }); if let Some((idx, _)) = pair { @@ -102,16 +88,3 @@ pub fn sys_waitpid(pid: isize, exit_code_ptr: *mut i32) -> isize { } // ---- release current PCB automatically } - -pub fn sys_kill(pid: usize, signal: u32) -> isize { - if let Some(process) = pid2process(pid) { - if let Some(flag) = SignalFlags::from_bits(signal) { - process.inner_exclusive_access().signals |= flag; - 0 - } else { - -1 - } - } else { - -1 - } -} diff --git a/os/src/syscall/sync.rs b/os/src/syscall/sync.rs deleted file mode 100644 index 1180669..0000000 --- a/os/src/syscall/sync.rs +++ /dev/null @@ -1,134 +0,0 @@ -use crate::sync::{Condvar, Mutex, MutexBlocking, MutexSpin, Semaphore}; -use crate::task::{block_current_and_run_next, current_process, current_task}; -use crate::timer::{add_timer, get_time_ms}; -use alloc::sync::Arc; - -pub fn sys_sleep(ms: usize) -> isize { - let expire_ms = get_time_ms() + ms; - let task = current_task().unwrap(); - add_timer(expire_ms, task); - block_current_and_run_next(); - 0 -} - -pub fn sys_mutex_create(blocking: bool) -> isize { - let process = current_process(); - let mutex: Option> = if !blocking { - Some(Arc::new(MutexSpin::new())) - } else { - Some(Arc::new(MutexBlocking::new())) - }; - let mut process_inner = process.inner_exclusive_access(); - if let Some(id) = process_inner - .mutex_list - .iter() - .enumerate() - .find(|(_, item)| item.is_none()) - .map(|(id, _)| id) - { - process_inner.mutex_list[id] = mutex; - id as isize - } else { - process_inner.mutex_list.push(mutex); - process_inner.mutex_list.len() as isize - 1 - } -} - -pub fn sys_mutex_lock(mutex_id: usize) -> isize { - let process = current_process(); - let process_inner = process.inner_exclusive_access(); - let mutex = Arc::clone(process_inner.mutex_list[mutex_id].as_ref().unwrap()); - drop(process_inner); - drop(process); - mutex.lock(); - 0 -} - -pub fn sys_mutex_unlock(mutex_id: usize) -> isize { - let process = current_process(); - let process_inner = process.inner_exclusive_access(); - let mutex = Arc::clone(process_inner.mutex_list[mutex_id].as_ref().unwrap()); - drop(process_inner); - drop(process); - mutex.unlock(); - 0 -} - -pub fn sys_semaphore_create(res_count: usize) -> isize { - let process = current_process(); - let mut process_inner = process.inner_exclusive_access(); - let id = if let Some(id) = process_inner - .semaphore_list - .iter() - .enumerate() - .find(|(_, item)| item.is_none()) - .map(|(id, _)| id) - { - process_inner.semaphore_list[id] = Some(Arc::new(Semaphore::new(res_count))); - id - } else { - process_inner - .semaphore_list - .push(Some(Arc::new(Semaphore::new(res_count)))); - process_inner.semaphore_list.len() - 1 - }; - id as isize -} - -pub fn sys_semaphore_up(sem_id: usize) -> isize { - let process = current_process(); - let process_inner = process.inner_exclusive_access(); - let sem = Arc::clone(process_inner.semaphore_list[sem_id].as_ref().unwrap()); - drop(process_inner); - sem.up(); - 0 -} - -pub fn sys_semaphore_down(sem_id: usize) -> isize { - let process = current_process(); - let process_inner = process.inner_exclusive_access(); - let sem = Arc::clone(process_inner.semaphore_list[sem_id].as_ref().unwrap()); - drop(process_inner); - sem.down(); - 0 -} - -pub fn sys_condvar_create() -> isize { - let process = current_process(); - let mut process_inner = process.inner_exclusive_access(); - let id = if let Some(id) = process_inner - .condvar_list - .iter() - .enumerate() - .find(|(_, item)| item.is_none()) - .map(|(id, _)| id) - { - process_inner.condvar_list[id] = Some(Arc::new(Condvar::new())); - id - } else { - process_inner - .condvar_list - .push(Some(Arc::new(Condvar::new()))); - process_inner.condvar_list.len() - 1 - }; - id as isize -} - -pub fn sys_condvar_signal(condvar_id: usize) -> isize { - let process = current_process(); - let process_inner = process.inner_exclusive_access(); - let condvar = Arc::clone(process_inner.condvar_list[condvar_id].as_ref().unwrap()); - drop(process_inner); - condvar.signal(); - 0 -} - -pub fn sys_condvar_wait(condvar_id: usize, mutex_id: usize) -> isize { - let process = current_process(); - let process_inner = process.inner_exclusive_access(); - let condvar = Arc::clone(process_inner.condvar_list[condvar_id].as_ref().unwrap()); - let mutex = Arc::clone(process_inner.mutex_list[mutex_id].as_ref().unwrap()); - drop(process_inner); - condvar.wait_with_mutex(mutex); - 0 -} diff --git a/os/src/syscall/thread.rs b/os/src/syscall/thread.rs deleted file mode 100644 index 3955d9d..0000000 --- a/os/src/syscall/thread.rs +++ /dev/null @@ -1,85 +0,0 @@ -use crate::{ - mm::kernel_token, - task::{add_task, current_task, TaskControlBlock}, - trap::{trap_handler, TrapContext}, -}; -use alloc::sync::Arc; - -pub fn sys_thread_create(entry: usize, arg: usize) -> isize { - let task = current_task().unwrap(); - let process = task.process.upgrade().unwrap(); - // create a new thread - let new_task = Arc::new(TaskControlBlock::new( - Arc::clone(&process), - task.inner_exclusive_access() - .res - .as_ref() - .unwrap() - .ustack_base, - true, - )); - // add new task to scheduler - add_task(Arc::clone(&new_task)); - let new_task_inner = new_task.inner_exclusive_access(); - let new_task_res = new_task_inner.res.as_ref().unwrap(); - let new_task_tid = new_task_res.tid; - let mut process_inner = process.inner_exclusive_access(); - // add new thread to current process - let tasks = &mut process_inner.tasks; - while tasks.len() < new_task_tid + 1 { - tasks.push(None); - } - tasks[new_task_tid] = Some(Arc::clone(&new_task)); - let new_task_trap_cx = new_task_inner.get_trap_cx(); - *new_task_trap_cx = TrapContext::app_init_context( - entry, - new_task_res.ustack_top(), - kernel_token(), - new_task.kstack.get_top(), - trap_handler as usize, - ); - (*new_task_trap_cx).x[10] = arg; - new_task_tid as isize -} - -pub fn sys_gettid() -> isize { - current_task() - .unwrap() - .inner_exclusive_access() - .res - .as_ref() - .unwrap() - .tid as isize -} - -/// thread does not exist, return -1 -/// thread has not exited yet, return -2 -/// otherwise, return thread's exit code -pub fn sys_waittid(tid: usize) -> i32 { - let task = current_task().unwrap(); - let process = task.process.upgrade().unwrap(); - let task_inner = task.inner_exclusive_access(); - let mut process_inner = process.inner_exclusive_access(); - // a thread cannot wait for itself - if task_inner.res.as_ref().unwrap().tid == tid { - return -1; - } - let mut exit_code: Option = None; - let waited_task = process_inner.tasks[tid].as_ref(); - if let Some(waited_task) = waited_task { - if let Some(waited_exit_code) = waited_task.inner_exclusive_access().exit_code { - exit_code = Some(waited_exit_code); - } - } else { - // waited thread does not exist - return -1; - } - if let Some(exit_code) = exit_code { - // dealloc the exited thread - process_inner.tasks[tid] = None; - exit_code - } else { - // waited thread has not exited - -2 - } -} diff --git a/os/src/task/context.rs b/os/src/task/context.rs index e4f59d8..520bce1 100644 --- a/os/src/task/context.rs +++ b/os/src/task/context.rs @@ -1,13 +1,19 @@ +//! Implementation of [`TaskContext`] use crate::trap::trap_return; #[repr(C)] +/// task context structure containing some registers pub struct TaskContext { + /// return address ( e.g. __restore ) of __switch ASM function ra: usize, + /// kernel stack pointer of app sp: usize, + /// s0-11 register, callee saved s: [usize; 12], } impl TaskContext { + /// init task context pub fn zero_init() -> Self { Self { ra: 0, @@ -15,6 +21,7 @@ impl TaskContext { s: [0; 12], } } + /// set Task Context{__restore ASM funciton: trap_return, sp: kstack_ptr, s: s_0..12} pub fn goto_trap_return(kstack_ptr: usize) -> Self { Self { ra: trap_return as usize, diff --git a/os/src/task/id.rs b/os/src/task/id.rs deleted file mode 100644 index 23ddf7b..0000000 --- a/os/src/task/id.rs +++ /dev/null @@ -1,226 +0,0 @@ -use super::ProcessControlBlock; -use crate::config::{KERNEL_STACK_SIZE, PAGE_SIZE, TRAMPOLINE, TRAP_CONTEXT_BASE, USER_STACK_SIZE}; -use crate::mm::{MapPermission, PhysPageNum, VirtAddr, KERNEL_SPACE}; -use crate::sync::UPIntrFreeCell; -use alloc::{ - sync::{Arc, Weak}, - vec::Vec, -}; -use lazy_static::*; - -pub struct RecycleAllocator { - current: usize, - recycled: Vec, -} - -impl RecycleAllocator { - pub fn new() -> Self { - RecycleAllocator { - current: 0, - recycled: Vec::new(), - } - } - pub fn alloc(&mut self) -> usize { - if let Some(id) = self.recycled.pop() { - id - } else { - self.current += 1; - self.current - 1 - } - } - pub fn dealloc(&mut self, id: usize) { - assert!(id < self.current); - assert!( - !self.recycled.iter().any(|i| *i == id), - "id {} has been deallocated!", - id - ); - self.recycled.push(id); - } -} - -lazy_static! { - static ref PID_ALLOCATOR: UPIntrFreeCell = - unsafe { UPIntrFreeCell::new(RecycleAllocator::new()) }; - static ref KSTACK_ALLOCATOR: UPIntrFreeCell = - unsafe { UPIntrFreeCell::new(RecycleAllocator::new()) }; -} - -pub const IDLE_PID: usize = 0; - -pub struct PidHandle(pub usize); - -pub fn pid_alloc() -> PidHandle { - PidHandle(PID_ALLOCATOR.exclusive_access().alloc()) -} - -impl Drop for PidHandle { - fn drop(&mut self) { - PID_ALLOCATOR.exclusive_access().dealloc(self.0); - } -} - -/// Return (bottom, top) of a kernel stack in kernel space. -pub fn kernel_stack_position(kstack_id: usize) -> (usize, usize) { - let top = TRAMPOLINE - kstack_id * (KERNEL_STACK_SIZE + PAGE_SIZE); - let bottom = top - KERNEL_STACK_SIZE; - (bottom, top) -} - -pub struct KernelStack(pub usize); - -pub fn kstack_alloc() -> KernelStack { - let kstack_id = KSTACK_ALLOCATOR.exclusive_access().alloc(); - let (kstack_bottom, kstack_top) = kernel_stack_position(kstack_id); - KERNEL_SPACE.exclusive_access().insert_framed_area( - kstack_bottom.into(), - kstack_top.into(), - MapPermission::R | MapPermission::W, - ); - KernelStack(kstack_id) -} - -impl Drop for KernelStack { - fn drop(&mut self) { - let (kernel_stack_bottom, _) = kernel_stack_position(self.0); - let kernel_stack_bottom_va: VirtAddr = kernel_stack_bottom.into(); - KERNEL_SPACE - .exclusive_access() - .remove_area_with_start_vpn(kernel_stack_bottom_va.into()); - KSTACK_ALLOCATOR.exclusive_access().dealloc(self.0); - } -} - -impl KernelStack { - #[allow(unused)] - pub fn push_on_top(&self, value: T) -> *mut T - where - T: Sized, - { - let kernel_stack_top = self.get_top(); - let ptr_mut = (kernel_stack_top - core::mem::size_of::()) as *mut T; - unsafe { - *ptr_mut = value; - } - ptr_mut - } - pub fn get_top(&self) -> usize { - let (_, kernel_stack_top) = kernel_stack_position(self.0); - kernel_stack_top - } -} - -pub struct TaskUserRes { - pub tid: usize, - pub ustack_base: usize, - pub process: Weak, -} - -fn trap_cx_bottom_from_tid(tid: usize) -> usize { - TRAP_CONTEXT_BASE - tid * PAGE_SIZE -} - -fn ustack_bottom_from_tid(ustack_base: usize, tid: usize) -> usize { - ustack_base + tid * (PAGE_SIZE + USER_STACK_SIZE) -} - -impl TaskUserRes { - pub fn new( - process: Arc, - ustack_base: usize, - alloc_user_res: bool, - ) -> Self { - let tid = process.inner_exclusive_access().alloc_tid(); - let task_user_res = Self { - tid, - ustack_base, - process: Arc::downgrade(&process), - }; - if alloc_user_res { - task_user_res.alloc_user_res(); - } - task_user_res - } - - pub fn alloc_user_res(&self) { - let process = self.process.upgrade().unwrap(); - let mut process_inner = process.inner_exclusive_access(); - // alloc user stack - let ustack_bottom = ustack_bottom_from_tid(self.ustack_base, self.tid); - let ustack_top = ustack_bottom + USER_STACK_SIZE; - process_inner.memory_set.insert_framed_area( - ustack_bottom.into(), - ustack_top.into(), - MapPermission::R | MapPermission::W | MapPermission::U, - ); - // alloc trap_cx - let trap_cx_bottom = trap_cx_bottom_from_tid(self.tid); - let trap_cx_top = trap_cx_bottom + PAGE_SIZE; - process_inner.memory_set.insert_framed_area( - trap_cx_bottom.into(), - trap_cx_top.into(), - MapPermission::R | MapPermission::W, - ); - } - - fn dealloc_user_res(&self) { - // dealloc tid - let process = self.process.upgrade().unwrap(); - let mut process_inner = process.inner_exclusive_access(); - // dealloc ustack manually - let ustack_bottom_va: VirtAddr = ustack_bottom_from_tid(self.ustack_base, self.tid).into(); - process_inner - .memory_set - .remove_area_with_start_vpn(ustack_bottom_va.into()); - // dealloc trap_cx manually - let trap_cx_bottom_va: VirtAddr = trap_cx_bottom_from_tid(self.tid).into(); - process_inner - .memory_set - .remove_area_with_start_vpn(trap_cx_bottom_va.into()); - } - - #[allow(unused)] - pub fn alloc_tid(&mut self) { - self.tid = self - .process - .upgrade() - .unwrap() - .inner_exclusive_access() - .alloc_tid(); - } - - pub fn dealloc_tid(&self) { - let process = self.process.upgrade().unwrap(); - let mut process_inner = process.inner_exclusive_access(); - process_inner.dealloc_tid(self.tid); - } - - pub fn trap_cx_user_va(&self) -> usize { - trap_cx_bottom_from_tid(self.tid) - } - - pub fn trap_cx_ppn(&self) -> PhysPageNum { - let process = self.process.upgrade().unwrap(); - let process_inner = process.inner_exclusive_access(); - let trap_cx_bottom_va: VirtAddr = trap_cx_bottom_from_tid(self.tid).into(); - process_inner - .memory_set - .translate(trap_cx_bottom_va.into()) - .unwrap() - .ppn() - } - - pub fn ustack_base(&self) -> usize { - self.ustack_base - } - pub fn ustack_top(&self) -> usize { - ustack_bottom_from_tid(self.ustack_base, self.tid) + USER_STACK_SIZE - } -} - -impl Drop for TaskUserRes { - fn drop(&mut self) { - self.dealloc_tid(); - self.dealloc_user_res(); - } -} diff --git a/os/src/task/manager.rs b/os/src/task/manager.rs index 7672cf5..315cd22 100644 --- a/os/src/task/manager.rs +++ b/os/src/task/manager.rs @@ -1,62 +1,41 @@ -use super::{ProcessControlBlock, TaskControlBlock, TaskStatus}; -use crate::sync::UPIntrFreeCell; -use alloc::collections::{BTreeMap, VecDeque}; +//!Implementation of [`TaskManager`] +use super::TaskControlBlock; +use crate::sync::UPSafeCell; +use alloc::collections::VecDeque; use alloc::sync::Arc; use lazy_static::*; - +///A array of `TaskControlBlock` that is thread-safe pub struct TaskManager { ready_queue: VecDeque>, } /// A simple FIFO scheduler. impl TaskManager { + ///Creat an empty TaskManager pub fn new() -> Self { Self { ready_queue: VecDeque::new(), } } + ///Add a task to `TaskManager` pub fn add(&mut self, task: Arc) { self.ready_queue.push_back(task); } + ///Remove the first task and return it,or `None` if `TaskManager` is empty pub fn fetch(&mut self) -> Option> { self.ready_queue.pop_front() } } lazy_static! { - pub static ref TASK_MANAGER: UPIntrFreeCell = - unsafe { UPIntrFreeCell::new(TaskManager::new()) }; - pub static ref PID2PCB: UPIntrFreeCell>> = - unsafe { UPIntrFreeCell::new(BTreeMap::new()) }; + pub static ref TASK_MANAGER: UPSafeCell = + unsafe { UPSafeCell::new(TaskManager::new()) }; } - +///Interface offered to add task pub fn add_task(task: Arc) { TASK_MANAGER.exclusive_access().add(task); } - -pub fn wakeup_task(task: Arc) { - let mut task_inner = task.inner_exclusive_access(); - task_inner.task_status = TaskStatus::Ready; - drop(task_inner); - add_task(task); -} - +///Interface offered to pop the first task pub fn fetch_task() -> Option> { TASK_MANAGER.exclusive_access().fetch() } - -pub fn pid2process(pid: usize) -> Option> { - let map = PID2PCB.exclusive_access(); - map.get(&pid).map(Arc::clone) -} - -pub fn insert_into_pid2process(pid: usize, process: Arc) { - PID2PCB.exclusive_access().insert(pid, process); -} - -pub fn remove_from_pid2process(pid: usize) { - let mut map = PID2PCB.exclusive_access(); - if map.remove(&pid).is_none() { - panic!("cannot find pid {} in pid2task!", pid); - } -} diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index fe1343b..47c13cd 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -1,32 +1,44 @@ +//! Task management implementation +//! +//! Everything about task management, like starting and switching tasks is +//! implemented here. +//! +//! A single global instance of [`TaskManager`] called `TASK_MANAGER` controls +//! all the tasks in the whole operating system. +//! +//! A single global instance of [`Processor`] called `PROCESSOR` monitors running +//! task(s) for each core. +//! +//! A single global instance of [`PidAllocator`] called `PID_ALLOCATOR` allocates +//! pid for user apps. +//! +//! Be careful when you see `__switch` ASM function in `switch.S`. Control flow around this function +//! might not be what you expect. mod context; -mod id; mod manager; -mod process; +mod pid; mod processor; -mod signal; mod switch; #[allow(clippy::module_inception)] +#[allow(rustdoc::private_intra_doc_links)] mod task; -use self::id::TaskUserRes; -use crate::fs::{open_file, OpenFlags}; +use crate::fs::{OpenFlags, open_file}; use crate::sbi::shutdown; -use alloc::{sync::Arc, vec::Vec}; -use lazy_static::*; -use manager::fetch_task; -use process::ProcessControlBlock; -use switch::__switch; - +use alloc::sync::Arc; pub use context::TaskContext; -pub use id::{kstack_alloc, pid_alloc, KernelStack, PidHandle, IDLE_PID}; -pub use manager::{add_task, pid2process, remove_from_pid2process, wakeup_task}; -pub use processor::{ - current_kstack_top, current_process, current_task, current_trap_cx, current_trap_cx_user_va, - current_user_token, run_tasks, schedule, take_current_task, -}; -pub use signal::SignalFlags; -pub use task::{TaskControlBlock, TaskStatus}; +use lazy_static::*; +pub use manager::{TaskManager, fetch_task}; +use switch::__switch; +use task::{TaskControlBlock, TaskStatus}; +pub use manager::add_task; +pub use pid::{KernelStack, PidAllocator, PidHandle, pid_alloc}; +pub use processor::{ + Processor, current_task, current_trap_cx, current_user_token, run_tasks, schedule, + take_current_task, +}; +/// Suspend the current 'Running' task and run the next task in task list. pub fn suspend_current_and_run_next() { // There must be an application running. let task = take_current_task().unwrap(); @@ -37,7 +49,7 @@ pub fn suspend_current_and_run_next() { // Change status to Ready task_inner.task_status = TaskStatus::Ready; drop(task_inner); - // ---- release current TCB + // ---- release current PCB // push back to ready queue. add_task(task); @@ -45,122 +57,68 @@ pub fn suspend_current_and_run_next() { schedule(task_cx_ptr); } -/// This function must be followed by a schedule -pub fn block_current_task() -> *mut TaskContext { - let task = take_current_task().unwrap(); - let mut task_inner = task.inner_exclusive_access(); - task_inner.task_status = TaskStatus::Blocked; - &mut task_inner.task_cx as *mut TaskContext -} - -pub fn block_current_and_run_next() { - let task_cx_ptr = block_current_task(); - schedule(task_cx_ptr); -} +/// pid of usertests app in make run TEST=1 +pub const IDLE_PID: usize = 0; /// Exit the current 'Running' task and run the next task in task list. pub fn exit_current_and_run_next(exit_code: i32) { + // take from Processor let task = take_current_task().unwrap(); - let mut task_inner = task.inner_exclusive_access(); - let process = task.process.upgrade().unwrap(); - let tid = task_inner.res.as_ref().unwrap().tid; - // record exit code - task_inner.exit_code = Some(exit_code); - task_inner.res = None; - // here we do not remove the thread since we are still using the kstack - // it will be deallocated when sys_waittid is called - drop(task_inner); - drop(task); - // however, if this is the main thread of current process - // the process should terminate at once - if tid == 0 { - let pid = process.getpid(); - if pid == IDLE_PID { - println!( - "[kernel] Idle process exit with exit_code {} ...", - exit_code - ); - if exit_code != 0 { - //crate::sbi::shutdown(255); //255 == -1 for err hint - shutdown(true); - } else { - //crate::sbi::shutdown(0); //0 for success hint - shutdown(false); - } - } - remove_from_pid2process(pid); - let mut process_inner = process.inner_exclusive_access(); - // mark this process as a zombie process - process_inner.is_zombie = true; - // record exit code of main process - process_inner.exit_code = exit_code; - { - // move all child processes under init process - let mut initproc_inner = INITPROC.inner_exclusive_access(); - for child in process_inner.children.iter() { - child.inner_exclusive_access().parent = Some(Arc::downgrade(&INITPROC)); - initproc_inner.children.push(child.clone()); - } - } - - // deallocate user res (including tid/trap_cx/ustack) of all threads - // it has to be done before we dealloc the whole memory_set - // otherwise they will be deallocated twice - let mut recycle_res = Vec::::new(); - for task in process_inner.tasks.iter().filter(|t| t.is_some()) { - let task = task.as_ref().unwrap(); - let mut task_inner = task.inner_exclusive_access(); - if let Some(res) = task_inner.res.take() { - recycle_res.push(res); - } - } - // dealloc_tid and dealloc_user_res require access to PCB inner, so we - // need to collect those user res first, then release process_inner - // for now to avoid deadlock/double borrow problem. - drop(process_inner); - recycle_res.clear(); - - let mut process_inner = process.inner_exclusive_access(); - process_inner.children.clear(); - // deallocate other data in user space i.e. program code/data section - process_inner.memory_set.recycle_data_pages(); - // drop file descriptors - process_inner.fd_table.clear(); - // Remove all tasks except for the main thread itself. - // This is because we are still using the kstack under the TCB - // of the main thread. This TCB, including its kstack, will be - // deallocated when the process is reaped via waitpid. - while process_inner.tasks.len() > 1 { - process_inner.tasks.pop(); + let pid = task.getpid(); + if pid == IDLE_PID { + println!( + "[kernel] Idle process exit with exit_code {} ...", + exit_code + ); + if exit_code != 0 { + //crate::sbi::shutdown(255); //255 == -1 for err hint + shutdown(true) + } else { + //crate::sbi::shutdown(0); //0 for success hint + shutdown(false) } } - drop(process); + + // **** access current TCB exclusively + let mut inner = task.inner_exclusive_access(); + // Change status to Zombie + inner.task_status = TaskStatus::Zombie; + // Record exit code + inner.exit_code = exit_code; + // do not move to its parent but under initproc + + // ++++++ access initproc TCB exclusively + { + let mut initproc_inner = INITPROC.inner_exclusive_access(); + for child in inner.children.iter() { + child.inner_exclusive_access().parent = Some(Arc::downgrade(&INITPROC)); + initproc_inner.children.push(child.clone()); + } + } + // ++++++ release parent PCB + + inner.children.clear(); + // deallocate user space + inner.memory_set.recycle_data_pages(); + drop(inner); + // **** release current PCB + // drop task manually to maintain rc correctly + drop(task); // we do not have to save task context let mut _unused = TaskContext::zero_init(); schedule(&mut _unused as *mut _); } lazy_static! { - pub static ref INITPROC: Arc = { + ///Globle process that init user shell + pub static ref INITPROC: Arc = Arc::new({ let inode = open_file("initproc", OpenFlags::RDONLY).unwrap(); let v = inode.read_all(); - ProcessControlBlock::new(v.as_slice()) - }; + TaskControlBlock::new(v.as_slice()) + }); } - +///Add init process to the manager pub fn add_initproc() { - let _initproc = INITPROC.clone(); -} - -pub fn check_signals_of_current() -> Option<(i32, &'static str)> { - let process = current_process(); - let process_inner = process.inner_exclusive_access(); - process_inner.signals.check_error() -} - -pub fn current_add_signal(signal: SignalFlags) { - let process = current_process(); - let mut process_inner = process.inner_exclusive_access(); - process_inner.signals |= signal; + add_task(INITPROC.clone()); } diff --git a/os/src/task/pid.rs b/os/src/task/pid.rs new file mode 100644 index 0000000..f0a5e2a --- /dev/null +++ b/os/src/task/pid.rs @@ -0,0 +1,111 @@ +//!Implementation of [`PidAllocator`] +use crate::config::{KERNEL_STACK_SIZE, PAGE_SIZE, TRAMPOLINE}; +use crate::mm::{KERNEL_SPACE, MapPermission, VirtAddr}; +use crate::sync::UPSafeCell; +use alloc::vec::Vec; +use lazy_static::*; +///Pid Allocator struct +pub struct PidAllocator { + current: usize, + recycled: Vec, +} + +impl PidAllocator { + ///Create an empty `PidAllocator` + pub fn new() -> Self { + PidAllocator { + current: 0, + recycled: Vec::new(), + } + } + ///Allocate a pid + pub fn alloc(&mut self) -> PidHandle { + if let Some(pid) = self.recycled.pop() { + PidHandle(pid) + } else { + self.current += 1; + PidHandle(self.current - 1) + } + } + ///Recycle a pid + pub fn dealloc(&mut self, pid: usize) { + assert!(pid < self.current); + assert!( + !self.recycled.iter().any(|ppid| *ppid == pid), + "pid {} has been deallocated!", + pid + ); + self.recycled.push(pid); + } +} + +lazy_static! { + pub static ref PID_ALLOCATOR: UPSafeCell = + unsafe { UPSafeCell::new(PidAllocator::new()) }; +} +///Bind pid lifetime to `PidHandle` +pub struct PidHandle(pub usize); + +impl Drop for PidHandle { + fn drop(&mut self) { + //println!("drop pid {}", self.0); + PID_ALLOCATOR.exclusive_access().dealloc(self.0); + } +} +///Allocate a pid from PID_ALLOCATOR +pub fn pid_alloc() -> PidHandle { + PID_ALLOCATOR.exclusive_access().alloc() +} + +/// 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) +} +///Kernelstack for app +pub struct KernelStack { + pid: usize, +} + +impl KernelStack { + ///Create a kernelstack from pid + pub fn new(pid_handle: &PidHandle) -> Self { + let pid = pid_handle.0; + let (kernel_stack_bottom, kernel_stack_top) = kernel_stack_position(pid); + KERNEL_SPACE.exclusive_access().insert_framed_area( + kernel_stack_bottom.into(), + kernel_stack_top.into(), + MapPermission::R | MapPermission::W, + ); + KernelStack { pid: pid_handle.0 } + } + #[allow(unused)] + ///Push a value on top of kernelstack + pub fn push_on_top(&self, value: T) -> *mut T + where + T: Sized, + { + let kernel_stack_top = self.get_top(); + let ptr_mut = (kernel_stack_top - core::mem::size_of::()) as *mut T; + unsafe { + *ptr_mut = value; + } + ptr_mut + } + ///Get the value on the top of kernelstack + pub fn get_top(&self) -> usize { + let (_, kernel_stack_top) = kernel_stack_position(self.pid); + kernel_stack_top + } +} + +impl Drop for KernelStack { + fn drop(&mut self) { + let (kernel_stack_bottom, _) = kernel_stack_position(self.pid); + let kernel_stack_bottom_va: VirtAddr = kernel_stack_bottom.into(); + KERNEL_SPACE + .exclusive_access() + .remove_area_with_start_vpn(kernel_stack_bottom_va.into()); + } +} diff --git a/os/src/task/process.rs b/os/src/task/process.rs deleted file mode 100644 index b3976b7..0000000 --- a/os/src/task/process.rs +++ /dev/null @@ -1,258 +0,0 @@ -use super::id::RecycleAllocator; -use super::manager::insert_into_pid2process; -use super::TaskControlBlock; -use super::{add_task, SignalFlags}; -use super::{pid_alloc, PidHandle}; -use crate::fs::{File, Stdin, Stdout}; -use crate::mm::{translated_refmut, MemorySet, KERNEL_SPACE}; -use crate::sync::{Condvar, Mutex, Semaphore, UPIntrFreeCell, UPIntrRefMut}; -use crate::trap::{trap_handler, TrapContext}; -use alloc::string::String; -use alloc::sync::{Arc, Weak}; -use alloc::vec; -use alloc::vec::Vec; - -pub struct ProcessControlBlock { - // immutable - pub pid: PidHandle, - // mutable - inner: UPIntrFreeCell, -} - -pub struct ProcessControlBlockInner { - pub is_zombie: bool, - pub memory_set: MemorySet, - pub parent: Option>, - pub children: Vec>, - pub exit_code: i32, - pub fd_table: Vec>>, - pub signals: SignalFlags, - pub tasks: Vec>>, - pub task_res_allocator: RecycleAllocator, - pub mutex_list: Vec>>, - pub semaphore_list: Vec>>, - pub condvar_list: Vec>>, -} - -impl ProcessControlBlockInner { - #[allow(unused)] - pub fn get_user_token(&self) -> usize { - self.memory_set.token() - } - - pub fn alloc_fd(&mut self) -> usize { - if let Some(fd) = (0..self.fd_table.len()).find(|fd| self.fd_table[*fd].is_none()) { - fd - } else { - self.fd_table.push(None); - self.fd_table.len() - 1 - } - } - - pub fn alloc_tid(&mut self) -> usize { - self.task_res_allocator.alloc() - } - - pub fn dealloc_tid(&mut self, tid: usize) { - self.task_res_allocator.dealloc(tid) - } - - pub fn thread_count(&self) -> usize { - self.tasks.len() - } - - pub fn get_task(&self, tid: usize) -> Arc { - self.tasks[tid].as_ref().unwrap().clone() - } -} - -impl ProcessControlBlock { - pub fn inner_exclusive_access(&self) -> UPIntrRefMut<'_, ProcessControlBlockInner> { - self.inner.exclusive_access() - } - - pub fn new(elf_data: &[u8]) -> Arc { - // memory_set with elf program headers/trampoline/trap context/user stack - let (memory_set, ustack_base, entry_point) = MemorySet::from_elf(elf_data); - // allocate a pid - let pid_handle = pid_alloc(); - let process = Arc::new(Self { - pid: pid_handle, - inner: unsafe { - UPIntrFreeCell::new(ProcessControlBlockInner { - is_zombie: false, - memory_set, - parent: None, - children: Vec::new(), - exit_code: 0, - fd_table: vec![ - // 0 -> stdin - Some(Arc::new(Stdin)), - // 1 -> stdout - Some(Arc::new(Stdout)), - // 2 -> stderr - Some(Arc::new(Stdout)), - ], - signals: SignalFlags::empty(), - tasks: Vec::new(), - task_res_allocator: RecycleAllocator::new(), - mutex_list: Vec::new(), - semaphore_list: Vec::new(), - condvar_list: Vec::new(), - }) - }, - }); - // create a main thread, we should allocate ustack and trap_cx here - let task = Arc::new(TaskControlBlock::new( - Arc::clone(&process), - ustack_base, - true, - )); - // prepare trap_cx of main thread - let task_inner = task.inner_exclusive_access(); - let trap_cx = task_inner.get_trap_cx(); - let ustack_top = task_inner.res.as_ref().unwrap().ustack_top(); - let kstack_top = task.kstack.get_top(); - drop(task_inner); - *trap_cx = TrapContext::app_init_context( - entry_point, - ustack_top, - KERNEL_SPACE.exclusive_access().token(), - kstack_top, - trap_handler as usize, - ); - // add main thread to the process - let mut process_inner = process.inner_exclusive_access(); - process_inner.tasks.push(Some(Arc::clone(&task))); - drop(process_inner); - insert_into_pid2process(process.getpid(), Arc::clone(&process)); - // add main thread to scheduler - add_task(task); - process - } - - /// Only support processes with a single thread. - pub fn exec(self: &Arc, elf_data: &[u8], args: Vec) { - assert_eq!(self.inner_exclusive_access().thread_count(), 1); - // memory_set with elf program headers/trampoline/trap context/user stack - let (memory_set, ustack_base, entry_point) = MemorySet::from_elf(elf_data); - let new_token = memory_set.token(); - // substitute memory_set - self.inner_exclusive_access().memory_set = memory_set; - // then we alloc user resource for main thread again - // since memory_set has been changed - let task = self.inner_exclusive_access().get_task(0); - let mut task_inner = task.inner_exclusive_access(); - task_inner.res.as_mut().unwrap().ustack_base = ustack_base; - task_inner.res.as_mut().unwrap().alloc_user_res(); - task_inner.trap_cx_ppn = task_inner.res.as_mut().unwrap().trap_cx_ppn(); - // push arguments on user stack - let mut user_sp = task_inner.res.as_mut().unwrap().ustack_top(); - user_sp -= (args.len() + 1) * core::mem::size_of::(); - let argv_base = user_sp; - let mut argv: Vec<_> = (0..=args.len()) - .map(|arg| { - translated_refmut( - new_token, - (argv_base + arg * core::mem::size_of::()) as *mut usize, - ) - }) - .collect(); - *argv[args.len()] = 0; - for i in 0..args.len() { - user_sp -= args[i].len() + 1; - *argv[i] = user_sp; - let mut p = user_sp; - for c in args[i].as_bytes() { - *translated_refmut(new_token, p as *mut u8) = *c; - p += 1; - } - *translated_refmut(new_token, p as *mut u8) = 0; - } - // make the user_sp aligned to 8B for k210 platform - user_sp -= user_sp % core::mem::size_of::(); - // initialize trap_cx - let mut trap_cx = TrapContext::app_init_context( - entry_point, - user_sp, - KERNEL_SPACE.exclusive_access().token(), - task.kstack.get_top(), - trap_handler as usize, - ); - trap_cx.x[10] = args.len(); - trap_cx.x[11] = argv_base; - *task_inner.get_trap_cx() = trap_cx; - } - - /// Only support processes with a single thread. - pub fn fork(self: &Arc) -> Arc { - let mut parent = self.inner_exclusive_access(); - assert_eq!(parent.thread_count(), 1); - // clone parent's memory_set completely including trampoline/ustacks/trap_cxs - let memory_set = MemorySet::from_existed_user(&parent.memory_set); - // alloc a pid - let pid = pid_alloc(); - // copy fd table - let mut new_fd_table: Vec>> = Vec::new(); - for fd in parent.fd_table.iter() { - if let Some(file) = fd { - new_fd_table.push(Some(file.clone())); - } else { - new_fd_table.push(None); - } - } - // create child process pcb - let child = Arc::new(Self { - pid, - inner: unsafe { - UPIntrFreeCell::new(ProcessControlBlockInner { - is_zombie: false, - memory_set, - parent: Some(Arc::downgrade(self)), - children: Vec::new(), - exit_code: 0, - fd_table: new_fd_table, - signals: SignalFlags::empty(), - tasks: Vec::new(), - task_res_allocator: RecycleAllocator::new(), - mutex_list: Vec::new(), - semaphore_list: Vec::new(), - condvar_list: Vec::new(), - }) - }, - }); - // add child - parent.children.push(Arc::clone(&child)); - // create main thread of child process - let task = Arc::new(TaskControlBlock::new( - Arc::clone(&child), - parent - .get_task(0) - .inner_exclusive_access() - .res - .as_ref() - .unwrap() - .ustack_base(), - // here we do not allocate trap_cx or ustack again - // but mention that we allocate a new kstack here - false, - )); - // attach task to child process - let mut child_inner = child.inner_exclusive_access(); - child_inner.tasks.push(Some(Arc::clone(&task))); - drop(child_inner); - // modify kstack_top in trap_cx of this thread - let task_inner = task.inner_exclusive_access(); - let trap_cx = task_inner.get_trap_cx(); - trap_cx.kernel_sp = task.kstack.get_top(); - drop(task_inner); - insert_into_pid2process(child.getpid(), Arc::clone(&child)); - // add this thread to scheduler - add_task(task); - child - } - - pub fn getpid(&self) -> usize { - self.pid.0 - } -} diff --git a/os/src/task/processor.rs b/os/src/task/processor.rs index 96361d7..7c05a21 100644 --- a/os/src/task/processor.rs +++ b/os/src/task/processor.rs @@ -1,110 +1,92 @@ +//!Implementation of [`Processor`] and Intersection of control flow use super::__switch; -use super::{fetch_task, TaskStatus}; -use super::{ProcessControlBlock, TaskContext, TaskControlBlock}; -use crate::sync::UPIntrFreeCell; +use super::{TaskContext, TaskControlBlock}; +use super::{TaskStatus, fetch_task}; +use crate::sync::UPSafeCell; use crate::trap::TrapContext; use alloc::sync::Arc; -use core::arch::asm; use lazy_static::*; - +///Processor management structure pub struct Processor { + ///The task currently executing on the current processor current: Option>, + ///The basic control flow of each core, helping to select and switch process idle_task_cx: TaskContext, } impl Processor { + ///Create an empty Processor pub fn new() -> Self { Self { current: None, idle_task_cx: TaskContext::zero_init(), } } + ///Get mutable reference to `idle_task_cx` fn get_idle_task_cx_ptr(&mut self) -> *mut TaskContext { &mut self.idle_task_cx as *mut _ } + ///Get current task in moving semanteme pub fn take_current(&mut self) -> Option> { self.current.take() } + ///Get current task in cloning semanteme pub fn current(&self) -> Option> { self.current.as_ref().map(Arc::clone) } } lazy_static! { - pub static ref PROCESSOR: UPIntrFreeCell = - unsafe { UPIntrFreeCell::new(Processor::new()) }; + pub static ref PROCESSOR: UPSafeCell = unsafe { UPSafeCell::new(Processor::new()) }; } - +///The main part of process execution and scheduling +///Loop `fetch_task` to get the process that needs to run, and switch the process through `__switch` pub fn run_tasks() { loop { let mut processor = PROCESSOR.exclusive_access(); if let Some(task) = fetch_task() { let idle_task_cx_ptr = processor.get_idle_task_cx_ptr(); // access coming task TCB exclusively - let next_task_cx_ptr = task.inner.exclusive_session(|task_inner| { - task_inner.task_status = TaskStatus::Running; - &task_inner.task_cx as *const TaskContext - }); + let mut task_inner = task.inner_exclusive_access(); + let next_task_cx_ptr = &task_inner.task_cx as *const TaskContext; + task_inner.task_status = TaskStatus::Running; + drop(task_inner); + // release coming task TCB manually processor.current = Some(task); // release processor manually drop(processor); unsafe { __switch(idle_task_cx_ptr, next_task_cx_ptr); } - } else { - println!("no tasks available in run_tasks"); } } } - +///Take the current task,leaving a None in its place pub fn take_current_task() -> Option> { PROCESSOR.exclusive_access().take_current() } - +///Get running task pub fn current_task() -> Option> { PROCESSOR.exclusive_access().current() } - -pub fn current_process() -> Arc { - current_task().unwrap().process.upgrade().unwrap() -} - +///Get token of the address space of current task pub fn current_user_token() -> usize { let task = current_task().unwrap(); - task.get_user_token() + let token = task.inner_exclusive_access().get_user_token(); + token } - +///Get the mutable reference to trap context of current task pub fn current_trap_cx() -> &'static mut TrapContext { current_task() .unwrap() .inner_exclusive_access() .get_trap_cx() } - -pub fn current_trap_cx_user_va() -> usize { - current_task() - .unwrap() - .inner_exclusive_access() - .res - .as_ref() - .unwrap() - .trap_cx_user_va() -} - -pub fn current_kstack_top() -> usize { - if let Some(task) = current_task() { - task.kstack.get_top() - } else { - let mut boot_stack_top; - unsafe { asm!("la {},boot_stack_top",out(reg) boot_stack_top) }; - boot_stack_top - } - // current_task().unwrap().kstack.get_top() -} - +///Return to idle control flow for new scheduling pub fn schedule(switched_task_cx_ptr: *mut TaskContext) { - let idle_task_cx_ptr = - PROCESSOR.exclusive_session(|processor| processor.get_idle_task_cx_ptr()); + let mut processor = PROCESSOR.exclusive_access(); + let idle_task_cx_ptr = processor.get_idle_task_cx_ptr(); + drop(processor); unsafe { __switch(switched_task_cx_ptr, idle_task_cx_ptr); } diff --git a/os/src/task/signal.rs b/os/src/task/signal.rs deleted file mode 100644 index 46f1ad9..0000000 --- a/os/src/task/signal.rs +++ /dev/null @@ -1,29 +0,0 @@ -use bitflags::*; - -bitflags! { - pub struct SignalFlags: u32 { - const SIGINT = 1 << 2; - const SIGILL = 1 << 4; - const SIGABRT = 1 << 6; - const SIGFPE = 1 << 8; - const SIGSEGV = 1 << 11; - } -} - -impl SignalFlags { - pub fn check_error(&self) -> Option<(i32, &'static str)> { - if self.contains(Self::SIGINT) { - Some((-2, "Killed, SIGINT=2")) - } else if self.contains(Self::SIGILL) { - Some((-4, "Illegal Instruction, SIGILL=4")) - } else if self.contains(Self::SIGABRT) { - Some((-6, "Aborted, SIGABRT=6")) - } else if self.contains(Self::SIGFPE) { - Some((-8, "Erroneous Arithmetic Operation, SIGFPE=8")) - } else if self.contains(Self::SIGSEGV) { - Some((-11, "Segmentation Fault, SIGSEGV=11")) - } else { - None - } - } -} diff --git a/os/src/task/switch.rs b/os/src/task/switch.rs index 59f8b1a..8f69fdf 100644 --- a/os/src/task/switch.rs +++ b/os/src/task/switch.rs @@ -1,8 +1,14 @@ +//!Wrap `switch.S` as a function use super::TaskContext; use core::arch::global_asm; global_asm!(include_str!("switch.S")); -extern "C" { - pub fn __switch(current_task_cx_ptr: *mut TaskContext, next_task_cx_ptr: *const TaskContext); +unsafe extern "C" { + /// Switch to the context of `next_task_cx_ptr`, saving the current context + /// in `current_task_cx_ptr`. + pub unsafe fn __switch( + current_task_cx_ptr: *mut TaskContext, + next_task_cx_ptr: *const TaskContext, + ); } diff --git a/os/src/task/task.rs b/os/src/task/task.rs index ffc5c0e..87d287a 100644 --- a/os/src/task/task.rs +++ b/os/src/task/task.rs @@ -1,74 +1,191 @@ -use super::id::TaskUserRes; -use super::{kstack_alloc, KernelStack, ProcessControlBlock, TaskContext}; -use crate::trap::TrapContext; -use crate::{ - mm::PhysPageNum, - sync::{UPIntrFreeCell, UPIntrRefMut}, -}; +//!Implementation of [`TaskControlBlock`] +use super::TaskContext; +use super::{KernelStack, PidHandle, pid_alloc}; +use crate::config::TRAP_CONTEXT; +use crate::fs::{File, Stdin, Stdout}; +use crate::mm::{KERNEL_SPACE, MemorySet, PhysPageNum, VirtAddr}; +use crate::sync::UPSafeCell; +use crate::trap::{TrapContext, trap_handler}; use alloc::sync::{Arc, Weak}; +use alloc::vec; +use alloc::vec::Vec; +use core::cell::RefMut; pub struct TaskControlBlock { // immutable - pub process: Weak, - pub kstack: KernelStack, + pub pid: PidHandle, + pub kernel_stack: KernelStack, // mutable - pub inner: UPIntrFreeCell, -} - -impl TaskControlBlock { - pub fn inner_exclusive_access(&self) -> UPIntrRefMut<'_, TaskControlBlockInner> { - self.inner.exclusive_access() - } - - pub fn get_user_token(&self) -> usize { - let process = self.process.upgrade().unwrap(); - let inner = process.inner_exclusive_access(); - inner.memory_set.token() - } + inner: UPSafeCell, } pub struct TaskControlBlockInner { - pub res: Option, pub trap_cx_ppn: PhysPageNum, + #[allow(unused)] + pub base_size: usize, pub task_cx: TaskContext, pub task_status: TaskStatus, - pub exit_code: Option, + pub memory_set: MemorySet, + pub parent: Option>, + pub children: Vec>, + pub exit_code: i32, + pub fd_table: Vec>>, + + // New: User + pub user: String, } impl TaskControlBlockInner { pub fn get_trap_cx(&self) -> &'static mut TrapContext { self.trap_cx_ppn.get_mut() } - - #[allow(unused)] + pub fn get_user_token(&self) -> usize { + self.memory_set.token() + } fn get_status(&self) -> TaskStatus { self.task_status } + pub fn is_zombie(&self) -> bool { + self.get_status() == TaskStatus::Zombie + } + pub fn alloc_fd(&mut self) -> usize { + if let Some(fd) = (0..self.fd_table.len()).find(|fd| self.fd_table[*fd].is_none()) { + fd + } else { + self.fd_table.push(None); + self.fd_table.len() - 1 + } + } } impl TaskControlBlock { - pub fn new( - process: Arc, - ustack_base: usize, - alloc_user_res: bool, - ) -> Self { - let res = TaskUserRes::new(Arc::clone(&process), ustack_base, alloc_user_res); - let trap_cx_ppn = res.trap_cx_ppn(); - let kstack = kstack_alloc(); - let kstack_top = kstack.get_top(); - Self { - process: Arc::downgrade(&process), - kstack, + pub fn inner_exclusive_access(&self) -> RefMut<'_, TaskControlBlockInner> { + self.inner.exclusive_access() + } + pub fn new(elf_data: &[u8]) -> Self { + // memory_set with elf program headers/trampoline/trap context/user stack + let (memory_set, user_sp, entry_point) = MemorySet::from_elf(elf_data); + let trap_cx_ppn = memory_set + .translate(VirtAddr::from(TRAP_CONTEXT).into()) + .unwrap() + .ppn(); + // alloc a pid and a kernel stack in kernel space + let pid_handle = pid_alloc(); + let kernel_stack = KernelStack::new(&pid_handle); + let kernel_stack_top = kernel_stack.get_top(); + let task_control_block = Self { + pid: pid_handle, + kernel_stack, inner: unsafe { - UPIntrFreeCell::new(TaskControlBlockInner { - res: Some(res), + UPSafeCell::new(TaskControlBlockInner { trap_cx_ppn, - task_cx: TaskContext::goto_trap_return(kstack_top), + base_size: user_sp, + task_cx: TaskContext::goto_trap_return(kernel_stack_top), task_status: TaskStatus::Ready, - exit_code: None, + memory_set, + parent: None, + children: Vec::new(), + exit_code: 0, + fd_table: vec![ + // 0 -> stdin + Some(Arc::new(Stdin)), + // 1 -> stdout + Some(Arc::new(Stdout)), + // 2 -> stderr + Some(Arc::new(Stdout)), + ], }) }, + }; + // prepare TrapContext in user space + let trap_cx = task_control_block.inner_exclusive_access().get_trap_cx(); + *trap_cx = TrapContext::app_init_context( + entry_point, + user_sp, + KERNEL_SPACE.exclusive_access().token(), + kernel_stack_top, + trap_handler as usize, + ); + task_control_block + } + pub fn exec(&self, elf_data: &[u8]) { + // memory_set with elf program headers/trampoline/trap context/user stack + let (memory_set, user_sp, entry_point) = MemorySet::from_elf(elf_data); + let trap_cx_ppn = memory_set + .translate(VirtAddr::from(TRAP_CONTEXT).into()) + .unwrap() + .ppn(); + + // **** access current TCB exclusively + let mut inner = self.inner_exclusive_access(); + // substitute memory_set + inner.memory_set = memory_set; + // update trap_cx ppn + inner.trap_cx_ppn = trap_cx_ppn; + // initialize trap_cx + let trap_cx = TrapContext::app_init_context( + entry_point, + user_sp, + KERNEL_SPACE.exclusive_access().token(), + self.kernel_stack.get_top(), + trap_handler as usize, + ); + *inner.get_trap_cx() = trap_cx; + // **** release current PCB + } + pub fn fork(self: &Arc) -> Arc { + // ---- hold parent PCB lock + let mut parent_inner = self.inner_exclusive_access(); + // copy user space(include trap context) + let memory_set = MemorySet::from_existed_user(&parent_inner.memory_set); + let trap_cx_ppn = memory_set + .translate(VirtAddr::from(TRAP_CONTEXT).into()) + .unwrap() + .ppn(); + // alloc a pid and a kernel stack in kernel space + let pid_handle = pid_alloc(); + let kernel_stack = KernelStack::new(&pid_handle); + let kernel_stack_top = kernel_stack.get_top(); + // copy fd table + let mut new_fd_table: Vec>> = Vec::new(); + for fd in parent_inner.fd_table.iter() { + if let Some(file) = fd { + new_fd_table.push(Some(file.clone())); + } else { + new_fd_table.push(None); + } } + let task_control_block = Arc::new(TaskControlBlock { + pid: pid_handle, + kernel_stack, + inner: unsafe { + UPSafeCell::new(TaskControlBlockInner { + trap_cx_ppn, + base_size: parent_inner.base_size, + task_cx: TaskContext::goto_trap_return(kernel_stack_top), + task_status: TaskStatus::Ready, + memory_set, + parent: Some(Arc::downgrade(self)), + children: Vec::new(), + exit_code: 0, + fd_table: new_fd_table, + user: username.to_string(), // Init User name + }) + }, + }); + // add child + parent_inner.children.push(task_control_block.clone()); + // modify kernel_sp in trap_cx + // **** access child PCB exclusively + let trap_cx = task_control_block.inner_exclusive_access().get_trap_cx(); + trap_cx.kernel_sp = kernel_stack_top; + // return + task_control_block + // **** release child PCB + // ---- release parent PCB + } + pub fn getpid(&self) -> usize { + self.pid.0 } } @@ -76,5 +193,5 @@ impl TaskControlBlock { pub enum TaskStatus { Ready, Running, - Blocked, + Zombie, } diff --git a/os/src/timer.rs b/os/src/timer.rs index 83c969d..50ce53a 100644 --- a/os/src/timer.rs +++ b/os/src/timer.rs @@ -1,74 +1,20 @@ -use core::cmp::Ordering; +//! RISC-V timer-related functionality use crate::config::CLOCK_FREQ; use crate::sbi::set_timer; -use crate::sync::UPIntrFreeCell; -use crate::task::{wakeup_task, TaskControlBlock}; -use alloc::collections::BinaryHeap; -use alloc::sync::Arc; -use lazy_static::*; use riscv::register::time; const TICKS_PER_SEC: usize = 100; const MSEC_PER_SEC: usize = 1000; - +///get current time pub fn get_time() -> usize { time::read() } - +/// get current time in microseconds pub fn get_time_ms() -> usize { time::read() / (CLOCK_FREQ / MSEC_PER_SEC) } - +/// set the next timer interrupt pub fn set_next_trigger() { set_timer(get_time() + CLOCK_FREQ / TICKS_PER_SEC); } - -pub struct TimerCondVar { - pub expire_ms: usize, - pub task: Arc, -} - -impl PartialEq for TimerCondVar { - fn eq(&self, other: &Self) -> bool { - self.expire_ms == other.expire_ms - } -} -impl Eq for TimerCondVar {} -impl PartialOrd for TimerCondVar { - fn partial_cmp(&self, other: &Self) -> Option { - let a = -(self.expire_ms as isize); - let b = -(other.expire_ms as isize); - Some(a.cmp(&b)) - } -} - -impl Ord for TimerCondVar { - fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(other).unwrap() - } -} - -lazy_static! { - static ref TIMERS: UPIntrFreeCell> = - unsafe { UPIntrFreeCell::new(BinaryHeap::::new()) }; -} - -pub fn add_timer(expire_ms: usize, task: Arc) { - let mut timers = TIMERS.exclusive_access(); - timers.push(TimerCondVar { expire_ms, task }); -} - -pub fn check_timer() { - let current_ms = get_time_ms(); - TIMERS.exclusive_session(|timers| { - while let Some(timer) = timers.peek() { - if timer.expire_ms <= current_ms { - wakeup_task(Arc::clone(&timer.task)); - timers.pop(); - } else { - break; - } - } - }); -} diff --git a/os/src/trap/context.rs b/os/src/trap/context.rs index 011b7fb..5f968e5 100644 --- a/os/src/trap/context.rs +++ b/os/src/trap/context.rs @@ -1,20 +1,30 @@ -use riscv::register::sstatus::{self, Sstatus, SPP}; +//! Implementation of [`TrapContext`] +use riscv::register::sstatus::{self, SPP, Sstatus}; #[repr(C)] #[derive(Debug)] +///trap context structure containing sstatus, sepc and registers pub struct TrapContext { + /// general regs[0..31] pub x: [usize; 32], + /// CSR sstatus pub sstatus: Sstatus, + /// CSR sepc pub sepc: usize, + /// Addr of Page Table pub kernel_satp: usize, + /// kernel stack pub kernel_sp: usize, + /// Addr of trap_handler function pub trap_handler: usize, } impl TrapContext { + ///set stack pointer to x_2 reg (sp) pub fn set_sp(&mut self, sp: usize) { self.x[2] = sp; } + ///init app context pub fn app_init_context( entry: usize, sp: usize, diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index 3287011..26e7895 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -1,34 +1,40 @@ +//! Trap handling functionality +//! +//! For rCore, we have a single trap entry point, namely `__alltraps`. At +//! initialization in [`init()`], we set the `stvec` CSR to point to it. +//! +//! All traps go through `__alltraps`, which is defined in `trap.S`. The +//! assembly language code does just enough work restore the kernel space +//! context, ensuring that Rust code safely runs, and transfers control to +//! [`trap_handler()`]. +//! +//! It then calls different functionality based on what exactly the exception +//! was. For example, timer interrupts trigger task preemption, and syscalls go +//! to [`syscall()`]. mod context; -use crate::config::TRAMPOLINE; +use crate::config::{TRAMPOLINE, TRAP_CONTEXT}; use crate::syscall::syscall; use crate::task::{ - check_signals_of_current, current_add_signal, current_trap_cx, current_trap_cx_user_va, - current_user_token, exit_current_and_run_next, suspend_current_and_run_next, SignalFlags, + current_trap_cx, current_user_token, exit_current_and_run_next, suspend_current_and_run_next, }; -use crate::timer::{check_timer, set_next_trigger}; +use crate::timer::set_next_trigger; use core::arch::{asm, global_asm}; use riscv::register::{ mtvec::TrapMode, scause::{self, Exception, Interrupt, Trap}, - sie, sip, sscratch, sstatus, stval, stvec, + sie, stval, stvec, }; global_asm!(include_str!("trap.S")); - +/// initialize CSR `stvec` as the entry of `__alltraps` pub fn init() { set_kernel_trap_entry(); } fn set_kernel_trap_entry() { - extern "C" { - fn __alltraps(); - fn __alltraps_k(); - } - let __alltraps_k_va = __alltraps_k as usize - __alltraps as usize + TRAMPOLINE; unsafe { - stvec::write(__alltraps_k_va, TrapMode::Direct); - sscratch::write(trap_from_kernel as usize); + stvec::write(trap_from_kernel as usize, TrapMode::Direct); } } @@ -37,39 +43,24 @@ fn set_user_trap_entry() { stvec::write(TRAMPOLINE as usize, TrapMode::Direct); } } - +/// enable timer interrupt in sie CSR pub fn enable_timer_interrupt() { unsafe { sie::set_stimer(); } } -fn enable_supervisor_interrupt() { - unsafe { - sstatus::set_sie(); - } -} - -fn disable_supervisor_interrupt() { - unsafe { - sstatus::clear_sie(); - } -} - -#[no_mangle] +#[unsafe(no_mangle)] +/// handle an interrupt, exception, or system call from user space pub fn trap_handler() -> ! { set_kernel_trap_entry(); let scause = scause::read(); let stval = stval::read(); - // println!("into {:?}", scause.cause()); match scause.cause() { Trap::Exception(Exception::UserEnvCall) => { // jump to next instruction anyway let mut cx = current_trap_cx(); cx.sepc += 4; - - enable_supervisor_interrupt(); - // get system call return value let result = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]); // cx is changed during sys_exec, so we have to call it again @@ -82,27 +73,24 @@ pub fn trap_handler() -> ! { | Trap::Exception(Exception::InstructionPageFault) | Trap::Exception(Exception::LoadFault) | Trap::Exception(Exception::LoadPageFault) => { - /* println!( "[kernel] {:?} in application, bad addr = {:#x}, bad instruction = {:#x}, kernel killed it.", scause.cause(), stval, current_trap_cx().sepc, ); - */ - current_add_signal(SignalFlags::SIGSEGV); + // page fault exit code + exit_current_and_run_next(-2); } Trap::Exception(Exception::IllegalInstruction) => { - current_add_signal(SignalFlags::SIGILL); + println!("[kernel] IllegalInstruction in application, kernel killed it."); + // illegal instruction exit code + exit_current_and_run_next(-3); } Trap::Interrupt(Interrupt::SupervisorTimer) => { set_next_trigger(); - check_timer(); suspend_current_and_run_next(); } - Trap::Interrupt(Interrupt::SupervisorExternal) => { - crate::board::irq_handler(); - } _ => { panic!( "Unsupported trap {:?}, stval = {:#x}!", @@ -111,59 +99,42 @@ pub fn trap_handler() -> ! { ); } } - // check signals - if let Some((errno, msg)) = check_signals_of_current() { - println!("[kernel] {}", msg); - exit_current_and_run_next(errno); - } + //println!("before trap_return"); trap_return(); } -#[no_mangle] +#[unsafe(no_mangle)] +/// set the new addr of __restore asm function in TRAMPOLINE page, +/// set the reg a0 = trap_cx_ptr, reg a1 = phy addr of usr page table, +/// finally, jump to new addr of __restore asm function pub fn trap_return() -> ! { - disable_supervisor_interrupt(); set_user_trap_entry(); - let trap_cx_user_va = current_trap_cx_user_va(); + let trap_cx_ptr = TRAP_CONTEXT; let user_satp = current_user_token(); - extern "C" { - fn __alltraps(); - fn __restore(); + unsafe extern "C" { + unsafe fn __alltraps(); + unsafe fn __restore(); } let restore_va = __restore as usize - __alltraps as usize + TRAMPOLINE; - //println!("before return"); unsafe { asm!( "fence.i", "jr {restore_va}", restore_va = in(reg) restore_va, - in("a0") trap_cx_user_va, + in("a0") trap_cx_ptr, in("a1") user_satp, options(noreturn) ); } } -#[no_mangle] -pub fn trap_from_kernel(_trap_cx: &TrapContext) { - let scause = scause::read(); - let stval = stval::read(); - match scause.cause() { - Trap::Interrupt(Interrupt::SupervisorExternal) => { - crate::board::irq_handler(); - } - Trap::Interrupt(Interrupt::SupervisorTimer) => { - set_next_trigger(); - check_timer(); - // do not schedule now - } - _ => { - panic!( - "Unsupported trap from kernel: {:?}, stval = {:#x}!", - scause.cause(), - stval - ); - } - } +#[unsafe(no_mangle)] +/// Unimplement: traps/interrupts/exceptions from kernel mode +/// Todo: Chapter 9: I/O device +pub fn trap_from_kernel() -> ! { + use riscv::register::sepc; + println!("stval = {:#x}, sepc = {:#x}", stval::read(), sepc::read()); + panic!("a trap {:?} from kernel!", scause::read().cause()); } pub use context::TrapContext; diff --git a/os/src/trap/trap.S b/os/src/trap/trap.S index 407307c..c0e2d15 100644 --- a/os/src/trap/trap.S +++ b/os/src/trap/trap.S @@ -8,8 +8,6 @@ .section .text.trampoline .globl __alltraps .globl __restore - .globl __alltraps_k - .globl __restore_k .align 2 __alltraps: csrrw sp, sscratch, sp @@ -69,36 +67,3 @@ __restore: # back to user stack ld sp, 2*8(sp) sret - - .align 2 -__alltraps_k: - addi sp, sp, -34*8 - sd x1, 1*8(sp) - sd x3, 3*8(sp) - .set n, 5 - .rept 27 - SAVE_GP %n - .set n, n+1 - .endr - csrr t0, sstatus - csrr t1, sepc - sd t0, 32*8(sp) - sd t1, 33*8(sp) - mv a0, sp - csrr t2, sscratch - jalr t2 - -__restore_k: - ld t0, 32*8(sp) - ld t1, 33*8(sp) - csrw sstatus, t0 - csrw sepc, t1 - ld x1, 1*8(sp) - ld x3, 3*8(sp) - .set n, 5 - .rept 27 - LOAD_GP %n - .set n, n+1 - .endr - addi sp, sp, 34*8 - sret diff --git a/ping.py b/ping.py deleted file mode 100644 index c68fc71..0000000 --- a/ping.py +++ /dev/null @@ -1,18 +0,0 @@ -import socket -import sys -import time - -sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) -addr = ('localhost', 26099) -sock.bind(addr) - - -print("pinging...", file=sys.stderr) -while True: - buf, raddr = sock.recvfrom(4096) - print("receive: " + buf.decode("utf-8")) - buf = "this is a ping to port 6200!".encode('utf-8') - sock.sendto(buf, ("127.0.0.1", 6200)) - buf = "this is a ping to reply!".encode('utf-8') - sock.sendto(buf, raddr) - time.sleep(1) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index c65d258..e6f10a1 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] profile = "minimal" # use the nightly version of the last stable toolchain, see -channel = "nightly-2024-05-01" +channel = "nightly-2025-02-18" components = ["rust-src", "llvm-tools", "rustfmt", "clippy"] targets = ["riscv64gc-unknown-none-elf"] diff --git a/setenv.sh b/setenv.sh deleted file mode 100644 index e3842d5..0000000 --- a/setenv.sh +++ /dev/null @@ -1,2 +0,0 @@ -export PATH=$(rustc --print sysroot)/bin:$PATH -export RUST_SRC_PATH=$(rustc --print sysroot)/lib/rustlib/src/rust/library/ diff --git a/user/Cargo.toml b/user/Cargo.toml index 1d7b2ef..92f3f7e 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -2,18 +2,17 @@ name = "user_lib" version = "0.1.0" authors = ["Yifan Wu "] -edition = "2018" +edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] buddy_system_allocator = "0.6" bitflags = "1.2.1" -riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } -lazy_static = { version = "1.4.0", features = ["spin_no_std"] } -embedded-graphics = "0.7.1" -oorandom ="11" -virtio-input-decoder = "0.1.4" [profile.release] debug = true + +# [features] +# board_qemu = [] +# board_k210 = [] \ No newline at end of file diff --git a/user/src/bin/adder.rs b/user/src/bin/adder.rs deleted file mode 100644 index 1cdce95..0000000 --- a/user/src/bin/adder.rs +++ /dev/null @@ -1,58 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use core::ptr::addr_of_mut; -use user_lib::{exit, get_time, thread_create, waittid}; - -static mut A: usize = 0; -const PER_THREAD_DEFAULT: usize = 10000; -const THREAD_COUNT_DEFAULT: usize = 16; -static mut PER_THREAD: usize = 0; - -unsafe fn critical_section(t: &mut usize) { - let a = addr_of_mut!(A); - let cur = a.read_volatile(); - for _ in 0..500 { - *t = (*t) * (*t) % 10007; - } - a.write_volatile(cur + 1); -} - -unsafe fn f() -> ! { - let mut t = 2usize; - for _ in 0..PER_THREAD { - critical_section(&mut t); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main(argc: usize, argv: &[&str]) -> i32 { - let mut thread_count = THREAD_COUNT_DEFAULT; - let mut per_thread = PER_THREAD_DEFAULT; - if argc >= 2 { - thread_count = argv[1].parse().unwrap(); - if argc >= 3 { - per_thread = argv[2].parse().unwrap(); - } - } - unsafe { - PER_THREAD = per_thread; - } - let start = get_time(); - let mut v = Vec::new(); - for _ in 0..thread_count { - v.push(thread_create(f as usize, 0) as usize); - } - for tid in v.into_iter() { - waittid(tid); - } - println!("time cost is {}ms", get_time() - start); - assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); - 0 -} diff --git a/user/src/bin/adder_atomic.rs b/user/src/bin/adder_atomic.rs deleted file mode 100644 index 5e216c6..0000000 --- a/user/src/bin/adder_atomic.rs +++ /dev/null @@ -1,75 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use core::ptr::addr_of_mut; -use core::sync::atomic::{AtomicBool, Ordering}; -use user_lib::{exit, get_time, thread_create, waittid, yield_}; - -static mut A: usize = 0; -static OCCUPIED: AtomicBool = AtomicBool::new(false); -const PER_THREAD_DEFAULT: usize = 10000; -const THREAD_COUNT_DEFAULT: usize = 16; -static mut PER_THREAD: usize = 0; - -unsafe fn critical_section(t: &mut usize) { - let a = addr_of_mut!(A); - let cur = a.read_volatile(); - for _ in 0..500 { - *t = (*t) * (*t) % 10007; - } - a.write_volatile(cur + 1); -} - -fn lock() { - while OCCUPIED - .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) - .is_err() - { - yield_(); - } -} - -fn unlock() { - OCCUPIED.store(false, Ordering::Relaxed); -} - -unsafe fn f() -> ! { - let mut t = 2usize; - for _ in 0..PER_THREAD { - lock(); - critical_section(&mut t); - unlock(); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main(argc: usize, argv: &[&str]) -> i32 { - let mut thread_count = THREAD_COUNT_DEFAULT; - let mut per_thread = PER_THREAD_DEFAULT; - if argc >= 2 { - thread_count = argv[1].parse().unwrap(); - if argc >= 3 { - per_thread = argv[2].parse().unwrap(); - } - } - unsafe { - PER_THREAD = per_thread; - } - let start = get_time(); - let mut v = Vec::new(); - for _ in 0..thread_count { - v.push(thread_create(f as usize, 0) as usize); - } - for tid in v.into_iter() { - waittid(tid); - } - println!("time cost is {}ms", get_time() - start); - assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); - 0 -} diff --git a/user/src/bin/adder_mutex_blocking.rs b/user/src/bin/adder_mutex_blocking.rs deleted file mode 100644 index 7fcb80b..0000000 --- a/user/src/bin/adder_mutex_blocking.rs +++ /dev/null @@ -1,62 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use core::ptr::addr_of_mut; -use user_lib::{exit, get_time, thread_create, waittid}; -use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock}; - -static mut A: usize = 0; -const PER_THREAD_DEFAULT: usize = 10000; -const THREAD_COUNT_DEFAULT: usize = 16; -static mut PER_THREAD: usize = 0; - -unsafe fn critical_section(t: &mut usize) { - let a = addr_of_mut!(A); - let cur = a.read_volatile(); - for _ in 0..500 { - *t = (*t) * (*t) % 10007; - } - a.write_volatile(cur + 1); -} -unsafe fn f() -> ! { - let mut t = 2usize; - for _ in 0..PER_THREAD { - mutex_lock(0); - critical_section(&mut t); - mutex_unlock(0); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main(argc: usize, argv: &[&str]) -> i32 { - let mut thread_count = THREAD_COUNT_DEFAULT; - let mut per_thread = PER_THREAD_DEFAULT; - if argc >= 2 { - thread_count = argv[1].parse().unwrap(); - if argc >= 3 { - per_thread = argv[2].parse().unwrap(); - } - } - unsafe { - PER_THREAD = per_thread; - } - - let start = get_time(); - assert_eq!(mutex_blocking_create(), 0); - let mut v = Vec::new(); - for _ in 0..thread_count { - v.push(thread_create(f as usize, 0) as usize); - } - for tid in v.into_iter() { - waittid(tid); - } - println!("time cost is {}ms", get_time() - start); - assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); - 0 -} diff --git a/user/src/bin/adder_mutex_spin.rs b/user/src/bin/adder_mutex_spin.rs deleted file mode 100644 index f5750af..0000000 --- a/user/src/bin/adder_mutex_spin.rs +++ /dev/null @@ -1,63 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use core::ptr::addr_of_mut; -use user_lib::{exit, get_time, thread_create, waittid}; -use user_lib::{mutex_create, mutex_lock, mutex_unlock}; - -static mut A: usize = 0; -const PER_THREAD_DEFAULT: usize = 10000; -const THREAD_COUNT_DEFAULT: usize = 16; -static mut PER_THREAD: usize = 0; - -unsafe fn critical_section(t: &mut usize) { - let a = addr_of_mut!(A); - let cur = a.read_volatile(); - for _ in 0..500 { - *t = (*t) * (*t) % 10007; - } - a.write_volatile(cur + 1); -} - -unsafe fn f() -> ! { - let mut t = 2usize; - for _ in 0..PER_THREAD { - mutex_lock(0); - critical_section(&mut t); - mutex_unlock(0); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main(argc: usize, argv: &[&str]) -> i32 { - let mut thread_count = THREAD_COUNT_DEFAULT; - let mut per_thread = PER_THREAD_DEFAULT; - if argc >= 2 { - thread_count = argv[1].parse().unwrap(); - if argc >= 3 { - per_thread = argv[2].parse().unwrap(); - } - } - unsafe { - PER_THREAD = per_thread; - } - - let start = get_time(); - assert_eq!(mutex_create(), 0); - let mut v = Vec::new(); - for _ in 0..thread_count { - v.push(thread_create(f as usize, 0) as usize); - } - for tid in v.into_iter() { - waittid(tid); - } - println!("time cost is {}ms", get_time() - start); - assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); - 0 -} diff --git a/user/src/bin/adder_peterson_spin.rs b/user/src/bin/adder_peterson_spin.rs deleted file mode 100644 index 44e8096..0000000 --- a/user/src/bin/adder_peterson_spin.rs +++ /dev/null @@ -1,95 +0,0 @@ -//! It only works on a single CPU! - -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use core::ptr::addr_of_mut; -use core::sync::atomic::{compiler_fence, Ordering}; -use user_lib::{exit, get_time, thread_create, waittid}; - -static mut A: usize = 0; -static mut FLAG: [bool; 2] = [false; 2]; -static mut TURN: usize = 0; -const PER_THREAD_DEFAULT: usize = 2000; -const THREAD_COUNT_DEFAULT: usize = 2; -static mut PER_THREAD: usize = 0; - -unsafe fn critical_section(t: &mut usize) { - let a = addr_of_mut!(A); - let cur = a.read_volatile(); - for _ in 0..500 { - *t = (*t) * (*t) % 10007; - } - a.write_volatile(cur + 1); -} - -unsafe fn lock(id: usize) { - FLAG[id] = true; - let j = 1 - id; - TURN = j; - // Tell the compiler not to reorder memory operations - // across this fence. - compiler_fence(Ordering::SeqCst); - // Why do we need to use volatile_read here? - // Otherwise the compiler will assume that they will never - // be changed on this thread. Thus, they will be accessed - // only once! - while vload!(FLAG[j]) && vload!(TURN) == j {} -} - -unsafe fn unlock(id: usize) { - FLAG[id] = false; -} - -unsafe fn f(id: usize) -> ! { - let mut t = 2usize; - for _iter in 0..PER_THREAD { - lock(id); - critical_section(&mut t); - unlock(id); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main(argc: usize, argv: &[&str]) -> i32 { - let mut thread_count = THREAD_COUNT_DEFAULT; - let mut per_thread = PER_THREAD_DEFAULT; - if argc >= 2 { - thread_count = argv[1].parse().unwrap(); - if argc >= 3 { - per_thread = argv[2].parse().unwrap(); - } - } - unsafe { - PER_THREAD = per_thread; - } - - // uncomment this if you want to check the assembly - // println!( - // "addr: lock={:#x}, unlock={:#x}", - // lock as usize, - // unlock as usize - // ); - let start = get_time(); - let mut v = Vec::new(); - assert_eq!( - thread_count, 2, - "Peterson works when there are only 2 threads." - ); - for id in 0..thread_count { - v.push(thread_create(f as usize, id) as usize); - } - let mut time_cost = Vec::new(); - for tid in v.iter() { - time_cost.push(waittid(*tid)); - } - println!("time cost is {}ms", get_time() - start); - assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); - 0 -} diff --git a/user/src/bin/adder_peterson_yield.rs b/user/src/bin/adder_peterson_yield.rs deleted file mode 100644 index b25adf6..0000000 --- a/user/src/bin/adder_peterson_yield.rs +++ /dev/null @@ -1,96 +0,0 @@ -//! It only works on a single CPU! - -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use core::{ - ptr::addr_of_mut, - sync::atomic::{compiler_fence, Ordering}, -}; -use user_lib::{exit, get_time, thread_create, waittid, yield_}; - -static mut A: usize = 0; -static mut FLAG: [bool; 2] = [false; 2]; -static mut TURN: usize = 0; -const PER_THREAD_DEFAULT: usize = 2000; -const THREAD_COUNT_DEFAULT: usize = 2; -static mut PER_THREAD: usize = 0; - -unsafe fn critical_section(t: &mut usize) { - let a = addr_of_mut!(A); - let cur = a.read_volatile(); - for _ in 0..500 { - *t = (*t) * (*t) % 10007; - } - a.write_volatile(cur + 1); -} - -unsafe fn lock(id: usize) { - FLAG[id] = true; - let j = 1 - id; - TURN = j; - // Tell the compiler not to reorder memory operations - // across this fence. - compiler_fence(Ordering::SeqCst); - while FLAG[j] && TURN == j { - yield_(); - } -} - -unsafe fn unlock(id: usize) { - FLAG[id] = false; -} - -unsafe fn f(id: usize) -> ! { - let mut t = 2usize; - for _iter in 0..PER_THREAD { - lock(id); - critical_section(&mut t); - unlock(id); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main(argc: usize, argv: &[&str]) -> i32 { - let mut thread_count = THREAD_COUNT_DEFAULT; - let mut per_thread = PER_THREAD_DEFAULT; - if argc >= 2 { - thread_count = argv[1].parse().unwrap(); - if argc >= 3 { - per_thread = argv[2].parse().unwrap(); - } - } - unsafe { - PER_THREAD = per_thread; - } - - // uncomment this if you want to check the assembly - // println!( - // "addr: lock={:#x}, unlock={:#x}", - // lock as usize, - // unlock as usize - // ); - - let start = get_time(); - let mut v = Vec::new(); - assert_eq!( - thread_count, 2, - "Peterson works when there are only 2 threads." - ); - for id in 0..thread_count { - v.push(thread_create(f as usize, id) as usize); - } - let mut time_cost = Vec::new(); - for tid in v.iter() { - time_cost.push(waittid(*tid)); - } - println!("time cost is {}ms", get_time() - start); - assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); - 0 -} diff --git a/user/src/bin/adder_simple_spin.rs b/user/src/bin/adder_simple_spin.rs deleted file mode 100644 index be99d28..0000000 --- a/user/src/bin/adder_simple_spin.rs +++ /dev/null @@ -1,70 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use core::ptr::addr_of_mut; -use user_lib::{exit, get_time, thread_create, waittid}; - -static mut A: usize = 0; -static mut OCCUPIED: bool = false; -const PER_THREAD_DEFAULT: usize = 10000; -const THREAD_COUNT_DEFAULT: usize = 16; -static mut PER_THREAD: usize = 0; - -unsafe fn critical_section(t: &mut usize) { - let a = addr_of_mut!(A); - let cur = a.read_volatile(); - for _ in 0..500 { - *t = (*t) * (*t) % 10007; - } - a.write_volatile(cur + 1); -} - -unsafe fn lock() { - while vload!(OCCUPIED) {} - OCCUPIED = true; -} - -unsafe fn unlock() { - OCCUPIED = false; -} - -unsafe fn f() -> ! { - let mut t = 2usize; - for _ in 0..PER_THREAD { - lock(); - critical_section(&mut t); - unlock(); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main(argc: usize, argv: &[&str]) -> i32 { - let mut thread_count = THREAD_COUNT_DEFAULT; - let mut per_thread = PER_THREAD_DEFAULT; - if argc >= 2 { - thread_count = argv[1].parse().unwrap(); - if argc >= 3 { - per_thread = argv[2].parse().unwrap(); - } - } - unsafe { - PER_THREAD = per_thread; - } - let start = get_time(); - let mut v = Vec::new(); - for _ in 0..thread_count { - v.push(thread_create(f as usize, 0) as usize); - } - for tid in v.into_iter() { - waittid(tid); - } - println!("time cost is {}ms", get_time() - start); - assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); - 0 -} diff --git a/user/src/bin/adder_simple_yield.rs b/user/src/bin/adder_simple_yield.rs deleted file mode 100644 index 2de7924..0000000 --- a/user/src/bin/adder_simple_yield.rs +++ /dev/null @@ -1,72 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use core::ptr::addr_of_mut; -use user_lib::{exit, get_time, thread_create, waittid, yield_}; - -static mut A: usize = 0; -static mut OCCUPIED: bool = false; -const PER_THREAD_DEFAULT: usize = 10000; -const THREAD_COUNT_DEFAULT: usize = 16; -static mut PER_THREAD: usize = 0; - -unsafe fn critical_section(t: &mut usize) { - let a = addr_of_mut!(A); - let cur = a.read_volatile(); - for _ in 0..500 { - *t = (*t) * (*t) % 10007; - } - a.write_volatile(cur + 1); -} - -unsafe fn lock() { - while OCCUPIED { - yield_(); - } - OCCUPIED = true; -} - -unsafe fn unlock() { - OCCUPIED = false; -} - -unsafe fn f() -> ! { - let mut t = 2usize; - for _ in 0..PER_THREAD { - lock(); - critical_section(&mut t); - unlock(); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main(argc: usize, argv: &[&str]) -> i32 { - let mut thread_count = THREAD_COUNT_DEFAULT; - let mut per_thread = PER_THREAD_DEFAULT; - if argc >= 2 { - thread_count = argv[1].parse().unwrap(); - if argc >= 3 { - per_thread = argv[2].parse().unwrap(); - } - } - unsafe { - PER_THREAD = per_thread; - } - let start = get_time(); - let mut v = Vec::new(); - for _ in 0..thread_count { - v.push(thread_create(f as usize, 0) as usize); - } - for tid in v.into_iter() { - waittid(tid); - } - println!("time cost is {}ms", get_time() - start); - assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); - 0 -} diff --git a/user/src/bin/barrier_condvar.rs b/user/src/bin/barrier_condvar.rs deleted file mode 100644 index 7157772..0000000 --- a/user/src/bin/barrier_condvar.rs +++ /dev/null @@ -1,83 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use core::cell::UnsafeCell; -use lazy_static::*; -use user_lib::{ - condvar_create, condvar_signal, condvar_wait, exit, mutex_create, mutex_lock, mutex_unlock, - thread_create, waittid, -}; - -const THREAD_NUM: usize = 3; - -struct Barrier { - mutex_id: usize, - condvar_id: usize, - count: UnsafeCell, -} - -impl Barrier { - pub fn new() -> Self { - Self { - mutex_id: mutex_create() as usize, - condvar_id: condvar_create() as usize, - count: UnsafeCell::new(0), - } - } - pub fn block(&self) { - mutex_lock(self.mutex_id); - let count = self.count.get(); - // SAFETY: Here, the accesses of the count is in the - // critical section protected by the mutex. - unsafe { - *count = *count + 1; - } - if unsafe { *count } == THREAD_NUM { - condvar_signal(self.condvar_id); - } else { - condvar_wait(self.condvar_id, self.mutex_id); - condvar_signal(self.condvar_id); - } - mutex_unlock(self.mutex_id); - } -} - -unsafe impl Sync for Barrier {} - -lazy_static! { - static ref BARRIER_AB: Barrier = Barrier::new(); - static ref BARRIER_BC: Barrier = Barrier::new(); -} - -fn thread_fn() { - for _ in 0..300 { - print!("a"); - } - BARRIER_AB.block(); - for _ in 0..300 { - print!("b"); - } - BARRIER_BC.block(); - for _ in 0..300 { - print!("c"); - } - exit(0) -} - -#[no_mangle] -pub fn main() -> i32 { - let mut v: Vec = Vec::new(); - for _ in 0..THREAD_NUM { - v.push(thread_create(thread_fn as usize, 0)); - } - for tid in v.into_iter() { - waittid(tid as usize); - } - println!("\nOK!"); - 0 -} diff --git a/user/src/bin/barrier_fail.rs b/user/src/bin/barrier_fail.rs deleted file mode 100644 index 11604ca..0000000 --- a/user/src/bin/barrier_fail.rs +++ /dev/null @@ -1,33 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use user_lib::{exit, thread_create, waittid}; - -const THREAD_NUM: usize = 3; - -fn thread_fn() { - for ch in 'a'..='c' { - for _ in 0..300 { - print!("{}", ch); - } - } - exit(0) -} - -#[no_mangle] -pub fn main() -> i32 { - let mut v: Vec = Vec::new(); - for _ in 0..THREAD_NUM { - v.push(thread_create(thread_fn as usize, 0)); - } - for tid in v.into_iter() { - waittid(tid as usize); - } - println!("\nOK!"); - 0 -} diff --git a/user/src/bin/cat.rs b/user/src/bin/cat.rs deleted file mode 100644 index fea5a24..0000000 --- a/user/src/bin/cat.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use user_lib::{close, open, read, OpenFlags}; - -#[no_mangle] -pub fn main(argc: usize, argv: &[&str]) -> i32 { - println!("argc = {}", argc); - for (i, arg) in argv.iter().enumerate() { - println!("argv[{}] = {}", i, arg); - } - assert!(argc == 2); - let fd = open(argv[1], OpenFlags::RDONLY); - if fd == -1 { - panic!("Error occurred when opening file"); - } - let fd = fd as usize; - let mut buf = [0u8; 256]; - loop { - let size = read(fd, &mut buf) as usize; - if size == 0 { - break; - } - print!("{}", core::str::from_utf8(&buf[..size]).unwrap()); - } - close(fd); - 0 -} diff --git a/user/src/bin/cat_filea.rs b/user/src/bin/cat_filea.rs new file mode 100644 index 0000000..20daf77 --- /dev/null +++ b/user/src/bin/cat_filea.rs @@ -0,0 +1,27 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use user_lib::{OpenFlags, close, open, read}; + +#[unsafe(no_mangle)] +pub fn main() -> i32 { + let fd = open("filea\0", OpenFlags::RDONLY); + if fd == -1 { + panic!("Error occured when opening file"); + } + let fd = fd as usize; + let mut buf = [0u8; 256]; + loop { + let size = read(fd, &mut buf) as usize; + if size == 0 { + break; + } + println!("{}", core::str::from_utf8(&buf[..size]).unwrap()); + } + close(fd); + 0 +} diff --git a/user/src/bin/cmdline_args.rs b/user/src/bin/cmdline_args.rs deleted file mode 100644 index 9a22745..0000000 --- a/user/src/bin/cmdline_args.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![no_std] -#![no_main] - -extern crate alloc; - -#[macro_use] -extern crate user_lib; - -#[no_mangle] -pub fn main(argc: usize, argv: &[&str]) -> i32 { - println!("argc = {}", argc); - for (i, arg) in argv.iter().enumerate() { - println!("argv[{}] = {}", i, arg); - } - 0 -} diff --git a/user/src/bin/condsync_condvar.rs b/user/src/bin/condsync_condvar.rs deleted file mode 100644 index 78605ad..0000000 --- a/user/src/bin/condsync_condvar.rs +++ /dev/null @@ -1,59 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -extern crate alloc; - -use alloc::vec; -use user_lib::exit; -use user_lib::{ - condvar_create, condvar_signal, condvar_wait, mutex_blocking_create, mutex_lock, mutex_unlock, -}; -use user_lib::{sleep, thread_create, waittid}; - -static mut A: usize = 0; - -const CONDVAR_ID: usize = 0; -const MUTEX_ID: usize = 0; - -unsafe fn first() -> ! { - sleep(10); - println!("First work, Change A --> 1 and wakeup Second"); - mutex_lock(MUTEX_ID); - A = 1; - condvar_signal(CONDVAR_ID); - mutex_unlock(MUTEX_ID); - exit(0) -} - -unsafe fn second() -> ! { - println!("Second want to continue,but need to wait A=1"); - mutex_lock(MUTEX_ID); - while A == 0 { - println!("Second: A is {}", A); - condvar_wait(CONDVAR_ID, MUTEX_ID); - } - println!("A is {}, Second can work now", A); - mutex_unlock(MUTEX_ID); - exit(0) -} - -#[no_mangle] -pub fn main() -> i32 { - // create condvar & mutex - assert_eq!(condvar_create() as usize, CONDVAR_ID); - assert_eq!(mutex_blocking_create() as usize, MUTEX_ID); - // create threads - let threads = vec![ - thread_create(first as usize, 0), - thread_create(second as usize, 0), - ]; - // wait for all threads to complete - for thread in threads.iter() { - waittid(*thread as usize); - } - println!("test_condvar passed!"); - 0 -} diff --git a/user/src/bin/condsync_sem.rs b/user/src/bin/condsync_sem.rs deleted file mode 100644 index ee08fac..0000000 --- a/user/src/bin/condsync_sem.rs +++ /dev/null @@ -1,64 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -extern crate alloc; - -use alloc::vec; -use user_lib::exit; -use user_lib::{ - mutex_blocking_create, mutex_lock, mutex_unlock, semaphore_create, semaphore_down, semaphore_up, -}; -use user_lib::{sleep, thread_create, waittid}; - -static mut A: usize = 0; - -const SEM_ID: usize = 0; -const MUTEX_ID: usize = 0; - -unsafe fn first() -> ! { - sleep(10); - println!("First work, Change A --> 1 and wakeup Second"); - mutex_lock(MUTEX_ID); - A = 1; - semaphore_up(SEM_ID); - mutex_unlock(MUTEX_ID); - exit(0) -} - -unsafe fn second() -> ! { - println!("Second want to continue,but need to wait A=1"); - loop { - mutex_lock(MUTEX_ID); - if A == 0 { - println!("Second: A is {}", A); - mutex_unlock(MUTEX_ID); - semaphore_down(SEM_ID); - } else { - mutex_unlock(MUTEX_ID); - break; - } - } - println!("A is {}, Second can work now", A); - exit(0) -} - -#[no_mangle] -pub fn main() -> i32 { - // create semaphore & mutex - assert_eq!(semaphore_create(0) as usize, SEM_ID); - assert_eq!(mutex_blocking_create() as usize, MUTEX_ID); - // create threads - let threads = vec![ - thread_create(first as usize, 0), - thread_create(second as usize, 0), - ]; - // wait for all threads to complete - for thread in threads.iter() { - waittid(*thread as usize); - } - println!("test_condvar passed!"); - 0 -} diff --git a/user/src/bin/count_lines.rs b/user/src/bin/count_lines.rs deleted file mode 100644 index 276e12e..0000000 --- a/user/src/bin/count_lines.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::read; - -#[no_mangle] -pub fn main(_argc: usize, _argv: &[&str]) -> i32 { - let mut buf = [0u8; 256]; - let mut lines = 0usize; - let mut total_size = 0usize; - loop { - let len = read(0, &mut buf) as usize; - if len == 0 { - break; - } - total_size += len; - let string = core::str::from_utf8(&buf[..len]).unwrap(); - lines += string - .chars() - .fold(0, |acc, c| acc + if c == '\n' { 1 } else { 0 }); - } - if total_size > 0 { - lines += 1; - } - println!("{}", lines); - 0 -} diff --git a/user/src/bin/eisenberg.rs b/user/src/bin/eisenberg.rs deleted file mode 100644 index 49a1d45..0000000 --- a/user/src/bin/eisenberg.rs +++ /dev/null @@ -1,139 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; -extern crate core; - -use alloc::vec::Vec; -use core::{ - sync::atomic::{AtomicUsize, Ordering}, -}; -use user_lib::{exit, sleep, thread_create, waittid}; - -const N: usize = 2; -const THREAD_NUM: usize = 10; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum FlagState { - Out, - Want, - In, -} - -static mut TURN: usize = 0; -static mut FLAG: [FlagState; THREAD_NUM] = [FlagState::Out; THREAD_NUM]; - -static GUARD: AtomicUsize = AtomicUsize::new(0); - -fn critical_test_enter() { - assert_eq!(GUARD.fetch_add(1, Ordering::SeqCst), 0); -} - -fn critical_test_claim() { - assert_eq!(GUARD.load(Ordering::SeqCst), 1); -} - -fn critical_test_exit() { - assert_eq!(GUARD.fetch_sub(1, Ordering::SeqCst), 1); -} - -unsafe fn eisenberg_enter_critical(id: usize) { - /* announce that we want to enter */ - loop { - println!("Thread[{}] try enter", id); - vstore!(FLAG[id], FlagState::Want); - loop { - /* check if any with higher priority is `Want` or `In` */ - let mut prior_thread: Option = None; - let turn = vload!(TURN); - let ring_id = if id < turn { id + THREAD_NUM } else { id }; - // FLAG.iter() may lead to some errors, use for-loop instead - for i in turn..ring_id { - if vload!(FLAG[i % THREAD_NUM]) != FlagState::Out { - prior_thread = Some(i % THREAD_NUM); - break; - } - } - if prior_thread.is_none() { - break; - } - println!( - "Thread[{}]: prior thread {} exist, sleep and retry", - id, - prior_thread.unwrap() - ); - sleep(1); - } - /* now tentatively claim the resource */ - vstore!(FLAG[id], FlagState::In); - /* enforce the order of `claim` and `conflict check`*/ - memory_fence!(); - /* check if anthor thread is also `In`, which imply a conflict*/ - let mut conflict = false; - for i in 0..THREAD_NUM { - if i != id && vload!(FLAG[i]) == FlagState::In { - conflict = true; - } - } - if !conflict { - break; - } - println!("Thread[{}]: CONFLECT!", id); - /* no need to sleep */ - } - /* clain the trun */ - vstore!(TURN, id); - println!("Thread[{}] enter", id); -} - -unsafe fn eisenberg_exit_critical(id: usize) { - /* find next one who wants to enter and give the turn to it*/ - let mut next = id; - let ring_id = id + THREAD_NUM; - for i in (id + 1)..ring_id { - let idx = i % THREAD_NUM; - if vload!(FLAG[idx]) == FlagState::Want { - next = idx; - break; - } - } - vstore!(TURN, next); - /* All done */ - vstore!(FLAG[id], FlagState::Out); - println!("Thread[{}] exit, give turn to {}", id, next); -} - -pub unsafe fn thread_fn(id: usize) -> ! { - println!("Thread[{}] init.", id); - for _ in 0..N { - eisenberg_enter_critical(id); - critical_test_enter(); - for _ in 0..3 { - critical_test_claim(); - sleep(2); - } - critical_test_exit(); - eisenberg_exit_critical(id); - } - exit(0) -} - -#[no_mangle] -pub fn main() -> i32 { - let mut v = Vec::new(); - // TODO: really shuffle - assert_eq!(THREAD_NUM, 10); - let shuffle: [usize; 10] = [0, 7, 4, 6, 2, 9, 8, 1, 3, 5]; - for i in 0..THREAD_NUM { - v.push(thread_create(thread_fn as usize, shuffle[i])); - } - for tid in v.iter() { - let exit_code = waittid(*tid as usize); - assert_eq!(exit_code, 0, "thread conflict happened!"); - println!("thread#{} exited with code {}", tid, exit_code); - } - println!("main thread exited."); - 0 -} diff --git a/user/src/bin/exit.rs b/user/src/bin/exit.rs index 60510c9..8e19542 100644 --- a/user/src/bin/exit.rs +++ b/user/src/bin/exit.rs @@ -7,7 +7,7 @@ use user_lib::{exit, fork, wait, waitpid, yield_}; const MAGIC: i32 = -0x10384; -#[no_mangle] +#[unsafe(no_mangle)] pub fn main() -> i32 { println!("I am the parent. Forking the child..."); let pid = fork(); diff --git a/user/src/bin/fantastic_text.rs b/user/src/bin/fantastic_text.rs index a3402ff..0850162 100644 --- a/user/src/bin/fantastic_text.rs +++ b/user/src/bin/fantastic_text.rs @@ -5,12 +5,12 @@ extern crate user_lib; macro_rules! color_text { - ($text:expr, $color:expr) => {{ + ($text:expr, $color:expr) => { format_args!("\x1b[{}m{}\x1b[0m", $color, $text) - }}; + }; } -#[no_mangle] +#[unsafe(no_mangle)] pub fn main() -> i32 { println!( "{}{}{}{}{} {}{}{}{} {}{}{}{}{}{}", diff --git a/user/src/bin/filetest_simple.rs b/user/src/bin/filetest_simple.rs index 3406d55..b192156 100644 --- a/user/src/bin/filetest_simple.rs +++ b/user/src/bin/filetest_simple.rs @@ -4,9 +4,9 @@ #[macro_use] extern crate user_lib; -use user_lib::{close, open, read, write, OpenFlags}; +use user_lib::{OpenFlags, close, open, read, write}; -#[no_mangle] +#[unsafe(no_mangle)] pub fn main() -> i32 { let test_str = "Hello, world!"; let filea = "filea\0"; diff --git a/user/src/bin/forktest.rs b/user/src/bin/forktest.rs index 5374a56..f6003c5 100644 --- a/user/src/bin/forktest.rs +++ b/user/src/bin/forktest.rs @@ -8,7 +8,7 @@ use user_lib::{exit, fork, wait}; const MAX_CHILD: usize = 30; -#[no_mangle] +#[unsafe(no_mangle)] pub fn main() -> i32 { for i in 0..MAX_CHILD { let pid = fork(); diff --git a/user/src/bin/forktest2.rs b/user/src/bin/forktest2.rs index c91ce15..ee452cc 100644 --- a/user/src/bin/forktest2.rs +++ b/user/src/bin/forktest2.rs @@ -8,7 +8,7 @@ use user_lib::{exit, fork, get_time, getpid, sleep, wait}; static NUM: usize = 30; -#[no_mangle] +#[unsafe(no_mangle)] pub fn main() -> i32 { for _ in 0..NUM { let pid = fork(); diff --git a/user/src/bin/forktest_simple.rs b/user/src/bin/forktest_simple.rs index 29a624b..b9cf587 100644 --- a/user/src/bin/forktest_simple.rs +++ b/user/src/bin/forktest_simple.rs @@ -6,7 +6,7 @@ extern crate user_lib; use user_lib::{fork, getpid, wait}; -#[no_mangle] +#[unsafe(no_mangle)] pub fn main() -> i32 { assert_eq!(wait(&mut 0i32), -1); println!("sys_wait without child process test passed!"); diff --git a/user/src/bin/forktree.rs b/user/src/bin/forktree.rs index 6b120ee..bcca4e6 100644 --- a/user/src/bin/forktree.rs +++ b/user/src/bin/forktree.rs @@ -4,7 +4,7 @@ #[macro_use] extern crate user_lib; -use user_lib::{exit, fork, getpid, sleep, wait, yield_}; +use user_lib::{exit, fork, getpid, sleep, yield_}; const DEPTH: usize = 4; @@ -27,19 +27,11 @@ fn fork_tree(cur: &str) { println!("pid{}: {}", getpid(), cur); fork_child(cur, '0'); fork_child(cur, '1'); - let mut exit_code: i32 = 0; - for _ in 0..2 { - wait(&mut exit_code); - } } -#[no_mangle] +#[unsafe(no_mangle)] pub fn main() -> i32 { fork_tree(""); - let mut exit_code: i32 = 0; - for _ in 0..2 { - wait(&mut exit_code); - } sleep(3000); 0 } diff --git a/user/src/bin/gui_move.rs b/user/src/bin/gui_move.rs deleted file mode 100644 index 240ff8f..0000000 --- a/user/src/bin/gui_move.rs +++ /dev/null @@ -1,82 +0,0 @@ -#![no_std] -#![no_main] - -extern crate user_lib; -extern crate alloc; - -use user_lib::console::getchar; -use user_lib::{Display, VIRTGPU_XRES, VIRTGPU_YRES}; - -use embedded_graphics::pixelcolor::Rgb888; -use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size}; -use embedded_graphics::primitives::Primitive; -use embedded_graphics::primitives::{PrimitiveStyle, Rectangle}; -use embedded_graphics::draw_target::DrawTarget; - -const INIT_X: i32 = 640; -const INIT_Y: i32 = 400; -const RECT_SIZE: u32 = 40; - -pub struct DrawingBoard { - disp: Display, - latest_pos: Point, -} - -impl DrawingBoard { - pub fn new() -> Self { - Self { - disp: Display::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES)), - latest_pos: Point::new(INIT_X, INIT_Y), - } - } - fn paint(&mut self) { - Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE)) - .into_styled(PrimitiveStyle::with_stroke(Rgb888::WHITE, 1)) - .draw(&mut self.disp) - .ok(); - } - fn unpaint(&mut self) { - Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE)) - .into_styled(PrimitiveStyle::with_stroke(Rgb888::BLACK, 1)) - .draw(&mut self.disp) - .ok(); - } - pub fn move_rect(&mut self, dx: i32, dy: i32) { - let new_x = self.latest_pos.x + dx; - let new_y = self.latest_pos.y + dy; - let r = (RECT_SIZE / 2) as i32; - if new_x > r && new_x + r < (VIRTGPU_XRES as i32) && new_y > r && new_y + r < (VIRTGPU_YRES as i32) { - self.unpaint(); - self.latest_pos.x = new_x; - self.latest_pos.y = new_y; - self.paint(); - } - } -} - -const LF: u8 = 0x0au8; -const CR: u8 = 0x0du8; -#[no_mangle] -pub fn main() -> i32 { - let mut board = DrawingBoard::new(); - let _ = board.disp.clear(Rgb888::BLACK).unwrap(); - board.disp.flush(); - loop { - let c = getchar(); - if c == LF || c == CR { - break; - } - let mut moved = true; - match c { - b'w' => board.move_rect(0, -10), - b'a' => board.move_rect(-10, 0), - b's' => board.move_rect(0, 10), - b'd' => board.move_rect(10, 0), - _ => moved = false, - } - if moved { - board.disp.flush(); - } - } - 0 -} diff --git a/user/src/bin/gui_shape.rs b/user/src/bin/gui_shape.rs deleted file mode 100644 index df03df3..0000000 --- a/user/src/bin/gui_shape.rs +++ /dev/null @@ -1,59 +0,0 @@ -#![no_std] -#![no_main] - -extern crate alloc; -extern crate user_lib; - -use user_lib::{Display, VIRTGPU_XRES, VIRTGPU_YRES}; - -use embedded_graphics::pixelcolor::Rgb888; -use embedded_graphics::prelude::{DrawTarget, Drawable, Point, RgbColor, Size}; -use embedded_graphics::primitives::{Circle, Primitive, PrimitiveStyle, Rectangle, Triangle}; - -const INIT_X: i32 = 80; -const INIT_Y: i32 = 400; -const RECT_SIZE: u32 = 150; - -pub struct DrawingBoard { - disp: Display, - latest_pos: Point, -} - -impl DrawingBoard { - pub fn new() -> Self { - Self { - disp: Display::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES)), - latest_pos: Point::new(INIT_X, INIT_Y), - } - } - fn paint(&mut self) { - Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE)) - .into_styled(PrimitiveStyle::with_stroke(Rgb888::RED, 10)) - .draw(&mut self.disp) - .ok(); - Circle::new(self.latest_pos + Point::new(-70, -300), 150) - .into_styled(PrimitiveStyle::with_fill(Rgb888::BLUE)) - .draw(&mut self.disp) - .ok(); - Triangle::new( - self.latest_pos + Point::new(0, 150), - self.latest_pos + Point::new(80, 200), - self.latest_pos + Point::new(-120, 300), - ) - .into_styled(PrimitiveStyle::with_stroke(Rgb888::GREEN, 10)) - .draw(&mut self.disp) - .ok(); - } -} - -#[no_mangle] -pub fn main() -> i32 { - let mut board = DrawingBoard::new(); - let _ = board.disp.clear(Rgb888::BLACK).unwrap(); - for _ in 0..5 { - board.latest_pos.x += RECT_SIZE as i32 + 20; - board.paint(); - } - board.disp.flush(); - 0 -} diff --git a/user/src/bin/gui_snake.rs b/user/src/bin/gui_snake.rs deleted file mode 100644 index 6dd4052..0000000 --- a/user/src/bin/gui_snake.rs +++ /dev/null @@ -1,352 +0,0 @@ -#![no_std] -#![no_main] - -extern crate alloc; -extern crate user_lib; - -use user_lib::console::getchar; -use user_lib::{key_pressed, sleep, Display, VIRTGPU_XRES, VIRTGPU_YRES}; - -use embedded_graphics::pixelcolor::*; -use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size}; -use embedded_graphics::primitives::Primitive; -use embedded_graphics::primitives::{PrimitiveStyle, Rectangle}; -use embedded_graphics::Pixel; -use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions}; -use oorandom; //random generator - -struct Snake { - parts: [Pixel; MAX_SIZE], - len: usize, - direction: Direction, - size_x: u32, - size_y: u32, -} - -struct SnakeIntoIterator<'a, T: PixelColor, const MAX_SIZE: usize> { - snake: &'a Snake, - index: usize, -} - -impl<'a, T: PixelColor, const MAX_SIZE: usize> IntoIterator for &'a Snake { - type Item = Pixel; - type IntoIter = SnakeIntoIterator<'a, T, MAX_SIZE>; - - fn into_iter(self) -> Self::IntoIter { - SnakeIntoIterator { - snake: self, - index: 0, - } - } -} - -impl<'a, T: PixelColor, const MAX_SIZE: usize> Iterator for SnakeIntoIterator<'a, T, MAX_SIZE> { - type Item = Pixel; - - fn next(&mut self) -> Option { - let cur = self.snake.parts[self.index]; - if self.index < self.snake.len { - self.index += 1; - return Some(cur); - } - None - } -} - -impl Snake { - fn new(color: T, size_x: u32, size_y: u32) -> Snake { - Snake { - parts: [Pixel::(Point { x: 0, y: 0 }, color); MAX_SIZE], - len: 1, - direction: Direction::None, - size_x, - size_y, - } - } - fn set_direction(&mut self, direction: Direction) { - self.direction = direction; - } - fn contains(&self, this: Point) -> bool { - for part in self.into_iter() { - if part.0 == this { - return true; - }; - } - false - } - fn grow(&mut self) { - if self.len < MAX_SIZE - 1 { - self.len += 1; - } - } - fn make_step(&mut self) { - let mut i = self.len; - while i > 0 { - self.parts[i] = self.parts[i - 1]; - i -= 1; - } - match self.direction { - Direction::Left => { - if self.parts[0].0.x == 0 { - self.parts[0].0.x = (self.size_x - 1) as i32; - } else { - self.parts[0].0.x -= 1; - } - } - Direction::Right => { - if self.parts[0].0.x == (self.size_x - 1) as i32 { - self.parts[0].0.x = 0; - } else { - self.parts[0].0.x += 1; - } - } - Direction::Up => { - if self.parts[0].0.y == 0 { - self.parts[0].0.y = (self.size_y - 1) as i32; - } else { - self.parts[0].0.y -= 1; - } - } - Direction::Down => { - if self.parts[0].0.y == (self.size_y - 1) as i32 { - self.parts[0].0.y = 0; - } else { - self.parts[0].0.y += 1; - } - } - Direction::None => {} - } - } -} - -struct Food { - size_x: u32, - size_y: u32, - place: Pixel, - rng: oorandom::Rand32, -} - -impl Food { - pub fn new(color: T, size_x: u32, size_y: u32) -> Self { - let seed = 4; - let rng = oorandom::Rand32::new(seed); - Food { - size_x, - size_y, - place: Pixel(Point { x: 0, y: 0 }, color), - rng, - } - } - fn replace<'a, const MAX_SIZE: usize>(&mut self, iter_source: &Snake) { - let mut p: Point; - 'outer: loop { - let random_number = self.rng.rand_u32(); - let blocked_positions = iter_source.into_iter(); - p = Point { - x: ((random_number >> 24) as u16 % self.size_x as u16).into(), - y: ((random_number >> 16) as u16 % self.size_y as u16).into(), - }; - for blocked_position in blocked_positions { - if p == blocked_position.0 { - continue 'outer; - } - } - break; - } - self.place = Pixel:: { - 0: p, - 1: self.place.1, - } - } - fn get_pixel(&self) -> Pixel { - self.place - } -} - -#[derive(PartialEq, Debug, Clone, Copy)] -pub enum Direction { - Left, - Right, - Up, - Down, - None, -} - -pub struct SnakeGame { - snake: Snake, - food: Food, - food_age: u32, - food_lifetime: u32, - size_x: u32, - size_y: u32, - scale_x: u32, - scale_y: u32, -} - -impl SnakeGame { - pub fn new( - size_x: u32, - size_y: u32, - scale_x: u32, - scale_y: u32, - snake_color: T, - food_color: T, - food_lifetime: u32, - ) -> Self { - let snake = Snake::::new(snake_color, size_x / scale_x, size_y / scale_y); - let mut food = Food::::new(food_color, size_x / scale_x, size_y / scale_y); - food.replace(&snake); - SnakeGame { - snake, - food, - food_age: 0, - food_lifetime, - size_x, - size_y, - scale_x, - scale_y, - } - } - pub fn set_direction(&mut self, direction: Direction) { - self.snake.set_direction(direction); - } - pub fn draw(&mut self, target: &mut D) -> () - where - D: DrawTarget, - { - self.snake.make_step(); - let hit = self.snake.contains(self.food.get_pixel().0); - if hit { - self.snake.grow(); - } - self.food_age += 1; - if self.food_age >= self.food_lifetime || hit { - self.food.replace(&self.snake); - self.food_age = 0; - } - - let mut scaled_display = ScaledDisplay:: { - real_display: target, - size_x: self.size_x / self.scale_x, - size_y: self.size_y / self.scale_y, - scale_x: self.scale_x, - scale_y: self.scale_y, - }; - - for part in self.snake.into_iter() { - _ = part.draw(&mut scaled_display); - } - _ = self.food.get_pixel().draw(&mut scaled_display); - } -} - -/// A dummy DrawTarget implementation that can magnify each pixel so the user code does not need to adapt for scaling things -struct ScaledDisplay<'a, T: DrawTarget> { - real_display: &'a mut T, - size_x: u32, - size_y: u32, - scale_x: u32, - scale_y: u32, -} - -impl<'a, T: DrawTarget> DrawTarget for ScaledDisplay<'a, T> { - type Color = T::Color; - type Error = T::Error; - - fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> - where - I: IntoIterator>, - { - for pixel in pixels { - let style = PrimitiveStyle::with_fill(pixel.1); - Rectangle::new( - Point::new( - pixel.0.x * self.scale_x as i32, - pixel.0.y * self.scale_y as i32, - ), - Size::new(self.scale_x as u32, self.scale_y as u32), - ) - .into_styled(style) - .draw(self.real_display)?; - } - Ok(()) - } -} - -impl<'a, T: DrawTarget> OriginDimensions for ScaledDisplay<'a, T> { - fn size(&self) -> Size { - Size::new(self.size_x as u32, self.size_y as u32) - } -} - -#[cfg(test)] -mod tests { - - use crate::Snake; - use embedded_graphics::pixelcolor::*; - use embedded_graphics::prelude::*; - - #[test] - fn snake_basic() { - let mut snake = Snake::::new(Rgb888::RED, 8, 8); - snake.set_direction(crate::Direction::Right); - assert_eq!( - Pixel::(Point { x: 0, y: 0 }, Rgb888::RED), - snake.into_iter().next().unwrap() - ); - snake.make_step(); - assert_eq!( - Pixel::(Point { x: 1, y: 0 }, Rgb888::RED), - snake.into_iter().nth(0).unwrap() - ); - assert_eq!( - Pixel::(Point { x: 0, y: 0 }, Rgb888::RED), - snake.into_iter().nth(1).unwrap() - ); - snake.set_direction(crate::Direction::Down); - snake.make_step(); - assert_eq!( - Pixel::(Point { x: 1, y: 1 }, Rgb888::RED), - snake.into_iter().nth(0).unwrap() - ); - assert_eq!( - Pixel::(Point { x: 1, y: 0 }, Rgb888::RED), - snake.into_iter().nth(1).unwrap() - ); - assert_eq!( - Pixel::(Point { x: 0, y: 0 }, Rgb888::RED), - snake.into_iter().nth(2).unwrap() - ); - assert_eq!(true, snake.contains(Point { x: 0, y: 0 })); - assert_eq!(true, snake.contains(Point { x: 1, y: 0 })); - assert_eq!(true, snake.contains(Point { x: 1, y: 1 })); - } -} - -const LF: u8 = 0x0au8; -const CR: u8 = 0x0du8; -#[no_mangle] -pub fn main() -> i32 { - let mut disp = Display::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES)); - let mut game = SnakeGame::<20, Rgb888>::new(1280, 800, 20, 20, Rgb888::RED, Rgb888::YELLOW, 200); - let _ = disp.clear(Rgb888::BLACK).unwrap(); - loop { - if key_pressed() { - let c = getchar(); - match c { - LF => break, - CR => break, - b'w' => game.set_direction(Direction::Up), - b's' => game.set_direction(Direction::Down), - b'a' => game.set_direction(Direction::Left), - b'd' => game.set_direction(Direction::Right), - _ => (), - } - } - let _ = disp.clear(Rgb888::BLACK).unwrap(); - game.draw(&mut disp); - disp.flush(); - sleep(40); - } - 0 -} diff --git a/user/src/bin/gui_tri.rs b/user/src/bin/gui_tri.rs deleted file mode 100644 index 69d47f5..0000000 --- a/user/src/bin/gui_tri.rs +++ /dev/null @@ -1,24 +0,0 @@ -#![no_std] -#![no_main] - -extern crate user_lib; - -use embedded_graphics::prelude::Size; -use user_lib::{Display, VIRTGPU_XRES, VIRTGPU_YRES}; - -#[no_mangle] -pub fn main() -> i32 { - let mut disp = Display::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES)); - disp.paint_on_framebuffer(|fb| { - for y in 0..VIRTGPU_YRES as usize { - for x in 0..VIRTGPU_XRES as usize { - let idx = (y * VIRTGPU_XRES as usize + x) * 4; - fb[idx] = x as u8; - fb[idx + 1] = y as u8; - fb[idx + 2] = (x + y) as u8; - } - } - }); - disp.flush(); - 0 -} diff --git a/user/src/bin/hello_world.rs b/user/src/bin/hello_world.rs index 10d3f26..cc651e7 100644 --- a/user/src/bin/hello_world.rs +++ b/user/src/bin/hello_world.rs @@ -4,7 +4,7 @@ #[macro_use] extern crate user_lib; -#[no_mangle] +#[unsafe(no_mangle)] pub fn main() -> i32 { println!("Hello world from user mode program!"); 0 diff --git a/user/src/bin/huge_write.rs b/user/src/bin/huge_write.rs index 2a977c9..9327261 100644 --- a/user/src/bin/huge_write.rs +++ b/user/src/bin/huge_write.rs @@ -4,9 +4,9 @@ #[macro_use] extern crate user_lib; -use user_lib::{close, get_time, open, write, OpenFlags}; +use user_lib::{OpenFlags, close, get_time, open, write}; -#[no_mangle] +#[unsafe(no_mangle)] pub fn main() -> i32 { let mut buffer = [0u8; 1024]; // 1KiB for (i, ch) in buffer.iter_mut().enumerate() { @@ -24,7 +24,7 @@ pub fn main() -> i32 { } close(f); let time_ms = (get_time() - start) as usize; - let speed_kbs = (size_mb << 20) / time_ms; + let speed_kbs = size_mb * 1000000 / time_ms; println!( "{}MiB written, time cost = {}ms, write speed = {}KiB/s", size_mb, time_ms, speed_kbs diff --git a/user/src/bin/huge_write_mt.rs b/user/src/bin/huge_write_mt.rs deleted file mode 100644 index 0a60fd8..0000000 --- a/user/src/bin/huge_write_mt.rs +++ /dev/null @@ -1,56 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::{fmt::format, vec::Vec}; -use user_lib::{close, get_time, gettid, open, write, OpenFlags}; -use user_lib::{exit, thread_create, waittid}; - -fn worker(size_kib: usize) { - let mut buffer = [0u8; 1024]; // 1KiB - for (i, ch) in buffer.iter_mut().enumerate() { - *ch = i as u8; - } - let filename = format(format_args!("testf{}\0", gettid())); - let f = open(filename.as_str(), OpenFlags::CREATE | OpenFlags::WRONLY); - if f < 0 { - panic!("Open test file failed!"); - } - let f = f as usize; - for _ in 0..size_kib { - write(f, &buffer); - } - close(f); - exit(0) -} - -#[no_mangle] -pub fn main(argc: usize, argv: &[&str]) -> i32 { - assert_eq!(argc, 2, "wrong argument"); - let size_mb = 1usize; - let size_kb = size_mb << 10; - let workers = argv[1].parse::().expect("wrong argument"); - assert!(workers >= 1 && size_kb % workers == 0, "wrong argument"); - - let start = get_time(); - - let mut v = Vec::new(); - let size_mb = 1usize; - for _ in 0..workers { - v.push(thread_create(worker as usize, size_kb / workers)); - } - for tid in v.iter() { - assert_eq!(0, waittid(*tid as usize)); - } - - let time_ms = (get_time() - start) as usize; - let speed_kbs = size_kb * 1000 / time_ms; - println!( - "{}MiB written by {} threads, time cost = {}ms, write speed = {}KiB/s", - size_mb, workers, time_ms, speed_kbs - ); - 0 -} diff --git a/user/src/bin/infloop.rs b/user/src/bin/infloop.rs deleted file mode 100644 index 1f24853..0000000 --- a/user/src/bin/infloop.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![no_std] -#![no_main] -#![allow(clippy::empty_loop)] - -extern crate user_lib; - -#[no_mangle] -pub fn main(_argc: usize, _argv: &[&str]) -> ! { - loop {} -} diff --git a/user/src/bin/initproc.rs b/user/src/bin/initproc.rs index d25aee1..d522b77 100644 --- a/user/src/bin/initproc.rs +++ b/user/src/bin/initproc.rs @@ -1,14 +1,15 @@ #![no_std] #![no_main] +#[macro_use] extern crate user_lib; use user_lib::{exec, fork, wait, yield_}; -#[no_mangle] +#[unsafe(no_mangle)] fn main() -> i32 { if fork() == 0 { - exec("user_shell\0", &[core::ptr::null::()]); + exec("user_shell\0"); } else { loop { let mut exit_code: i32 = 0; @@ -17,13 +18,10 @@ fn main() -> i32 { yield_(); continue; } - /* println!( "[initproc] Released a zombie process, pid={}, exit_code={}", - pid, - exit_code, + pid, exit_code, ); - */ } } 0 diff --git a/user/src/bin/inputdev_event.rs b/user/src/bin/inputdev_event.rs deleted file mode 100644 index ea56f3a..0000000 --- a/user/src/bin/inputdev_event.rs +++ /dev/null @@ -1,25 +0,0 @@ -#![no_std] -#![no_main] - -use user_lib::{event_get, DecodeType, Key, KeyType}; - -#[macro_use] -extern crate user_lib; - -#[no_mangle] -pub fn main() -> i32 { - println!("Input device event test"); - loop { - if let Some(event) = event_get() { - if let Some(decoder_type) = event.decode() { - println!("{:?}", decoder_type); - if let DecodeType::Key(key, keytype) = decoder_type { - if key == Key::Enter && keytype == KeyType::Press { - break; - } - } - } - } - } - 0 -} diff --git a/user/src/bin/matrix.rs b/user/src/bin/matrix.rs index 9ebf48f..846f4c6 100644 --- a/user/src/bin/matrix.rs +++ b/user/src/bin/matrix.rs @@ -44,7 +44,7 @@ fn work(times: isize) { exit(0); } -#[no_mangle] +#[unsafe(no_mangle)] pub fn main() -> i32 { for _ in 0..NUM { let pid = fork(); diff --git a/user/src/bin/mpsc_sem.rs b/user/src/bin/mpsc_sem.rs deleted file mode 100644 index 7b72bbb..0000000 --- a/user/src/bin/mpsc_sem.rs +++ /dev/null @@ -1,73 +0,0 @@ -#![no_std] -#![no_main] -#![allow(clippy::println_empty_string)] - -#[macro_use] -extern crate user_lib; - -extern crate alloc; - -use alloc::vec::Vec; -use user_lib::exit; -use user_lib::{semaphore_create, semaphore_down, semaphore_up}; -use user_lib::{thread_create, waittid}; - -const SEM_MUTEX: usize = 0; -const SEM_EMPTY: usize = 1; -const SEM_AVAIL: usize = 2; -const BUFFER_SIZE: usize = 8; -static mut BUFFER: [usize; BUFFER_SIZE] = [0; BUFFER_SIZE]; -static mut FRONT: usize = 0; -static mut TAIL: usize = 0; -const PRODUCER_COUNT: usize = 4; -const NUMBER_PER_PRODUCER: usize = 100; - -unsafe fn producer(id: *const usize) -> ! { - let id = *id; - for _ in 0..NUMBER_PER_PRODUCER { - semaphore_down(SEM_EMPTY); - semaphore_down(SEM_MUTEX); - BUFFER[TAIL] = id; - TAIL = (TAIL + 1) % BUFFER_SIZE; - semaphore_up(SEM_MUTEX); - semaphore_up(SEM_AVAIL); - } - exit(0) -} - -unsafe fn consumer() -> ! { - for _ in 0..PRODUCER_COUNT * NUMBER_PER_PRODUCER { - semaphore_down(SEM_AVAIL); - semaphore_down(SEM_MUTEX); - print!("{} ", BUFFER[FRONT]); - FRONT = (FRONT + 1) % BUFFER_SIZE; - semaphore_up(SEM_MUTEX); - semaphore_up(SEM_EMPTY); - } - println!(""); - exit(0) -} - -#[no_mangle] -pub fn main() -> i32 { - // create semaphores - assert_eq!(semaphore_create(1) as usize, SEM_MUTEX); - assert_eq!(semaphore_create(BUFFER_SIZE) as usize, SEM_EMPTY); - assert_eq!(semaphore_create(0) as usize, SEM_AVAIL); - // create threads - let ids: Vec<_> = (0..PRODUCER_COUNT).collect(); - let mut threads = Vec::new(); - for i in 0..PRODUCER_COUNT { - threads.push(thread_create( - producer as usize, - &ids.as_slice()[i] as *const _ as usize, - )); - } - threads.push(thread_create(consumer as usize, 0)); - // wait for all threads to complete - for thread in threads.iter() { - waittid(*thread as usize); - } - println!("mpsc_sem passed!"); - 0 -} diff --git a/user/src/bin/peterson.rs b/user/src/bin/peterson.rs deleted file mode 100644 index e03e2a4..0000000 --- a/user/src/bin/peterson.rs +++ /dev/null @@ -1,79 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; -extern crate core; - -use alloc::vec::Vec; -use core::sync::atomic::{AtomicUsize, Ordering}; -use user_lib::{exit, sleep, thread_create, waittid}; -const N: usize = 1000; - -static mut TURN: usize = 0; -static mut FLAG: [bool; 2] = [false; 2]; -static GUARD: AtomicUsize = AtomicUsize::new(0); - -fn critical_test_enter() { - assert_eq!(GUARD.fetch_add(1, Ordering::SeqCst), 0); -} - -fn critical_test_claim() { - assert_eq!(GUARD.load(Ordering::SeqCst), 1); -} - -fn critical_test_exit() { - assert_eq!(GUARD.fetch_sub(1, Ordering::SeqCst), 1); -} - -unsafe fn peterson_enter_critical(id: usize, peer_id: usize) { - // println!("Thread[{}] try enter", id); - vstore!(FLAG[id], true); - vstore!(TURN, peer_id); - memory_fence!(); - while vload!(FLAG[peer_id]) && vload!(TURN) == peer_id { - // println!("Thread[{}] enter fail", id); - sleep(1); - // println!("Thread[{}] retry enter", id); - } - // println!("Thread[{}] enter", id); -} - -unsafe fn peterson_exit_critical(id: usize) { - vstore!(FLAG[id], false); - // println!("Thread[{}] exit", id); -} - -pub unsafe fn thread_fn(id: usize) -> ! { - // println!("Thread[{}] init.", id); - let peer_id: usize = id ^ 1; - for iter in 0..N { - if iter % 10 == 0 { - println!("[{}] it={}", id, iter); - } - peterson_enter_critical(id, peer_id); - critical_test_enter(); - for _ in 0..3 { - critical_test_claim(); - sleep(2); - } - critical_test_exit(); - peterson_exit_critical(id); - } - exit(0) -} - -#[no_mangle] -pub fn main() -> i32 { - let mut v = Vec::new(); - v.push(thread_create(thread_fn as usize, 0)); - // v.push(thread_create(thread_fn as usize, 1)); - for tid in v.iter() { - let exit_code = waittid(*tid as usize); - assert_eq!(exit_code, 0, "thread conflict happened!"); - println!("thread#{} exited with code {}", tid, exit_code); - } - println!("main thread exited."); - 0 -} diff --git a/user/src/bin/phil_din_mutex.rs b/user/src/bin/phil_din_mutex.rs deleted file mode 100644 index 8e7b566..0000000 --- a/user/src/bin/phil_din_mutex.rs +++ /dev/null @@ -1,107 +0,0 @@ -#![no_std] -#![no_main] -#![allow(clippy::println_empty_string)] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use user_lib::{exit, get_time, sleep}; -use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock}; -use user_lib::{thread_create, waittid}; - -const N: usize = 5; -const ROUND: usize = 4; -// A round: think -> wait for forks -> eat -const GRAPH_SCALE: usize = 100; - -fn get_time_u() -> usize { - get_time() as usize -} - -// Time unit: ms -const ARR: [[usize; ROUND * 2]; N] = [ - [700, 800, 1000, 400, 500, 600, 200, 400], - [300, 600, 200, 700, 1000, 100, 300, 600], - [500, 200, 900, 200, 400, 600, 1200, 400], - [500, 1000, 600, 500, 800, 600, 200, 900], - [600, 100, 600, 600, 200, 500, 600, 200], -]; -static mut THINK: [[usize; ROUND * 2]; N] = [[0; ROUND * 2]; N]; -static mut EAT: [[usize; ROUND * 2]; N] = [[0; ROUND * 2]; N]; - -fn philosopher_dining_problem(id: *const usize) { - let id = unsafe { *id }; - let left = id; - let right = if id == N - 1 { 0 } else { id + 1 }; - let min = if left < right { left } else { right }; - let max = left + right - min; - for round in 0..ROUND { - // thinking - unsafe { - THINK[id][2 * round] = get_time_u(); - } - sleep(ARR[id][2 * round]); - unsafe { - THINK[id][2 * round + 1] = get_time_u(); - } - // wait for forks - mutex_lock(min); - mutex_lock(max); - // eating - unsafe { - EAT[id][2 * round] = get_time_u(); - } - sleep(ARR[id][2 * round + 1]); - unsafe { - EAT[id][2 * round + 1] = get_time_u(); - } - mutex_unlock(max); - mutex_unlock(min); - } - exit(0) -} - -#[no_mangle] -pub fn main() -> i32 { - let mut v = Vec::new(); - let ids: Vec<_> = (0..N).collect(); - let start = get_time_u(); - for i in 0..N { - assert_eq!(mutex_blocking_create(), i as isize); - v.push(thread_create( - philosopher_dining_problem as usize, - &ids.as_slice()[i] as *const _ as usize, - )); - } - for tid in v.iter() { - waittid(*tid as usize); - } - let time_cost = get_time_u() - start; - println!("time cost = {}", time_cost); - println!("'-' -> THINKING; 'x' -> EATING; ' ' -> WAITING "); - for id in (0..N).into_iter().chain(0..=0) { - print!("#{}:", id); - for j in 0..time_cost / GRAPH_SCALE { - let current_time = j * GRAPH_SCALE + start; - if (0..ROUND).any(|round| unsafe { - let start_thinking = THINK[id][2 * round]; - let end_thinking = THINK[id][2 * round + 1]; - start_thinking <= current_time && current_time <= end_thinking - }) { - print!("-"); - } else if (0..ROUND).any(|round| unsafe { - let start_eating = EAT[id][2 * round]; - let end_eating = EAT[id][2 * round + 1]; - start_eating <= current_time && current_time <= end_eating - }) { - print!("x"); - } else { - print!(" "); - }; - } - println!(""); - } - 0 -} diff --git a/user/src/bin/pipe_large_test.rs b/user/src/bin/pipe_large_test.rs deleted file mode 100644 index e85d0a6..0000000 --- a/user/src/bin/pipe_large_test.rs +++ /dev/null @@ -1,71 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -extern crate alloc; - -use alloc::format; -use user_lib::{close, fork, get_time, pipe, read, wait, write}; - -const LENGTH: usize = 3000; -#[no_mangle] -pub fn main() -> i32 { - // create pipes - // parent write to child - let mut down_pipe_fd = [0usize; 2]; - // child write to parent - let mut up_pipe_fd = [0usize; 2]; - pipe(&mut down_pipe_fd); - pipe(&mut up_pipe_fd); - let mut random_str = [0u8; LENGTH]; - if fork() == 0 { - // close write end of down pipe - close(down_pipe_fd[1]); - // close read end of up pipe - close(up_pipe_fd[0]); - assert_eq!(read(down_pipe_fd[0], &mut random_str) as usize, LENGTH); - close(down_pipe_fd[0]); - let sum: usize = random_str.iter().map(|v| *v as usize).sum::(); - println!("sum = {}(child)", sum); - let sum_str = format!("{}", sum); - write(up_pipe_fd[1], sum_str.as_bytes()); - close(up_pipe_fd[1]); - println!("Child process exited!"); - 0 - } else { - // close read end of down pipe - close(down_pipe_fd[0]); - // close write end of up pipe - close(up_pipe_fd[1]); - // generate a long random string - for ch in random_str.iter_mut() { - *ch = get_time() as u8; - } - // send it - assert_eq!( - write(down_pipe_fd[1], &random_str) as usize, - random_str.len() - ); - // close write end of down pipe - close(down_pipe_fd[1]); - // calculate sum(parent) - let sum: usize = random_str.iter().map(|v| *v as usize).sum::(); - println!("sum = {}(parent)", sum); - // recv sum(child) - let mut child_result = [0u8; 32]; - let result_len = read(up_pipe_fd[0], &mut child_result) as usize; - close(up_pipe_fd[0]); - // check - assert_eq!( - sum, - str::parse::(core::str::from_utf8(&child_result[..result_len]).unwrap()) - .unwrap() - ); - let mut _unused: i32 = 0; - wait(&mut _unused); - println!("pipe_large_test passed!"); - 0 - } -} diff --git a/user/src/bin/pipetest.rs b/user/src/bin/pipetest.rs deleted file mode 100644 index 5436c63..0000000 --- a/user/src/bin/pipetest.rs +++ /dev/null @@ -1,44 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{close, fork, pipe, read, wait, write}; - -static STR: &str = "Hello, world!"; - -#[no_mangle] -pub fn main() -> i32 { - // create pipe - let mut pipe_fd = [0usize; 2]; - pipe(&mut pipe_fd); - // read end - assert_eq!(pipe_fd[0], 3); - // write end - assert_eq!(pipe_fd[1], 4); - if fork() == 0 { - // child process, read from parent - // close write_end - close(pipe_fd[1]); - let mut buffer = [0u8; 32]; - let len_read = read(pipe_fd[0], &mut buffer) as usize; - // close read_end - close(pipe_fd[0]); - assert_eq!(core::str::from_utf8(&buffer[..len_read]).unwrap(), STR); - println!("Read OK, child process exited!"); - 0 - } else { - // parent process, write to child - // close read end - close(pipe_fd[0]); - assert_eq!(write(pipe_fd[1], STR.as_bytes()), STR.len() as isize); - // close write end - close(pipe_fd[1]); - let mut child_exit_code: i32 = 0; - wait(&mut child_exit_code); - assert_eq!(child_exit_code, 0); - println!("pipetest passed!"); - 0 - } -} diff --git a/user/src/bin/priv_csr.rs b/user/src/bin/priv_csr.rs deleted file mode 100644 index fbd678f..0000000 --- a/user/src/bin/priv_csr.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use riscv::register::sstatus::{self, SPP}; - -#[no_mangle] -fn main() -> i32 { - println!("Try to access privileged CSR in U Mode"); - println!("Kernel should kill this application!"); - unsafe { - sstatus::set_spp(SPP::User); - } - 0 -} diff --git a/user/src/bin/priv_inst.rs b/user/src/bin/priv_inst.rs deleted file mode 100644 index 04dac37..0000000 --- a/user/src/bin/priv_inst.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use core::arch::asm; - -#[no_mangle] -fn main() -> i32 { - println!("Try to execute privileged instruction in U Mode"); - println!("Kernel should kill this application!"); - unsafe { - asm!("sret"); - } - 0 -} diff --git a/user/src/bin/race_adder_arg.rs b/user/src/bin/race_adder_arg.rs deleted file mode 100644 index f33c660..0000000 --- a/user/src/bin/race_adder_arg.rs +++ /dev/null @@ -1,57 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use crate::alloc::string::ToString; -use alloc::vec::Vec; -use core::ptr::addr_of_mut; -use user_lib::{exit, get_time, thread_create, waittid}; - -static mut A: usize = 0; -const PER_THREAD: usize = 1000; -const THREAD_COUNT: usize = 16; - -unsafe fn f(count: usize) -> ! { - let mut t = 2usize; - for _ in 0..PER_THREAD { - let a = addr_of_mut!(A); - let cur = a.read_volatile(); - for _ in 0..count { - t = t * t % 10007; - } - a.write_volatile(cur + 1); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main(argc: usize, argv: &[&str]) -> i32 { - let count: usize; - if argc == 1 { - count = THREAD_COUNT; - } else if argc == 2 { - count = argv[1].to_string().parse::().unwrap(); - } else { - println!( - "ERROR in argv, argc is {}, argv[0] {} , argv[1] {} , argv[2] {}", - argc, argv[0], argv[1], argv[2] - ); - exit(-1); - } - - let start = get_time(); - let mut v = Vec::new(); - for _ in 0..THREAD_COUNT { - v.push(thread_create(f as usize, count) as usize); - } - let mut time_cost = Vec::new(); - for tid in v.iter() { - time_cost.push(waittid(*tid)); - } - println!("time cost is {}ms", get_time() - start); - assert_eq!(unsafe { A }, PER_THREAD * THREAD_COUNT); - 0 -} diff --git a/user/src/bin/random_num.rs b/user/src/bin/random_num.rs deleted file mode 100644 index d68bb13..0000000 --- a/user/src/bin/random_num.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -use oorandom; - -#[no_mangle] -pub fn main() -> i32 { - println!("random num program!"); - let seed = 4; - let mut rng = oorandom::Rand32::new(seed); - println!("OORandom: Random number 32bit: {}", rng.rand_i32()); - println!("OORandom: Random number range: {}", rng.rand_range(1..100)); - 0 -} diff --git a/user/src/bin/run_pipe_test.rs b/user/src/bin/run_pipe_test.rs deleted file mode 100644 index d3e329d..0000000 --- a/user/src/bin/run_pipe_test.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{exec, fork, wait}; - -#[no_mangle] -pub fn main() -> i32 { - for i in 0..5 { - if fork() == 0 { - exec("pipe_large_test\0", &[core::ptr::null::()]); - } else { - let mut _unused: i32 = 0; - wait(&mut _unused); - println!("Iter {} OK.", i); - } - } - 0 -} diff --git a/user/src/bin/sleep.rs b/user/src/bin/sleep.rs index 641a4f9..e02b3ed 100644 --- a/user/src/bin/sleep.rs +++ b/user/src/bin/sleep.rs @@ -15,7 +15,7 @@ fn sleepy() { exit(0); } -#[no_mangle] +#[unsafe(no_mangle)] pub fn main() -> i32 { let current_time = get_time(); let pid = fork(); diff --git a/user/src/bin/sleep_simple.rs b/user/src/bin/sleep_simple.rs index 7015a3d..9f6e2e4 100644 --- a/user/src/bin/sleep_simple.rs +++ b/user/src/bin/sleep_simple.rs @@ -6,7 +6,7 @@ extern crate user_lib; use user_lib::{get_time, sleep}; -#[no_mangle] +#[unsafe(no_mangle)] pub fn main() -> i32 { println!("into sleep test!"); let start = get_time(); diff --git a/user/src/bin/stack_overflow.rs b/user/src/bin/stack_overflow.rs index 3bec557..731982a 100644 --- a/user/src/bin/stack_overflow.rs +++ b/user/src/bin/stack_overflow.rs @@ -12,7 +12,7 @@ fn f(depth: usize) { f(depth + 1); } -#[no_mangle] +#[unsafe(no_mangle)] pub fn main() -> i32 { println!("It should trigger segmentation fault!"); f(0); diff --git a/user/src/bin/stackful_coroutine.rs b/user/src/bin/stackful_coroutine.rs deleted file mode 100644 index 3f61979..0000000 --- a/user/src/bin/stackful_coroutine.rs +++ /dev/null @@ -1,350 +0,0 @@ -// we porting below codes to Rcore Tutorial v3 -// https://cfsamson.gitbook.io/green-threads-explained-in-200-lines-of-rust/ -// https://github.com/cfsamson/example-greenthreads -#![no_std] -#![no_main] -#![feature(naked_functions)] -//#![feature(asm)] - -extern crate alloc; -#[macro_use] -extern crate user_lib; - -use core::arch::asm; - -//#[macro_use] -use alloc::vec; -use alloc::vec::Vec; - -use user_lib::exit; - -// In our simple example we set most constraints here. -const DEFAULT_STACK_SIZE: usize = 4096; //128 got SEGFAULT, 256(1024, 4096) got right results. -const MAX_TASKS: usize = 5; -static mut RUNTIME: usize = 0; - -pub struct Runtime { - tasks: Vec, - current: usize, -} - -#[derive(PartialEq, Eq, Debug)] -enum State { - Available, - Running, - Ready, -} - -struct Task { - id: usize, - stack: Vec, - ctx: TaskContext, - state: State, -} - -#[derive(Debug, Default)] -#[repr(C)] // not strictly needed but Rust ABI is not guaranteed to be stable -pub struct TaskContext { - // 15 u64 - x1: u64, //ra: return addres - x2: u64, //sp - x8: u64, //s0,fp - x9: u64, //s1 - x18: u64, //x18-27: s2-11 - x19: u64, - x20: u64, - x21: u64, - x22: u64, - x23: u64, - x24: u64, - x25: u64, - x26: u64, - x27: u64, - nx1: u64, //new return addres -} - -impl Task { - fn new(id: usize) -> Self { - // We initialize each task here and allocate the stack. This is not neccesary, - // we can allocate memory for it later, but it keeps complexity down and lets us focus on more interesting parts - // to do it here. The important part is that once allocated it MUST NOT move in memory. - Task { - id: id, - stack: vec![0_u8; DEFAULT_STACK_SIZE], - ctx: TaskContext::default(), - state: State::Available, - } - } -} - -impl Runtime { - pub fn new() -> Self { - // This will be our base task, which will be initialized in the `running` state - let base_task = Task { - id: 0, - stack: vec![0_u8; DEFAULT_STACK_SIZE], - ctx: TaskContext::default(), - state: State::Running, - }; - - // We initialize the rest of our tasks. - let mut tasks = vec![base_task]; - let mut available_tasks: Vec = (1..MAX_TASKS).map(|i| Task::new(i)).collect(); - tasks.append(&mut available_tasks); - - Runtime { tasks, current: 0 } - } - - /// This is cheating a bit, but we need a pointer to our Runtime stored so we can call yield on it even if - /// we don't have a reference to it. - pub fn init(&self) { - unsafe { - let r_ptr: *const Runtime = self; - RUNTIME = r_ptr as usize; - } - } - - /// This is where we start running our runtime. If it is our base task, we call yield until - /// it returns false (which means that there are no tasks scheduled) and we are done. - pub fn run(&mut self) { - while self.t_yield() {} - println!("All tasks finished!"); - } - - /// This is our return function. The only place we use this is in our `guard` function. - /// If the current task is not our base task we set its state to Available. It means - /// we're finished with it. Then we yield which will schedule a new task to be run. - fn t_return(&mut self) { - if self.current != 0 { - self.tasks[self.current].state = State::Available; - self.t_yield(); - } - } - - /// This is the heart of our runtime. Here we go through all tasks and see if anyone is in the `Ready` state. - /// If no task is `Ready` we're all done. This is an extremely simple scheduler using only a round-robin algorithm. - /// - /// If we find a task that's ready to be run we change the state of the current task from `Running` to `Ready`. - /// Then we call switch which will save the current context (the old context) and load the new context - /// into the CPU which then resumes based on the context it was just passed. - /// - /// NOITCE: if we comment below `#[inline(never)]`, we can not get the corrent running result - #[inline(never)] - fn t_yield(&mut self) -> bool { - let mut pos = self.current; - while self.tasks[pos].state != State::Ready { - pos += 1; - if pos == self.tasks.len() { - pos = 0; - } - if pos == self.current { - return false; - } - } - - if self.tasks[self.current].state != State::Available { - self.tasks[self.current].state = State::Ready; - } - - self.tasks[pos].state = State::Running; - let old_pos = self.current; - self.current = pos; - - unsafe { - switch(&mut self.tasks[old_pos].ctx, &self.tasks[pos].ctx); - } - - // NOTE: this might look strange and it is. Normally we would just mark this as `unreachable!()` but our compiler - // is too smart for it's own good so it optimized our code away on release builds. Curiously this happens on windows - // and not on linux. This is a common problem in tests so Rust has a `black_box` function in the `test` crate that - // will "pretend" to use a value we give it to prevent the compiler from eliminating code. I'll just do this instead, - // this code will never be run anyways and if it did it would always be `true`. - self.tasks.len() > 0 - } - - /// While `yield` is the logically interesting function I think this the technically most interesting. - /// - /// When we spawn a new task we first check if there are any available tasks (tasks in `Parked` state). - /// If we run out of tasks we panic in this scenario but there are several (better) ways to handle that. - /// We keep things simple for now. - /// - /// When we find an available task we get the stack length and a pointer to our u8 bytearray. - /// - /// The next part we have to use some unsafe functions. First we write an address to our `guard` function - /// that will be called if the function we provide returns. Then we set the address to the function we - /// pass inn. - /// - /// Third, we set the value of `sp` which is the stack pointer to the address of our provided function so we start - /// executing that first when we are scheuled to run. - /// - /// Lastly we set the state as `Ready` which means we have work to do and is ready to do it. - pub fn spawn(&mut self, f: fn()) { - let available = self - .tasks - .iter_mut() - .find(|t| t.state == State::Available) - .expect("no available task."); - - println!("RUNTIME: spawning task {}\n", available.id); - let size = available.stack.len(); - unsafe { - let s_ptr = available.stack.as_mut_ptr().offset(size as isize); - - // make sure our stack itself is 8 byte aligned - it will always - // offset to a lower memory address. Since we know we're at the "high" - // memory address of our allocated space, we know that offsetting to - // a lower one will be a valid address (given that we actually allocated) - // enough space to actually get an aligned pointer in the first place). - let s_ptr = (s_ptr as usize & !7) as *mut u8; - - available.ctx.x1 = guard as u64; //ctx.x1 is old return address - available.ctx.nx1 = f as u64; //ctx.nx2 is new return address - available.ctx.x2 = s_ptr.offset(-32) as u64; //cxt.x2 is sp - } - available.state = State::Ready; - } -} - -/// This is our guard function that we place on top of the stack. All this function does is set the -/// state of our current task and then `yield` which will then schedule a new task to be run. -fn guard() { - unsafe { - let rt_ptr = RUNTIME as *mut Runtime; - (*rt_ptr).t_return(); - }; -} - -/// We know that Runtime is alive the length of the program and that we only access from one core -/// (so no datarace). We yield execution of the current task by dereferencing a pointer to our -/// Runtime and then calling `t_yield` -pub fn yield_task() { - unsafe { - let rt_ptr = RUNTIME as *mut Runtime; - (*rt_ptr).t_yield(); - }; -} - -/// So here is our inline Assembly. As you remember from our first example this is just a bit more elaborate where we first -/// read out the values of all the registers we need and then sets all the register values to the register values we -/// saved when we suspended exceution on the "new" task. -/// -/// This is essentially all we need to do to save and resume execution. -/// -/// Some details about inline assembly. -/// -/// The assembly commands in the string literal is called the assemblt template. It is preceeded by -/// zero or up to four segments indicated by ":": -/// -/// - First ":" we have our output parameters, this parameters that this function will return. -/// - Second ":" we have the input parameters which is our contexts. We only read from the "new" context -/// but we modify the "old" context saving our registers there (see volatile option below) -/// - Third ":" This our clobber list, this is information to the compiler that these registers can't be used freely -/// - Fourth ":" This is options we can pass inn, Rust has 3: "alignstack", "volatile" and "intel" -/// -/// For this to work on windows we need to use "alignstack" where the compiler adds the neccesary padding to -/// make sure our stack is aligned. Since we modify one of our inputs, our assembly has "side effects" -/// therefore we should use the `volatile` option. I **think** this is actually set for us by default -/// when there are no output parameters given (my own assumption after going through the source code) -/// for the `asm` macro, but we should make it explicit anyway. -/// -/// One last important part (it will not work without this) is the #[naked] attribute. Basically this lets us have full -/// control over the stack layout since normal functions has a prologue-and epilogue added by the -/// compiler that will cause trouble for us. We avoid this by marking the funtion as "Naked". -/// For this to work on `release` builds we also need to use the `#[inline(never)] attribute or else -/// the compiler decides to inline this function (curiously this currently only happens on Windows). -/// If the function is inlined we get a curious runtime error where it fails when switching back -/// to as saved context and in general our assembly will not work as expected. -/// -/// see: https://github.com/rust-lang/rfcs/blob/master/text/1201-naked-fns.md -/// see: https://doc.rust-lang.org/nightly/reference/inline-assembly.html -/// see: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html -#[naked] -#[no_mangle] -unsafe extern "C" fn switch(old: *mut TaskContext, new: *const TaskContext) { - // a0: _old, a1: _new - asm!( - " - sd x1, 0x00(a0) - sd x2, 0x08(a0) - sd x8, 0x10(a0) - sd x9, 0x18(a0) - sd x18, 0x20(a0) - sd x19, 0x28(a0) - sd x20, 0x30(a0) - sd x21, 0x38(a0) - sd x22, 0x40(a0) - sd x23, 0x48(a0) - sd x24, 0x50(a0) - sd x25, 0x58(a0) - sd x26, 0x60(a0) - sd x27, 0x68(a0) - sd x1, 0x70(a0) - - ld x1, 0x00(a1) - ld x2, 0x08(a1) - ld x8, 0x10(a1) - ld x9, 0x18(a1) - ld x18, 0x20(a1) - ld x19, 0x28(a1) - ld x20, 0x30(a1) - ld x21, 0x38(a1) - ld x22, 0x40(a1) - ld x23, 0x48(a1) - ld x24, 0x50(a1) - ld x25, 0x58(a1) - ld x26, 0x60(a1) - ld x27, 0x68(a1) - ld t0, 0x70(a1) - - jr t0 - ", - options(noreturn) - ); -} - -#[no_mangle] -pub fn main() { - println!("stackful_coroutine begin..."); - println!("TASK 0(Runtime) STARTING"); - let mut runtime = Runtime::new(); - runtime.init(); - runtime.spawn(|| { - println!("TASK 1 STARTING"); - let id = 1; - for i in 0..4 { - println!("task: {} counter: {}", id, i); - yield_task(); - } - println!("TASK 1 FINISHED"); - }); - runtime.spawn(|| { - println!("TASK 2 STARTING"); - let id = 2; - for i in 0..8 { - println!("task: {} counter: {}", id, i); - yield_task(); - } - println!("TASK 2 FINISHED"); - }); - runtime.spawn(|| { - println!("TASK 3 STARTING"); - let id = 3; - for i in 0..12 { - println!("task: {} counter: {}", id, i); - yield_task(); - } - println!("TASK 3 FINISHED"); - }); - runtime.spawn(|| { - println!("TASK 4 STARTING"); - let id = 4; - for i in 0..16 { - println!("task: {} counter: {}", id, i); - yield_task(); - } - println!("TASK 4 FINISHED"); - }); - runtime.run(); - println!("stackful_coroutine PASSED"); - exit(0); -} diff --git a/user/src/bin/stackless_coroutine.rs b/user/src/bin/stackless_coroutine.rs deleted file mode 100644 index 43aeb2d..0000000 --- a/user/src/bin/stackless_coroutine.rs +++ /dev/null @@ -1,129 +0,0 @@ -// https://blog.aloni.org/posts/a-stack-less-rust-coroutine-100-loc/ -// https://github.com/chyyuu/example-coroutine-and-thread/tree/stackless-coroutine-x86 -#![no_std] -#![no_main] - -use core::future::Future; -use core::pin::Pin; -use core::task::{Context, Poll}; -use core::task::{RawWaker, RawWakerVTable, Waker}; - -extern crate alloc; -use alloc::collections::VecDeque; - -use alloc::boxed::Box; - -#[macro_use] -extern crate user_lib; - -enum State { - Halted, - Running, -} - -struct Task { - state: State, -} - -impl Task { - fn waiter<'a>(&'a mut self) -> Waiter<'a> { - Waiter { task: self } - } -} - -struct Waiter<'a> { - task: &'a mut Task, -} - -impl<'a> Future for Waiter<'a> { - type Output = (); - - fn poll(mut self: Pin<&mut Self>, _cx: &mut Context) -> Poll { - match self.task.state { - State::Halted => { - self.task.state = State::Running; - Poll::Ready(()) - } - State::Running => { - self.task.state = State::Halted; - Poll::Pending - } - } - } -} - -struct Executor { - tasks: VecDeque>>>, -} - -impl Executor { - fn new() -> Self { - Executor { - tasks: VecDeque::new(), - } - } - - fn push(&mut self, closure: C) - where - F: Future + 'static, - C: FnOnce(Task) -> F, - { - let task = Task { - state: State::Running, - }; - self.tasks.push_back(Box::pin(closure(task))); - } - - fn run(&mut self) { - let waker = create_waker(); - let mut context = Context::from_waker(&waker); - - while let Some(mut task) = self.tasks.pop_front() { - match task.as_mut().poll(&mut context) { - Poll::Pending => { - self.tasks.push_back(task); - } - Poll::Ready(()) => {} - } - } - } -} - -pub fn create_waker() -> Waker { - // Safety: The waker points to a vtable with functions that do nothing. Doing - // nothing is memory-safe. - unsafe { Waker::from_raw(RAW_WAKER) } -} - -const RAW_WAKER: RawWaker = RawWaker::new(core::ptr::null(), &VTABLE); -const VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop); - -unsafe fn clone(_: *const ()) -> RawWaker { - RAW_WAKER -} -unsafe fn wake(_: *const ()) {} -unsafe fn wake_by_ref(_: *const ()) {} -unsafe fn drop(_: *const ()) {} - -#[no_mangle] -pub fn main() -> i32 { - println!("stackless coroutine Begin.."); - let mut exec = Executor::new(); - println!(" Create futures"); - for instance in 1..=3 { - exec.push(move |mut task| async move { - println!(" Task {}: begin state", instance); - task.waiter().await; - println!(" Task {}: next state", instance); - task.waiter().await; - println!(" Task {}: end state", instance); - }); - } - - println!(" Running"); - exec.run(); - println!(" Done"); - println!("stackless coroutine PASSED"); - - 0 -} diff --git a/user/src/bin/store_fault.rs b/user/src/bin/store_fault.rs deleted file mode 100644 index f8023eb..0000000 --- a/user/src/bin/store_fault.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -#[no_mangle] -fn main() -> i32 { - println!("Into Test store_fault, we will insert an invalid store operation..."); - println!("Kernel should kill this application!"); - unsafe { - core::ptr::null_mut::().write_volatile(0); - } - 0 -} diff --git a/user/src/bin/sync_sem.rs b/user/src/bin/sync_sem.rs deleted file mode 100644 index b8d1f79..0000000 --- a/user/src/bin/sync_sem.rs +++ /dev/null @@ -1,45 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -extern crate alloc; - -use alloc::vec; -use user_lib::exit; -use user_lib::{semaphore_create, semaphore_down, semaphore_up}; -use user_lib::{sleep, thread_create, waittid}; - -const SEM_SYNC: usize = 0; - -unsafe fn first() -> ! { - sleep(10); - println!("First work and wakeup Second"); - semaphore_up(SEM_SYNC); - exit(0) -} - -unsafe fn second() -> ! { - println!("Second want to continue,but need to wait first"); - semaphore_down(SEM_SYNC); - println!("Second can work now"); - exit(0) -} - -#[no_mangle] -pub fn main() -> i32 { - // create semaphores - assert_eq!(semaphore_create(0) as usize, SEM_SYNC); - // create threads - let threads = vec![ - thread_create(first as usize, 0), - thread_create(second as usize, 0), - ]; - // wait for all threads to complete - for thread in threads.iter() { - waittid(*thread as usize); - } - println!("sync_sem passed!"); - 0 -} diff --git a/user/src/bin/tcp_simplehttp.rs b/user/src/bin/tcp_simplehttp.rs deleted file mode 100644 index 3e61950..0000000 --- a/user/src/bin/tcp_simplehttp.rs +++ /dev/null @@ -1,188 +0,0 @@ -#![no_std] -#![no_main] - -use alloc::string::{String, ToString}; - -#[macro_use] -extern crate user_lib; -#[macro_use] -extern crate alloc; - -// use http://localhost:6201/ to access the http server - -use user_lib::{accept, listen, read, write}; - -// get url from the tcp request list. -fn get_url_from_tcp_request(req: &[u8]) -> String { - let mut index = 0; - for i in 4..req.len() { - if req[i] == 0x20 { - index = i; - break; - } - } - - String::from_utf8_lossy(&req[4..index]).to_string() -} - -// just receive GET requests -fn handle_tcp_client(client_fd: usize) -> bool { - // a buf to receive the data from the server - let mut buf = vec![0u8; 1024]; - - let len = read(client_fd as usize, &mut buf); - - println!("receive {} bytes", len); - hexdump(&buf[..len as usize]); - - // verify whether it is a valid HTTP request simply, [0x47,0x45,0x54, 0x20] is GET - if len < 4 || buf[..4] != [0x47, 0x45, 0x54, 0x20] { - println!("it's not a valid http request"); - return false; - } - - let url = get_url_from_tcp_request(&buf); - - if url == "/close" { - let content = r#" - - - - - - - - - - -
-

server closed

-
- - "#; - let response = format!("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: {}\r\nConnecion: Close\r\n\r\n{}", content.len(),content); - write(client_fd, response.as_bytes()); - // terminate the connection immediately. - return true; - } - - let content = r#" - - - - - - - - - - -
-

rCore-tutorial-V3

-

rCore-tutorial-V3 是一个 基于 RISC-V 架构的 类 Unix 内核.

-
- -
-
-
-

Rust

-

Rust

-

Rust是一门系统编程语言,专注于安全,尤其是并发安全,支持函数式和命令式以及泛型等编程范式的多范式语言

-
-
-

仓库地址

-

repo url

-

https://github.com/rcore-os/rCore-Tutorial-v3

-
-
-

QQ 群号

-

Official QQ group number

-

735045051

-
-
-
- -
-

点击下列按钮即可关闭服务器。

- -
- - - "#; - - let response = format!("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: {}\r\nConnecion: Close\r\n\r\n{}", content.len(),content); - - // write a response - write(client_fd, response.as_bytes()); - - false -} - -#[no_mangle] -pub fn main() -> i32 { - println!("This is a very simple http server"); - - let tcp_fd = listen(80); - - if tcp_fd < 0 { - println!("Failed to listen on port 80"); - return -1; - } - - loop { - let client = accept(tcp_fd as usize); - println!("client connected: {}", client); - - if client < 1 { - println!("Failed to accept a client on port 80"); - return -1; - } - - if handle_tcp_client(client as usize) { - break; - } - } - - println!("finish tcp test"); - - // String::from_utf8_lossy(&buf[..len as usize]) - - 0 -} - -#[allow(unused)] -pub fn hexdump(data: &[u8]) { - const PRELAND_WIDTH: usize = 70; - println!("{:-^1$}", " hexdump ", PRELAND_WIDTH); - for offset in (0..data.len()).step_by(16) { - for i in 0..16 { - if offset + i < data.len() { - print!("{:02x} ", data[offset + i]); - } else { - print!("{:02} ", ""); - } - } - - print!("{:>6}", ' '); - - for i in 0..16 { - if offset + i < data.len() { - let c = data[offset + i]; - if c >= 0x20 && c <= 0x7e { - print!("{}", c as char); - } else { - print!("."); - } - } else { - print!("{:02} ", ""); - } - } - - println!(""); - } - println!("{:-^1$}", " hexdump end ", PRELAND_WIDTH); -} diff --git a/user/src/bin/threads.rs b/user/src/bin/threads.rs deleted file mode 100644 index 3d374fe..0000000 --- a/user/src/bin/threads.rs +++ /dev/null @@ -1,45 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec; -use user_lib::{exit, thread_create, waittid}; - -pub fn thread_a() -> ! { - for _ in 0..1000 { - print!("a"); - } - exit(1) -} - -pub fn thread_b() -> ! { - for _ in 0..1000 { - print!("b"); - } - exit(2) -} - -pub fn thread_c() -> ! { - for _ in 0..1000 { - print!("c"); - } - exit(3) -} - -#[no_mangle] -pub fn main() -> i32 { - let v = vec![ - thread_create(thread_a as usize, 0), - thread_create(thread_b as usize, 0), - thread_create(thread_c as usize, 0), - ]; - for tid in v.iter() { - let exit_code = waittid(*tid as usize); - println!("thread#{} exited with code {}", tid, exit_code); - } - println!("main thread exited."); - 0 -} diff --git a/user/src/bin/threads_arg.rs b/user/src/bin/threads_arg.rs deleted file mode 100644 index c5b26ed..0000000 --- a/user/src/bin/threads_arg.rs +++ /dev/null @@ -1,44 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use user_lib::{exit, thread_create, waittid}; - -struct Argument { - pub ch: char, - pub rc: i32, -} - -fn thread_print(arg: *const Argument) -> ! { - let arg = unsafe { &*arg }; - for _ in 0..1000 { - print!("{}", arg.ch); - } - exit(arg.rc) -} - -#[no_mangle] -pub fn main() -> i32 { - let mut v = Vec::new(); - let args = [ - Argument { ch: 'a', rc: 1 }, - Argument { ch: 'b', rc: 2 }, - Argument { ch: 'c', rc: 3 }, - ]; - for arg in args.iter() { - v.push(thread_create( - thread_print as usize, - arg as *const _ as usize, - )); - } - for tid in v.iter() { - let exit_code = waittid(*tid as usize); - println!("thread#{} exited with code {}", tid, exit_code); - } - println!("main thread exited."); - 0 -} diff --git a/user/src/bin/udp.rs b/user/src/bin/udp.rs deleted file mode 100644 index 68a1a10..0000000 --- a/user/src/bin/udp.rs +++ /dev/null @@ -1,46 +0,0 @@ -#![no_std] -#![no_main] - -use alloc::string::String; - -#[macro_use] -extern crate user_lib; -#[macro_use] -extern crate alloc; - -use user_lib::{connect, read, write}; - -#[no_mangle] -pub fn main() -> i32 { - println!("udp test open!"); - - let udp_fd = connect(10 << 24 | 0 << 16 | 2 << 8 | 2, 2001, 26099); - - if udp_fd < 0 { - println!("failed to create udp connection."); - return -1; - } - - let buf = "Hello rCoreOS user program!"; - - println!("send <{}>", buf); - - write(udp_fd as usize, buf.as_bytes()); - - println!("udp send done, waiting for reply."); - - let mut buf = vec![0u8; 1024]; - - let len = read(udp_fd as usize, &mut buf); - - if len < 0 { - println!("can't receive udp packet"); - return -1; - } - - let recv_str = String::from_utf8_lossy(&buf[..len as usize]); - - println!("receive reply <{}>", recv_str); - - 0 -} diff --git a/user/src/bin/until_timeout.rs b/user/src/bin/until_timeout.rs deleted file mode 100644 index a0007cb..0000000 --- a/user/src/bin/until_timeout.rs +++ /dev/null @@ -1,46 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{exec, fork, get_time, kill, waitpid, waitpid_nb, SignalFlags}; - -#[no_mangle] -pub fn main(argc: usize, argv: &[&str]) -> i32 { - assert_eq!(argc, 3, "argc must be 3!"); - let timeout_ms = argv[2] - .parse::() - .expect("Error when parsing timeout!"); - let pid = fork() as usize; - if pid == 0 { - if exec(argv[1], &[core::ptr::null::()]) != 0 { - println!("Error when executing '{}'", argv[1]); - return -4; - } - } else { - let start_time = get_time(); - let mut child_exited = false; - let mut exit_code: i32 = 0; - loop { - if get_time() - start_time > timeout_ms { - break; - } - if waitpid_nb(pid, &mut exit_code) as usize == pid { - child_exited = true; - println!( - "child exited in {}ms, exit_code = {}", - get_time() - start_time, - exit_code, - ); - } - } - if !child_exited { - println!("child has run for {}ms, kill it!", timeout_ms); - kill(pid, SignalFlags::SIGINT.bits()); - assert_eq!(waitpid(pid, &mut exit_code) as usize, pid); - println!("exit code of the child is {}", exit_code); - } - } - 0 -} diff --git a/user/src/bin/user_shell.rs b/user/src/bin/user_shell.rs index 4288248..1ca120b 100644 --- a/user/src/bin/user_shell.rs +++ b/user/src/bin/user_shell.rs @@ -11,191 +11,40 @@ const LF: u8 = 0x0au8; const CR: u8 = 0x0du8; const DL: u8 = 0x7fu8; const BS: u8 = 0x08u8; -const LINE_START: &str = ">> "; use alloc::string::String; -use alloc::vec::Vec; use user_lib::console::getchar; -use user_lib::{close, dup, exec, fork, open, pipe, waitpid, OpenFlags}; +use user_lib::{exec, fork, waitpid}; -#[derive(Debug)] -struct ProcessArguments { - input: String, - output: String, - args_copy: Vec, - args_addr: Vec<*const u8>, -} - -impl ProcessArguments { - pub fn new(command: &str) -> Self { - let args: Vec<_> = command.split(' ').collect(); - let mut args_copy: Vec = args - .iter() - .filter(|&arg| !arg.is_empty()) - .map(|&arg| { - let mut string = String::new(); - string.push_str(arg); - string.push('\0'); - string - }) - .collect(); - - // redirect input - let mut input = String::new(); - if let Some((idx, _)) = args_copy - .iter() - .enumerate() - .find(|(_, arg)| arg.as_str() == "<\0") - { - input = args_copy[idx + 1].clone(); - args_copy.drain(idx..=idx + 1); - } - - // redirect output - let mut output = String::new(); - if let Some((idx, _)) = args_copy - .iter() - .enumerate() - .find(|(_, arg)| arg.as_str() == ">\0") - { - output = args_copy[idx + 1].clone(); - args_copy.drain(idx..=idx + 1); - } - - let mut args_addr: Vec<*const u8> = args_copy.iter().map(|arg| arg.as_ptr()).collect(); - args_addr.push(core::ptr::null::()); - - Self { - input, - output, - args_copy, - args_addr, - } - } -} - -#[no_mangle] +#[unsafe(no_mangle)] pub fn main() -> i32 { println!("Rust user shell"); let mut line: String = String::new(); - print!("{}", LINE_START); + print!(">> "); loop { let c = getchar(); match c { LF | CR => { println!(""); if !line.is_empty() { - let splited: Vec<_> = line.as_str().split('|').collect(); - let process_arguments_list: Vec<_> = splited - .iter() - .map(|&cmd| ProcessArguments::new(cmd)) - .collect(); - let mut valid = true; - for (i, process_args) in process_arguments_list.iter().enumerate() { - if i == 0 { - if !process_args.output.is_empty() { - valid = false; - } - } else if i == process_arguments_list.len() - 1 { - if !process_args.input.is_empty() { - valid = false; - } - } else if !process_args.output.is_empty() || !process_args.input.is_empty() - { - valid = false; + line.push('\0'); + let pid = fork(); + if pid == 0 { + // child process + if exec(line.as_str()) == -1 { + println!("Error when executing!"); + return -4; } - } - if process_arguments_list.len() == 1 { - valid = true; - } - if !valid { - println!("Invalid command: Inputs/Outputs cannot be correctly binded!"); + unreachable!(); } else { - // create pipes - let mut pipes_fd: Vec<[usize; 2]> = Vec::new(); - if !process_arguments_list.is_empty() { - for _ in 0..process_arguments_list.len() - 1 { - let mut pipe_fd = [0usize; 2]; - pipe(&mut pipe_fd); - pipes_fd.push(pipe_fd); - } - } - let mut children: Vec<_> = Vec::new(); - for (i, process_argument) in process_arguments_list.iter().enumerate() { - let pid = fork(); - if pid == 0 { - let input = &process_argument.input; - let output = &process_argument.output; - let args_copy = &process_argument.args_copy; - let args_addr = &process_argument.args_addr; - // redirect input - if !input.is_empty() { - let input_fd = open(input.as_str(), OpenFlags::RDONLY); - if input_fd == -1 { - println!("Error when opening file {}", input); - return -4; - } - let input_fd = input_fd as usize; - close(0); - assert_eq!(dup(input_fd), 0); - close(input_fd); - } - // redirect output - if !output.is_empty() { - let output_fd = open( - output.as_str(), - OpenFlags::CREATE | OpenFlags::WRONLY, - ); - if output_fd == -1 { - println!("Error when opening file {}", output); - return -4; - } - let output_fd = output_fd as usize; - close(1); - assert_eq!(dup(output_fd), 1); - close(output_fd); - } - // receive input from the previous process - if i > 0 { - close(0); - let read_end = pipes_fd.get(i - 1).unwrap()[0]; - assert_eq!(dup(read_end), 0); - } - // send output to the next process - if i < process_arguments_list.len() - 1 { - close(1); - let write_end = pipes_fd.get(i).unwrap()[1]; - assert_eq!(dup(write_end), 1); - } - // close all pipe ends inherited from the parent process - for pipe_fd in pipes_fd.iter() { - close(pipe_fd[0]); - close(pipe_fd[1]); - } - // execute new application - if exec(args_copy[0].as_str(), args_addr.as_slice()) == -1 { - println!("Error when executing!"); - return -4; - } - unreachable!(); - } else { - children.push(pid); - } - } - for pipe_fd in pipes_fd.iter() { - close(pipe_fd[0]); - close(pipe_fd[1]); - } let mut exit_code: i32 = 0; - for pid in children.into_iter() { - let exit_pid = waitpid(pid as usize, &mut exit_code); - assert_eq!(pid, exit_pid); - //println!("Shell: Process {} exited with code {}", pid, exit_code); - } + let exit_pid = waitpid(pid as usize, &mut exit_code); + assert_eq!(pid, exit_pid); + println!("Shell: Process {} exited with code {}", pid, exit_code); } line.clear(); } - print!("{}", LINE_START); + print!(">> "); } BS | DL => { if !line.is_empty() { diff --git a/user/src/bin/usertests.rs b/user/src/bin/usertests.rs index b522af2..d47dc20 100644 --- a/user/src/bin/usertests.rs +++ b/user/src/bin/usertests.rs @@ -10,9 +10,7 @@ extern crate user_lib; // item of TESTS : app_name(argv_0), argv_1, argv_2, argv_3, exit_code static SUCC_TESTS: &[(&str, &str, &str, &str, i32)] = &[ ("filetest_simple\0", "\0", "\0", "\0", 0), - ("cat\0", "filea\0", "\0", "\0", 0), - ("cmdline_args\0", "1\0", "2\0", "3\0", 0), - ("eisenberg\0", "\0", "\0", "\0", 0), + ("cat_filea\0", "\0", "\0", "\0", 0), ("exit\0", "\0", "\0", "\0", 0), ("fantastic_text\0", "\0", "\0", "\0", 0), ("forktest_simple\0", "\0", "\0", "\0", 0), @@ -22,40 +20,12 @@ static SUCC_TESTS: &[(&str, &str, &str, &str, i32)] = &[ ("hello_world\0", "\0", "\0", "\0", 0), ("huge_write\0", "\0", "\0", "\0", 0), ("matrix\0", "\0", "\0", "\0", 0), - ("mpsc_sem\0", "\0", "\0", "\0", 0), - ("peterson\0", "\0", "\0", "\0", 0), - ("phil_din_mutex\0", "\0", "\0", "\0", 0), - ("pipe_large_test\0", "\0", "\0", "\0", 0), - ("pipetest\0", "\0", "\0", "\0", 0), - ("adder_peterson_spin\0", "\0", "\0", "\0", 0), - ("adder_peterson_yield\0", "\0", "\0", "\0", 0), - ("adder_mutex_blocking\0", "\0", "\0", "\0", 0), - ("adder_mutex_spin\0", "\0", "\0", "\0", 0), - ("run_pipe_test\0", "\0", "\0", "\0", 0), ("sleep_simple\0", "\0", "\0", "\0", 0), ("sleep\0", "\0", "\0", "\0", 0), - ("sleep_simple\0", "\0", "\0", "\0", 0), - ("sync_sem\0", "\0", "\0", "\0", 0), - ("condsync_sem\0", "\0", "\0", "\0", 0), - ("condsync_condvar\0", "\0", "\0", "\0", 0), - ("threads_arg\0", "\0", "\0", "\0", 0), - ("threads\0", "\0", "\0", "\0", 0), ("yield\0", "\0", "\0", "\0", 0), - ("barrier_fail\0", "\0", "\0", "\0", 0), - ("barrier_condvar\0", "\0", "\0", "\0", 0), ]; -static FAIL_TESTS: &[(&str, &str, &str, &str, i32)] = &[ - ("stack_overflow\0", "\0", "\0", "\0", -11), - ("race_adder_loop\0", "\0", "\0", "\0", -6), - ("priv_csr\0", "\0", "\0", "\0", -4), - ("priv_inst\0", "\0", "\0", "\0", -4), - ("store_fault\0", "\0", "\0", "\0", -11), - ("until_timeout\0", "\0", "\0", "\0", -6), - ("adder\0", "\0", "\0", "\0", -6), - ("adder_simple_spin\0", "\0", "\0", "\0", -6), - ("adder_simple_yield\0", "\0", "\0", "\0", -6), -]; +static FAIL_TESTS: &[(&str, &str, &str, &str, i32)] = &[("stack_overflow\0", "\0", "\0", "\0", -2)]; use user_lib::{exec, fork, waitpid}; @@ -95,7 +65,7 @@ fn run_tests(tests: &[(&str, &str, &str, &str, i32)]) -> i32 { let pid = fork(); if pid == 0 { - exec(test.0, &arr[..]); + exec(test.0); panic!("unreachable!"); } else { let mut exit_code: i32 = Default::default(); @@ -114,7 +84,7 @@ fn run_tests(tests: &[(&str, &str, &str, &str, i32)]) -> i32 { pass_num } -#[no_mangle] +#[unsafe(no_mangle)] pub fn main() -> i32 { let succ_num = run_tests(SUCC_TESTS); let err_num = run_tests(FAIL_TESTS); diff --git a/user/src/bin/usertests_simple.rs b/user/src/bin/usertests_simple.rs new file mode 100644 index 0000000..0a73edd --- /dev/null +++ b/user/src/bin/usertests_simple.rs @@ -0,0 +1,43 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +static TESTS: &[&str] = &[ + "exit\0", + "fantastic_text\0", + "forktest\0", + "forktest2\0", + "forktest_simple\0", + "hello_world\0", + "matrix\0", + "sleep\0", + "sleep_simple\0", + "stack_overflow\0", + "yield\0", +]; + +use user_lib::{exec, fork, waitpid}; + +#[unsafe(no_mangle)] +pub fn main() -> i32 { + for test in TESTS { + println!("Usertests: Running {}", test); + let pid = fork(); + if pid == 0 { + exec(*test); + panic!("unreachable!"); + } else { + let mut exit_code: i32 = Default::default(); + let wait_pid = waitpid(pid as usize, &mut exit_code); + assert_eq!(pid, wait_pid); + println!( + "\x1b[32mUsertests: Test {} in Process {} exited with code {}\x1b[0m", + test, pid, exit_code + ); + } + } + println!("Usertests passed!"); + 0 +} diff --git a/user/src/bin/yield.rs b/user/src/bin/yield.rs index 78b1468..b9558ef 100644 --- a/user/src/bin/yield.rs +++ b/user/src/bin/yield.rs @@ -5,7 +5,7 @@ extern crate user_lib; use user_lib::{getpid, yield_}; -#[no_mangle] +#[unsafe(no_mangle)] pub fn main() -> i32 { println!("Hello, I am process {}.", getpid()); for i in 0..5 { diff --git a/user/src/file.rs b/user/src/file.rs deleted file mode 100644 index 19e2564..0000000 --- a/user/src/file.rs +++ /dev/null @@ -1,30 +0,0 @@ -use super::*; - -bitflags! { - pub struct OpenFlags: u32 { - const RDONLY = 0; - const WRONLY = 1 << 0; - const RDWR = 1 << 1; - const CREATE = 1 << 9; - const TRUNC = 1 << 10; - } -} - -pub fn dup(fd: usize) -> isize { - sys_dup(fd) -} -pub fn open(path: &str, flags: OpenFlags) -> isize { - sys_open(path, flags.bits) -} -pub fn close(fd: usize) -> isize { - sys_close(fd) -} -pub fn pipe(pipe_fd: &mut [usize]) -> isize { - sys_pipe(pipe_fd) -} -pub fn read(fd: usize, buf: &mut [u8]) -> isize { - sys_read(fd, buf) -} -pub fn write(fd: usize, buf: &[u8]) -> isize { - sys_write(fd, buf) -} diff --git a/user/src/io.rs b/user/src/io.rs deleted file mode 100644 index d2c2a0a..0000000 --- a/user/src/io.rs +++ /dev/null @@ -1,117 +0,0 @@ -use super::*; -use embedded_graphics::pixelcolor::Rgb888; -use embedded_graphics::prelude::{RgbColor, Size}; -use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions}; -use virtio_input_decoder::Decoder; -pub use virtio_input_decoder::{DecodeType, Key, KeyType, Mouse}; - -pub const VIRTGPU_XRES: u32 = 1280; -pub const VIRTGPU_YRES: u32 = 800; -pub const VIRTGPU_LEN: usize = (VIRTGPU_XRES * VIRTGPU_YRES * 4) as usize; - -pub fn framebuffer() -> isize { - sys_framebuffer() -} -pub fn framebuffer_flush() -> isize { - sys_framebuffer_flush() -} - -pub struct Display { - pub size: Size, - pub fb: &'static mut [u8], -} - -impl Display { - pub fn new(size: Size) -> Self { - let fb_ptr = framebuffer() as *mut u8; - let fb = unsafe { core::slice::from_raw_parts_mut(fb_ptr, VIRTGPU_LEN as usize) }; - Self { size, fb } - } - pub fn framebuffer(&mut self) -> &mut [u8] { - self.fb - } - pub fn paint_on_framebuffer(&mut self, p: impl FnOnce(&mut [u8]) -> ()) { - p(self.framebuffer()); - } - pub fn flush(&self) { - framebuffer_flush(); - } -} - -impl OriginDimensions for Display { - fn size(&self) -> Size { - self.size - } -} - -impl DrawTarget for Display { - type Color = Rgb888; - - type Error = core::convert::Infallible; - - fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> - where - I: IntoIterator>, - { - pixels.into_iter().for_each(|px| { - let idx = (px.0.y * VIRTGPU_XRES as i32 + px.0.x) as usize * 4; - if idx + 2 >= self.fb.len() { - return; - } - self.fb[idx] = px.1.b(); - self.fb[idx + 1] = px.1.g(); - self.fb[idx + 2] = px.1.r(); - }); - Ok(()) - } -} - -pub fn event_get() -> Option { - let raw_value = sys_event_get(); - if raw_value == 0 { - None - } else { - Some((raw_value as u64).into()) - } -} - -pub fn key_pressed() -> bool { - if sys_key_pressed() == 1 { - true - } else { - false - } -} - -#[repr(C)] -pub struct InputEvent { - pub event_type: u16, - pub code: u16, - pub value: u32, -} - -impl From for InputEvent { - fn from(mut v: u64) -> Self { - let value = v as u32; - v >>= 32; - let code = v as u16; - v >>= 16; - let event_type = v as u16; - Self { - event_type, - code, - value, - } - } -} - -impl InputEvent { - pub fn decode(&self) -> Option { - Decoder::decode( - self.event_type as usize, - self.code as usize, - self.value as usize, - ) - .ok() - } -} diff --git a/user/src/lang_items.rs b/user/src/lang_items.rs index df0467c..b03e8eb 100644 --- a/user/src/lang_items.rs +++ b/user/src/lang_items.rs @@ -1,8 +1,8 @@ -use super::{getpid, kill, SignalFlags}; +use super::exit; #[panic_handler] fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! { - let err = panic_info.message().unwrap(); + let err = panic_info.message(); if let Some(location) = panic_info.location() { println!( "Panicked at {}:{}, {}", @@ -13,6 +13,5 @@ fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! { } else { println!("Panicked: {}", err); } - kill(getpid() as usize, SignalFlags::SIGABRT.bits()); - unreachable!() + exit(-1); } diff --git a/user/src/lib.rs b/user/src/lib.rs index 8c709fc..a5584c2 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -1,30 +1,19 @@ #![no_std] #![feature(linkage)] -#![feature(panic_info_message)] #![feature(alloc_error_handler)] #[macro_use] pub mod console; -mod file; -mod io; mod lang_items; -mod net; -mod sync; mod syscall; -mod task; extern crate alloc; #[macro_use] extern crate bitflags; -use alloc::vec::Vec; use buddy_system_allocator::LockedHeap; -pub use file::*; -pub use io::*; -pub use net::*; -pub use sync::*; +use core::ptr::addr_of_mut; use syscall::*; -pub use task::*; const USER_HEAP_SIZE: usize = 32768; @@ -38,55 +27,88 @@ pub fn handle_alloc_error(layout: core::alloc::Layout) -> ! { panic!("Heap allocation error, layout = {:?}", layout); } -#[no_mangle] -#[link_section = ".text.entry"] -pub extern "C" fn _start(argc: usize, argv: usize) -> ! { +#[unsafe(no_mangle)] +#[unsafe(link_section = ".text.entry")] +pub extern "C" fn _start() -> ! { unsafe { HEAP.lock() - .init(HEAP_SPACE.as_ptr() as usize, USER_HEAP_SIZE); + .init(addr_of_mut!(HEAP_SPACE) as usize, USER_HEAP_SIZE); } - let mut v: Vec<&'static str> = Vec::new(); - for i in 0..argc { - let str_start = - unsafe { ((argv + i * core::mem::size_of::()) as *const usize).read_volatile() }; - let len = (0usize..) - .find(|i| unsafe { ((str_start + *i) as *const u8).read_volatile() == 0 }) - .unwrap(); - v.push( - core::str::from_utf8(unsafe { - core::slice::from_raw_parts(str_start as *const u8, len) - }) - .unwrap(), - ); - } - exit(main(argc, v.as_slice())); + exit(main()); } #[linkage = "weak"] -#[no_mangle] -fn main(_argc: usize, _argv: &[&str]) -> i32 { +#[unsafe(no_mangle)] +fn main() -> i32 { panic!("Cannot find main!"); } -#[macro_export] -macro_rules! vstore { - ($var: expr, $value: expr) => { - // unsafe { core::intrinsics::volatile_store($var_ref as *const _ as _, $value) } - unsafe { core::ptr::write_volatile(core::ptr::addr_of_mut!($var), $value); } - }; +bitflags! { + pub struct OpenFlags: u32 { + const RDONLY = 0; + const WRONLY = 1 << 0; + const RDWR = 1 << 1; + const CREATE = 1 << 9; + const TRUNC = 1 << 10; + } } -#[macro_export] -macro_rules! vload { - ($var: expr) => { - // unsafe { core::intrinsics::volatile_load($var_ref as *const _ as _) } - unsafe { core::ptr::read_volatile(core::ptr::addr_of!($var)) } - }; +pub fn open(path: &str, flags: OpenFlags) -> isize { + sys_open(path, flags.bits) +} +pub fn close(fd: usize) -> isize { + sys_close(fd) +} +pub fn read(fd: usize, buf: &mut [u8]) -> isize { + sys_read(fd, buf) +} +pub fn write(fd: usize, buf: &[u8]) -> isize { + sys_write(fd, buf) +} +pub fn exit(exit_code: i32) -> ! { + sys_exit(exit_code); +} +pub fn yield_() -> isize { + sys_yield() +} +pub fn get_time() -> isize { + sys_get_time() +} +pub fn getpid() -> isize { + sys_getpid() +} +pub fn fork() -> isize { + sys_fork() +} +pub fn exec(path: &str) -> isize { + sys_exec(path) +} +pub fn wait(exit_code: &mut i32) -> isize { + loop { + match sys_waitpid(-1, exit_code as *mut _) { + -2 => { + yield_(); + } + // -1 or a real pid + exit_pid => return exit_pid, + } + } } -#[macro_export] -macro_rules! memory_fence { - () => { - core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst) - }; +pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize { + loop { + match sys_waitpid(pid as isize, exit_code as *mut _) { + -2 => { + yield_(); + } + // -1 or a real pid + exit_pid => return exit_pid, + } + } +} +pub fn sleep(period_ms: usize) { + let start = sys_get_time(); + while sys_get_time() < start + period_ms as isize { + sys_yield(); + } } diff --git a/user/src/net.rs b/user/src/net.rs deleted file mode 100644 index 78529d0..0000000 --- a/user/src/net.rs +++ /dev/null @@ -1,13 +0,0 @@ -use super::*; - -pub fn connect(ip: u32, sport: u16, dport: u16) -> isize { - sys_connect(ip, sport, dport) -} - -pub fn listen(sport: u16) -> isize { - sys_listen(sport) -} - -pub fn accept(socket_fd: usize) -> isize { - sys_accept(socket_fd) -} diff --git a/user/src/sync.rs b/user/src/sync.rs deleted file mode 100644 index 82cd2a0..0000000 --- a/user/src/sync.rs +++ /dev/null @@ -1,32 +0,0 @@ -use super::*; - -pub fn mutex_create() -> isize { - sys_mutex_create(false) -} -pub fn mutex_blocking_create() -> isize { - sys_mutex_create(true) -} -pub fn mutex_lock(mutex_id: usize) { - sys_mutex_lock(mutex_id); -} -pub fn mutex_unlock(mutex_id: usize) { - sys_mutex_unlock(mutex_id); -} -pub fn semaphore_create(res_count: usize) -> isize { - sys_semaphore_create(res_count) -} -pub fn semaphore_up(sem_id: usize) { - sys_semaphore_up(sem_id); -} -pub fn semaphore_down(sem_id: usize) { - sys_semaphore_down(sem_id); -} -pub fn condvar_create() -> isize { - sys_condvar_create() -} -pub fn condvar_signal(condvar_id: usize) { - sys_condvar_signal(condvar_id); -} -pub fn condvar_wait(condvar_id: usize, mutex_id: usize) { - sys_condvar_wait(condvar_id, mutex_id); -} diff --git a/user/src/syscall.rs b/user/src/syscall.rs index 48b3e99..5423cce 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -1,42 +1,21 @@ -const SYSCALL_DUP: usize = 24; -const SYSCALL_CONNECT: usize = 29; -const SYSCALL_LISTEN: usize = 30; -const SYSCALL_ACCEPT: usize = 31; +use core::arch::asm; + const SYSCALL_OPEN: usize = 56; const SYSCALL_CLOSE: usize = 57; -const SYSCALL_PIPE: usize = 59; const SYSCALL_READ: usize = 63; const SYSCALL_WRITE: usize = 64; const SYSCALL_EXIT: usize = 93; -const SYSCALL_SLEEP: usize = 101; const SYSCALL_YIELD: usize = 124; -const SYSCALL_KILL: usize = 129; const SYSCALL_GET_TIME: usize = 169; const SYSCALL_GETPID: usize = 172; const SYSCALL_FORK: usize = 220; const SYSCALL_EXEC: usize = 221; const SYSCALL_WAITPID: usize = 260; -const SYSCALL_THREAD_CREATE: usize = 1000; -const SYSCALL_GETTID: usize = 1001; -const SYSCALL_WAITTID: usize = 1002; -const SYSCALL_MUTEX_CREATE: usize = 1010; -const SYSCALL_MUTEX_LOCK: usize = 1011; -const SYSCALL_MUTEX_UNLOCK: usize = 1012; -const SYSCALL_SEMAPHORE_CREATE: usize = 1020; -const SYSCALL_SEMAPHORE_UP: usize = 1021; -const SYSCALL_SEMAPHORE_DOWN: usize = 1022; -const SYSCALL_CONDVAR_CREATE: usize = 1030; -const SYSCALL_CONDVAR_SIGNAL: usize = 1031; -const SYSCALL_CONDVAR_WAIT: usize = 1032; -const SYSCALL_FRAMEBUFFER: usize = 2000; -const SYSCALL_FRAMEBUFFER_FLUSH: usize = 2001; -const SYSCALL_EVENT_GET: usize = 3000; -const SYSCALL_KEY_PRESSED: usize = 3001; fn syscall(id: usize, args: [usize; 3]) -> isize { let mut ret: isize; unsafe { - core::arch::asm!( + asm!( "ecall", inlateout("x10") args[0] => ret, in("x11") args[1], @@ -47,26 +26,6 @@ fn syscall(id: usize, args: [usize; 3]) -> isize { ret } -pub fn sys_dup(fd: usize) -> isize { - syscall(SYSCALL_DUP, [fd, 0, 0]) -} - -pub fn sys_connect(dest: u32, sport: u16, dport: u16) -> isize { - syscall( - SYSCALL_CONNECT, - [dest as usize, sport as usize, dport as usize], - ) -} - -// just listen for tcp connections now -pub fn sys_listen(sport: u16) -> isize { - syscall(SYSCALL_LISTEN, [sport as usize, 0, 0]) -} - -pub fn sys_accept(socket_fd: usize) -> isize { - syscall(SYSCALL_ACCEPT, [socket_fd, 0, 0]) -} - pub fn sys_open(path: &str, flags: u32) -> isize { syscall(SYSCALL_OPEN, [path.as_ptr() as usize, flags as usize, 0]) } @@ -75,10 +34,6 @@ pub fn sys_close(fd: usize) -> isize { syscall(SYSCALL_CLOSE, [fd, 0, 0]) } -pub fn sys_pipe(pipe: &mut [usize]) -> isize { - syscall(SYSCALL_PIPE, [pipe.as_mut_ptr() as usize, 0, 0]) -} - pub fn sys_read(fd: usize, buffer: &mut [u8]) -> isize { syscall( SYSCALL_READ, @@ -95,18 +50,10 @@ pub fn sys_exit(exit_code: i32) -> ! { panic!("sys_exit never returns!"); } -pub fn sys_sleep(sleep_ms: usize) -> isize { - syscall(SYSCALL_SLEEP, [sleep_ms, 0, 0]) -} - pub fn sys_yield() -> isize { syscall(SYSCALL_YIELD, [0, 0, 0]) } -pub fn sys_kill(pid: usize, signal: i32) -> isize { - syscall(SYSCALL_KILL, [pid, signal as usize, 0]) -} - pub fn sys_get_time() -> isize { syscall(SYSCALL_GET_TIME, [0, 0, 0]) } @@ -119,77 +66,10 @@ pub fn sys_fork() -> isize { syscall(SYSCALL_FORK, [0, 0, 0]) } -pub fn sys_exec(path: &str, args: &[*const u8]) -> isize { - syscall( - SYSCALL_EXEC, - [path.as_ptr() as usize, args.as_ptr() as usize, 0], - ) +pub fn sys_exec(path: &str) -> isize { + syscall(SYSCALL_EXEC, [path.as_ptr() as usize, 0, 0]) } pub fn sys_waitpid(pid: isize, exit_code: *mut i32) -> isize { syscall(SYSCALL_WAITPID, [pid as usize, exit_code as usize, 0]) } - -pub fn sys_thread_create(entry: usize, arg: usize) -> isize { - syscall(SYSCALL_THREAD_CREATE, [entry, arg, 0]) -} - -pub fn sys_gettid() -> isize { - syscall(SYSCALL_GETTID, [0; 3]) -} - -pub fn sys_waittid(tid: usize) -> isize { - syscall(SYSCALL_WAITTID, [tid, 0, 0]) -} - -pub fn sys_mutex_create(blocking: bool) -> isize { - syscall(SYSCALL_MUTEX_CREATE, [blocking as usize, 0, 0]) -} - -pub fn sys_mutex_lock(id: usize) -> isize { - syscall(SYSCALL_MUTEX_LOCK, [id, 0, 0]) -} - -pub fn sys_mutex_unlock(id: usize) -> isize { - syscall(SYSCALL_MUTEX_UNLOCK, [id, 0, 0]) -} - -pub fn sys_semaphore_create(res_count: usize) -> isize { - syscall(SYSCALL_SEMAPHORE_CREATE, [res_count, 0, 0]) -} - -pub fn sys_semaphore_up(sem_id: usize) -> isize { - syscall(SYSCALL_SEMAPHORE_UP, [sem_id, 0, 0]) -} - -pub fn sys_semaphore_down(sem_id: usize) -> isize { - syscall(SYSCALL_SEMAPHORE_DOWN, [sem_id, 0, 0]) -} - -pub fn sys_condvar_create() -> isize { - syscall(SYSCALL_CONDVAR_CREATE, [0, 0, 0]) -} - -pub fn sys_condvar_signal(condvar_id: usize) -> isize { - syscall(SYSCALL_CONDVAR_SIGNAL, [condvar_id, 0, 0]) -} - -pub fn sys_condvar_wait(condvar_id: usize, mutex_id: usize) -> isize { - syscall(SYSCALL_CONDVAR_WAIT, [condvar_id, mutex_id, 0]) -} - -pub fn sys_framebuffer() -> isize { - syscall(SYSCALL_FRAMEBUFFER, [0, 0, 0]) -} - -pub fn sys_framebuffer_flush() -> isize { - syscall(SYSCALL_FRAMEBUFFER_FLUSH, [0, 0, 0]) -} - -pub fn sys_event_get() -> isize { - syscall(SYSCALL_EVENT_GET, [0, 0, 0]) -} - -pub fn sys_key_pressed() -> isize { - syscall(SYSCALL_KEY_PRESSED, [0, 0, 0]) -} diff --git a/user/src/task.rs b/user/src/task.rs deleted file mode 100644 index 9e72b32..0000000 --- a/user/src/task.rs +++ /dev/null @@ -1,83 +0,0 @@ -use super::*; - -pub fn exit(exit_code: i32) -> ! { - sys_exit(exit_code); -} -pub fn yield_() -> isize { - sys_yield() -} -pub fn get_time() -> isize { - sys_get_time() -} -pub fn getpid() -> isize { - sys_getpid() -} -pub fn fork() -> isize { - sys_fork() -} -pub fn exec(path: &str, args: &[*const u8]) -> isize { - sys_exec(path, args) -} - -pub fn wait(exit_code: &mut i32) -> isize { - loop { - match sys_waitpid(-1, exit_code as *mut _) { - -2 => { - yield_(); - } - // -1 or a real pid - exit_pid => return exit_pid, - } - } -} - -pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize { - loop { - match sys_waitpid(pid as isize, exit_code as *mut _) { - -2 => { - yield_(); - } - // -1 or a real pid - exit_pid => return exit_pid, - } - } -} - -pub fn waitpid_nb(pid: usize, exit_code: &mut i32) -> isize { - sys_waitpid(pid as isize, exit_code as *mut _) -} - -bitflags! { - pub struct SignalFlags: i32 { - const SIGINT = 1 << 2; - const SIGILL = 1 << 4; - const SIGABRT = 1 << 6; - const SIGFPE = 1 << 8; - const SIGSEGV = 1 << 11; - } -} - -pub fn kill(pid: usize, signal: i32) -> isize { - sys_kill(pid, signal) -} - -pub fn sleep(sleep_ms: usize) { - sys_sleep(sleep_ms); -} - -pub fn thread_create(entry: usize, arg: usize) -> isize { - sys_thread_create(entry, arg) -} -pub fn gettid() -> isize { - sys_gettid() -} -pub fn waittid(tid: usize) -> isize { - loop { - match sys_waittid(tid) { - -2 => { - yield_(); - } - exit_code => return exit_code, - } - } -}