diff --git a/.gitignore b/.gitignore index 74b65454..489e9b75 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ os/target/* os/.idea/* os/src/link_app.S +os/last-* os/Cargo.lock user/target/* user/.idea/* diff --git a/easy-fs-fuse/src/main.rs b/easy-fs-fuse/src/main.rs index 498b61ec..d36d566d 100644 --- a/easy-fs-fuse/src/main.rs +++ b/easy-fs-fuse/src/main.rs @@ -56,13 +56,13 @@ fn easy_fs_pack() -> std::io::Result<()> { .write(true) .create(true) .open(format!("{}{}", target_path, "fs.img"))?; - f.set_len(8192 * 512).unwrap(); + f.set_len(128 * 2048 * 512).unwrap(); f }))); - // 4MiB, at most 4095 files + // 128MiB, at most 4095 files let efs = EasyFileSystem::create( block_file.clone(), - 8192, + 128 * 2048, 1, ); let root_inode = Arc::new(EasyFileSystem::root_inode(&efs)); @@ -165,4 +165,4 @@ fn efs_test() -> std::io::Result<()> { random_str_test(2000 * BLOCK_SZ); Ok(()) -} \ No newline at end of file +} diff --git a/easy-fs/src/block_cache.rs b/easy-fs/src/block_cache.rs index 57265812..ba945b1d 100644 --- a/easy-fs/src/block_cache.rs +++ b/easy-fs/src/block_cache.rs @@ -17,7 +17,7 @@ pub struct BlockCache { impl BlockCache { /// Load a new BlockCache from disk. pub fn new( - block_id: usize, + block_id: usize, block_device: Arc ) -> Self { let mut cache = [0u8; BLOCK_SZ]; @@ -125,4 +125,11 @@ pub fn get_block_cache( block_device: Arc ) -> Arc> { BLOCK_CACHE_MANAGER.lock().get_block_cache(block_id, block_device) -} \ No newline at end of file +} + +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/efs.rs b/easy-fs/src/efs.rs index 4cc541e4..8b7adf26 100644 --- a/easy-fs/src/efs.rs +++ b/easy-fs/src/efs.rs @@ -8,6 +8,7 @@ use super::{ DiskInodeType, Inode, get_block_cache, + block_cache_sync_all, }; use crate::BLOCK_SZ; @@ -50,7 +51,7 @@ impl EasyFileSystem { // clear all blocks for i in 0..total_blocks { get_block_cache( - i as usize, + i as usize, Arc::clone(&block_device) ) .lock() @@ -82,6 +83,7 @@ impl EasyFileSystem { .modify(root_inode_offset, |disk_inode: &mut DiskInode| { disk_inode.initialize(DiskInodeType::Directory); }); + block_cache_sync_all(); Arc::new(Mutex::new(efs)) } @@ -107,7 +109,7 @@ impl EasyFileSystem { 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 { diff --git a/easy-fs/src/layout.rs b/easy-fs/src/layout.rs index 8ad3b847..c6f7b315 100644 --- a/easy-fs/src/layout.rs +++ b/easy-fs/src/layout.rs @@ -231,7 +231,7 @@ impl DiskInode { b0 = 0; a0 += 1; } - } + } }); } @@ -416,7 +416,7 @@ impl DirEntry { } pub fn new(name: &str, inode_number: u32) -> Self { let mut bytes = [0u8; NAME_LENGTH_LIMIT + 1]; - &mut bytes[..name.len()].copy_from_slice(name.as_bytes()); + bytes[..name.len()].copy_from_slice(name.as_bytes()); Self { name: bytes, inode_number, diff --git a/easy-fs/src/lib.rs b/easy-fs/src/lib.rs index 10a5af76..afb957ac 100644 --- a/easy-fs/src/lib.rs +++ b/easy-fs/src/lib.rs @@ -15,4 +15,4 @@ pub use efs::EasyFileSystem; pub use vfs::Inode; use layout::*; use bitmap::Bitmap; -use block_cache::get_block_cache; \ No newline at end of file +use block_cache::{get_block_cache, block_cache_sync_all}; \ No newline at end of file diff --git a/easy-fs/src/vfs.rs b/easy-fs/src/vfs.rs index de4f41db..9534c39a 100644 --- a/easy-fs/src/vfs.rs +++ b/easy-fs/src/vfs.rs @@ -6,6 +6,7 @@ use super::{ EasyFileSystem, DIRENT_SZ, get_block_cache, + block_cache_sync_all, }; use alloc::sync::Arc; use alloc::string::String; @@ -145,6 +146,7 @@ impl Inode { }); 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, @@ -185,10 +187,12 @@ impl Inode { pub fn write_at(&self, offset: usize, buf: &[u8]) -> usize { let mut fs = self.fs.lock(); - self.modify_disk_inode(|disk_inode| { + 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) { @@ -201,5 +205,6 @@ impl Inode { fs.dealloc_data(data_block); } }); + block_cache_sync_all(); } } diff --git a/os/Cargo.toml b/os/Cargo.toml index bded6409..b07fa034 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -10,7 +10,6 @@ edition = "2018" riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } lazy_static = { version = "1.4.0", features = ["spin_no_std"] } buddy_system_allocator = "0.6" -spin = "0.7.0" bitflags = "1.2.1" xmas-elf = "0.7.0" virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers" } diff --git a/os/Makefile b/os/Makefile index a23f6cf3..07c10082 100644 --- a/os/Makefile +++ b/os/Makefile @@ -32,7 +32,14 @@ OBJCOPY := rust-objcopy --binary-architecture=riscv64 # Disassembly DISASM ?= -x -build: env $(KERNEL_BIN) $(FS_IMG) +build: env switch-check $(KERNEL_BIN) fs-img + +switch-check: +ifeq ($(BOARD), qemu) + (which last-qemu) || (rm last-k210 -f && touch last-qemu && make clean) +else ifeq ($(BOARD), k210) + (which last-k210) || (rm last-qemu -f && touch last-k210 && make clean) +endif env: (rustup target list | grep "riscv64gc-unknown-none-elf (installed)") || rustup target add $(TARGET) @@ -40,16 +47,17 @@ env: rustup component add rust-src rustup component add llvm-tools-preview -sdcard: $(FS_IMG) +sdcard: fs-img @echo "Are you sure write to $(SDCARD) ? [y/N] " && read ans && [ $${ans:-N} = y ] - @sudo dd if=/dev/zero of=$(SDCARD) bs=1048576 count=16 + @sudo dd if=/dev/zero of=$(SDCARD) bs=1048576 count=256 @sudo dd if=$(FS_IMG) of=$(SDCARD) $(KERNEL_BIN): kernel @$(OBJCOPY) $(KERNEL_ELF) --strip-all -O binary $@ -$(FS_IMG): $(APPS) +fs-img: $(APPS) @cd ../user && make build + @rm $(FS_IMG) @cd ../easy-fs-fuse && cargo run --release -- -s ../user/src/bin/ -t ../user/target/riscv64gc-unknown-none-elf/release/ $(APPS): @@ -73,8 +81,6 @@ disasm-vim: kernel run: run-inner - - run-inner: build ifeq ($(BOARD),qemu) @qemu-system-riscv64 \ @@ -100,4 +106,4 @@ debug: build tmux split-window -h "riscv64-unknown-elf-gdb -ex 'file $(KERNEL_ELF)' -ex 'set arch riscv:rv64' -ex 'target remote localhost:1234'" && \ tmux -2 attach-session -d -.PHONY: build env kernel clean disasm disasm-vim run-inner +.PHONY: build env kernel clean disasm disasm-vim run-inner switch-check fs-img diff --git a/os/src/drivers/block/sdcard.rs b/os/src/drivers/block/sdcard.rs index efc377b1..e550cc01 100644 --- a/os/src/drivers/block/sdcard.rs +++ b/os/src/drivers/block/sdcard.rs @@ -13,7 +13,7 @@ use k210_soc::{ sysctl, sleep::usleep, }; -use spin::Mutex; +use crate::sync::UPSafeCell; use lazy_static::*; use super::BlockDevice; use core::convert::TryInto; @@ -711,7 +711,9 @@ fn io_init() { } lazy_static! { - static ref PERIPHERALS: Mutex = Mutex::new(Peripherals::take().unwrap()); + static ref PERIPHERALS: UPSafeCell = unsafe { + UPSafeCell::new(Peripherals::take().unwrap()) + }; } fn init_sdcard() -> SDCard> { @@ -735,19 +737,19 @@ fn init_sdcard() -> SDCard> { sd } -pub struct SDCardWrapper(Mutex>>); +pub struct SDCardWrapper(UPSafeCell>>); impl SDCardWrapper { pub fn new() -> Self { - Self(Mutex::new(init_sdcard())) + unsafe { Self(UPSafeCell::new(init_sdcard())) } } } impl BlockDevice for SDCardWrapper { fn read_block(&self, block_id: usize, buf: &mut [u8]) { - self.0.lock().read_sector(buf,block_id as u32).unwrap(); + self.0.exclusive_access().read_sector(buf,block_id as u32).unwrap(); } fn write_block(&self, block_id: usize, buf: &[u8]) { - self.0.lock().write_sector(buf,block_id as u32).unwrap(); + self.0.exclusive_access().write_sector(buf,block_id as u32).unwrap(); } } \ No newline at end of file diff --git a/os/src/drivers/block/virtio_blk.rs b/os/src/drivers/block/virtio_blk.rs index fde3428c..ed344342 100644 --- a/os/src/drivers/block/virtio_blk.rs +++ b/os/src/drivers/block/virtio_blk.rs @@ -12,34 +12,42 @@ use crate::mm::{ kernel_token, }; use super::BlockDevice; -use spin::Mutex; +use crate::sync::UPSafeCell; use alloc::vec::Vec; use lazy_static::*; #[allow(unused)] const VIRTIO0: usize = 0x10001000; -pub struct VirtIOBlock(Mutex>); +pub struct VirtIOBlock(UPSafeCell>); lazy_static! { - static ref QUEUE_FRAMES: Mutex> = Mutex::new(Vec::new()); + static ref QUEUE_FRAMES: UPSafeCell> = unsafe { + UPSafeCell::new(Vec::new()) + }; } impl BlockDevice for VirtIOBlock { fn read_block(&self, block_id: usize, buf: &mut [u8]) { - self.0.lock().read_block(block_id, buf).expect("Error when reading VirtIOBlk"); + self.0.exclusive_access() + .read_block(block_id, buf) + .expect("Error when reading VirtIOBlk"); } fn write_block(&self, block_id: usize, buf: &[u8]) { - self.0.lock().write_block(block_id, buf).expect("Error when writing VirtIOBlk"); + self.0.exclusive_access() + .write_block(block_id, buf) + .expect("Error when writing VirtIOBlk"); } } impl VirtIOBlock { #[allow(unused)] pub fn new() -> Self { - Self(Mutex::new(VirtIOBlk::new( - unsafe { &mut *(VIRTIO0 as *mut VirtIOHeader) } - ).unwrap())) + unsafe { + Self(UPSafeCell::new(VirtIOBlk::new( + &mut *(VIRTIO0 as *mut VirtIOHeader) + ).unwrap())) + } } } @@ -50,7 +58,7 @@ pub extern "C" fn virtio_dma_alloc(pages: usize) -> PhysAddr { let frame = frame_alloc().unwrap(); if i == 0 { ppn_base = frame.ppn; } assert_eq!(frame.ppn.0, ppn_base.0 + i); - QUEUE_FRAMES.lock().push(frame); + QUEUE_FRAMES.exclusive_access().push(frame); } ppn_base.into() } diff --git a/os/src/fs/inode.rs b/os/src/fs/inode.rs index 04ccb45f..f03225b6 100644 --- a/os/src/fs/inode.rs +++ b/os/src/fs/inode.rs @@ -3,18 +3,18 @@ use easy_fs::{ Inode, }; use crate::drivers::BLOCK_DEVICE; +use crate::sync::UPSafeCell; use alloc::sync::Arc; use lazy_static::*; use bitflags::*; use alloc::vec::Vec; -use spin::Mutex; use super::File; use crate::mm::UserBuffer; pub struct OSInode { readable: bool, writable: bool, - inner: Mutex, + inner: UPSafeCell, } pub struct OSInodeInner { @@ -31,14 +31,14 @@ impl OSInode { Self { readable, writable, - inner: Mutex::new(OSInodeInner { + inner: unsafe { UPSafeCell::new(OSInodeInner { offset: 0, inode, - }), + })}, } } pub fn read_all(&self) -> Vec { - let mut inner = self.inner.lock(); + let mut inner = self.inner.exclusive_access(); let mut buffer = [0u8; 512]; let mut v: Vec = Vec::new(); loop { @@ -133,7 +133,7 @@ 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.lock(); + 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); @@ -146,7 +146,7 @@ impl File for OSInode { total_read_size } fn write(&self, buf: UserBuffer) -> usize { - let mut inner = self.inner.lock(); + 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); diff --git a/os/src/fs/pipe.rs b/os/src/fs/pipe.rs index 1027b472..ed2dde15 100644 --- a/os/src/fs/pipe.rs +++ b/os/src/fs/pipe.rs @@ -1,26 +1,25 @@ use super::File; use alloc::sync::{Arc, Weak}; -use spin::Mutex; -use crate::mm::{ - UserBuffer, -}; +use crate::sync::UPSafeCell; +use crate::mm::UserBuffer; + use crate::task::suspend_current_and_run_next; pub struct Pipe { readable: bool, writable: bool, - buffer: Arc>, + buffer: Arc>, } impl Pipe { - pub fn read_end_with_buffer(buffer: Arc>) -> Self { + pub fn read_end_with_buffer(buffer: Arc>) -> Self { Self { readable: true, writable: false, buffer, } } - pub fn write_end_with_buffer(buffer: Arc>) -> Self { + pub fn write_end_with_buffer(buffer: Arc>) -> Self { Self { readable: false, writable: true, @@ -101,14 +100,16 @@ impl PipeRingBuffer { /// Return (read_end, write_end) pub fn make_pipe() -> (Arc, Arc) { - let buffer = Arc::new(Mutex::new(PipeRingBuffer::new())); + let buffer = Arc::new(unsafe { + UPSafeCell::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.lock().set_write_end(&write_end); + buffer.exclusive_access().set_write_end(&write_end); (read_end, write_end) } @@ -120,7 +121,7 @@ impl File for Pipe { let mut buf_iter = buf.into_iter(); let mut read_size = 0usize; loop { - let mut ring_buffer = self.buffer.lock(); + 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() { @@ -146,7 +147,7 @@ impl File for Pipe { let mut buf_iter = buf.into_iter(); let mut write_size = 0usize; loop { - let mut ring_buffer = self.buffer.lock(); + let mut ring_buffer = self.buffer.exclusive_access(); let loop_write = ring_buffer.available_write(); if loop_write == 0 { drop(ring_buffer); diff --git a/os/src/main.rs b/os/src/main.rs index e9a34bb8..1512ec32 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -1,9 +1,8 @@ #![no_std] #![no_main] #![feature(global_asm)] -#![feature(llvm_asm)] +#![feature(asm)] #![feature(panic_info_message)] -#![feature(const_in_array_repeat_expressions)] #![feature(alloc_error_handler)] extern crate alloc; @@ -20,6 +19,7 @@ mod trap; mod config; mod task; mod timer; +mod sync; mod mm; mod fs; mod drivers; @@ -31,9 +31,12 @@ fn clear_bss() { fn sbss(); fn ebss(); } - (sbss as usize..ebss as usize).for_each(|a| { - unsafe { (a as *mut u8).write_volatile(0) } - }); + unsafe { + core::slice::from_raw_parts_mut( + sbss as usize as *mut u8, + ebss as usize - sbss as usize, + ).fill(0); + } } #[no_mangle] diff --git a/os/src/mm/frame_allocator.rs b/os/src/mm/frame_allocator.rs index 2cb6427b..357db707 100644 --- a/os/src/mm/frame_allocator.rs +++ b/os/src/mm/frame_allocator.rs @@ -1,6 +1,6 @@ use super::{PhysAddr, PhysPageNum}; use alloc::vec::Vec; -use spin::Mutex; +use crate::sync::UPSafeCell; use crate::config::MEMORY_END; use lazy_static::*; use core::fmt::{self, Debug, Formatter}; @@ -88,8 +88,9 @@ impl FrameAllocator for StackFrameAllocator { type FrameAllocatorImpl = StackFrameAllocator; lazy_static! { - pub static ref FRAME_ALLOCATOR: Mutex = - Mutex::new(FrameAllocatorImpl::new()); + pub static ref FRAME_ALLOCATOR: UPSafeCell = unsafe { + UPSafeCell::new(FrameAllocatorImpl::new()) + }; } pub fn init_frame_allocator() { @@ -97,20 +98,20 @@ pub fn init_frame_allocator() { fn ekernel(); } FRAME_ALLOCATOR - .lock() + .exclusive_access() .init(PhysAddr::from(ekernel as usize).ceil(), PhysAddr::from(MEMORY_END).floor()); } pub fn frame_alloc() -> Option { FRAME_ALLOCATOR - .lock() + .exclusive_access() .alloc() .map(|ppn| FrameTracker::new(ppn)) } pub fn frame_dealloc(ppn: PhysPageNum) { FRAME_ALLOCATOR - .lock() + .exclusive_access() .dealloc(ppn); } diff --git a/os/src/mm/memory_set.rs b/os/src/mm/memory_set.rs index b3a8b2e4..c33008d9 100644 --- a/os/src/mm/memory_set.rs +++ b/os/src/mm/memory_set.rs @@ -7,7 +7,7 @@ use alloc::vec::Vec; use riscv::register::satp; use alloc::sync::Arc; use lazy_static::*; -use spin::Mutex; +use crate::sync::UPSafeCell; use crate::config::{ MEMORY_END, PAGE_SIZE, @@ -31,13 +31,13 @@ extern "C" { } lazy_static! { - pub static ref KERNEL_SPACE: Arc> = Arc::new(Mutex::new( - MemorySet::new_kernel() - )); + pub static ref KERNEL_SPACE: Arc> = Arc::new(unsafe { + UPSafeCell::new(MemorySet::new_kernel()) + }); } pub fn kernel_token() -> usize { - KERNEL_SPACE.lock().token() + KERNEL_SPACE.exclusive_access().token() } pub struct MemorySet { @@ -220,7 +220,7 @@ impl MemorySet { let satp = self.page_table.token(); unsafe { satp::write(satp); - llvm_asm!("sfence.vma" :::: "volatile"); + asm!("sfence.vma"); } } pub fn translate(&self, vpn: VirtPageNum) -> Option { @@ -338,7 +338,7 @@ bitflags! { #[allow(unused)] pub fn remap_test() { - let mut kernel_space = KERNEL_SPACE.lock(); + let mut kernel_space = KERNEL_SPACE.exclusive_access(); let mid_text: VirtAddr = ((stext as usize + etext as usize) / 2).into(); let mid_rodata: VirtAddr = ((srodata as usize + erodata as usize) / 2).into(); let mid_data: VirtAddr = ((sdata as usize + edata as usize) / 2).into(); diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs index dbd47fe7..85e8c16a 100644 --- a/os/src/mm/mod.rs +++ b/os/src/mm/mod.rs @@ -24,5 +24,5 @@ pub use memory_set::remap_test; pub fn init() { heap_allocator::init_heap(); frame_allocator::init_frame_allocator(); - KERNEL_SPACE.lock().activate(); + KERNEL_SPACE.exclusive_access().activate(); } \ No newline at end of file diff --git a/os/src/sbi.rs b/os/src/sbi.rs index 36e15fcc..276c199d 100644 --- a/os/src/sbi.rs +++ b/os/src/sbi.rs @@ -14,11 +14,12 @@ const SBI_SHUTDOWN: usize = 8; fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize { let mut ret; unsafe { - llvm_asm!("ecall" - : "={x10}" (ret) - : "{x10}" (arg0), "{x11}" (arg1), "{x12}" (arg2), "{x17}" (which) - : "memory" - : "volatile" + asm!( + "ecall", + inlateout("x10") arg0 => ret, + in("x11") arg1, + in("x12") arg2, + in("x17") which, ); } ret diff --git a/os/src/sync/mod.rs b/os/src/sync/mod.rs new file mode 100644 index 00000000..77295248 --- /dev/null +++ b/os/src/sync/mod.rs @@ -0,0 +1,3 @@ +mod up; + +pub use up::UPSafeCell; \ No newline at end of file diff --git a/os/src/sync/up.rs b/os/src/sync/up.rs new file mode 100644 index 00000000..642668c1 --- /dev/null +++ b/os/src/sync/up.rs @@ -0,0 +1,27 @@ +use core::cell::{RefCell, RefMut}; + +/// Wrap a static data structure inside it so that we are +/// able to access it without any `unsafe`. +/// +/// We should only use it in uniprocessor. +/// +/// In order to get mutable reference of inner data, call +/// `exclusive_access`. +pub struct UPSafeCell { + /// inner data + inner: RefCell, +} + +unsafe impl Sync for UPSafeCell {} + +impl UPSafeCell { + /// User is responsible to guarantee that inner struct is only used in + /// uniprocessor. + pub unsafe fn new(value: T) -> Self { + Self { inner: RefCell::new(value) } + } + /// Panic if the data has been borrowed. + pub fn exclusive_access(&self) -> RefMut<'_, T> { + self.inner.borrow_mut() + } +} \ No newline at end of file diff --git a/os/src/syscall/fs.rs b/os/src/syscall/fs.rs index 79eac32a..9e7c1857 100644 --- a/os/src/syscall/fs.rs +++ b/os/src/syscall/fs.rs @@ -11,7 +11,7 @@ use alloc::sync::Arc; pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize { let token = current_user_token(); let task = current_task().unwrap(); - let inner = task.acquire_inner_lock(); + let inner = task.inner_exclusive_access(); if fd >= inner.fd_table.len() { return -1; } @@ -20,7 +20,7 @@ pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize { return -1; } let file = file.clone(); - // release Task lock manually to avoid deadlock + // release current task TCB manually to avoid multi-borrow drop(inner); file.write( UserBuffer::new(translated_byte_buffer(token, buf, len)) @@ -33,7 +33,7 @@ pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize { pub fn sys_read(fd: usize, buf: *const u8, len: usize) -> isize { let token = current_user_token(); let task = current_task().unwrap(); - let inner = task.acquire_inner_lock(); + let inner = task.inner_exclusive_access(); if fd >= inner.fd_table.len() { return -1; } @@ -42,7 +42,7 @@ pub fn sys_read(fd: usize, buf: *const u8, len: usize) -> isize { if !file.readable() { return -1; } - // release Task lock manually to avoid deadlock + // release current task TCB manually to avoid multi-borrow drop(inner); file.read( UserBuffer::new(translated_byte_buffer(token, buf, len)) @@ -60,7 +60,7 @@ pub fn sys_open(path: *const u8, flags: u32) -> isize { path.as_str(), OpenFlags::from_bits(flags).unwrap() ) { - let mut inner = task.acquire_inner_lock(); + let mut inner = task.inner_exclusive_access(); let fd = inner.alloc_fd(); inner.fd_table[fd] = Some(inode); fd as isize @@ -71,7 +71,7 @@ pub fn sys_open(path: *const u8, flags: u32) -> isize { pub fn sys_close(fd: usize) -> isize { let task = current_task().unwrap(); - let mut inner = task.acquire_inner_lock(); + let mut inner = task.inner_exclusive_access(); if fd >= inner.fd_table.len() { return -1; } @@ -85,7 +85,7 @@ pub fn sys_close(fd: usize) -> isize { pub fn sys_pipe(pipe: *mut usize) -> isize { let task = current_task().unwrap(); let token = current_user_token(); - let mut inner = task.acquire_inner_lock(); + let mut inner = task.inner_exclusive_access(); let (pipe_read, pipe_write) = make_pipe(); let read_fd = inner.alloc_fd(); inner.fd_table[read_fd] = Some(pipe_read); @@ -98,7 +98,7 @@ pub fn sys_pipe(pipe: *mut usize) -> isize { pub fn sys_dup(fd: usize) -> isize { let task = current_task().unwrap(); - let mut inner = task.acquire_inner_lock(); + let mut inner = task.inner_exclusive_access(); if fd >= inner.fd_table.len() { return -1; } diff --git a/os/src/syscall/process.rs b/os/src/syscall/process.rs index bfd592d6..cf3cbcb4 100644 --- a/os/src/syscall/process.rs +++ b/os/src/syscall/process.rs @@ -42,7 +42,7 @@ pub fn sys_fork() -> isize { let new_task = current_task.fork(); let new_pid = new_task.pid.0; // modify trap context of new_task, because it returns immediately after switching - let trap_cx = new_task.acquire_inner_lock().get_trap_cx(); + let trap_cx = new_task.inner_exclusive_access().get_trap_cx(); // we do not have to move to next instruction since we have done it before // for child process, fork returns 0 trap_cx.x[10] = 0; @@ -81,35 +81,35 @@ pub fn sys_waitpid(pid: isize, exit_code_ptr: *mut i32) -> isize { let task = current_task().unwrap(); // find a child process - // ---- hold current PCB lock - let mut inner = task.acquire_inner_lock(); + // ---- access current PCB exclusively + let mut inner = task.inner_exclusive_access(); if inner.children .iter() .find(|p| {pid == -1 || pid as usize == p.getpid()}) .is_none() { return -1; - // ---- release current PCB lock + // ---- release current PCB } let pair = inner.children .iter() .enumerate() .find(|(_, p)| { - // ++++ temporarily hold child PCB lock - p.acquire_inner_lock().is_zombie() && (pid == -1 || pid as usize == p.getpid()) - // ++++ release child PCB lock + // ++++ 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 hold child lock - let exit_code = child.acquire_inner_lock().exit_code; - // ++++ release child PCB lock + // ++++ 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 } - // ---- release current PCB lock automatically + // ---- release current PCB automatically } \ No newline at end of file diff --git a/os/src/task/context.rs b/os/src/task/context.rs index 340bc098..d25cc2c8 100644 --- a/os/src/task/context.rs +++ b/os/src/task/context.rs @@ -3,13 +3,22 @@ use crate::trap::trap_return; #[repr(C)] pub struct TaskContext { ra: usize, + sp: usize, s: [usize; 12], } impl TaskContext { - pub fn goto_trap_return() -> Self { + pub fn zero_init() -> Self { + Self { + ra: 0, + sp: 0, + s: [0; 12], + } + } + pub fn goto_trap_return(kstack_ptr: usize) -> Self { Self { ra: trap_return as usize, + sp: kstack_ptr, s: [0; 12], } } diff --git a/os/src/task/manager.rs b/os/src/task/manager.rs index ed223916..2e3708d7 100644 --- a/os/src/task/manager.rs +++ b/os/src/task/manager.rs @@ -1,7 +1,7 @@ +use crate::sync::UPSafeCell; use super::TaskControlBlock; use alloc::collections::VecDeque; use alloc::sync::Arc; -use spin::Mutex; use lazy_static::*; pub struct TaskManager { @@ -22,13 +22,15 @@ impl TaskManager { } lazy_static! { - pub static ref TASK_MANAGER: Mutex = Mutex::new(TaskManager::new()); + pub static ref TASK_MANAGER: UPSafeCell = unsafe { + UPSafeCell::new(TaskManager::new()) + }; } pub fn add_task(task: Arc) { - TASK_MANAGER.lock().add(task); + TASK_MANAGER.exclusive_access().add(task); } pub fn fetch_task() -> Option> { - TASK_MANAGER.lock().fetch() + TASK_MANAGER.exclusive_access().fetch() } \ No newline at end of file diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index e943016c..81d6a09b 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -28,51 +28,51 @@ pub fn suspend_current_and_run_next() { // There must be an application running. let task = take_current_task().unwrap(); - // ---- hold current PCB lock - let mut task_inner = task.acquire_inner_lock(); - let task_cx_ptr2 = task_inner.get_task_cx_ptr2(); + // ---- 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 PCB lock + // ---- release current PCB // push back to ready queue. add_task(task); // jump to scheduling cycle - schedule(task_cx_ptr2); + schedule(task_cx_ptr); } pub fn exit_current_and_run_next(exit_code: i32) { // take from Processor let task = take_current_task().unwrap(); - // **** hold current PCB lock - let mut inner = task.acquire_inner_lock(); + // **** access current TCB exclusively + let mut inner = task.inner_exclusive_access(); // Change status to Zombie inner.task_status = TaskStatus::Zombie; // Record exit code inner.exit_code = exit_code; // do not move to its parent but under initproc - // ++++++ hold initproc PCB lock here + // ++++++ access initproc TCB exclusively { - let mut initproc_inner = INITPROC.acquire_inner_lock(); + let mut initproc_inner = INITPROC.inner_exclusive_access(); for child in inner.children.iter() { - child.acquire_inner_lock().parent = Some(Arc::downgrade(&INITPROC)); + child.inner_exclusive_access().parent = Some(Arc::downgrade(&INITPROC)); initproc_inner.children.push(child.clone()); } } - // ++++++ release parent PCB lock here + // ++++++ release parent PCB inner.children.clear(); // deallocate user space inner.memory_set.recycle_data_pages(); drop(inner); - // **** release current PCB lock + // **** release current PCB // drop task manually to maintain rc correctly drop(task); // we do not have to save task context - let _unused: usize = 0; - schedule(&_unused as *const _); + let mut _unused = TaskContext::zero_init(); + schedule(&mut _unused as *mut _); } lazy_static! { diff --git a/os/src/task/pid.rs b/os/src/task/pid.rs index 7cfdb83d..517cd1d4 100644 --- a/os/src/task/pid.rs +++ b/os/src/task/pid.rs @@ -1,6 +1,6 @@ use alloc::vec::Vec; use lazy_static::*; -use spin::Mutex; +use crate::sync::UPSafeCell; use crate::mm::{KERNEL_SPACE, MapPermission, VirtAddr}; use crate::config::{ PAGE_SIZE, @@ -39,7 +39,9 @@ impl PidAllocator { } lazy_static! { - static ref PID_ALLOCATOR : Mutex = Mutex::new(PidAllocator::new()); + static ref PID_ALLOCATOR : UPSafeCell = unsafe { + UPSafeCell::new(PidAllocator::new()) + }; } pub struct PidHandle(pub usize); @@ -47,12 +49,12 @@ pub struct PidHandle(pub usize); impl Drop for PidHandle { fn drop(&mut self) { //println!("drop pid {}", self.0); - PID_ALLOCATOR.lock().dealloc(self.0); + PID_ALLOCATOR.exclusive_access().dealloc(self.0); } } pub fn pid_alloc() -> PidHandle { - PID_ALLOCATOR.lock().alloc() + PID_ALLOCATOR.exclusive_access().alloc() } /// Return (bottom, top) of a kernel stack in kernel space. @@ -71,7 +73,7 @@ impl KernelStack { let pid = pid_handle.0; let (kernel_stack_bottom, kernel_stack_top) = kernel_stack_position(pid); KERNEL_SPACE - .lock() + .exclusive_access() .insert_framed_area( kernel_stack_bottom.into(), kernel_stack_top.into(), @@ -81,6 +83,7 @@ impl KernelStack { pid: pid_handle.0, } } + #[allow(unused)] pub fn push_on_top(&self, value: T) -> *mut T where T: Sized, { let kernel_stack_top = self.get_top(); @@ -99,7 +102,7 @@ impl Drop for KernelStack { let (kernel_stack_bottom, _) = kernel_stack_position(self.pid); let kernel_stack_bottom_va: VirtAddr = kernel_stack_bottom.into(); KERNEL_SPACE - .lock() + .exclusive_access() .remove_area_with_start_vpn(kernel_stack_bottom_va.into()); } } \ No newline at end of file diff --git a/os/src/task/processor.rs b/os/src/task/processor.rs index e6895c40..a9f9db8c 100644 --- a/os/src/task/processor.rs +++ b/os/src/task/processor.rs @@ -1,95 +1,90 @@ -use super::TaskControlBlock; +use super::{TaskContext, TaskControlBlock}; use alloc::sync::Arc; -use core::cell::RefCell; use lazy_static::*; use super::{fetch_task, TaskStatus}; use super::__switch; use crate::trap::TrapContext; +use crate::sync::UPSafeCell; pub struct Processor { - inner: RefCell, -} - -unsafe impl Sync for Processor {} - -struct ProcessorInner { current: Option>, - idle_task_cx_ptr: usize, + idle_task_cx: TaskContext, } impl Processor { pub fn new() -> Self { Self { - inner: RefCell::new(ProcessorInner { - current: None, - idle_task_cx_ptr: 0, - }), + current: None, + idle_task_cx: TaskContext::zero_init(), } } - fn get_idle_task_cx_ptr2(&self) -> *const usize { - let inner = self.inner.borrow(); - &inner.idle_task_cx_ptr as *const usize + fn get_idle_task_cx_ptr(&mut self) -> *mut TaskContext { + &mut self.idle_task_cx as *mut _ } - pub fn run(&self) { - loop { - if let Some(task) = fetch_task() { - let idle_task_cx_ptr2 = self.get_idle_task_cx_ptr2(); - // acquire - let mut task_inner = task.acquire_inner_lock(); - let next_task_cx_ptr2 = task_inner.get_task_cx_ptr2(); - task_inner.task_status = TaskStatus::Running; - drop(task_inner); - // release - self.inner.borrow_mut().current = Some(task); - unsafe { - __switch( - idle_task_cx_ptr2, - next_task_cx_ptr2, - ); - } - } - } - } - pub fn take_current(&self) -> Option> { - self.inner.borrow_mut().current.take() + pub fn take_current(&mut self) -> Option> { + self.current.take() } pub fn current(&self) -> Option> { - self.inner.borrow().current.as_ref().map(|task| Arc::clone(task)) + self.current.as_ref().map(|task| Arc::clone(task)) } } lazy_static! { - pub static ref PROCESSOR: Processor = Processor::new(); + pub static ref PROCESSOR: UPSafeCell = unsafe { + UPSafeCell::new(Processor::new()) + }; } pub fn run_tasks() { - PROCESSOR.run(); + 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 mut task_inner = task.inner_exclusive_access(); + let next_task_cx_ptr = &task_inner.task_cx as *const TaskContext; + task_inner.task_status = TaskStatus::Running; + drop(task_inner); + // release coming task TCB manually + processor.current = Some(task); + // release processor manually + drop(processor); + unsafe { + __switch( + idle_task_cx_ptr, + next_task_cx_ptr, + ); + } + } + } } pub fn take_current_task() -> Option> { - PROCESSOR.take_current() + PROCESSOR.exclusive_access().take_current() } pub fn current_task() -> Option> { - PROCESSOR.current() + PROCESSOR.exclusive_access().current() } pub fn current_user_token() -> usize { let task = current_task().unwrap(); - let token = task.acquire_inner_lock().get_user_token(); + let token = task.inner_exclusive_access().get_user_token(); token } pub fn current_trap_cx() -> &'static mut TrapContext { - current_task().unwrap().acquire_inner_lock().get_trap_cx() + current_task().unwrap().inner_exclusive_access().get_trap_cx() } -pub fn schedule(switched_task_cx_ptr2: *const usize) { - let idle_task_cx_ptr2 = PROCESSOR.get_idle_task_cx_ptr2(); +pub fn schedule(switched_task_cx_ptr: *mut TaskContext) { + let mut processor = PROCESSOR.exclusive_access(); + let idle_task_cx_ptr = processor.get_idle_task_cx_ptr(); + drop(processor); unsafe { __switch( - switched_task_cx_ptr2, - idle_task_cx_ptr2, + switched_task_cx_ptr, + idle_task_cx_ptr, ); } } diff --git a/os/src/task/switch.S b/os/src/task/switch.S index 262511fe..3f985d24 100644 --- a/os/src/task/switch.S +++ b/os/src/task/switch.S @@ -1,37 +1,34 @@ .altmacro .macro SAVE_SN n - sd s\n, (\n+1)*8(sp) + sd s\n, (\n+2)*8(a0) .endm .macro LOAD_SN n - ld s\n, (\n+1)*8(sp) + ld s\n, (\n+2)*8(a1) .endm .section .text .globl __switch __switch: # __switch( - # current_task_cx_ptr2: &*const TaskContext, - # next_task_cx_ptr2: &*const TaskContext + # current_task_cx_ptr: *mut TaskContext, + # next_task_cx_ptr: *const TaskContext # ) - # push TaskContext to current sp and save its address to where a0 points to - addi sp, sp, -13*8 - sd sp, 0(a0) - # fill TaskContext with ra & s0-s11 - sd ra, 0(sp) + # save kernel stack of current task + sd sp, 8(a0) + # save ra & s0~s11 of current execution + sd ra, 0(a0) .set n, 0 .rept 12 SAVE_SN %n .set n, n + 1 .endr - # ready for loading TaskContext a1 points to - ld sp, 0(a1) - # load registers in the TaskContext - ld ra, 0(sp) + # restore ra & s0~s11 of next execution + ld ra, 0(a1) .set n, 0 .rept 12 LOAD_SN %n .set n, n + 1 .endr - # pop TaskContext - addi sp, sp, 13*8 + # restore kernel stack of next task + ld sp, 8(a1) ret diff --git a/os/src/task/switch.rs b/os/src/task/switch.rs index 867fcb1e..fa75be1a 100644 --- a/os/src/task/switch.rs +++ b/os/src/task/switch.rs @@ -1,8 +1,10 @@ global_asm!(include_str!("switch.S")); +use super::TaskContext; + extern "C" { pub fn __switch( - current_task_cx_ptr2: *const usize, - next_task_cx_ptr2: *const usize + 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 ee5fc53e..25b2226d 100644 --- a/os/src/task/task.rs +++ b/os/src/task/task.rs @@ -6,14 +6,15 @@ use crate::mm::{ translated_refmut, }; use crate::trap::{TrapContext, trap_handler}; -use crate::config::{TRAP_CONTEXT}; +use crate::config::TRAP_CONTEXT; +use crate::sync::UPSafeCell; +use core::cell::RefMut; use super::TaskContext; use super::{PidHandle, pid_alloc, KernelStack}; use alloc::sync::{Weak, Arc}; use alloc::vec; use alloc::vec::Vec; use alloc::string::String; -use spin::{Mutex, MutexGuard}; use crate::fs::{File, Stdin, Stdout}; pub struct TaskControlBlock { @@ -21,13 +22,13 @@ pub struct TaskControlBlock { pub pid: PidHandle, pub kernel_stack: KernelStack, // mutable - inner: Mutex, + inner: UPSafeCell, } pub struct TaskControlBlockInner { pub trap_cx_ppn: PhysPageNum, pub base_size: usize, - pub task_cx_ptr: usize, + pub task_cx: TaskContext, pub task_status: TaskStatus, pub memory_set: MemorySet, pub parent: Option>, @@ -37,9 +38,6 @@ pub struct TaskControlBlockInner { } impl TaskControlBlockInner { - pub fn get_task_cx_ptr2(&self) -> *const usize { - &self.task_cx_ptr as *const usize - } pub fn get_trap_cx(&self) -> &'static mut TrapContext { self.trap_cx_ppn.get_mut() } @@ -64,8 +62,8 @@ impl TaskControlBlockInner { } impl TaskControlBlock { - pub fn acquire_inner_lock(&self) -> MutexGuard { - self.inner.lock() + pub fn inner_exclusive_access(&self) -> RefMut<'_, TaskControlBlockInner> { + self.inner.exclusive_access() } pub fn new(elf_data: &[u8]) -> Self { // memory_set with elf program headers/trampoline/trap context/user stack @@ -78,15 +76,13 @@ impl TaskControlBlock { let pid_handle = pid_alloc(); let kernel_stack = KernelStack::new(&pid_handle); let kernel_stack_top = kernel_stack.get_top(); - // push a task context which goes to trap_return to the top of kernel stack - let task_cx_ptr = kernel_stack.push_on_top(TaskContext::goto_trap_return()); let task_control_block = Self { pid: pid_handle, kernel_stack, - inner: Mutex::new(TaskControlBlockInner { + inner: unsafe { UPSafeCell::new(TaskControlBlockInner { trap_cx_ppn, base_size: user_sp, - task_cx_ptr: task_cx_ptr as usize, + task_cx: TaskContext::goto_trap_return(kernel_stack_top), task_status: TaskStatus::Ready, memory_set, parent: None, @@ -100,14 +96,14 @@ impl TaskControlBlock { // 2 -> stderr Some(Arc::new(Stdout)), ], - }), + })}, }; // prepare TrapContext in user space - let trap_cx = task_control_block.acquire_inner_lock().get_trap_cx(); + let trap_cx = task_control_block.inner_exclusive_access().get_trap_cx(); *trap_cx = TrapContext::app_init_context( entry_point, user_sp, - KERNEL_SPACE.lock().token(), + KERNEL_SPACE.exclusive_access().token(), kernel_stack_top, trap_handler as usize, ); @@ -145,8 +141,8 @@ impl TaskControlBlock { // make the user_sp aligned to 8B for k210 platform user_sp -= user_sp % core::mem::size_of::(); - // **** hold current PCB lock - let mut inner = self.acquire_inner_lock(); + // **** access current TCB exclusively + let mut inner = self.inner_exclusive_access(); // substitute memory_set inner.memory_set = memory_set; // update trap_cx ppn @@ -155,18 +151,18 @@ impl TaskControlBlock { let mut trap_cx = TrapContext::app_init_context( entry_point, user_sp, - KERNEL_SPACE.lock().token(), + KERNEL_SPACE.exclusive_access().token(), self.kernel_stack.get_top(), trap_handler as usize, ); trap_cx.x[10] = args.len(); trap_cx.x[11] = argv_base; *inner.get_trap_cx() = trap_cx; - // **** release current PCB lock + // **** release current PCB } pub fn fork(self: &Arc) -> Arc { // ---- hold parent PCB lock - let mut parent_inner = self.acquire_inner_lock(); + let mut parent_inner = self.inner_exclusive_access(); // copy user space(include trap context) let memory_set = MemorySet::from_existed_user( &parent_inner.memory_set @@ -179,8 +175,6 @@ impl TaskControlBlock { let pid_handle = pid_alloc(); let kernel_stack = KernelStack::new(&pid_handle); let kernel_stack_top = kernel_stack.get_top(); - // push a goto_trap_return task_cx on the top of kernel stack - let task_cx_ptr = kernel_stack.push_on_top(TaskContext::goto_trap_return()); // copy fd table let mut new_fd_table: Vec>> = Vec::new(); for fd in parent_inner.fd_table.iter() { @@ -193,28 +187,28 @@ impl TaskControlBlock { let task_control_block = Arc::new(TaskControlBlock { pid: pid_handle, kernel_stack, - inner: Mutex::new(TaskControlBlockInner { + inner: unsafe { UPSafeCell::new(TaskControlBlockInner { trap_cx_ppn, base_size: parent_inner.base_size, - task_cx_ptr: task_cx_ptr as usize, + task_cx: TaskContext::goto_trap_return(kernel_stack_top), task_status: TaskStatus::Ready, memory_set, parent: Some(Arc::downgrade(self)), children: Vec::new(), exit_code: 0, fd_table: new_fd_table, - }), + })}, }); // add child parent_inner.children.push(task_control_block.clone()); // modify kernel_sp in trap_cx - // **** acquire child PCB lock - let trap_cx = task_control_block.acquire_inner_lock().get_trap_cx(); - // **** release child PCB lock + // **** access child PCB exclusively + let trap_cx = task_control_block.inner_exclusive_access().get_trap_cx(); trap_cx.kernel_sp = kernel_stack_top; // return task_control_block - // ---- release parent PCB lock + // **** release child PCB + // ---- release parent PCB } pub fn getpid(&self) -> usize { self.pid.0 diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index f83560b2..d04e1aa4 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -103,10 +103,15 @@ pub fn trap_return() -> ! { } let restore_va = __restore as usize - __alltraps as usize + TRAMPOLINE; unsafe { - llvm_asm!("fence.i" :::: "volatile"); - llvm_asm!("jr $0" :: "r"(restore_va), "{a0}"(trap_cx_ptr), "{a1}"(user_satp) :: "volatile"); + asm!( + "fence.i", + "jr {restore_va}", + restore_va = in(reg) restore_va, + in("a0") trap_cx_ptr, + in("a1") user_satp, + options(noreturn) + ); } - panic!("Unreachable in back_to_user!"); } #[no_mangle] diff --git a/rust-toolchain b/rust-toolchain index a08f00d1..2c78ef84 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2021-01-30 +nightly-2021-07-15 diff --git a/user/src/bin/forktree.rs b/user/src/bin/forktree.rs index 26954b7a..2debf6c5 100644 --- a/user/src/bin/forktree.rs +++ b/user/src/bin/forktree.rs @@ -14,7 +14,7 @@ fn fork_child(cur: &str, branch: char) { if l >= DEPTH { return; } - &mut next[..l].copy_from_slice(cur.as_bytes()); + 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()); diff --git a/user/src/bin/huge_write.rs b/user/src/bin/huge_write.rs new file mode 100644 index 00000000..25f92943 --- /dev/null +++ b/user/src/bin/huge_write.rs @@ -0,0 +1,36 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{ + OpenFlags, + open, + close, + write, + get_time, +}; + +#[no_mangle] +pub fn main() -> i32 { + let mut buffer = [0u8; 1024]; // 1KiB + for i in 0..buffer.len() { + buffer[i] = i as u8; + } + let f = open("testf", OpenFlags::CREATE | OpenFlags::WRONLY); + if f < 0 { + panic!("Open test file failed!"); + } + let f = f as usize; + let start = get_time(); + let size_mb = 5usize; + for _ in 0..1024*size_mb { + write(f, &buffer); + } + close(f); + let time_ms = (get_time() - start) as usize; + let speed_kbs = size_mb * 1000000 / time_ms; + println!("time cost = {}ms, write speed = {}KiB/s", time_ms, speed_kbs); + 0 +} \ No newline at end of file diff --git a/user/src/lib.rs b/user/src/lib.rs index 0ef03bfb..d7f51cf2 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -1,5 +1,5 @@ #![no_std] -#![feature(llvm_asm)] +#![feature(asm)] #![feature(linkage)] #![feature(panic_info_message)] #![feature(alloc_error_handler)] diff --git a/user/src/syscall.rs b/user/src/syscall.rs index 1cd30f84..4863bd3d 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -15,11 +15,12 @@ const SYSCALL_WAITPID: usize = 260; fn syscall(id: usize, args: [usize; 3]) -> isize { let mut ret: isize; unsafe { - llvm_asm!("ecall" - : "={x10}" (ret) - : "{x10}" (args[0]), "{x11}" (args[1]), "{x12}" (args[2]), "{x17}" (id) - : "memory" - : "volatile" + asm!( + "ecall", + inlateout("x10") args[0] => ret, + in("x11") args[1], + in("x12") args[2], + in("x17") id ); } ret