diff --git a/.github/workflows/doc-and-test.yml b/.github/workflows/doc-and-test.yml index f4027c2..0a05371 100644 --- a/.github/workflows/doc-and-test.yml +++ b/.github/workflows/doc-and-test.yml @@ -65,4 +65,4 @@ jobs: - name: Run usertests run: cd os && make run TEST=1 timeout-minutes: 10 - + diff --git a/.gitignore b/.gitignore index 45fffb0..67ee557 100644 --- a/.gitignore +++ b/.gitignore @@ -3,14 +3,23 @@ !.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 +*.bak diff --git a/Makefile b/Makefile index ee4d7d1..80fe9a1 100644 --- a/Makefile +++ b/Makefile @@ -8,5 +8,5 @@ build_docker: docker build -t ${DOCKER_TAG} --target build . fmt: - cd easy-fs; cargo fmt; cd ../easy-fs-fuse cargo fmt; cd ../os ; cargo fmt; cd ../user; cargo fmt; cd .. + cd os ; cargo fmt; cd .. 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/Cargo.toml b/easy-fs-fuse/Cargo.toml deleted file mode 100644 index d8d4e7f..0000000 --- a/easy-fs-fuse/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "easy-fs-fuse" -version = "0.1.0" -authors = ["Yifan Wu "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -clap = "2.33.3" -easy-fs = { path = "../easy-fs" } -rand = "0.8.0" - -# [features] -# board_qemu = [] -# board_k210 = [] diff --git a/easy-fs-fuse/src/main.rs b/easy-fs-fuse/src/main.rs deleted file mode 100644 index dceec15..0000000 --- a/easy-fs-fuse/src/main.rs +++ /dev/null @@ -1,155 +0,0 @@ -use clap::{App, Arg}; -use easy_fs::{BlockDevice, EasyFileSystem}; -use std::fs::{read_dir, File, OpenOptions}; -use std::io::{Read, Seek, SeekFrom, Write}; -use std::sync::Arc; -use std::sync::Mutex; - -const BLOCK_SZ: usize = 512; - -struct BlockFile(Mutex); - -impl BlockDevice for BlockFile { - fn read_block(&self, block_id: usize, buf: &mut [u8]) { - let mut file = self.0.lock().unwrap(); - file.seek(SeekFrom::Start((block_id * BLOCK_SZ) as u64)) - .expect("Error when seeking!"); - assert_eq!(file.read(buf).unwrap(), BLOCK_SZ, "Not a complete block!"); - } - - fn write_block(&self, block_id: usize, buf: &[u8]) { - let mut file = self.0.lock().unwrap(); - file.seek(SeekFrom::Start((block_id * BLOCK_SZ) as u64)) - .expect("Error when seeking!"); - assert_eq!(file.write(buf).unwrap(), BLOCK_SZ, "Not a complete block!"); - } - - fn handle_irq(&self) { - unimplemented!(); - } -} - -fn main() { - easy_fs_pack().expect("Error when packing easy-fs!"); -} - -fn easy_fs_pack() -> std::io::Result<()> { - let matches = App::new("EasyFileSystem packer") - .arg( - Arg::with_name("source") - .short("s") - .long("source") - .takes_value(true) - .help("Executable source dir(with backslash)"), - ) - .arg( - Arg::with_name("target") - .short("t") - .long("target") - .takes_value(true) - .help("Executable target dir(with backslash)"), - ) - .get_matches(); - let src_path = matches.value_of("source").unwrap(); - let target_path = matches.value_of("target").unwrap(); - println!("src_path = {}\ntarget_path = {}", src_path, target_path); - let block_file = Arc::new(BlockFile(Mutex::new({ - let f = OpenOptions::new() - .read(true) - .write(true) - .create(true) - .open(format!("{}{}", target_path, "fs.img"))?; - f.set_len(32 * 2048 * 512).unwrap(); - f - }))); - // 32MiB, at most 4095 files - let efs = EasyFileSystem::create(block_file, 32 * 2048, 1); - let root_inode = Arc::new(EasyFileSystem::root_inode(&efs)); - let apps: Vec<_> = read_dir(src_path) - .unwrap() - .into_iter() - .map(|dir_entry| { - let mut name_with_ext = dir_entry.unwrap().file_name().into_string().unwrap(); - name_with_ext.drain(name_with_ext.find('.').unwrap()..name_with_ext.len()); - name_with_ext - }) - .collect(); - for app in apps { - // load app data from host file system - let mut host_file = File::open(format!("{}{}", target_path, app)).unwrap(); - let mut all_data: Vec = Vec::new(); - host_file.read_to_end(&mut all_data).unwrap(); - // create a file in easy-fs - let inode = root_inode.create(app.as_str()).unwrap(); - // write data to easy-fs - inode.write_at(0, all_data.as_slice()); - } - // list apps - // for app in root_inode.ls() { - // println!("{}", app); - // } - Ok(()) -} - -#[test] -fn efs_test() -> std::io::Result<()> { - let block_file = Arc::new(BlockFile(Mutex::new({ - let f = OpenOptions::new() - .read(true) - .write(true) - .create(true) - .open("target/fs.img")?; - f.set_len(8192 * 512).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("filea"); - root_inode.create("fileb"); - for name in root_inode.ls() { - println!("{}", name); - } - let filea = root_inode.find("filea").unwrap(); - let greet_str = "Hello, world!"; - filea.write_at(0, greet_str.as_bytes()); - //let mut buffer = [0u8; 512]; - let mut buffer = [0u8; 233]; - let len = filea.read_at(0, &mut buffer); - assert_eq!(greet_str, core::str::from_utf8(&buffer[..len]).unwrap(),); - - let mut random_str_test = |len: usize| { - filea.clear(); - assert_eq!(filea.read_at(0, &mut buffer), 0,); - let mut str = String::new(); - use rand; - // random digit - for _ in 0..len { - str.push(char::from('0' as u8 + rand::random::() % 10)); - } - filea.write_at(0, str.as_bytes()); - let mut read_buffer = [0u8; 127]; - let mut offset = 0usize; - let mut read_str = String::new(); - loop { - let len = filea.read_at(offset, &mut read_buffer); - if len == 0 { - break; - } - offset += len; - read_str.push_str(core::str::from_utf8(&read_buffer[..len]).unwrap()); - } - assert_eq!(str, read_str); - }; - - random_str_test(4 * BLOCK_SZ); - random_str_test(8 * BLOCK_SZ + BLOCK_SZ / 2); - random_str_test(100 * BLOCK_SZ); - random_str_test(70 * BLOCK_SZ + BLOCK_SZ / 7); - random_str_test((12 + 128) * BLOCK_SZ); - random_str_test(400 * BLOCK_SZ); - random_str_test(1000 * BLOCK_SZ); - random_str_test(2000 * BLOCK_SZ); - - Ok(()) -} diff --git a/easy-fs/.gitignore b/easy-fs/.gitignore deleted file mode 100644 index 79f5db6..0000000 --- a/easy-fs/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.idea/ -target/ -Cargo.lock diff --git a/easy-fs/Cargo.toml b/easy-fs/Cargo.toml deleted file mode 100644 index 7a2f38e..0000000 --- a/easy-fs/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "easy-fs" -version = "0.1.0" -authors = ["Yifan Wu "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -spin = "0.7.0" -lazy_static = { version = "1.4.0", features = ["spin_no_std"] } - -[profile.release] -debug = true - -[features] -board_qemu = [] -board_k210 = [] \ No newline at end of file diff --git a/easy-fs/src/bitmap.rs b/easy-fs/src/bitmap.rs deleted file mode 100644 index 2cea613..0000000 --- a/easy-fs/src/bitmap.rs +++ /dev/null @@ -1,69 +0,0 @@ -use super::{get_block_cache, BlockDevice, BLOCK_SZ}; -use alloc::sync::Arc; - -type BitmapBlock = [u64; 64]; - -const BLOCK_BITS: usize = BLOCK_SZ * 8; - -pub struct Bitmap { - start_block_id: usize, - blocks: usize, -} - -/// Return (block_pos, bits64_pos, inner_pos) -fn decomposition(mut bit: usize) -> (usize, usize, usize) { - let block_pos = bit / BLOCK_BITS; - bit %= BLOCK_BITS; - (block_pos, bit / 64, bit % 64) -} - -impl Bitmap { - pub fn new(start_block_id: usize, blocks: usize) -> Self { - Self { - start_block_id, - blocks, - } - } - - pub fn alloc(&self, block_device: &Arc) -> Option { - for block_id in 0..self.blocks { - let pos = get_block_cache( - block_id + self.start_block_id as usize, - Arc::clone(block_device), - ) - .lock() - .modify(0, |bitmap_block: &mut BitmapBlock| { - if let Some((bits64_pos, inner_pos)) = bitmap_block - .iter() - .enumerate() - .find(|(_, bits64)| **bits64 != u64::MAX) - .map(|(bits64_pos, bits64)| (bits64_pos, bits64.trailing_ones() as usize)) - { - // modify cache - bitmap_block[bits64_pos] |= 1u64 << inner_pos; - Some(block_id * BLOCK_BITS + bits64_pos * 64 + inner_pos as usize) - } else { - None - } - }); - if pos.is_some() { - return pos; - } - } - None - } - - 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)) - .lock() - .modify(0, |bitmap_block: &mut BitmapBlock| { - assert!(bitmap_block[bits64_pos] & (1u64 << inner_pos) > 0); - bitmap_block[bits64_pos] -= 1u64 << inner_pos; - }); - } - - 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 deleted file mode 100644 index 1b3b969..0000000 --- a/easy-fs/src/block_cache.rs +++ /dev/null @@ -1,142 +0,0 @@ -use super::{BlockDevice, BLOCK_SZ}; -use alloc::collections::VecDeque; -use alloc::sync::Arc; -use alloc::vec; -use alloc::vec::Vec; -use lazy_static::*; -use spin::Mutex; - -pub struct BlockCache { - cache: Vec, - block_id: usize, - block_device: Arc, - modified: bool, -} - -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); - Self { - cache, - block_id, - block_device, - modified: false, - } - } - - fn addr_of_offset(&self, offset: usize) -> usize { - &self.cache[offset] as *const _ as usize - } - - pub fn get_ref(&self, offset: usize) -> &T - where - T: Sized, - { - 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) } - } - - pub fn get_mut(&mut self, offset: usize) -> &mut T - where - T: Sized, - { - 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) } - } - - pub fn read(&self, offset: usize, f: impl FnOnce(&T) -> V) -> V { - f(self.get_ref(offset)) - } - - pub fn modify(&mut self, offset: usize, f: impl FnOnce(&mut T) -> V) -> V { - f(self.get_mut(offset)) - } - - pub fn sync(&mut self) { - if self.modified { - self.modified = false; - self.block_device.write_block(self.block_id, &self.cache); - } - } -} - -impl Drop for BlockCache { - fn drop(&mut self) { - self.sync() - } -} - -const BLOCK_CACHE_SIZE: usize = 16; - -pub struct BlockCacheManager { - queue: VecDeque<(usize, Arc>)>, -} - -impl BlockCacheManager { - pub fn new() -> Self { - Self { - queue: VecDeque::new(), - } - } - - pub fn get_block_cache( - &mut self, - block_id: usize, - block_device: Arc, - ) -> Arc> { - if let Some(pair) = self.queue.iter().find(|pair| pair.0 == block_id) { - Arc::clone(&pair.1) - } else { - // substitute - if self.queue.len() == BLOCK_CACHE_SIZE { - // from front to tail - if let Some((idx, _)) = self - .queue - .iter() - .enumerate() - .find(|(_, pair)| Arc::strong_count(&pair.1) == 1) - { - self.queue.drain(idx..=idx); - } else { - panic!("Run out of BlockCache!"); - } - } - // load block into mem and push back - let block_cache = Arc::new(Mutex::new(BlockCache::new( - block_id, - Arc::clone(&block_device), - ))); - self.queue.push_back((block_id, Arc::clone(&block_cache))); - block_cache - } - } -} - -lazy_static! { - pub static ref BLOCK_CACHE_MANAGER: Mutex = - Mutex::new(BlockCacheManager::new()); -} - -pub fn get_block_cache( - block_id: usize, - block_device: Arc, -) -> Arc> { - BLOCK_CACHE_MANAGER - .lock() - .get_block_cache(block_id, block_device) -} - -pub fn block_cache_sync_all() { - let manager = BLOCK_CACHE_MANAGER.lock(); - for (_, cache) in manager.queue.iter() { - cache.lock().sync(); - } -} diff --git a/easy-fs/src/block_dev.rs b/easy-fs/src/block_dev.rs deleted file mode 100644 index eb39fbd..0000000 --- a/easy-fs/src/block_dev.rs +++ /dev/null @@ -1,7 +0,0 @@ -use core::any::Any; - -pub trait BlockDevice: Send + Sync + Any { - fn read_block(&self, block_id: usize, buf: &mut [u8]); - 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 deleted file mode 100644 index 82e95ae..0000000 --- a/easy-fs/src/efs.rs +++ /dev/null @@ -1,147 +0,0 @@ -use super::{ - block_cache_sync_all, get_block_cache, Bitmap, BlockDevice, DiskInode, DiskInodeType, Inode, - SuperBlock, -}; -use crate::BLOCK_SZ; -use alloc::sync::Arc; -use spin::Mutex; - -pub struct EasyFileSystem { - pub block_device: Arc, - pub inode_bitmap: Bitmap, - pub data_bitmap: Bitmap, - inode_area_start_block: u32, - data_area_start_block: u32, -} - -type DataBlock = [u8; BLOCK_SZ]; - -impl EasyFileSystem { - pub fn create( - block_device: Arc, - total_blocks: u32, - inode_bitmap_blocks: u32, - ) -> Arc> { - // calculate block size of areas & create bitmaps - let inode_bitmap = Bitmap::new(1, inode_bitmap_blocks as usize); - let inode_num = inode_bitmap.maximum(); - let inode_area_blocks = - ((inode_num * core::mem::size_of::() + BLOCK_SZ - 1) / BLOCK_SZ) as u32; - let inode_total_blocks = inode_bitmap_blocks + inode_area_blocks; - let data_total_blocks = total_blocks - 1 - inode_total_blocks; - 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, - data_bitmap_blocks as usize, - ); - let mut efs = Self { - block_device: Arc::clone(&block_device), - inode_bitmap, - data_bitmap, - inode_area_start_block: 1 + inode_bitmap_blocks, - data_area_start_block: 1 + inode_total_blocks + data_bitmap_blocks, - }; - // clear all blocks - for i in 0..total_blocks { - get_block_cache(i as usize, Arc::clone(&block_device)) - .lock() - .modify(0, |data_block: &mut DataBlock| { - for byte in data_block.iter_mut() { - *byte = 0; - } - }); - } - // initialize SuperBlock - get_block_cache(0, Arc::clone(&block_device)).lock().modify( - 0, - |super_block: &mut SuperBlock| { - super_block.initialize( - total_blocks, - inode_bitmap_blocks, - inode_area_blocks, - data_bitmap_blocks, - data_area_blocks, - ); - }, - ); - // write back immediately - // create a inode for root node "/" - assert_eq!(efs.alloc_inode(), 0); - let (root_inode_block_id, root_inode_offset) = efs.get_disk_inode_pos(0); - get_block_cache(root_inode_block_id as usize, Arc::clone(&block_device)) - .lock() - .modify(root_inode_offset, |disk_inode: &mut DiskInode| { - disk_inode.initialize(DiskInodeType::Directory); - }); - block_cache_sync_all(); - Arc::new(Mutex::new(efs)) - } - - pub fn open(block_device: Arc) -> Arc> { - // read SuperBlock - get_block_cache(0, Arc::clone(&block_device)) - .lock() - .read(0, |super_block: &SuperBlock| { - assert!(super_block.is_valid(), "Error loading EFS!"); - let inode_total_blocks = - super_block.inode_bitmap_blocks + super_block.inode_area_blocks; - let efs = Self { - block_device, - inode_bitmap: Bitmap::new(1, super_block.inode_bitmap_blocks as usize), - data_bitmap: Bitmap::new( - (1 + inode_total_blocks) as usize, - super_block.data_bitmap_blocks as usize, - ), - inode_area_start_block: 1 + super_block.inode_bitmap_blocks, - data_area_start_block: 1 + inode_total_blocks + super_block.data_bitmap_blocks, - }; - Arc::new(Mutex::new(efs)) - }) - } - - pub fn root_inode(efs: &Arc>) -> Inode { - let block_device = Arc::clone(&efs.lock().block_device); - // acquire efs lock temporarily - let (block_id, block_offset) = efs.lock().get_disk_inode_pos(0); - // release efs lock - Inode::new(block_id, block_offset, Arc::clone(efs), block_device) - } - - 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; - let block_id = self.inode_area_start_block + inode_id / inodes_per_block; - ( - block_id, - (inode_id % inodes_per_block) as usize * inode_size, - ) - } - - pub fn get_data_block_id(&self, data_block_id: u32) -> u32 { - self.data_area_start_block + data_block_id - } - - 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. - pub fn alloc_data(&mut self) -> u32 { - self.data_bitmap.alloc(&self.block_device).unwrap() as u32 + self.data_area_start_block - } - - pub fn dealloc_data(&mut self, block_id: u32) { - get_block_cache(block_id as usize, Arc::clone(&self.block_device)) - .lock() - .modify(0, |data_block: &mut DataBlock| { - data_block.iter_mut().for_each(|p| { - *p = 0; - }) - }); - self.data_bitmap.dealloc( - &self.block_device, - (block_id - self.data_area_start_block) as usize, - ) - } -} diff --git a/easy-fs/src/layout.rs b/easy-fs/src/layout.rs deleted file mode 100644 index 618484c..0000000 --- a/easy-fs/src/layout.rs +++ /dev/null @@ -1,409 +0,0 @@ -use super::{get_block_cache, BlockDevice, BLOCK_SZ}; -use alloc::sync::Arc; -use alloc::vec::Vec; -use core::fmt::{Debug, Formatter, Result}; - -const EFS_MAGIC: u32 = 0x3b800001; -const INODE_DIRECT_COUNT: usize = 28; -const NAME_LENGTH_LIMIT: usize = 27; -const INODE_INDIRECT1_COUNT: usize = BLOCK_SZ / 4; -const INODE_INDIRECT2_COUNT: usize = INODE_INDIRECT1_COUNT * INODE_INDIRECT1_COUNT; -const DIRECT_BOUND: usize = INODE_DIRECT_COUNT; -const INDIRECT1_BOUND: usize = DIRECT_BOUND + INODE_INDIRECT1_COUNT; -#[allow(unused)] -const INDIRECT2_BOUND: usize = INDIRECT1_BOUND + INODE_INDIRECT2_COUNT; - -#[repr(C)] -pub struct SuperBlock { - magic: u32, - pub total_blocks: u32, - pub inode_bitmap_blocks: u32, - pub inode_area_blocks: u32, - pub data_bitmap_blocks: u32, - pub data_area_blocks: u32, -} - -impl Debug for SuperBlock { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - f.debug_struct("SuperBlock") - .field("total_blocks", &self.total_blocks) - .field("inode_bitmap_blocks", &self.inode_bitmap_blocks) - .field("inode_area_blocks", &self.inode_area_blocks) - .field("data_bitmap_blocks", &self.data_bitmap_blocks) - .field("data_area_blocks", &self.data_area_blocks) - .finish() - } -} - -impl SuperBlock { - pub fn initialize( - &mut self, - total_blocks: u32, - inode_bitmap_blocks: u32, - inode_area_blocks: u32, - data_bitmap_blocks: u32, - data_area_blocks: u32, - ) { - *self = Self { - magic: EFS_MAGIC, - total_blocks, - inode_bitmap_blocks, - inode_area_blocks, - data_bitmap_blocks, - data_area_blocks, - } - } - pub fn is_valid(&self) -> bool { - self.magic == EFS_MAGIC - } -} - -#[derive(PartialEq)] -pub enum DiskInodeType { - File, - Directory, -} - -type IndirectBlock = [u32; BLOCK_SZ / 4]; -type DataBlock = [u8; BLOCK_SZ]; - -#[repr(C)] -pub struct DiskInode { - pub size: u32, - pub direct: [u32; INODE_DIRECT_COUNT], - pub indirect1: u32, - pub indirect2: u32, - type_: DiskInodeType, -} - -impl DiskInode { - /// 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); - self.indirect1 = 0; - self.indirect2 = 0; - self.type_ = type_; - } - pub fn is_dir(&self) -> bool { - self.type_ == DiskInodeType::Directory - } - #[allow(unused)] - pub fn is_file(&self) -> bool { - self.type_ == DiskInodeType::File - } - /// Return block number correspond to size. - pub fn data_blocks(&self) -> u32 { - Self::_data_blocks(self.size) - } - fn _data_blocks(size: u32) -> u32 { - (size + BLOCK_SZ as u32 - 1) / BLOCK_SZ as u32 - } - /// Return number of blocks needed include indirect1/2. - pub fn total_blocks(size: u32) -> u32 { - let data_blocks = Self::_data_blocks(size) as usize; - let mut total = data_blocks as usize; - // indirect1 - if data_blocks > INODE_DIRECT_COUNT { - total += 1; - } - // indirect2 - if data_blocks > INDIRECT1_BOUND { - total += 1; - // sub indirect1 - total += - (data_blocks - INDIRECT1_BOUND + INODE_INDIRECT1_COUNT - 1) / INODE_INDIRECT1_COUNT; - } - total as u32 - } - 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) - } - 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 { - self.direct[inner_id] - } else if inner_id < INDIRECT1_BOUND { - get_block_cache(self.indirect1 as usize, Arc::clone(block_device)) - .lock() - .read(0, |indirect_block: &IndirectBlock| { - indirect_block[inner_id - INODE_DIRECT_COUNT] - }) - } else { - let last = inner_id - INDIRECT1_BOUND; - let indirect1 = get_block_cache(self.indirect2 as usize, Arc::clone(block_device)) - .lock() - .read(0, |indirect2: &IndirectBlock| { - indirect2[last / INODE_INDIRECT1_COUNT] - }); - get_block_cache(indirect1 as usize, Arc::clone(block_device)) - .lock() - .read(0, |indirect1: &IndirectBlock| { - indirect1[last % INODE_INDIRECT1_COUNT] - }) - } - } - pub fn increase_size( - &mut self, - new_size: u32, - new_blocks: Vec, - block_device: &Arc, - ) { - let mut current_blocks = self.data_blocks(); - self.size = new_size; - let mut total_blocks = self.data_blocks(); - let mut new_blocks = new_blocks.into_iter(); - // fill direct - while current_blocks < total_blocks.min(INODE_DIRECT_COUNT as u32) { - self.direct[current_blocks as usize] = new_blocks.next().unwrap(); - current_blocks += 1; - } - // alloc indirect1 - if total_blocks > INODE_DIRECT_COUNT as u32 { - if current_blocks == INODE_DIRECT_COUNT as u32 { - self.indirect1 = new_blocks.next().unwrap(); - } - current_blocks -= INODE_DIRECT_COUNT as u32; - total_blocks -= INODE_DIRECT_COUNT as u32; - } else { - return; - } - // fill indirect1 - get_block_cache(self.indirect1 as usize, Arc::clone(block_device)) - .lock() - .modify(0, |indirect1: &mut IndirectBlock| { - while current_blocks < total_blocks.min(INODE_INDIRECT1_COUNT as u32) { - indirect1[current_blocks as usize] = new_blocks.next().unwrap(); - current_blocks += 1; - } - }); - // alloc indirect2 - if total_blocks > INODE_INDIRECT1_COUNT as u32 { - if current_blocks == INODE_INDIRECT1_COUNT as u32 { - self.indirect2 = new_blocks.next().unwrap(); - } - current_blocks -= INODE_INDIRECT1_COUNT as u32; - total_blocks -= INODE_INDIRECT1_COUNT as u32; - } else { - return; - } - // fill indirect2 from (a0, b0) -> (a1, b1) - let mut a0 = current_blocks as usize / INODE_INDIRECT1_COUNT; - let mut b0 = current_blocks as usize % INODE_INDIRECT1_COUNT; - let a1 = total_blocks as usize / INODE_INDIRECT1_COUNT; - let b1 = total_blocks as usize % INODE_INDIRECT1_COUNT; - // alloc low-level indirect1 - get_block_cache(self.indirect2 as usize, Arc::clone(block_device)) - .lock() - .modify(0, |indirect2: &mut IndirectBlock| { - while (a0 < a1) || (a0 == a1 && b0 < b1) { - if b0 == 0 { - indirect2[a0] = new_blocks.next().unwrap(); - } - // fill current - get_block_cache(indirect2[a0] as usize, Arc::clone(block_device)) - .lock() - .modify(0, |indirect1: &mut IndirectBlock| { - indirect1[b0] = new_blocks.next().unwrap(); - }); - // move to next - b0 += 1; - if b0 == INODE_INDIRECT1_COUNT { - b0 = 0; - a0 += 1; - } - } - }); - } - - /// 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(); - let mut data_blocks = self.data_blocks() as usize; - self.size = 0; - let mut current_blocks = 0usize; - // direct - while current_blocks < data_blocks.min(INODE_DIRECT_COUNT) { - v.push(self.direct[current_blocks]); - self.direct[current_blocks] = 0; - current_blocks += 1; - } - // indirect1 block - if data_blocks > INODE_DIRECT_COUNT { - v.push(self.indirect1); - data_blocks -= INODE_DIRECT_COUNT; - current_blocks = 0; - } else { - return v; - } - // indirect1 - get_block_cache(self.indirect1 as usize, Arc::clone(block_device)) - .lock() - .modify(0, |indirect1: &mut IndirectBlock| { - while current_blocks < data_blocks.min(INODE_INDIRECT1_COUNT) { - v.push(indirect1[current_blocks]); - //indirect1[current_blocks] = 0; - current_blocks += 1; - } - }); - self.indirect1 = 0; - // indirect2 block - if data_blocks > INODE_INDIRECT1_COUNT { - v.push(self.indirect2); - data_blocks -= INODE_INDIRECT1_COUNT; - } else { - return v; - } - // indirect2 - assert!(data_blocks <= INODE_INDIRECT2_COUNT); - let a1 = data_blocks / INODE_INDIRECT1_COUNT; - let b1 = data_blocks % INODE_INDIRECT1_COUNT; - get_block_cache(self.indirect2 as usize, Arc::clone(block_device)) - .lock() - .modify(0, |indirect2: &mut IndirectBlock| { - // full indirect1 blocks - for entry in indirect2.iter_mut().take(a1) { - v.push(*entry); - get_block_cache(*entry as usize, Arc::clone(block_device)) - .lock() - .modify(0, |indirect1: &mut IndirectBlock| { - for entry in indirect1.iter() { - v.push(*entry); - } - }); - } - // last indirect1 block - if b1 > 0 { - v.push(indirect2[a1]); - get_block_cache(indirect2[a1] as usize, Arc::clone(block_device)) - .lock() - .modify(0, |indirect1: &mut IndirectBlock| { - for entry in indirect1.iter().take(b1) { - v.push(*entry); - } - }); - //indirect2[a1] = 0; - } - }); - self.indirect2 = 0; - v - } - pub fn read_at( - &self, - offset: usize, - buf: &mut [u8], - block_device: &Arc, - ) -> usize { - let mut start = offset; - let end = (offset + buf.len()).min(self.size as usize); - if start >= end { - return 0; - } - let mut start_block = start / BLOCK_SZ; - let mut read_size = 0usize; - loop { - // calculate end of current block - let mut end_current_block = (start / BLOCK_SZ + 1) * BLOCK_SZ; - end_current_block = end_current_block.min(end); - // read and update read size - let block_read_size = end_current_block - start; - let dst = &mut buf[read_size..read_size + block_read_size]; - get_block_cache( - self.get_block_id(start_block as u32, block_device) as usize, - Arc::clone(block_device), - ) - .lock() - .read(0, |data_block: &DataBlock| { - let src = &data_block[start % BLOCK_SZ..start % BLOCK_SZ + block_read_size]; - dst.copy_from_slice(src); - }); - read_size += block_read_size; - // move to next block - if end_current_block == end { - break; - } - start_block += 1; - start = end_current_block; - } - read_size - } - /// File size must be adjusted before. - pub fn write_at( - &mut self, - offset: usize, - buf: &[u8], - block_device: &Arc, - ) -> usize { - let mut start = offset; - let end = (offset + buf.len()).min(self.size as usize); - assert!(start <= end); - let mut start_block = start / BLOCK_SZ; - let mut write_size = 0usize; - loop { - // calculate end of current block - let mut end_current_block = (start / BLOCK_SZ + 1) * BLOCK_SZ; - end_current_block = end_current_block.min(end); - // write and update write size - let block_write_size = end_current_block - start; - get_block_cache( - self.get_block_id(start_block as u32, block_device) as usize, - Arc::clone(block_device), - ) - .lock() - .modify(0, |data_block: &mut DataBlock| { - let src = &buf[write_size..write_size + block_write_size]; - let dst = &mut data_block[start % BLOCK_SZ..start % BLOCK_SZ + block_write_size]; - dst.copy_from_slice(src); - }); - write_size += block_write_size; - // move to next block - if end_current_block == end { - break; - } - start_block += 1; - start = end_current_block; - } - write_size - } -} - -#[repr(C)] -pub struct DirEntry { - name: [u8; NAME_LENGTH_LIMIT + 1], - inode_number: u32, -} - -pub const DIRENT_SZ: usize = 32; - -impl DirEntry { - pub fn empty() -> Self { - Self { - name: [0u8; NAME_LENGTH_LIMIT + 1], - inode_number: 0, - } - } - 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()); - Self { - name: bytes, - inode_number, - } - } - pub fn as_bytes(&self) -> &[u8] { - unsafe { core::slice::from_raw_parts(self as *const _ as usize as *const u8, DIRENT_SZ) } - } - 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) } - } - pub fn name(&self) -> &str { - let len = (0usize..).find(|i| self.name[*i] == 0).unwrap(); - core::str::from_utf8(&self.name[..len]).unwrap() - } - pub fn inode_number(&self) -> u32 { - self.inode_number - } -} diff --git a/easy-fs/src/lib.rs b/easy-fs/src/lib.rs deleted file mode 100644 index fa36e6b..0000000 --- a/easy-fs/src/lib.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![no_std] - -extern crate alloc; - -mod bitmap; -mod block_cache; -mod block_dev; -mod efs; -mod layout; -mod vfs; - -pub const BLOCK_SZ: usize = 512; -use bitmap::Bitmap; -use block_cache::{block_cache_sync_all, get_block_cache}; -pub use block_dev::BlockDevice; -pub use efs::EasyFileSystem; -use layout::*; -pub use vfs::Inode; diff --git a/easy-fs/src/vfs.rs b/easy-fs/src/vfs.rs deleted file mode 100644 index 7290fa4..0000000 --- a/easy-fs/src/vfs.rs +++ /dev/null @@ -1,186 +0,0 @@ -use super::{ - block_cache_sync_all, get_block_cache, BlockDevice, DirEntry, DiskInode, DiskInodeType, - EasyFileSystem, DIRENT_SZ, -}; -use alloc::string::String; -use alloc::sync::Arc; -use alloc::vec::Vec; -use spin::{Mutex, MutexGuard}; - -pub struct Inode { - block_id: usize, - block_offset: usize, - fs: Arc>, - block_device: Arc, -} - -impl Inode { - /// We should not acquire efs lock here. - pub fn new( - block_id: u32, - block_offset: usize, - fs: Arc>, - block_device: Arc, - ) -> Self { - Self { - block_id: block_id as usize, - block_offset, - fs, - block_device, - } - } - - 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) - } - - 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) - } - - fn find_inode_id(&self, name: &str, disk_inode: &DiskInode) -> Option { - // assert it is a directory - assert!(disk_inode.is_dir()); - let file_count = (disk_inode.size as usize) / DIRENT_SZ; - let mut dirent = DirEntry::empty(); - for i in 0..file_count { - assert_eq!( - disk_inode.read_at(DIRENT_SZ * i, dirent.as_bytes_mut(), &self.block_device,), - DIRENT_SZ, - ); - if dirent.name() == name { - return Some(dirent.inode_number() as u32); - } - } - None - } - - pub fn find(&self, name: &str) -> Option> { - let fs = self.fs.lock(); - self.read_disk_inode(|disk_inode| { - self.find_inode_id(name, disk_inode).map(|inode_id| { - let (block_id, block_offset) = fs.get_disk_inode_pos(inode_id); - Arc::new(Self::new( - block_id, - block_offset, - self.fs.clone(), - self.block_device.clone(), - )) - }) - }) - } - - fn increase_size( - &self, - new_size: u32, - disk_inode: &mut DiskInode, - fs: &mut MutexGuard, - ) { - if new_size < disk_inode.size { - return; - } - let blocks_needed = disk_inode.blocks_num_needed(new_size); - let mut v: Vec = Vec::new(); - for _ in 0..blocks_needed { - v.push(fs.alloc_data()); - } - disk_inode.increase_size(new_size, v, &self.block_device); - } - - pub fn create(&self, name: &str) -> Option> { - let mut fs = self.fs.lock(); - let op = |root_inode: &mut 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() { - return None; - } - // create a new file - // alloc a inode with an indirect block - let new_inode_id = fs.alloc_inode(); - // initialize inode - let (new_inode_block_id, new_inode_block_offset) = fs.get_disk_inode_pos(new_inode_id); - get_block_cache(new_inode_block_id as usize, Arc::clone(&self.block_device)) - .lock() - .modify(new_inode_block_offset, |new_inode: &mut DiskInode| { - new_inode.initialize(DiskInodeType::File); - }); - self.modify_disk_inode(|root_inode| { - // append file in the dirent - let file_count = (root_inode.size as usize) / DIRENT_SZ; - let new_size = (file_count + 1) * DIRENT_SZ; - // increase size - self.increase_size(new_size as u32, root_inode, &mut fs); - // write dirent - let dirent = DirEntry::new(name, new_inode_id); - root_inode.write_at( - file_count * DIRENT_SZ, - dirent.as_bytes(), - &self.block_device, - ); - }); - - let (block_id, block_offset) = fs.get_disk_inode_pos(new_inode_id); - block_cache_sync_all(); - // return inode - Some(Arc::new(Self::new( - block_id, - block_offset, - self.fs.clone(), - self.block_device.clone(), - ))) - // release efs lock automatically by compiler - } - - pub fn ls(&self) -> Vec { - let _fs = self.fs.lock(); - self.read_disk_inode(|disk_inode| { - let file_count = (disk_inode.size as usize) / DIRENT_SZ; - let mut v: Vec = Vec::new(); - for i in 0..file_count { - let mut dirent = DirEntry::empty(); - assert_eq!( - disk_inode.read_at(i * DIRENT_SZ, dirent.as_bytes_mut(), &self.block_device,), - DIRENT_SZ, - ); - v.push(String::from(dirent.name())); - } - v - }) - } - - 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)) - } - - pub fn write_at(&self, offset: usize, buf: &[u8]) -> usize { - let mut fs = self.fs.lock(); - let size = self.modify_disk_inode(|disk_inode| { - self.increase_size((offset + buf.len()) as u32, disk_inode, &mut fs); - disk_inode.write_at(offset, buf, &self.block_device) - }); - block_cache_sync_all(); - size - } - - pub fn clear(&self) { - let mut fs = self.fs.lock(); - self.modify_disk_inode(|disk_inode| { - let size = disk_inode.size; - let data_blocks_dealloc = disk_inode.clear_size(&self.block_device); - assert!(data_blocks_dealloc.len() == DiskInode::total_blocks(size) as usize); - for data_block in data_blocks_dealloc.into_iter() { - fs.dealloc_data(data_block); - } - }); - block_cache_sync_all(); - } -} 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..9c2a7d3 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -12,12 +12,6 @@ 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..a4c7967 100644 --- a/os/Makefile +++ b/os/Makefile @@ -4,20 +4,12 @@ MODE := release KERNEL_ELF := target/$(TARGET)/$(MODE)/os KERNEL_BIN := $(KERNEL_ELF).bin DISASM_TMP := target/$(TARGET)/$(MODE)/asm -FS_IMG := ../user/target/$(TARGET)/$(MODE)/fs.img -APPS := ../user/src/bin/* # BOARD 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 @@ -33,10 +25,7 @@ OBJCOPY := rust-objcopy --binary-architecture=riscv64 # Disassembly DISASM ?= -x -# Run usertests or usershell -TEST ?= - -build: env $(KERNEL_BIN) fs-img +build: env $(KERNEL_BIN) env: (rustup target list | grep "riscv64gc-unknown-none-elf (installed)") || rustup target add $(TARGET) @@ -47,17 +36,11 @@ env: $(KERNEL_BIN): kernel @$(OBJCOPY) $(KERNEL_ELF) --strip-all -O binary $@ -fs-img: $(APPS) - @cd ../user && make build TEST=$(TEST) - @rm -f $(FS_IMG) - @cd ../easy-fs-fuse && cargo run --release -- -s ../user/src/bin/ -t ../user/target/riscv64gc-unknown-none-elf/release/ - -$(APPS): - kernel: + @cd ../user && make build @echo Platform: $(BOARD) @cp src/linker-$(BOARD).ld src/linker.ld - @cargo build --release + @cargo build $(MODE_ARG) @rm src/linker.ld clean: @@ -68,27 +51,15 @@ 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 loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) QEMU_NAME := qemu-system-riscv64 qemu-version-check: @@ -109,4 +80,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 gdbserver gdbclient qemu-version-check diff --git a/os/build.rs b/os/build.rs index 5529b4f..905e21e 100644 --- a/os/build.rs +++ b/os/build.rs @@ -1,6 +1,57 @@ -static TARGET_PATH: &str = "../user/target/riscv64gc-unknown-none-elf/release/"; +use std::fs::{read_dir, File}; +use std::io::{Result, Write}; fn main() { println!("cargo:rerun-if-changed=../user/src/"); println!("cargo:rerun-if-changed={}", TARGET_PATH); + insert_app_data().unwrap(); +} + +static TARGET_PATH: &str = "../user/target/riscv64gc-unknown-none-elf/release/"; + +fn insert_app_data() -> Result<()> { + let mut f = File::create("src/link_app.S").unwrap(); + let mut apps: Vec<_> = read_dir("../user/src/bin") + .unwrap() + .into_iter() + .map(|dir_entry| { + let mut name_with_ext = dir_entry.unwrap().file_name().into_string().unwrap(); + name_with_ext.drain(name_with_ext.find('.').unwrap()..name_with_ext.len()); + name_with_ext + }) + .collect(); + apps.sort(); + + writeln!( + f, + r#" + .align 3 + .section .data + .global _num_app +_num_app: + .quad {}"#, + apps.len() + )?; + + for i in 0..apps.len() { + writeln!(f, r#" .quad app_{}_start"#, i)?; + } + writeln!(f, r#" .quad app_{}_end"#, apps.len() - 1)?; + + for (idx, app) in apps.iter().enumerate() { + println!("app_{}: {}", idx, app); + writeln!( + f, + r#" + .section .data + .global app_{0}_start + .global app_{0}_end + .align 3 +app_{0}_start: + .incbin "{2}{1}" +app_{0}_end:"#, + idx, app, TARGET_PATH + )?; + } + Ok(()) } 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..f1f4e56 100644 --- a/os/src/boards/qemu.rs +++ b/os/src/boards/qemu.rs @@ -1,55 +1,8 @@ +//! Constants used in rCore for qemu + pub const CLOCK_FREQ: usize = 12500000; 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 ]; - -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..8c3c88f 100644 --- a/os/src/config.rs +++ b/os/src/config.rs @@ -1,12 +1,18 @@ -#[allow(unused)] +//! Constants used in rCore 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 = 0x30_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; +/// Return (bottom, top) of a kernel stack in kernel space. +pub fn kernel_stack_position(app_id: usize) -> (usize, usize) { + let top = TRAMPOLINE - app_id * (KERNEL_STACK_SIZE + PAGE_SIZE); + let bottom = top - KERNEL_STACK_SIZE; + (bottom, top) +} pub use crate::board::{CLOCK_FREQ, MEMORY_END, MMIO}; diff --git a/os/src/console.rs b/os/src/console.rs index 085637b..7e44bb2 100644 --- a/os/src/console.rs +++ b/os/src/console.rs @@ -1,5 +1,6 @@ -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 +8,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 +19,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/mod.rs b/os/src/drivers/block/mod.rs deleted file mode 100644 index add8da0..0000000 --- a/os/src/drivers/block/mod.rs +++ /dev/null @@ -1,28 +0,0 @@ -mod virtio_blk; - -pub use virtio_blk::VirtIOBlock; - -use crate::board::BlockDeviceImpl; -use alloc::sync::Arc; -use easy_fs::BlockDevice; -use lazy_static::*; - -lazy_static! { - pub static ref BLOCK_DEVICE: Arc = Arc::new(BlockDeviceImpl::new()); -} - -#[allow(unused)] -pub fn block_device_test() { - let block_device = BLOCK_DEVICE.clone(); - let mut write_buffer = [0u8; 512]; - let mut read_buffer = [0u8; 512]; - for i in 0..512 { - for byte in write_buffer.iter_mut() { - *byte = i as u8; - } - block_device.write_block(i as usize, &write_buffer); - block_device.read_block(i as usize, &mut read_buffer); - assert_eq!(write_buffer, read_buffer); - } - println!("block device test passed!"); -} diff --git a/os/src/drivers/block/virtio_blk.rs b/os/src/drivers/block/virtio_blk.rs deleted file mode 100644 index fb89084..0000000 --- a/os/src/drivers/block/virtio_blk.rs +++ /dev/null @@ -1,87 +0,0 @@ -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}; - -#[allow(unused)] -const VIRTIO0: usize = 0x10008000; - -pub struct VirtIOBlock { - virtio_blk: UPIntrFreeCell>, - condvars: BTreeMap, -} - -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"); - } - } - 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(); - } - }); - } -} - -impl VirtIOBlock { - pub fn new() -> Self { - let virtio_blk = unsafe { - UPIntrFreeCell::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, - } - } -} 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 deleted file mode 100644 index 605397d..0000000 --- a/os/src/drivers/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -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 deleted file mode 100644 index 321338d..0000000 --- a/os/src/fs/inode.rs +++ /dev/null @@ -1,139 +0,0 @@ -use super::File; -use crate::drivers::BLOCK_DEVICE; -use crate::mm::UserBuffer; -use crate::sync::UPIntrFreeCell; -use alloc::sync::Arc; -use alloc::vec::Vec; -use bitflags::*; -use easy_fs::{EasyFileSystem, Inode}; -use lazy_static::*; - -pub struct OSInode { - readable: bool, - writable: bool, - inner: UPIntrFreeCell, -} - -pub struct OSInodeInner { - offset: usize, - inode: Arc, -} - -impl OSInode { - pub fn new(readable: bool, writable: bool, inode: Arc) -> Self { - Self { - readable, - writable, - inner: unsafe { UPIntrFreeCell::new(OSInodeInner { offset: 0, inode }) }, - } - } - pub fn read_all(&self) -> Vec { - let mut inner = self.inner.exclusive_access(); - let mut buffer = [0u8; 512]; - let mut v: Vec = Vec::new(); - loop { - let len = inner.inode.read_at(inner.offset, &mut buffer); - if len == 0 { - break; - } - inner.offset += len; - v.extend_from_slice(&buffer[..len]); - } - v - } -} - -lazy_static! { - pub static ref ROOT_INODE: Arc = { - let efs = EasyFileSystem::open(BLOCK_DEVICE.clone()); - Arc::new(EasyFileSystem::root_inode(&efs)) - }; -} - -pub fn list_apps() { - println!("/**** APPS ****"); - for app in ROOT_INODE.ls() { - println!("{}", app); - } - println!("**************/") -} - -bitflags! { - pub struct OpenFlags: u32 { - const RDONLY = 0; - const WRONLY = 1 << 0; - const RDWR = 1 << 1; - const CREATE = 1 << 9; - const TRUNC = 1 << 10; - } -} - -impl OpenFlags { - /// Do not check validity for simplicity - /// Return (readable, writable) - pub fn read_write(&self) -> (bool, bool) { - if self.is_empty() { - (true, false) - } else if self.contains(Self::WRONLY) { - (false, true) - } else { - (true, true) - } - } -} - -pub fn open_file(name: &str, flags: OpenFlags) -> Option> { - let (readable, writable) = flags.read_write(); - if flags.contains(OpenFlags::CREATE) { - if let Some(inode) = ROOT_INODE.find(name) { - // clear size - inode.clear(); - Some(Arc::new(OSInode::new(readable, writable, inode))) - } else { - // create file - ROOT_INODE - .create(name) - .map(|inode| Arc::new(OSInode::new(readable, writable, inode))) - } - } else { - ROOT_INODE.find(name).map(|inode| { - if flags.contains(OpenFlags::TRUNC) { - inode.clear(); - } - Arc::new(OSInode::new(readable, writable, inode)) - }) - } -} - -impl File for OSInode { - fn readable(&self) -> bool { - self.readable - } - fn writable(&self) -> bool { - self.writable - } - fn read(&self, mut buf: UserBuffer) -> usize { - let mut inner = self.inner.exclusive_access(); - let mut total_read_size = 0usize; - for slice in buf.buffers.iter_mut() { - let read_size = inner.inode.read_at(inner.offset, *slice); - if read_size == 0 { - break; - } - inner.offset += read_size; - total_read_size += read_size; - } - total_read_size - } - fn write(&self, buf: UserBuffer) -> usize { - let mut inner = self.inner.exclusive_access(); - let mut total_write_size = 0usize; - for slice in buf.buffers.iter() { - let write_size = inner.inode.write_at(inner.offset, *slice); - assert_eq!(write_size, slice.len()); - inner.offset += write_size; - total_write_size += write_size; - } - total_write_size - } -} diff --git a/os/src/fs/mod.rs b/os/src/fs/mod.rs deleted file mode 100644 index cbde739..0000000 --- a/os/src/fs/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -mod inode; -mod pipe; -mod stdio; - -use crate::mm::UserBuffer; - -pub trait File: Send + Sync { - fn readable(&self) -> bool; - fn writable(&self) -> bool; - fn read(&self, buf: UserBuffer) -> usize; - fn write(&self, buf: UserBuffer) -> usize; -} - -pub use inode::{list_apps, open_file, OpenFlags}; -pub use pipe::make_pipe; -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 deleted file mode 100644 index 66f4c5a..0000000 --- a/os/src/fs/stdio.rs +++ /dev/null @@ -1,46 +0,0 @@ -use super::File; -use crate::drivers::chardev::CharDevice; -use crate::drivers::chardev::UART; -use crate::mm::UserBuffer; - -pub struct Stdin; -pub struct Stdout; - -impl File for Stdin { - fn readable(&self) -> bool { - true - } - fn writable(&self) -> bool { - false - } - 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(); - unsafe { - user_buf.buffers[0].as_mut_ptr().write_volatile(ch); - } - 1 - } - fn write(&self, _user_buf: UserBuffer) -> usize { - panic!("Cannot write to stdin!"); - } -} - -impl File for Stdout { - fn readable(&self) -> bool { - false - } - fn writable(&self) -> bool { - true - } - fn read(&self, _user_buf: UserBuffer) -> usize { - panic!("Cannot read from stdout!"); - } - fn write(&self, user_buf: UserBuffer) -> usize { - for buffer in user_buf.buffers.iter() { - print!("{}", core::str::from_utf8(*buffer).unwrap()); - } - user_buf.len() - } -} diff --git a/os/src/lang_items.rs b/os/src/lang_items.rs index 021f16f..a9111ce 100644 --- a/os/src/lang_items.rs +++ b/os/src/lang_items.rs @@ -1,10 +1,11 @@ +//! The panic handler + use crate::sbi::shutdown; -use crate::task::current_kstack_top; -use core::arch::asm; use core::panic::PanicInfo; use log::*; #[panic_handler] +/// panic handler fn panic(info: &PanicInfo) -> ! { if let Some(location) = info.location() { error!( @@ -16,23 +17,5 @@ fn panic(info: &PanicInfo) -> ! { } else { error!("[kernel] Panicked: {}", info.message().unwrap()); } - unsafe { - backtrace(); - } 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/loader.rs b/os/src/loader.rs new file mode 100644 index 0000000..855187d --- /dev/null +++ b/os/src/loader.rs @@ -0,0 +1,26 @@ +//! Loading user applications into memory + +/// Get the total number of applications. +pub fn get_num_app() -> usize { + extern "C" { + fn _num_app(); + } + unsafe { (_num_app as usize as *const usize).read_volatile() } +} + +/// get applications data +pub fn get_app_data(app_id: usize) -> &'static [u8] { + extern "C" { + fn _num_app(); + } + let num_app_ptr = _num_app as usize as *const usize; + let num_app = get_num_app(); + let app_start = unsafe { core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1) }; + assert!(app_id < num_app); + unsafe { + core::slice::from_raw_parts( + app_start[app_id] as *const u8, + app_start[app_id + 1] - app_start[app_id], + ) + } +} diff --git a/os/src/main.rs b/os/src/main.rs index 276aaf5..8016590 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -1,10 +1,27 @@ +//! 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 +//! +//! 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_first_task()`] and for the first time go to +//! userspace. + +#![deny(missing_docs)] +#![deny(warnings)] #![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] @@ -16,23 +33,20 @@ mod board; #[macro_use] mod console; mod config; -mod drivers; -mod fs; mod lang_items; +mod loader; mod mm; -mod net; mod sbi; mod sync; -mod syscall; -mod task; +pub mod syscall; +pub mod task; mod timer; -mod trap; - -use crate::drivers::chardev::CharDevice; -use crate::drivers::chardev::UART; +pub mod trap; core::arch::global_asm!(include_str!("entry.asm")); +core::arch::global_asm!(include_str!("link_app.S")); +/// clear BSS segment fn clear_bss() { extern "C" { fn sbss(); @@ -44,33 +58,18 @@ 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 pub fn rust_main() -> ! { clear_bss(); + println!("[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"); + println!("[kernel] back to world!"); + mm::remap_test(); trap::init(); + //trap::enable_interrupt(); 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(); + task::run_first_task(); panic!("Unreachable in rust_main!"); } diff --git a/os/src/mm/address.rs b/os/src/mm/address.rs index df3e130..a438c25 100644 --- a/os/src/mm/address.rs +++ b/os/src/mm/address.rs @@ -1,26 +1,28 @@ +//! 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}; +/// physical address const PA_WIDTH_SV39: usize = 56; const VA_WIDTH_SV39: usize = 39; const PPN_WIDTH_SV39: usize = PA_WIDTH_SV39 - PAGE_SIZE_BITS; const VPN_WIDTH_SV39: usize = VA_WIDTH_SV39 - PAGE_SIZE_BITS; /// Definitions -#[repr(C)] #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct PhysAddr(pub usize); -#[repr(C)] +/// virtual address #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct VirtAddr(pub usize); -#[repr(C)] +/// physical page number #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct PhysPageNum(pub usize); -#[repr(C)] +/// virtual page number #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct VirtPageNum(pub usize); @@ -167,14 +169,6 @@ impl VirtPageNum { } } -impl PhysAddr { - pub fn get_ref(&self) -> &'static T { - unsafe { (self.0 as *const T).as_ref().unwrap() } - } - pub fn get_mut(&self) -> &'static mut T { - unsafe { (self.0 as *mut T).as_mut().unwrap() } - } -} impl PhysPageNum { pub fn get_pte_array(&self) -> &'static mut [PageTableEntry] { let pa: PhysAddr = (*self).into(); @@ -186,7 +180,7 @@ impl PhysPageNum { } pub fn get_mut(&self) -> &'static mut T { let pa: PhysAddr = (*self).into(); - pa.get_mut() + unsafe { (pa.0 as *mut T).as_mut().unwrap() } } } @@ -198,13 +192,9 @@ impl StepByOne for VirtPageNum { self.0 += 1; } } -impl StepByOne for PhysPageNum { - fn step(&mut self) { - self.0 += 1; - } -} #[derive(Copy, Clone)] +/// a simple range structure for type T pub struct SimpleRange where T: StepByOne + Copy + PartialEq + PartialOrd + Debug, @@ -237,6 +227,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 +258,6 @@ 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..7818ba8 100644 --- a/os/src/mm/frame_allocator.rs +++ b/os/src/mm/frame_allocator.rs @@ -1,10 +1,14 @@ +//! 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, } @@ -35,10 +39,10 @@ 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,6 @@ 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); } } impl FrameAllocator for StackFrameAllocator { @@ -70,16 +73,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,10 +87,12 @@ 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(); @@ -108,6 +103,7 @@ pub fn init_frame_allocator() { ); } +/// allocate a frame pub fn frame_alloc() -> Option { FRAME_ALLOCATOR .exclusive_access() @@ -115,18 +111,13 @@ pub fn frame_alloc() -> Option { .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()) -} - -pub fn frame_dealloc(ppn: PhysPageNum) { +/// deallocate a frame +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 +134,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..07a53f7 100644 --- a/os/src/mm/heap_allocator.rs +++ b/os/src/mm/heap_allocator.rs @@ -1,16 +1,22 @@ +//! The global allocator + use crate::config::KERNEL_HEAP_SIZE; use buddy_system_allocator::LockedHeap; #[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 diff --git a/os/src/mm/memory_set.rs b/os/src/mm/memory_set.rs index d607c88..3a187f0 100644 --- a/os/src/mm/memory_set.rs +++ b/os/src/mm/memory_set.rs @@ -1,9 +1,11 @@ +//! Implementation of [`MapArea`] and [`MemorySet`]. + use super::{frame_alloc, FrameTracker}; 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; @@ -25,14 +27,12 @@ extern "C" { } lazy_static! { - pub static ref KERNEL_SPACE: Arc> = - Arc::new(unsafe { UPIntrFreeCell::new(MemorySet::new_kernel()) }); -} - -pub fn kernel_token() -> usize { - KERNEL_SPACE.exclusive_access().token() + /// a memory set instance through lazy_static! managing kernel space + pub static ref KERNEL_SPACE: Arc> = + Arc::new(unsafe { UPSafeCell::new(MemorySet::new_kernel()) }); } +/// memory set structure, controls virtual-memory space pub struct MemorySet { page_table: PageTable, areas: Vec, @@ -60,21 +60,7 @@ impl MemorySet { None, ); } - pub fn remove_area_with_start_vpn(&mut self, start_vpn: VirtPageNum) { - if let Some((idx, area)) = self - .areas - .iter_mut() - .enumerate() - .find(|(_, area)| area.vpn_range.get_start() == start_vpn) - { - area.unmap(&mut self.page_table); - 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 +81,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 +98,7 @@ impl MemorySet { ), None, ); - // println!("mapping .rodata section"); + println!("mapping .rodata section"); memory_set.push( MapArea::new( (srodata as usize).into(), @@ -122,7 +108,7 @@ impl MemorySet { ), None, ); - // println!("mapping .data section"); + println!("mapping .data section"); memory_set.push( MapArea::new( (sdata as usize).into(), @@ -132,7 +118,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 +128,7 @@ impl MemorySet { ), None, ); - // println!("mapping physical memory"); + println!("mapping physical memory"); memory_set.push( MapArea::new( (ekernel as usize).into(), @@ -152,7 +138,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 +152,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,34 +189,47 @@ 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, + ); + // used in sbrk + memory_set.push( + MapArea::new( + user_stack_top.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, ) } - pub fn from_existed_user(user_space: &MemorySet) -> MemorySet { - let mut memory_set = Self::new_bare(); - // map trampoline - memory_set.map_trampoline(); - // copy data sections/trap_context/user_stack - for area in user_space.areas.iter() { - let new_area = MapArea::from_another(area); - memory_set.push(new_area, None); - // copy data from another space - for vpn in area.vpn_range { - let src_ppn = user_space.translate(vpn).unwrap().ppn(); - let dst_ppn = memory_set.translate(vpn).unwrap().ppn(); - dst_ppn - .get_bytes_array() - .copy_from_slice(src_ppn.get_bytes_array()); - } - } - memory_set - } pub fn activate(&self) { let satp = self.page_table.token(); unsafe { @@ -241,12 +240,38 @@ impl MemorySet { pub fn translate(&self, vpn: VirtPageNum) -> Option { self.page_table.translate(vpn) } - pub fn recycle_data_pages(&mut self) { - //*self = Self::new_bare(); - self.areas.clear(); + #[allow(unused)] + pub fn shrink_to(&mut self, start: VirtAddr, new_end: VirtAddr) -> bool { + if let Some(area) = self + .areas + .iter_mut() + .find(|area| area.vpn_range.get_start() == start.floor()) + { + area.shrink_to(&mut self.page_table, new_end.ceil()); + true + } else { + false + } + } + #[allow(unused)] + pub fn append_to(&mut self, start: VirtAddr, new_end: VirtAddr) -> bool { + if let Some(area) = self + .areas + .iter_mut() + .find(|area| area.vpn_range.get_start() == start.floor()) + { + area.append_to(&mut self.page_table, new_end.ceil()); + true + } else { + false + } + } + pub fn unmap(&mut self, vpn: VirtPageNum) { + self.page_table.unmap(vpn) } } +/// map area structure, controls a contiguous piece of virtual memory pub struct MapArea { vpn_range: VPNRange, data_frames: BTreeMap, @@ -270,14 +295,6 @@ impl MapArea { map_perm, } } - pub fn from_another(another: &MapArea) -> Self { - Self { - vpn_range: VPNRange::new(another.vpn_range.get_start(), another.vpn_range.get_end()), - data_frames: BTreeMap::new(), - map_type: another.map_type, - map_perm: another.map_perm, - } - } pub fn map_one(&mut self, page_table: &mut PageTable, vpn: VirtPageNum) { let ppn: PhysPageNum; match self.map_type { @@ -289,15 +306,11 @@ 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); } + #[allow(unused)] pub fn unmap_one(&mut self, page_table: &mut PageTable, vpn: VirtPageNum) { if self.map_type == MapType::Framed { self.data_frames.remove(&vpn); @@ -309,11 +322,26 @@ impl MapArea { self.map_one(page_table, vpn); } } + #[allow(unused)] pub fn unmap(&mut self, page_table: &mut PageTable) { for vpn in self.vpn_range { self.unmap_one(page_table, vpn); } } + #[allow(unused)] + pub fn shrink_to(&mut self, page_table: &mut PageTable, new_end: VirtPageNum) { + for vpn in VPNRange::new(new_end, self.vpn_range.get_end()) { + self.unmap_one(page_table, vpn) + } + self.vpn_range = VPNRange::new(self.vpn_range.get_start(), new_end); + } + #[allow(unused)] + pub fn append_to(&mut self, page_table: &mut PageTable, new_end: VirtPageNum) { + for vpn in VPNRange::new(self.vpn_range.get_end(), new_end) { + self.map_one(page_table, vpn) + } + self.vpn_range = VPNRange::new(self.vpn_range.get_start(), new_end); + } /// data: start-aligned but maybe with shorter length /// assume that all frames were cleared before pub fn copy_data(&mut self, page_table: &PageTable, data: &[u8]) { @@ -339,14 +367,14 @@ 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 { const R = 1 << 1; const W = 1 << 2; diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs index 642d0b7..f7024cf 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::{PhysAddr, PhysPageNum, VirtAddr, VirtPageNum}; +use address::StepByOne; pub 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}; -use page_table::PTEFlags; -pub use page_table::{ - translated_byte_buffer, translated_ref, translated_refmut, translated_str, PageTable, - PageTableEntry, UserBuffer, -}; +pub use frame_allocator::{frame_alloc, FrameTracker}; +pub use memory_set::remap_test; +pub use memory_set::{MapPermission, MemorySet, KERNEL_SPACE}; +pub use page_table::{translated_byte_buffer, PageTableEntry}; +use page_table::{PTEFlags, PageTable}; +/// 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..eb37634 100644 --- a/os/src/mm/page_table.rs +++ b/os/src/mm/page_table.rs @@ -1,10 +1,12 @@ -use super::{frame_alloc, FrameTracker, PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum}; -use alloc::string::String; +//! Implementation of [`PageTableEntry`] and [`PageTable`]. + +use super::{frame_alloc, FrameTracker, PhysPageNum, StepByOne, VirtAddr, VirtPageNum}; use alloc::vec; use alloc::vec::Vec; use bitflags::*; bitflags! { + /// page table entry flags pub struct PTEFlags: u8 { const V = 1 << 0; const R = 1 << 1; @@ -19,6 +21,7 @@ bitflags! { #[derive(Copy, Clone)] #[repr(C)] +/// page table entry structure pub struct PageTableEntry { pub bits: usize, } @@ -52,6 +55,7 @@ impl PageTableEntry { } } +/// page table structure pub struct PageTable { root_ppn: PhysPageNum, frames: Vec, @@ -124,19 +128,12 @@ impl PageTable { pub fn translate(&self, vpn: VirtPageNum) -> Option { self.find_pte(vpn).map(|pte| *pte) } - pub fn translate_va(&self, va: VirtAddr) -> Option { - self.find_pte(va.clone().floor()).map(|pte| { - let aligned_pa: PhysAddr = pte.ppn().into(); - let offset = va.page_offset(); - let aligned_pa_usize: usize = aligned_pa.into(); - (aligned_pa_usize + offset).into() - }) - } 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; @@ -158,92 +155,3 @@ 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`. -pub fn translated_str(token: usize, ptr: *const u8) -> String { - let page_table = PageTable::from_token(token); - let mut string = String::new(); - let mut va = ptr as usize; - loop { - let ch: u8 = *(page_table - .translate_va(VirtAddr::from(va)) - .unwrap() - .get_mut()); - if ch == 0 { - break; - } - string.push(ch as char); - va += 1; - } - string -} - -pub fn translated_ref(token: usize, ptr: *const T) -> &'static T { - let page_table = PageTable::from_token(token); - page_table - .translate_va(VirtAddr::from(ptr as usize)) - .unwrap() - .get_ref() -} - -pub fn translated_refmut(token: usize, ptr: *mut T) -> &'static mut T { - let page_table = PageTable::from_token(token); - let va = ptr as usize; - page_table - .translate_va(VirtAddr::from(va)) - .unwrap() - .get_mut() -} - -pub struct UserBuffer { - pub buffers: Vec<&'static mut [u8]>, -} - -impl UserBuffer { - pub fn new(buffers: Vec<&'static mut [u8]>) -> Self { - Self { buffers } - } - pub fn len(&self) -> usize { - let mut total: usize = 0; - for b in self.buffers.iter() { - total += b.len(); - } - total - } -} - -impl IntoIterator for UserBuffer { - type Item = *mut u8; - type IntoIter = UserBufferIterator; - fn into_iter(self) -> Self::IntoIter { - UserBufferIterator { - buffers: self.buffers, - current_buffer: 0, - current_idx: 0, - } - } -} - -pub struct UserBufferIterator { - buffers: Vec<&'static mut [u8]>, - current_buffer: usize, - current_idx: usize, -} - -impl Iterator for UserBufferIterator { - type Item = *mut u8; - fn next(&mut self) -> Option { - if self.current_buffer >= self.buffers.len() { - None - } else { - let r = &mut self.buffers[self.current_buffer][self.current_idx] as *mut _; - if self.current_idx + 1 == self.buffers[self.current_buffer].len() { - self.current_idx = 0; - self.current_buffer += 1; - } else { - self.current_idx += 1; - } - Some(r) - } - } -} 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..5a2eed2 100644 --- a/os/src/sbi.rs +++ b/os/src/sbi.rs @@ -1,3 +1,11 @@ +//! SBI call wrappers + +/// 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 set timer pub fn set_timer(timer: usize) { sbi_rt::set_timer(timer as _); 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..4743e31 100644 --- a/os/src/sync/mod.rs +++ b/os/src/sync/mod.rs @@ -1,9 +1,5 @@ -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..e8ba20c 100644 --- a/os/src/sync/up.rs +++ b/os/src/sync/up.rs @@ -1,9 +1,7 @@ -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 +24,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..2fe02bc 100644 --- a/os/src/syscall/fs.rs +++ b/os/src/syscall/fs.rs @@ -1,99 +1,22 @@ -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::mm::translated_byte_buffer; +use crate::task::current_user_token; + +const FD_STDOUT: usize = 1; + +/// write buf of length `len` to a file with `fd` 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(); - if fd >= inner.fd_table.len() { - return -1; - } - if let Some(file) = &inner.fd_table[fd] { - if !file.writable() { - return -1; + match fd { + FD_STDOUT => { + let buffers = translated_byte_buffer(current_user_token(), buf, len); + for buffer in buffers { + print!("{}", core::str::from_utf8(buffer).unwrap()); + } + len as isize } - let file = file.clone(); - // release current task TCB manually to avoid multi-borrow - drop(inner); - file.write(UserBuffer::new(translated_byte_buffer(token, buf, len))) as isize - } else { - -1 - } -} - -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(); - if fd >= inner.fd_table.len() { - return -1; - } - if let Some(file) = &inner.fd_table[fd] { - let file = file.clone(); - if !file.readable() { - return -1; + _ => { + panic!("Unsupported fd in sys_write!"); } - // release current task TCB manually to avoid multi-borrow - drop(inner); - file.read(UserBuffer::new(translated_byte_buffer(token, buf, len))) as isize - } else { - -1 } } - -pub fn sys_open(path: *const u8, flags: u32) -> isize { - let process = current_process(); - let token = current_user_token(); - let path = translated_str(token, path); - if let Some(inode) = open_file(path.as_str(), OpenFlags::from_bits(flags).unwrap()) { - let mut inner = process.inner_exclusive_access(); - let fd = inner.alloc_fd(); - inner.fd_table[fd] = Some(inode); - fd as isize - } else { - -1 - } -} - -pub fn sys_close(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; - } - 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..d29ad2c 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -1,90 +1,39 @@ -const SYSCALL_DUP: usize = 24; -const SYSCALL_CONNECT: usize = 29; -const SYSCALL_LISTEN: usize = 30; -const SYSCALL_ACCEPT: usize = 31; -const SYSCALL_OPEN: usize = 56; -const SYSCALL_CLOSE: usize = 57; -const SYSCALL_PIPE: usize = 59; -const SYSCALL_READ: usize = 63; +//! 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_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; +const SYSCALL_SBRK: usize = 214; +const SYSCALL_MMAP: usize = 222; +const SYSCALL_MUNMAP: usize = 215; 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_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(), + SYSCALL_GET_TIME => sys_get_time(args[0] as *mut TimeVal, args[1]), + SYSCALL_SBRK => sys_sbrk(args[0] as i32), + SYSCALL_MMAP => sys_mmap(args[0], args[1], args[2]), + SYSCALL_MUNMAP => sys_munmap(args[0], args[1]), _ => 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..f60a3df 100644 --- a/os/src/syscall/process.rs +++ b/os/src/syscall/process.rs @@ -1,117 +1,105 @@ -use crate::fs::{open_file, OpenFlags}; -use crate::mm::{translated_ref, 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, -}; -use crate::timer::get_time_ms; -use alloc::string::String; -use alloc::sync::Arc; -use alloc::vec::Vec; +//! Process management syscalls +use crate::config::PAGE_SIZE; +use crate::mm::{translated_byte_buffer, MapPermission, VPNRange, VirtAddr}; +use crate::task::{change_program_brk, create_new_map_area, current_user_token, exit_current_and_run_next, get_current_task_page_table_entry, suspend_current_and_run_next, unmap_virtual_page}; +use crate::timer::get_time_us; + +/// task exits and submit an exit code pub fn sys_exit(exit_code: i32) -> ! { - exit_current_and_run_next(exit_code); + println!("[kernel] Application exited with code {}", exit_code); + exit_current_and_run_next(); panic!("Unreachable in sys_exit!"); } +/// current task gives up resources for other tasks pub fn sys_yield() -> isize { suspend_current_and_run_next(); 0 } -pub fn sys_get_time() -> isize { - get_time_ms() as isize +#[repr(C)] +#[derive(Debug)] +pub struct TimeVal { + pub sec: usize, + pub usec: usize, } -pub fn sys_getpid() -> isize { - current_task().unwrap().process.upgrade().unwrap().getpid() as isize -} - -pub fn sys_fork() -> isize { - let current_process = current_process(); - let new_process = current_process.fork(); - let new_pid = new_process.getpid(); - // 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(); - // 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; - new_pid as isize -} - -pub fn sys_exec(path: *const u8, mut args: *const usize) -> 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)); +/// get current time +pub fn sys_get_time(ts: *mut TimeVal, _tz: usize) -> isize { + let us = get_time_us(); + let dst_vec = translated_byte_buffer( + current_user_token(), + ts as *const u8, core::mem::size_of::() + ); + let ref time_val = TimeVal { + sec: us / 1_000_000, + usec: us % 1_000_000, + }; + let src_ptr = time_val as *const TimeVal; + for (idx, dst) in dst_vec.into_iter().enumerate() { + let unit_len = dst.len(); unsafe { - args = args.add(1); + dst.copy_from_slice( + core::slice::from_raw_parts( + src_ptr.wrapping_byte_add(idx * unit_len) as *const u8, + unit_len + ) + ); } } - 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 + 0 +} + +/// change data segment size +pub fn sys_sbrk(size: i32) -> isize { + if let Some(old_brk) = change_program_brk(size) { + old_brk as isize } else { -1 } } -/// 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(); - // find a child process - - let mut inner = process.inner_exclusive_access(); - if !inner - .children - .iter() - .any(|p| pid == -1 || pid as usize == p.getpid()) - { +/// map files or devices into memory +pub fn sys_mmap(start: usize, len: usize, prot: usize) -> isize { + if start % PAGE_SIZE != 0 || prot & !0x7 != 0 || prot & 0x7 == 0 { return -1; - // ---- release current PCB } - 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()) - // ++++ release child PCB - }); - if let Some((idx, _)) = pair { - let child = inner.children.remove(idx); - // confirm that child will be deallocated after being removed from children list - assert_eq!(Arc::strong_count(&child), 1); - let found_pid = child.getpid(); - // ++++ temporarily access child PCB exclusively - let exit_code = child.inner_exclusive_access().exit_code; - // ++++ release child PCB - *translated_refmut(inner.memory_set.token(), exit_code_ptr) = exit_code; - found_pid as isize - } else { - -2 + let vpn_start = VirtAddr::from(start).floor(); + let vpn_end = VirtAddr::from(start + len).ceil(); + let vpn_range = VPNRange::new(vpn_start, vpn_end); + for vpn in vpn_range { + if let Some(pte) = get_current_task_page_table_entry(vpn) { + if pte.is_valid() { + return -1; + } + } } - // ---- release current PCB automatically + create_new_map_area( + vpn_start.into(), + vpn_end.into(), + MapPermission::from_bits_truncate((prot << 1) as u8) | MapPermission::U + ); + 0 } -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 +/// unmap files or devices into memory +pub fn sys_munmap(start: usize, len: usize) -> isize { + if start % PAGE_SIZE != 0 { + return -1; } + let vpn_start = VirtAddr::from(start).floor(); + let vpn_end = VirtAddr::from(start + len).ceil(); + let vpn_range = VPNRange::new(vpn_start, vpn_end); + for vpn in vpn_range { + if let Some(pte) = get_current_task_page_table_entry(vpn) { + if !pte.is_valid() { + return -1; + } + unmap_virtual_page(vpn) + } else { + return -1; + } + } + 0 } 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..d945c5e 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, + /// callee saved registers: s 0..11 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 deleted file mode 100644 index 7672cf5..0000000 --- a/os/src/task/manager.rs +++ /dev/null @@ -1,62 +0,0 @@ -use super::{ProcessControlBlock, TaskControlBlock, TaskStatus}; -use crate::sync::UPIntrFreeCell; -use alloc::collections::{BTreeMap, VecDeque}; -use alloc::sync::Arc; -use lazy_static::*; - -pub struct TaskManager { - ready_queue: VecDeque>, -} - -/// A simple FIFO scheduler. -impl TaskManager { - pub fn new() -> Self { - Self { - ready_queue: VecDeque::new(), - } - } - pub fn add(&mut self, task: Arc) { - self.ready_queue.push_back(task); - } - 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 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); -} - -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..d89f20e 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -1,166 +1,228 @@ +//! 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 operating system. +//! +//! 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 processor; -mod signal; mod switch; #[allow(clippy::module_inception)] mod task; -use self::id::TaskUserRes; -use crate::fs::{open_file, OpenFlags}; +use crate::loader::{get_app_data, get_num_app}; +use crate::mm::{MapPermission, PageTableEntry, VirtAddr, VirtPageNum}; use crate::sbi::shutdown; -use alloc::{sync::Arc, vec::Vec}; +use crate::sync::UPSafeCell; +use crate::trap::TrapContext; +use alloc::vec::Vec; use lazy_static::*; -use manager::fetch_task; -use process::ProcessControlBlock; use switch::__switch; +use task::{TaskControlBlock, TaskStatus}; 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}; -pub fn suspend_current_and_run_next() { - // There must be an application running. - let task = take_current_task().unwrap(); - - // ---- access current TCB exclusively - let mut task_inner = task.inner_exclusive_access(); - let task_cx_ptr = &mut task_inner.task_cx as *mut TaskContext; - // Change status to Ready - task_inner.task_status = TaskStatus::Ready; - drop(task_inner); - // ---- release current TCB - - // push back to ready queue. - add_task(task); - // jump to scheduling cycle - schedule(task_cx_ptr); +/// The task manager, where all the tasks are managed. +/// +/// Functions implemented on `TaskManager` deals with all task state transitions +/// and task context switching. For convenience, you can find wrappers around it +/// in the module level. +/// +/// Most of `TaskManager` are hidden behind the field `inner`, to defer +/// borrowing checks to runtime. You can see examples on how to use `inner` in +/// existing functions on `TaskManager`. +pub struct TaskManager { + /// total number of tasks + num_app: usize, + /// use inner value to get mutable access + inner: UPSafeCell, } -/// 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); -} - -/// Exit the current 'Running' task and run the next task in task list. -pub fn exit_current_and_run_next(exit_code: i32) { - 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(); - } - } - drop(process); - // we do not have to save task context - let mut _unused = TaskContext::zero_init(); - schedule(&mut _unused as *mut _); +/// The task manager inner in 'UPSafeCell' +struct TaskManagerInner { + /// task list + tasks: Vec, + /// id of current `Running` task + current_task: usize, } lazy_static! { - pub static ref INITPROC: Arc = { - let inode = open_file("initproc", OpenFlags::RDONLY).unwrap(); - let v = inode.read_all(); - ProcessControlBlock::new(v.as_slice()) + /// a `TaskManager` global instance through lazy_static! + pub static ref TASK_MANAGER: TaskManager = { + println!("init TASK_MANAGER"); + let num_app = get_num_app(); + println!("num_app = {}", num_app); + let mut tasks: Vec = Vec::new(); + for i in 0..num_app { + tasks.push(TaskControlBlock::new(get_app_data(i), i)); + } + TaskManager { + num_app, + inner: unsafe { + UPSafeCell::new(TaskManagerInner { + tasks, + current_task: 0, + }) + }, + } }; } -pub fn add_initproc() { - let _initproc = INITPROC.clone(); +impl TaskManager { + /// Run the first task in task list. + /// + /// Generally, the first task in task list is an idle task (we call it zero process later). + /// But in ch4, we load apps statically, so the first task is a real app. + fn run_first_task(&self) -> ! { + let mut inner = self.inner.exclusive_access(); + let next_task = &mut inner.tasks[0]; + next_task.task_status = TaskStatus::Running; + let next_task_cx_ptr = &next_task.task_cx as *const TaskContext; + drop(inner); + let mut _unused = TaskContext::zero_init(); + // before this, we should drop local variables that must be dropped manually + unsafe { + __switch(&mut _unused as *mut _, next_task_cx_ptr); + } + panic!("unreachable in run_first_task!"); + } + + /// Change the status of current `Running` task into `Ready`. + fn mark_current_suspended(&self) { + let mut inner = self.inner.exclusive_access(); + let cur = inner.current_task; + inner.tasks[cur].task_status = TaskStatus::Ready; + } + + /// Change the status of current `Running` task into `Exited`. + fn mark_current_exited(&self) { + let mut inner = self.inner.exclusive_access(); + let cur = inner.current_task; + inner.tasks[cur].task_status = TaskStatus::Exited; + } + + /// Find next task to run and return task id. + /// + /// In this case, we only return the first `Ready` task in task list. + fn find_next_task(&self) -> Option { + let inner = self.inner.exclusive_access(); + let current = inner.current_task; + (current + 1..current + self.num_app + 1) + .map(|id| id % self.num_app) + .find(|id| inner.tasks[*id].task_status == TaskStatus::Ready) + } + + /// Get the current 'Running' task's token. + fn get_current_token(&self) -> usize { + let inner = self.inner.exclusive_access(); + inner.tasks[inner.current_task].get_user_token() + } + + /// Get the current 'Running' task's trap contexts. + fn get_current_trap_cx(&self) -> &'static mut TrapContext { + let inner = self.inner.exclusive_access(); + inner.tasks[inner.current_task].get_trap_cx() + } + + /// Change the current 'Running' task's program break + pub fn change_current_program_brk(&self, size: i32) -> Option { + let mut inner = self.inner.exclusive_access(); + let cur = inner.current_task; + inner.tasks[cur].change_program_brk(size) + } + + /// Switch current `Running` task to the task we have found, + /// or there is no `Ready` task and we can exit with all applications completed + fn run_next_task(&self) { + if let Some(next) = self.find_next_task() { + let mut inner = self.inner.exclusive_access(); + let current = inner.current_task; + inner.tasks[next].task_status = TaskStatus::Running; + inner.current_task = next; + let current_task_cx_ptr = &mut inner.tasks[current].task_cx as *mut TaskContext; + let next_task_cx_ptr = &inner.tasks[next].task_cx as *const TaskContext; + drop(inner); + // before this, we should drop local variables that must be dropped manually + unsafe { + __switch(current_task_cx_ptr, next_task_cx_ptr); + } + // go back to user mode + } else { + println!("All applications completed!"); + shutdown(false); + } + } } -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() +/// Run the first task in task list. +pub fn run_first_task() { + TASK_MANAGER.run_first_task(); } -pub fn current_add_signal(signal: SignalFlags) { - let process = current_process(); - let mut process_inner = process.inner_exclusive_access(); - process_inner.signals |= signal; +/// Switch current `Running` task to the task we have found, +/// or there is no `Ready` task and we can exit with all applications completed +fn run_next_task() { + TASK_MANAGER.run_next_task(); +} + +/// Change the status of current `Running` task into `Ready`. +fn mark_current_suspended() { + TASK_MANAGER.mark_current_suspended(); +} + +/// Change the status of current `Running` task into `Exited`. +fn mark_current_exited() { + TASK_MANAGER.mark_current_exited(); +} + +/// Suspend the current 'Running' task and run the next task in task list. +pub fn suspend_current_and_run_next() { + mark_current_suspended(); + run_next_task(); +} + +/// Exit the current 'Running' task and run the next task in task list. +pub fn exit_current_and_run_next() { + mark_current_exited(); + run_next_task(); +} + +/// Get the current 'Running' task's token. +pub fn current_user_token() -> usize { + TASK_MANAGER.get_current_token() +} + +/// Get the current 'Running' task's trap contexts. +pub fn current_trap_cx() -> &'static mut TrapContext { + TASK_MANAGER.get_current_trap_cx() +} + +/// Change the current 'Running' task's program break +pub fn change_program_brk(size: i32) -> Option { + TASK_MANAGER.change_current_program_brk(size) +} + +/// Get the curent 'Running' task's PTE +pub fn get_current_task_page_table_entry(vpn: VirtPageNum) -> Option { + let inner = TASK_MANAGER.inner.exclusive_access(); + let current = inner.current_task; + inner.tasks[current].memory_set.translate(vpn) +} + +/// create new mapping area +pub fn create_new_map_area(start_va: VirtAddr, end_va: VirtAddr, perm: MapPermission) { + let mut inner = TASK_MANAGER.inner.exclusive_access(); + let current = inner.current_task; + inner.tasks[current].memory_set.insert_framed_area(start_va, end_va, perm); +} + +/// unmap virtual page +pub fn unmap_virtual_page(vpn: VirtPageNum) { + let mut inner = TASK_MANAGER.inner.exclusive_access(); + let current = inner.current_task; + inner.tasks[current].memory_set.unmap(vpn); } 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 deleted file mode 100644 index 96361d7..0000000 --- a/os/src/task/processor.rs +++ /dev/null @@ -1,111 +0,0 @@ -use super::__switch; -use super::{fetch_task, TaskStatus}; -use super::{ProcessControlBlock, TaskContext, TaskControlBlock}; -use crate::sync::UPIntrFreeCell; -use crate::trap::TrapContext; -use alloc::sync::Arc; -use core::arch::asm; -use lazy_static::*; - -pub struct Processor { - current: Option>, - idle_task_cx: TaskContext, -} - -impl Processor { - pub fn new() -> Self { - Self { - current: None, - idle_task_cx: TaskContext::zero_init(), - } - } - fn get_idle_task_cx_ptr(&mut self) -> *mut TaskContext { - &mut self.idle_task_cx as *mut _ - } - pub fn take_current(&mut self) -> Option> { - self.current.take() - } - 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 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 - }); - 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"); - } - } -} - -pub fn take_current_task() -> Option> { - PROCESSOR.exclusive_access().take_current() -} - -pub fn current_task() -> Option> { - PROCESSOR.exclusive_access().current() -} - -pub fn current_process() -> Arc { - current_task().unwrap().process.upgrade().unwrap() -} - -pub fn current_user_token() -> usize { - let task = current_task().unwrap(); - task.get_user_token() -} - -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() -} - -pub fn schedule(switched_task_cx_ptr: *mut TaskContext) { - let idle_task_cx_ptr = - PROCESSOR.exclusive_session(|processor| processor.get_idle_task_cx_ptr()); - 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..960b0b3 100644 --- a/os/src/task/switch.rs +++ b/os/src/task/switch.rs @@ -1,8 +1,15 @@ -use super::TaskContext; -use core::arch::global_asm; +//! Rust wrapper around `__switch`. +//! +//! Switching to a different task's context happens here. The actual +//! implementation must not be in Rust and (essentially) has to be in assembly +//! language (Do you know why?), so this module really is just a wrapper around +//! `switch.S`. -global_asm!(include_str!("switch.S")); +core::arch::global_asm!(include_str!("switch.S")); +use super::TaskContext; extern "C" { + /// Switch to the context of `next_task_cx_ptr`, saving the current context + /// in `current_task_cx_ptr`. pub 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..be97639 100644 --- a/os/src/task/task.rs +++ b/os/src/task/task.rs @@ -1,80 +1,90 @@ -use super::id::TaskUserRes; -use super::{kstack_alloc, KernelStack, ProcessControlBlock, TaskContext}; -use crate::trap::TrapContext; -use crate::{ - mm::PhysPageNum, - sync::{UPIntrFreeCell, UPIntrRefMut}, -}; -use alloc::sync::{Arc, Weak}; +//! Types related to task management +use super::TaskContext; +use crate::config::{kernel_stack_position, TRAP_CONTEXT}; +use crate::mm::{MapPermission, MemorySet, PhysPageNum, VirtAddr, KERNEL_SPACE}; +use crate::trap::{trap_handler, TrapContext}; +/// task control block structure pub struct TaskControlBlock { - // immutable - pub process: Weak, - pub kstack: KernelStack, - // mutable - pub inner: UPIntrFreeCell, + pub task_status: TaskStatus, + pub task_cx: TaskContext, + pub memory_set: MemorySet, + pub trap_cx_ppn: PhysPageNum, + #[allow(unused)] + pub base_size: usize, + pub heap_bottom: usize, + pub program_brk: usize, } 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() - } -} - -pub struct TaskControlBlockInner { - pub res: Option, - pub trap_cx_ppn: PhysPageNum, - pub task_cx: TaskContext, - pub task_status: TaskStatus, - pub exit_code: Option, -} - -impl TaskControlBlockInner { pub fn get_trap_cx(&self) -> &'static mut TrapContext { self.trap_cx_ppn.get_mut() } - - #[allow(unused)] - fn get_status(&self) -> TaskStatus { - self.task_status + pub fn get_user_token(&self) -> usize { + self.memory_set.token() } -} - -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, - inner: unsafe { - UPIntrFreeCell::new(TaskControlBlockInner { - res: Some(res), - trap_cx_ppn, - task_cx: TaskContext::goto_trap_return(kstack_top), - task_status: TaskStatus::Ready, - exit_code: None, - }) - }, + pub fn new(elf_data: &[u8], app_id: usize) -> 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(); + let task_status = TaskStatus::Ready; + // map a kernel-stack in kernel space + let (kernel_stack_bottom, kernel_stack_top) = kernel_stack_position(app_id); + KERNEL_SPACE.exclusive_access().insert_framed_area( + kernel_stack_bottom.into(), + kernel_stack_top.into(), + MapPermission::R | MapPermission::W, + ); + let task_control_block = Self { + task_status, + task_cx: TaskContext::goto_trap_return(kernel_stack_top), + memory_set, + trap_cx_ppn, + base_size: user_sp, + heap_bottom: user_sp, + program_brk: user_sp, + }; + // prepare TrapContext in user space + let trap_cx = task_control_block.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 + } + /// change the location of the program break. return None if failed. + pub fn change_program_brk(&mut self, size: i32) -> Option { + let old_break = self.program_brk; + let new_brk = self.program_brk as isize + size as isize; + if new_brk < self.heap_bottom as isize { + return None; + } + let result = if size < 0 { + self.memory_set + .shrink_to(VirtAddr(self.heap_bottom), VirtAddr(new_brk as usize)) + } else { + self.memory_set + .append_to(VirtAddr(self.heap_bottom), VirtAddr(new_brk as usize)) + }; + if result { + self.program_brk = new_brk as usize; + Some(old_break) + } else { + None } } } #[derive(Copy, Clone, PartialEq)] +/// task status: UnInit, Ready, Running, Exited pub enum TaskStatus { Ready, Running, - Blocked, + Exited, } diff --git a/os/src/timer.rs b/os/src/timer.rs index 83c969d..8ddca7c 100644 --- a/os/src/timer.rs +++ b/os/src/timer.rs @@ -1,74 +1,29 @@ -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; +const MICRO_PER_SEC: usize = 1_000_000; pub fn get_time() -> usize { time::read() } +/// get current time in microseconds +#[allow(unused)] pub fn get_time_ms() -> usize { time::read() / (CLOCK_FREQ / MSEC_PER_SEC) } +/// get current time in us +pub fn get_time_us() -> usize { + time::read() / (CLOCK_FREQ / MICRO_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..dc8b78d 100644 --- a/os/src/trap/context.rs +++ b/os/src/trap/context.rs @@ -1,20 +1,30 @@ +//! Implementation of [`TrapContext`] + use riscv::register::sstatus::{self, Sstatus, SPP}; #[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, @@ -22,18 +32,17 @@ impl TrapContext { kernel_sp: usize, trap_handler: usize, ) -> Self { - let mut sstatus = sstatus::read(); - // set CPU privilege to User after trapping back - sstatus.set_spp(SPP::User); + let mut sstatus = sstatus::read(); // CSR sstatus + sstatus.set_spp(SPP::User); //previous privilege mode: user mode let mut cx = Self { x: [0; 32], sstatus, - sepc: entry, - kernel_satp, - kernel_sp, - trap_handler, + sepc: entry, // entry point of app + kernel_satp, // addr of page table + kernel_sp, // kernel stack + trap_handler, // addr of trap_handler function }; - cx.set_sp(sp); - cx + cx.set_sp(sp); // app's user stack pointer + cx // return initial Trap Context of app } } diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index 3287011..4a11dc0 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -1,34 +1,41 @@ +//! 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); } } @@ -38,71 +45,40 @@ fn set_user_trap_entry() { } } +/// 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] +/// handle an interrupt, exception, or system call from user space pub fn trap_handler() -> ! { set_kernel_trap_entry(); + let cx = current_trap_cx(); 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 - cx = current_trap_cx(); - cx.x[10] = result as usize; + cx.x[10] = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]) as usize; } Trap::Exception(Exception::StoreFault) | Trap::Exception(Exception::StorePageFault) - | Trap::Exception(Exception::InstructionFault) - | 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); + println!("[kernel] PageFault in application, bad addr = {:#x}, bad instruction = {:#x}, kernel killed it.", stval, cx.sepc); + exit_current_and_run_next(); } Trap::Exception(Exception::IllegalInstruction) => { - current_add_signal(SignalFlags::SIGILL); + println!("[kernel] IllegalInstruction in application, kernel killed it."); + exit_current_and_run_next(); } 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 +87,39 @@ pub fn trap_handler() -> ! { ); } } - // check signals - if let Some((errno, msg)) = check_signals_of_current() { - println!("[kernel] {}", msg); - exit_current_and_run_next(errno); - } trap_return(); } #[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(); } let restore_va = __restore as usize - __alltraps as usize + TRAMPOLINE; - //println!("before return"); unsafe { asm!( "fence.i", - "jr {restore_va}", + "jr {restore_va}", // jump to new addr of __restore asm function restore_va = in(reg) restore_va, - in("a0") trap_cx_user_va, - in("a1") user_satp, + in("a0") trap_cx_ptr, // a0 = virt addr of Trap Context + in("a1") user_satp, // a1 = phy addr of usr page table 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 - ); - } - } +/// Unimplement: traps/interrupts/exceptions from kernel mode +/// Todo: Chapter 9: I/O device +pub fn trap_from_kernel() -> ! { + panic!("a trap from kernel!"); } 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/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..d3384a7 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -7,13 +7,10 @@ edition = "2018" # 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/Makefile b/user/Makefile index 5170327..9ec3185 100644 --- a/user/Makefile +++ b/user/Makefile @@ -8,15 +8,9 @@ BINS := $(patsubst $(APP_DIR)/%.rs, $(TARGET_DIR)/%.bin, $(APPS)) OBJDUMP := rust-objdump --arch-name=riscv64 OBJCOPY := rust-objcopy --binary-architecture=riscv64 -CP := cp - -TEST ?= elf: $(APPS) @cargo build --release -ifeq ($(TEST), 1) - @$(CP) $(TARGET_DIR)/usertests $(TARGET_DIR)/initproc -endif binary: elf @$(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));) @@ -26,4 +20,4 @@ build: binary clean: @cargo clean -.PHONY: elf binary build clean +.PHONY: elf binary build clean \ No newline at end of file diff --git a/user/src/bin/00power_3.rs b/user/src/bin/00power_3.rs new file mode 100644 index 0000000..125e670 --- /dev/null +++ b/user/src/bin/00power_3.rs @@ -0,0 +1,29 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +const LEN: usize = 100; + +static mut S: [u64; LEN] = [0u64; LEN]; + +#[no_mangle] +unsafe fn main() -> i32 { + let p = 3u64; + let m = 998244353u64; + let iter: usize = 300000; + let mut cur = 0usize; + S[cur] = 1; + for i in 1..=iter { + let next = if cur + 1 == LEN { 0 } else { cur + 1 }; + S[next] = S[cur] * p % m; + cur = next; + if i % 10000 == 0 { + println!("power_3 [{}/{}]", i, iter); + } + } + println!("{}^{} = {}(MOD {})", p, iter, S[cur], m); + println!("Test power_3 OK!"); + 0 +} diff --git a/user/src/bin/01power_5.rs b/user/src/bin/01power_5.rs new file mode 100644 index 0000000..1bbe734 --- /dev/null +++ b/user/src/bin/01power_5.rs @@ -0,0 +1,29 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +const LEN: usize = 100; + +static mut S: [u64; LEN] = [0u64; LEN]; + +#[no_mangle] +unsafe fn main() -> i32 { + let p = 5u64; + let m = 998244353u64; + let iter: usize = 210000; + let mut cur = 0usize; + S[cur] = 1; + for i in 1..=iter { + let next = if cur + 1 == LEN { 0 } else { cur + 1 }; + S[next] = S[cur] * p % m; + cur = next; + if i % 10000 == 0 { + println!("power_5 [{}/{}]", i, iter); + } + } + println!("{}^{} = {}(MOD {})", p, iter, S[cur], m); + println!("Test power_5 OK!"); + 0 +} diff --git a/user/src/bin/02power_7.rs b/user/src/bin/02power_7.rs new file mode 100644 index 0000000..8c50344 --- /dev/null +++ b/user/src/bin/02power_7.rs @@ -0,0 +1,29 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +const LEN: usize = 100; + +static mut S: [u64; LEN] = [0u64; LEN]; + +#[no_mangle] +unsafe fn main() -> i32 { + let p = 7u64; + let m = 998244353u64; + let iter: usize = 240000; + let mut cur = 0usize; + S[cur] = 1; + for i in 1..=iter { + let next = if cur + 1 == LEN { 0 } else { cur + 1 }; + S[next] = S[cur] * p % m; + cur = next; + if i % 10000 == 0 { + println!("power_7 [{}/{}]", i, iter); + } + } + println!("{}^{} = {}(MOD {})", p, iter, S[cur], m); + println!("Test power_7 OK!"); + 0 +} diff --git a/user/src/bin/03sleep.rs b/user/src/bin/03sleep.rs new file mode 100644 index 0000000..d98c660 --- /dev/null +++ b/user/src/bin/03sleep.rs @@ -0,0 +1,24 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{get_time, yield_}; + +/// 正确输出:(无报错信息) +/// get_time OK! {...} +/// Test sleep OK! + +#[no_mangle] +fn main() -> i32 { + let current_time = get_time(); + assert!(current_time > 0); + println!("get_time OK! {}", current_time); + let wait_for = current_time + 3000; + while get_time() < wait_for { + yield_(); + } + println!("Test sleep OK!"); + 0 +} \ No newline at end of file diff --git a/user/src/bin/sleep_simple.rs b/user/src/bin/03sleep1.rs similarity index 84% rename from user/src/bin/sleep_simple.rs rename to user/src/bin/03sleep1.rs index 7015a3d..23b8060 100644 --- a/user/src/bin/sleep_simple.rs +++ b/user/src/bin/03sleep1.rs @@ -8,7 +8,6 @@ use user_lib::{get_time, sleep}; #[no_mangle] pub fn main() -> i32 { - println!("into sleep test!"); let start = get_time(); println!("current time_msec = {}", start); sleep(100); @@ -18,6 +17,6 @@ pub fn main() -> i32 { end, end - start ); - println!("r_sleep passed!"); + println!("Test sleep1 passed!"); 0 -} +} \ No newline at end of file diff --git a/user/src/bin/04load_fault.rs b/user/src/bin/04load_fault.rs new file mode 100644 index 0000000..2927e85 --- /dev/null +++ b/user/src/bin/04load_fault.rs @@ -0,0 +1,18 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use core::ptr::{null_mut, read_volatile}; + +#[no_mangle] +fn main() -> i32 { + println!("\nload_fault APP running...\n"); + println!("Into Test load_fault, we will insert an invalid load operation..."); + println!("Kernel should kill this application!"); + unsafe { + let _i = read_volatile(null_mut::()); + } + 0 +} diff --git a/user/src/bin/store_fault.rs b/user/src/bin/05store_fault.rs similarity index 68% rename from user/src/bin/store_fault.rs rename to user/src/bin/05store_fault.rs index f8023eb..0c86200 100644 --- a/user/src/bin/store_fault.rs +++ b/user/src/bin/05store_fault.rs @@ -4,12 +4,15 @@ #[macro_use] extern crate user_lib; +use core::ptr::null_mut; + #[no_mangle] fn main() -> i32 { + println!("\nstore_fault APP running...\n"); 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); + null_mut::().write_volatile(1); } 0 } 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/ch4_mmap0.rs b/user/src/bin/ch4_mmap0.rs new file mode 100644 index 0000000..5247eec --- /dev/null +++ b/user/src/bin/ch4_mmap0.rs @@ -0,0 +1,33 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::mmap; + +/* +理想结果:输出 Test 04_1 OK! +*/ + +#[no_mangle] +fn main() -> i32 { + let start: usize = 0x10000000; + let len: usize = 4096; + let prot: usize = 3; + assert_eq!(0, mmap(start, len, prot)); + for i in start..(start + len) { + let addr: *mut u8 = i as *mut u8; + unsafe { + *addr = i as u8; + } + } + for i in start..(start + len) { + let addr: *mut u8 = i as *mut u8; + unsafe { + assert_eq!(*addr, i as u8); + } + } + println!("Test 04_1 OK!"); + 0 +} diff --git a/user/src/bin/ch4_mmap1.rs b/user/src/bin/ch4_mmap1.rs new file mode 100644 index 0000000..63d6411 --- /dev/null +++ b/user/src/bin/ch4_mmap1.rs @@ -0,0 +1,25 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::mmap; + +/* +理想结果:程序触发访存异常,被杀死。不输出 error 就算过。 +*/ + +#[no_mangle] +fn main() -> i32 { + let start: usize = 0x10000000; + let len: usize = 4096; + let prot: usize = 1; + assert_eq!(0, mmap(start, len, prot)); + let addr: *mut u8 = start as *mut u8; + unsafe { + *addr = start as u8; + } + println!("Should cause error, Test 04_2 fail!"); + 0 +} diff --git a/user/src/bin/ch4_mmap2.rs b/user/src/bin/ch4_mmap2.rs new file mode 100644 index 0000000..2489fa6 --- /dev/null +++ b/user/src/bin/ch4_mmap2.rs @@ -0,0 +1,26 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::mmap; + +/* +理想结果:程序触发访存异常,被杀死。不输出 error 就算过。 +*/ + +#[no_mangle] +fn main() -> i32 { + let start: usize = 0x10000000; + let len: usize = 4096; + let prot: usize = 2; + assert_eq!(0, mmap(start, len, prot)); + let addr: *mut u8 = start as *mut u8; + unsafe { + // *addr = start as u8; // can't write, R == 0 && W == 1 is illegal in riscv + assert!(*addr != 0); + } + println!("Should cause error, Test 04_2 fail!"); + 0 +} diff --git a/user/src/bin/ch4_mmap3.rs b/user/src/bin/ch4_mmap3.rs new file mode 100644 index 0000000..d9d04b6 --- /dev/null +++ b/user/src/bin/ch4_mmap3.rs @@ -0,0 +1,25 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::mmap; + +/* +理想结果:对于错误的 mmap 返回 -1,最终输出 Test 04_4 test OK! +*/ + +#[no_mangle] +fn main() -> i32 { + let start: usize = 0x10000000; + let len: usize = 4096; + let prot: usize = 3; + assert_eq!(0, mmap(start, len, prot)); + assert_eq!(mmap(start - len, len + 1, prot), -1); + assert_eq!(mmap(start + len + 1, len, prot), -1); + assert_eq!(mmap(start + len, len, 0), -1); + assert_eq!(mmap(start + len, len, prot | 8), -1); + println!("Test 04_4 test OK!"); + 0 +} diff --git a/user/src/bin/ch4_unmap.rs b/user/src/bin/ch4_unmap.rs new file mode 100644 index 0000000..b64f862 --- /dev/null +++ b/user/src/bin/ch4_unmap.rs @@ -0,0 +1,36 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{mmap, munmap}; + +/* +理想结果:输出 Test 04_5 ummap OK! +*/ + +#[no_mangle] +fn main() -> i32 { + let start: usize = 0x10000000; + let len: usize = 4096; + let prot: usize = 3; + assert_eq!(0, mmap(start, len, prot)); + assert_eq!(mmap(start + len, len * 2, prot), 0); + assert_eq!(munmap(start, len), 0); + assert_eq!(mmap(start - len, len + 1, prot), 0); + for i in (start - len)..(start + len * 3) { + let addr: *mut u8 = i as *mut u8; + unsafe { + *addr = i as u8; + } + } + for i in (start - len)..(start + len * 3) { + let addr: *mut u8 = i as *mut u8; + unsafe { + assert_eq!(*addr, i as u8); + } + } + println!("Test 04_5 ummap OK!"); + 0 +} diff --git a/user/src/bin/ch4_unmap2.rs b/user/src/bin/ch4_unmap2.rs new file mode 100644 index 0000000..85ddb75 --- /dev/null +++ b/user/src/bin/ch4_unmap2.rs @@ -0,0 +1,23 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{mmap, munmap}; + +/* +理想结果:输出 Test 04_6 ummap2 OK! +*/ + +#[no_mangle] +fn main() -> i32 { + let start: usize = 0x10000000; + let len: usize = 4096; + let prot: usize = 3; + assert_eq!(0, mmap(start, len, prot)); + assert_eq!(munmap(start, len + 1), -1); + assert_eq!(munmap(start + 1, len - 1), -1); + println!("Test 04_6 ummap2 OK!"); + 0 +} diff --git a/user/src/bin/ch4b_sbrk.rs b/user/src/bin/ch4b_sbrk.rs new file mode 100644 index 0000000..72bffe2 --- /dev/null +++ b/user/src/bin/ch4b_sbrk.rs @@ -0,0 +1,47 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::sbrk; +use core::ptr::slice_from_raw_parts_mut; + +#[no_mangle] +fn main() -> i32 { + println!("Test sbrk start."); + const PAGE_SIZE: usize = 0x1000; + let origin_brk = sbrk(0); + println!("origin break point = {:x}", origin_brk); + let brk = sbrk(PAGE_SIZE as i32); + if brk != origin_brk { + return -1 + } + let brk = sbrk(0); + println!("one page allocated, break point = {:x}", brk); + println!("try write to allocated page"); + let new_page = unsafe { &mut *slice_from_raw_parts_mut(origin_brk as usize as *const u8 as *mut u8, PAGE_SIZE) }; + for pos in 0..PAGE_SIZE { + new_page[pos] = 1; + } + println!("write ok"); + sbrk(PAGE_SIZE as i32 * 10); + let brk = sbrk(0); + println!("10 page allocated, break point = {:x}", brk); + sbrk(PAGE_SIZE as i32 * -11); + let brk = sbrk(0); + println!("11 page DEALLOCATED, break point = {:x}", brk); + println!("try DEALLOCATED more one page, should be failed."); + let ret = sbrk(PAGE_SIZE as i32 * -1); + if ret != -1 { + println!("Test sbrk failed!"); + return -1 + } + println!("Test sbrk almost OK!"); + println!("now write to deallocated page, should cause page fault."); + for pos in 0..PAGE_SIZE { + new_page[pos] = 2; + } + println!("Test sbrk failed!"); + 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 deleted file mode 100644 index 60510c9..0000000 --- a/user/src/bin/exit.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -use user_lib::{exit, fork, wait, waitpid, yield_}; - -const MAGIC: i32 = -0x10384; - -#[no_mangle] -pub fn main() -> i32 { - println!("I am the parent. Forking the child..."); - let pid = fork(); - if pid == 0 { - println!("I am the child."); - for _ in 0..7 { - yield_(); - } - exit(MAGIC); - } else { - println!("I am parent, fork a child pid {}", pid); - } - println!("I am the parent, waiting now.."); - let mut xstate: i32 = 0; - assert!(waitpid(pid as usize, &mut xstate) == pid && xstate == MAGIC); - assert!(waitpid(pid as usize, &mut xstate) < 0 && wait(&mut xstate) <= 0); - println!("waitpid {} ok.", pid); - println!("exit pass."); - 0 -} diff --git a/user/src/bin/fantastic_text.rs b/user/src/bin/fantastic_text.rs deleted file mode 100644 index a3402ff..0000000 --- a/user/src/bin/fantastic_text.rs +++ /dev/null @@ -1,44 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -macro_rules! color_text { - ($text:expr, $color:expr) => {{ - format_args!("\x1b[{}m{}\x1b[0m", $color, $text) - }}; -} - -#[no_mangle] -pub fn main() -> i32 { - println!( - "{}{}{}{}{} {}{}{}{} {}{}{}{}{}{}", - color_text!("H", 31), - color_text!("e", 32), - color_text!("l", 33), - color_text!("l", 34), - color_text!("o", 35), - color_text!("R", 36), - color_text!("u", 37), - color_text!("s", 90), - color_text!("t", 91), - color_text!("u", 92), - color_text!("C", 93), - color_text!("o", 94), - color_text!("r", 95), - color_text!("e", 96), - color_text!("!", 97), - ); - - let text = - "reguler \x1b[4munderline\x1b[24m \x1b[7mreverse\x1b[27m \x1b[9mstrikethrough\x1b[29m"; - println!("\x1b[47m{}\x1b[0m", color_text!(text, 30)); - for i in 31..38 { - println!("{}", color_text!(text, i)); - } - for i in 90..98 { - println!("{}", color_text!(text, i)); - } - 0 -} diff --git a/user/src/bin/filetest_simple.rs b/user/src/bin/filetest_simple.rs deleted file mode 100644 index 3406d55..0000000 --- a/user/src/bin/filetest_simple.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{close, open, read, write, OpenFlags}; - -#[no_mangle] -pub fn main() -> i32 { - let test_str = "Hello, world!"; - let filea = "filea\0"; - let fd = open(filea, OpenFlags::CREATE | OpenFlags::WRONLY); - assert!(fd > 0); - let fd = fd as usize; - write(fd, test_str.as_bytes()); - close(fd); - - let fd = open(filea, OpenFlags::RDONLY); - assert!(fd > 0); - let fd = fd as usize; - let mut buffer = [0u8; 100]; - let read_len = read(fd, &mut buffer) as usize; - close(fd); - - assert_eq!(test_str, core::str::from_utf8(&buffer[..read_len]).unwrap(),); - println!("file_test passed!"); - 0 -} diff --git a/user/src/bin/forktest.rs b/user/src/bin/forktest.rs deleted file mode 100644 index 5374a56..0000000 --- a/user/src/bin/forktest.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{exit, fork, wait}; - -const MAX_CHILD: usize = 30; - -#[no_mangle] -pub fn main() -> i32 { - for i in 0..MAX_CHILD { - let pid = fork(); - if pid == 0 { - println!("I am child {}", i); - exit(0); - } else { - println!("forked child pid = {}", pid); - } - assert!(pid > 0); - } - let mut exit_code: i32 = 0; - for _ in 0..MAX_CHILD { - if wait(&mut exit_code) <= 0 { - panic!("wait stopped early"); - } - } - if wait(&mut exit_code) > 0 { - panic!("wait got too many"); - } - println!("forktest pass."); - 0 -} diff --git a/user/src/bin/forktest2.rs b/user/src/bin/forktest2.rs deleted file mode 100644 index c91ce15..0000000 --- a/user/src/bin/forktest2.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{exit, fork, get_time, getpid, sleep, wait}; - -static NUM: usize = 30; - -#[no_mangle] -pub fn main() -> i32 { - for _ in 0..NUM { - let pid = fork(); - if pid == 0 { - let current_time = get_time(); - let sleep_length = - (current_time as i32 as isize) * (current_time as i32 as isize) % 1000 + 1000; - println!("pid {} sleep for {} ms", getpid(), sleep_length); - sleep(sleep_length as usize); - println!("pid {} OK!", getpid()); - exit(0); - } - } - - let mut exit_code: i32 = 0; - for _ in 0..NUM { - assert!(wait(&mut exit_code) > 0); - assert_eq!(exit_code, 0); - } - assert!(wait(&mut exit_code) < 0); - println!("forktest2 test passed!"); - 0 -} diff --git a/user/src/bin/forktest_simple.rs b/user/src/bin/forktest_simple.rs deleted file mode 100644 index 29a624b..0000000 --- a/user/src/bin/forktest_simple.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{fork, getpid, wait}; - -#[no_mangle] -pub fn main() -> i32 { - assert_eq!(wait(&mut 0i32), -1); - println!("sys_wait without child process test passed!"); - println!("parent start, pid = {}!", getpid()); - let pid = fork(); - if pid == 0 { - // child process - println!("hello child process!"); - 100 - } else { - // parent process - let mut exit_code: i32 = 0; - println!("ready waiting on parent process!"); - assert_eq!(pid, wait(&mut exit_code)); - assert_eq!(exit_code, 100); - println!("child process pid = {}, exit code = {}", pid, exit_code); - 0 - } -} diff --git a/user/src/bin/forktree.rs b/user/src/bin/forktree.rs deleted file mode 100644 index 6b120ee..0000000 --- a/user/src/bin/forktree.rs +++ /dev/null @@ -1,45 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{exit, fork, getpid, sleep, wait, yield_}; - -const DEPTH: usize = 4; - -fn fork_child(cur: &str, branch: char) { - let mut next = [0u8; DEPTH + 1]; - let l = cur.len(); - if l >= DEPTH { - return; - } - next[..l].copy_from_slice(cur.as_bytes()); - next[l] = branch as u8; - if fork() == 0 { - fork_tree(core::str::from_utf8(&next[..l + 1]).unwrap()); - yield_(); - exit(0); - } -} - -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] -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 deleted file mode 100644 index 10d3f26..0000000 --- a/user/src/bin/hello_world.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -#[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 deleted file mode 100644 index 2a977c9..0000000 --- a/user/src/bin/huge_write.rs +++ /dev/null @@ -1,33 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{close, get_time, open, write, OpenFlags}; - -#[no_mangle] -pub fn main() -> i32 { - let mut buffer = [0u8; 1024]; // 1KiB - for (i, ch) in buffer.iter_mut().enumerate() { - *ch = i as u8; - } - let f = open("testf\0", OpenFlags::CREATE | OpenFlags::WRONLY); - if f < 0 { - panic!("Open test file failed!"); - } - let f = f as usize; - let start = get_time(); - let size_mb = 1usize; - for _ in 0..1024 * size_mb { - write(f, &buffer); - } - close(f); - let time_ms = (get_time() - start) as usize; - let speed_kbs = (size_mb << 20) / time_ms; - println!( - "{}MiB written, time cost = {}ms, write speed = {}KiB/s", - size_mb, time_ms, speed_kbs - ); - 0 -} 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 deleted file mode 100644 index d25aee1..0000000 --- a/user/src/bin/initproc.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![no_std] -#![no_main] - -extern crate user_lib; - -use user_lib::{exec, fork, wait, yield_}; - -#[no_mangle] -fn main() -> i32 { - if fork() == 0 { - exec("user_shell\0", &[core::ptr::null::()]); - } else { - loop { - let mut exit_code: i32 = 0; - let pid = wait(&mut exit_code); - if pid == -1 { - yield_(); - continue; - } - /* - println!( - "[initproc] Released a zombie process, 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 deleted file mode 100644 index 9ebf48f..0000000 --- a/user/src/bin/matrix.rs +++ /dev/null @@ -1,69 +0,0 @@ -#![no_std] -#![no_main] -#![allow(clippy::needless_range_loop)] - -#[macro_use] -extern crate user_lib; - -use user_lib::{exit, fork, get_time, getpid, wait, yield_}; - -static NUM: usize = 30; -const N: usize = 10; -static P: i32 = 10007; -type Arr = [[i32; N]; N]; - -fn work(times: isize) { - let mut a: Arr = Default::default(); - let mut b: Arr = Default::default(); - let mut c: Arr = Default::default(); - for i in 0..N { - for j in 0..N { - a[i][j] = 1; - b[i][j] = 1; - } - } - yield_(); - println!("pid {} is running ({} times)!.", getpid(), times); - for _ in 0..times { - for i in 0..N { - for j in 0..N { - c[i][j] = 0; - for k in 0..N { - c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % P; - } - } - } - for i in 0..N { - for j in 0..N { - a[i][j] = c[i][j]; - b[i][j] = c[i][j]; - } - } - } - println!("pid {} done!.", getpid()); - exit(0); -} - -#[no_mangle] -pub fn main() -> i32 { - for _ in 0..NUM { - let pid = fork(); - if pid == 0 { - let current_time = get_time(); - let times = (current_time as i32 as isize) * (current_time as i32 as isize) % 1000; - work(times * 10); - } - } - - println!("fork ok."); - - let mut exit_code: i32 = 0; - for _ in 0..NUM { - if wait(&mut exit_code) < 0 { - panic!("wait failed."); - } - } - assert!(wait(&mut exit_code) < 0); - println!("matrix passed."); - 0 -} 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/sbrk_test.rs b/user/src/bin/sbrk_test.rs new file mode 100644 index 0000000..780693d --- /dev/null +++ b/user/src/bin/sbrk_test.rs @@ -0,0 +1,48 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use core::ptr::slice_from_raw_parts_mut; +use user_lib::sbrk; + +#[no_mangle] +fn main() -> i32 { + println!("Test sbrk start."); + const PAGE_SIZE: usize = 0x1000; + let origin_brk = sbrk(0); + println!("origin break point = {:x}", origin_brk); + let brk = sbrk(PAGE_SIZE as i32); + if brk != origin_brk { + return -1; + } + let brk = sbrk(0); + println!("one page allocated, break point = {:x}", brk); + println!("try write to allocated page"); + let new_page = unsafe { + &mut *slice_from_raw_parts_mut(origin_brk as usize as *const u8 as *mut u8, PAGE_SIZE) + }; + for pos in 0..PAGE_SIZE { + new_page[pos] = 1; + } + println!("write ok"); + sbrk(PAGE_SIZE as i32 * 10); + let brk = sbrk(0); + println!("10 page allocated, break point = {:x}", brk); + sbrk(PAGE_SIZE as i32 * -11); + let brk = sbrk(0); + println!("11 page DEALLOCATED, break point = {:x}", brk); + println!("try DEALLOCATED more one page, should be failed."); + let ret = sbrk(PAGE_SIZE as i32 * -1); + if ret != -1 { + println!("Test sbrk failed!"); + return -1; + } + println!("Test sbrk almost OK!"); + println!("now write to deallocated page, should cause page fault."); + for pos in 0..PAGE_SIZE { + new_page[pos] = 2; + } + 0 +} diff --git a/user/src/bin/sleep.rs b/user/src/bin/sleep.rs deleted file mode 100644 index 641a4f9..0000000 --- a/user/src/bin/sleep.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{exit, fork, get_time, sleep, waitpid}; - -fn sleepy() { - let time: usize = 100; - for i in 0..5 { - sleep(time); - println!("sleep {} x {} msecs.", i + 1, time); - } - exit(0); -} - -#[no_mangle] -pub fn main() -> i32 { - let current_time = get_time(); - let pid = fork(); - let mut exit_code: i32 = 0; - if pid == 0 { - sleepy(); - } - assert!(waitpid(pid as usize, &mut exit_code) == pid && exit_code == 0); - println!("use {} msecs.", get_time() - current_time); - println!("sleep pass."); - 0 -} diff --git a/user/src/bin/stack_overflow.rs b/user/src/bin/stack_overflow.rs deleted file mode 100644 index 3bec557..0000000 --- a/user/src/bin/stack_overflow.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -#[allow(unconditional_recursion)] -fn f(depth: usize) { - if depth % 10 == 0 { - println!("depth = {}", depth); - } - f(depth + 1); -} - -#[no_mangle] -pub fn main() -> i32 { - println!("It should trigger segmentation fault!"); - f(0); - 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/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 deleted file mode 100644 index 4288248..0000000 --- a/user/src/bin/user_shell.rs +++ /dev/null @@ -1,214 +0,0 @@ -#![no_std] -#![no_main] -#![allow(clippy::println_empty_string)] - -extern crate alloc; - -#[macro_use] -extern crate user_lib; - -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}; - -#[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] -pub fn main() -> i32 { - println!("Rust user shell"); - let mut line: String = String::new(); - print!("{}", LINE_START); - 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; - } - } - if process_arguments_list.len() == 1 { - valid = true; - } - if !valid { - println!("Invalid command: Inputs/Outputs cannot be correctly binded!"); - } 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); - } - } - line.clear(); - } - print!("{}", LINE_START); - } - BS | DL => { - if !line.is_empty() { - print!("{}", BS as char); - print!(" "); - print!("{}", BS as char); - line.pop(); - } - } - _ => { - print!("{}", c as char); - line.push(c as char); - } - } - } -} diff --git a/user/src/bin/usertests.rs b/user/src/bin/usertests.rs deleted file mode 100644 index b522af2..0000000 --- a/user/src/bin/usertests.rs +++ /dev/null @@ -1,145 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -// not in SUCC_TESTS & FAIL_TESTS -// count_lines, infloop, user_shell, usertests - -// 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), - ("exit\0", "\0", "\0", "\0", 0), - ("fantastic_text\0", "\0", "\0", "\0", 0), - ("forktest_simple\0", "\0", "\0", "\0", 0), - ("forktest\0", "\0", "\0", "\0", 0), - ("forktest2\0", "\0", "\0", "\0", 0), - ("forktree\0", "\0", "\0", "\0", 0), - ("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), -]; - -use user_lib::{exec, fork, waitpid}; - -fn run_tests(tests: &[(&str, &str, &str, &str, i32)]) -> i32 { - let mut pass_num = 0; - let mut arr: [*const u8; 4] = [ - core::ptr::null::(), - core::ptr::null::(), - core::ptr::null::(), - core::ptr::null::(), - ]; - - for test in tests { - println!("Usertests: Running {}", test.0); - arr[0] = test.0.as_ptr(); - if test.1 != "\0" { - arr[1] = test.1.as_ptr(); - arr[2] = core::ptr::null::(); - arr[3] = core::ptr::null::(); - if test.2 != "\0" { - arr[2] = test.2.as_ptr(); - arr[3] = core::ptr::null::(); - if test.3 != "\0" { - arr[3] = test.3.as_ptr(); - } else { - arr[3] = core::ptr::null::(); - } - } else { - arr[2] = core::ptr::null::(); - arr[3] = core::ptr::null::(); - } - } else { - arr[1] = core::ptr::null::(); - arr[2] = core::ptr::null::(); - arr[3] = core::ptr::null::(); - } - - let pid = fork(); - if pid == 0 { - exec(test.0, &arr[..]); - 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); - if exit_code == test.4 { - // summary apps with exit_code - pass_num = pass_num + 1; - } - println!( - "\x1b[32mUsertests: Test {} in Process {} exited with code {}\x1b[0m", - test.0, pid, exit_code - ); - } - } - pass_num -} - -#[no_mangle] -pub fn main() -> i32 { - let succ_num = run_tests(SUCC_TESTS); - let err_num = run_tests(FAIL_TESTS); - if succ_num == SUCC_TESTS.len() as i32 && err_num == FAIL_TESTS.len() as i32 { - println!( - "{} of sueecssed apps, {} of failed apps run correctly. \nUsertests passed!", - SUCC_TESTS.len(), - FAIL_TESTS.len() - ); - return 0; - } - if succ_num != SUCC_TESTS.len() as i32 { - println!( - "all successed app_num is {} , but only passed {}", - SUCC_TESTS.len(), - succ_num - ); - } - if err_num != FAIL_TESTS.len() as i32 { - println!( - "all failed app_num is {} , but only passed {}", - FAIL_TESTS.len(), - err_num - ); - } - println!(" Usertests failed!"); - return -1; -} diff --git a/user/src/bin/yield.rs b/user/src/bin/yield.rs deleted file mode 100644 index 78b1468..0000000 --- a/user/src/bin/yield.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -use user_lib::{getpid, yield_}; - -#[no_mangle] -pub fn main() -> i32 { - println!("Hello, I am process {}.", getpid()); - for i in 0..5 { - yield_(); - println!("Back in process {}, iteration {}.", getpid(), i); - } - println!("yield pass."); - 0 -} diff --git a/user/src/console.rs b/user/src/console.rs index 810ebba..d37e867 100644 --- a/user/src/console.rs +++ b/user/src/console.rs @@ -1,12 +1,10 @@ +use super::write; use core::fmt::{self, Write}; -const STDIN: usize = 0; -const STDOUT: usize = 1; - -use super::{read, write}; - struct Stdout; +const STDOUT: usize = 1; + impl Write for Stdout { fn write_str(&mut self, s: &str) -> fmt::Result { write(STDOUT, s.as_bytes()); @@ -31,9 +29,3 @@ macro_rules! println { $crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?)); } } - -pub fn getchar() -> u8 { - let mut c = [0u8; 1]; - read(STDIN, &mut c); - c[0] -} 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..3aee17b 100644 --- a/user/src/lang_items.rs +++ b/user/src/lang_items.rs @@ -1,5 +1,3 @@ -use super::{getpid, kill, SignalFlags}; - #[panic_handler] fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! { let err = panic_info.message().unwrap(); @@ -13,6 +11,5 @@ fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! { } else { println!("Panicked: {}", err); } - kill(getpid() as usize, SignalFlags::SIGABRT.bits()); - unreachable!() + loop {} } diff --git a/user/src/lib.rs b/user/src/lib.rs index 8c709fc..9d39c52 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -1,92 +1,72 @@ #![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 syscall::*; -pub use task::*; - -const USER_HEAP_SIZE: usize = 32768; - -static mut HEAP_SPACE: [u8; USER_HEAP_SIZE] = [0; USER_HEAP_SIZE]; - -#[global_allocator] -static HEAP: LockedHeap = LockedHeap::empty(); - -#[alloc_error_handler] -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 { - HEAP.lock() - .init(HEAP_SPACE.as_ptr() 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())); +pub extern "C" fn _start() -> ! { + exit(main()); + panic!("unreachable after sys_exit!"); } #[linkage = "weak"] #[no_mangle] -fn main(_argc: usize, _argv: &[&str]) -> i32 { +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); } - }; +#[repr(C)] +#[derive(Debug, Default)] +pub struct TimeVal { + pub sec: usize, + pub usec: usize, } -#[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)) } - }; +impl TimeVal { + pub fn new() -> Self { + Self::default() + } } -#[macro_export] -macro_rules! memory_fence { - () => { - core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst) - }; +use syscall::*; + +pub fn write(fd: usize, buf: &[u8]) -> isize { + sys_write(fd, buf) } +pub fn exit(exit_code: i32) -> isize { + sys_exit(exit_code) +} +pub fn yield_() -> isize { + sys_yield() +} +pub fn get_time() -> isize { + let time = TimeVal::new(); + match sys_get_time(&time, 0) { + 0 => ((time.sec & 0xffff) * 1000 + time.usec / 1000) as isize, + _ => -1, + } +} + +pub fn sbrk(size: i32) -> isize { + sys_sbrk(size) +} + +pub fn munmap(start: usize, len: usize) -> isize { + sys_munmap(start, len) +} + +pub fn mmap(start: usize, len: usize, prot: usize) -> isize { + sys_mmap(start, len, prot) +} + +pub fn sleep(period_ms: usize) { + let start = get_time(); + while get_time() < start + period_ms as isize { + sys_yield(); + } +} \ No newline at end of file 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..9ce185d 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -1,42 +1,19 @@ -const SYSCALL_DUP: usize = 24; -const SYSCALL_CONNECT: usize = 29; -const SYSCALL_LISTEN: usize = 30; -const SYSCALL_ACCEPT: usize = 31; -const SYSCALL_OPEN: usize = 56; -const SYSCALL_CLOSE: usize = 57; -const SYSCALL_PIPE: usize = 59; -const SYSCALL_READ: usize = 63; +use core::arch::asm; + +use crate::TimeVal; + 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; +const SYSCALL_SBRK: usize = 214; +const SYSCALL_MMAP: usize = 222; +const SYSCALL_MUNMAP: usize = 215; 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,149 +24,30 @@ 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]) -} - -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, - [fd, buffer.as_mut_ptr() as usize, buffer.len()], - ) -} - pub fn sys_write(fd: usize, buffer: &[u8]) -> isize { syscall(SYSCALL_WRITE, [fd, buffer.as_ptr() as usize, buffer.len()]) } -pub fn sys_exit(exit_code: i32) -> ! { - syscall(SYSCALL_EXIT, [exit_code as usize, 0, 0]); - panic!("sys_exit never returns!"); -} - -pub fn sys_sleep(sleep_ms: usize) -> isize { - syscall(SYSCALL_SLEEP, [sleep_ms, 0, 0]) +pub fn sys_exit(exit_code: i32) -> isize { + syscall(SYSCALL_EXIT, [exit_code as usize, 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(time: &TimeVal, tz: usize) -> isize { + syscall(SYSCALL_GET_TIME, [time as *const _ as usize, tz, 0]) } -pub fn sys_get_time() -> isize { - syscall(SYSCALL_GET_TIME, [0, 0, 0]) +pub fn sys_sbrk(size: i32) -> isize { + syscall(SYSCALL_SBRK, [size as usize, 0, 0]) } -pub fn sys_getpid() -> isize { - syscall(SYSCALL_GETPID, [0, 0, 0]) +pub fn sys_mmap(start: usize, len: usize, prot: usize) -> isize { + syscall(SYSCALL_MMAP, [start, len, prot]) } -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_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]) +pub fn sys_munmap(start: usize, len: usize) -> isize { + syscall(SYSCALL_MUNMAP, [start, len, 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, - } - } -}