diff --git a/bootloader/rustsbi-qemu.bin b/bootloader/rustsbi-qemu.bin index ddbf336a..5f319c3d 100755 Binary files a/bootloader/rustsbi-qemu.bin and b/bootloader/rustsbi-qemu.bin differ diff --git a/easy-fs-fuse/src/main.rs b/easy-fs-fuse/src/main.rs index cac1b797..d3320165 100644 --- a/easy-fs-fuse/src/main.rs +++ b/easy-fs-fuse/src/main.rs @@ -23,6 +23,8 @@ impl BlockDevice for BlockFile { .expect("Error when seeking!"); assert_eq!(file.write(buf).unwrap(), BLOCK_SZ, "Not a complete block!"); } + + fn handle_irq(&self) { unimplemented!(); } } fn main() { diff --git a/easy-fs/src/block_dev.rs b/easy-fs/src/block_dev.rs index 8a01eddb..eb39fbd7 100644 --- a/easy-fs/src/block_dev.rs +++ b/easy-fs/src/block_dev.rs @@ -3,4 +3,5 @@ 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/os/Cargo.toml b/os/Cargo.toml index b07fa034..b8327164 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -12,6 +12,7 @@ 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" } k210-pac = { git = "https://github.com/wyfcyx/k210-pac" } k210-hal = { git = "https://github.com/wyfcyx/k210-hal" } @@ -20,4 +21,4 @@ easy-fs = { path = "../easy-fs" } [features] board_qemu = [] -board_k210 = [] \ No newline at end of file +board_k210 = [] diff --git a/os/Makefile b/os/Makefile index 0c1fb7c7..3e5caad7 100644 --- a/os/Makefile +++ b/os/Makefile @@ -76,7 +76,7 @@ disasm: kernel disasm-vim: kernel @$(OBJDUMP) $(DISASM) $(KERNEL_ELF) > $(DISASM_TMP) - @vim $(DISASM_TMP) + @nvim $(DISASM_TMP) @rm $(DISASM_TMP) run: run-inner diff --git a/os/src/boards/k210.rs b/os/src/boards/k210.rs index 4b2fd444..249e49fe 100644 --- a/os/src/boards/k210.rs +++ b/os/src/boards/k210.rs @@ -21,3 +21,10 @@ pub const MMIO: &[(usize, usize)] = &[ pub type BlockDeviceImpl = crate::drivers::block::SDCardWrapper; +pub fn device_init() { + unimplemented!(); +} + +pub fn irq_handler() { + unimplemented!(); +} diff --git a/os/src/boards/qemu.rs b/os/src/boards/qemu.rs index b3492526..0c3ba66d 100644 --- a/os/src/boards/qemu.rs +++ b/os/src/boards/qemu.rs @@ -1,6 +1,45 @@ pub const CLOCK_FREQ: usize = 12500000; -pub const MMIO: &[(usize, usize)] = &[(0x10001000, 0x1000)]; +pub const MMIO: &[(usize, usize)] = &[ + (0x1000_0000, 0x1000), + (0x1000_1000, 0x1000), + (0xC00_0000, 0x40_0000), +]; 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; + +use crate::drivers::block::BLOCK_DEVICE; +use crate::drivers::chardev::{CharDevice, UART}; +use crate::drivers::plic::{IntrTargetPriority, PLIC}; + +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); + for intr_src_id in [1usize, 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 { + 1 => 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 c1b2fa45..41fe977c 100644 --- a/os/src/config.rs +++ b/os/src/config.rs @@ -11,4 +11,3 @@ pub const TRAMPOLINE: usize = usize::MAX - PAGE_SIZE + 1; pub const TRAP_CONTEXT_BASE: usize = TRAMPOLINE - PAGE_SIZE; pub use crate::board::{CLOCK_FREQ, MMIO}; - diff --git a/os/src/console.rs b/os/src/console.rs index c8a5cd4e..31614c64 100644 --- a/os/src/console.rs +++ b/os/src/console.rs @@ -1,4 +1,4 @@ -use crate::sbi::console_putchar; +use crate::drivers::chardev::{CharDevice, UART}; use core::fmt::{self, Write}; struct Stdout; @@ -6,7 +6,7 @@ struct Stdout; impl Write for Stdout { fn write_str(&mut self, s: &str) -> fmt::Result { for c in s.chars() { - console_putchar(c as usize); + UART.write(c as u8); } Ok(()) } diff --git a/os/src/drivers/block/mod.rs b/os/src/drivers/block/mod.rs index 7c1bb55d..7361ec83 100644 --- a/os/src/drivers/block/mod.rs +++ b/os/src/drivers/block/mod.rs @@ -1,13 +1,13 @@ mod sdcard; mod virtio_blk; -pub use virtio_blk::VirtIOBlock; pub use sdcard::SDCardWrapper; +pub use virtio_blk::VirtIOBlock; +use crate::board::BlockDeviceImpl; use alloc::sync::Arc; use easy_fs::BlockDevice; use lazy_static::*; -use crate::board::BlockDeviceImpl; lazy_static! { pub static ref BLOCK_DEVICE: Arc = Arc::new(BlockDeviceImpl::new()); diff --git a/os/src/drivers/block/sdcard.rs b/os/src/drivers/block/sdcard.rs index 1e9f1cc9..d736632a 100644 --- a/os/src/drivers/block/sdcard.rs +++ b/os/src/drivers/block/sdcard.rs @@ -3,7 +3,7 @@ #![allow(unused)] use super::BlockDevice; -use crate::sync::UPSafeCell; +use crate::sync::UPIntrFreeCell; use core::convert::TryInto; use k210_hal::prelude::*; use k210_pac::{Peripherals, SPI0}; @@ -715,8 +715,8 @@ fn io_init() { } lazy_static! { - static ref PERIPHERALS: UPSafeCell = - unsafe { UPSafeCell::new(Peripherals::take().unwrap()) }; + static ref PERIPHERALS: UPIntrFreeCell = + unsafe { UPIntrFreeCell::new(Peripherals::take().unwrap()) }; } fn init_sdcard() -> SDCard> { @@ -740,11 +740,11 @@ fn init_sdcard() -> SDCard> { sd } -pub struct SDCardWrapper(UPSafeCell>>); +pub struct SDCardWrapper(UPIntrFreeCell>>); impl SDCardWrapper { pub fn new() -> Self { - unsafe { Self(UPSafeCell::new(init_sdcard())) } + unsafe { Self(UPIntrFreeCell::new(init_sdcard())) } } } @@ -761,4 +761,7 @@ impl BlockDevice for SDCardWrapper { .write_sector(buf, block_id as u32) .unwrap(); } + fn handle_irq(&self) { + unimplemented!(); + } } diff --git a/os/src/drivers/block/virtio_blk.rs b/os/src/drivers/block/virtio_blk.rs index cca839da..a30e3bf8 100644 --- a/os/src/drivers/block/virtio_blk.rs +++ b/os/src/drivers/block/virtio_blk.rs @@ -3,42 +3,92 @@ use crate::mm::{ frame_alloc, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum, StepByOne, VirtAddr, }; -use crate::sync::UPSafeCell; +use crate::sync::{Condvar, UPIntrFreeCell}; +use crate::task::schedule; +use crate::DEV_NON_BLOCKING_ACCESS; +use alloc::collections::BTreeMap; use alloc::vec::Vec; use lazy_static::*; -use virtio_drivers::{VirtIOBlk, VirtIOHeader}; +use virtio_drivers::{BlkResp, RespStatus, VirtIOBlk, VirtIOHeader}; #[allow(unused)] const VIRTIO0: usize = 0x10001000; -pub struct VirtIOBlock(UPSafeCell>); +pub struct VirtIOBlock { + virtio_blk: UPIntrFreeCell>, + condvars: BTreeMap, +} lazy_static! { - static ref QUEUE_FRAMES: UPSafeCell> = unsafe { UPSafeCell::new(Vec::new()) }; + static ref QUEUE_FRAMES: UPIntrFreeCell> = unsafe { UPIntrFreeCell::new(Vec::new()) }; } impl BlockDevice for VirtIOBlock { fn read_block(&self, block_id: usize, buf: &mut [u8]) { - self.0 - .exclusive_access() - .read_block(block_id, buf) - .expect("Error when reading VirtIOBlk"); + 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]) { - self.0 - .exclusive_access() - .write_block(block_id, buf) - .expect("Error when writing VirtIOBlk"); + 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 { - #[allow(unused)] pub fn new() -> Self { - unsafe { - Self(UPSafeCell::new( - VirtIOBlk::new(&mut *(VIRTIO0 as *mut VirtIOHeader)).unwrap(), - )) + 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/chardev/mod.rs b/os/src/drivers/chardev/mod.rs new file mode 100644 index 00000000..28665769 --- /dev/null +++ b/os/src/drivers/chardev/mod.rs @@ -0,0 +1,17 @@ +mod ns16550a; + +pub use ns16550a::NS16550a; + +use crate::board::CharDeviceImpl; +use alloc::sync::Arc; +use lazy_static::*; + +pub trait CharDevice { + 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 new file mode 100644 index 00000000..667a6604 --- /dev/null +++ b/os/src/drivers/chardev/ns16550a.rs @@ -0,0 +1,176 @@ +///! 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_AVALIABLE = 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_AVALIABLE; + 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 mut inner = NS16550aInner { + ns16550a: NS16550aRaw::new(BASE_ADDR), + read_buffer: VecDeque::new(), + }; + inner.ns16550a.init(); + Self { + inner: unsafe { UPIntrFreeCell::new(inner) }, + condvar: Condvar::new(), + } + } +} + +impl CharDevice for NS16550a { + 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/mod.rs b/os/src/drivers/mod.rs index c2dea36b..c1b1231f 100644 --- a/os/src/drivers/mod.rs +++ b/os/src/drivers/mod.rs @@ -1,3 +1,6 @@ pub mod block; +pub mod chardev; +pub mod plic; pub use block::BLOCK_DEVICE; +pub use chardev::UART; diff --git a/os/src/drivers/plic.rs b/os/src/drivers/plic.rs new file mode 100644 index 00000000..77bad5f3 --- /dev/null +++ b/os/src/drivers/plic.rs @@ -0,0 +1,124 @@ +#[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/fs/inode.rs b/os/src/fs/inode.rs index 19e4953d..321338d4 100644 --- a/os/src/fs/inode.rs +++ b/os/src/fs/inode.rs @@ -1,7 +1,7 @@ use super::File; use crate::drivers::BLOCK_DEVICE; use crate::mm::UserBuffer; -use crate::sync::UPSafeCell; +use crate::sync::UPIntrFreeCell; use alloc::sync::Arc; use alloc::vec::Vec; use bitflags::*; @@ -11,7 +11,7 @@ use lazy_static::*; pub struct OSInode { readable: bool, writable: bool, - inner: UPSafeCell, + inner: UPIntrFreeCell, } pub struct OSInodeInner { @@ -24,7 +24,7 @@ impl OSInode { Self { readable, writable, - inner: unsafe { UPSafeCell::new(OSInodeInner { offset: 0, inode }) }, + inner: unsafe { UPIntrFreeCell::new(OSInodeInner { offset: 0, inode }) }, } } pub fn read_all(&self) -> Vec { diff --git a/os/src/fs/pipe.rs b/os/src/fs/pipe.rs index 75caac54..18c74d51 100644 --- a/os/src/fs/pipe.rs +++ b/os/src/fs/pipe.rs @@ -1,6 +1,6 @@ use super::File; use crate::mm::UserBuffer; -use crate::sync::UPSafeCell; +use crate::sync::UPIntrFreeCell; use alloc::sync::{Arc, Weak}; use crate::task::suspend_current_and_run_next; @@ -8,18 +8,18 @@ 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, @@ -98,7 +98,7 @@ impl PipeRingBuffer { /// Return (read_end, write_end) pub fn make_pipe() -> (Arc, Arc) { - let buffer = Arc::new(unsafe { UPSafeCell::new(PipeRingBuffer::new()) }); + 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); diff --git a/os/src/fs/stdio.rs b/os/src/fs/stdio.rs index 7c74d3e1..7326822d 100644 --- a/os/src/fs/stdio.rs +++ b/os/src/fs/stdio.rs @@ -1,10 +1,8 @@ use super::File; +use crate::drivers::chardev::{CharDevice, UART}; use crate::mm::UserBuffer; -use crate::sbi::console_getchar; -use crate::task::suspend_current_and_run_next; pub struct Stdin; - pub struct Stdout; impl File for Stdin { @@ -16,18 +14,8 @@ impl File for Stdin { } fn read(&self, mut user_buf: UserBuffer) -> usize { assert_eq!(user_buf.len(), 1); - // busy loop - let mut c: usize; - loop { - c = console_getchar(); - if c == 0 { - suspend_current_and_run_next(); - continue; - } else { - break; - } - } - let ch = c as u8; + //println!("before UART.read() in Stdin::read()"); + let ch = UART.read(); unsafe { user_buf.buffers[0].as_mut_ptr().write_volatile(ch); } diff --git a/os/src/main.rs b/os/src/main.rs index cbc4ab40..a9323be1 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -29,9 +29,7 @@ mod task; mod timer; mod trap; -use core::arch::global_asm; - -global_asm!(include_str!("entry.asm")); +core::arch::global_asm!(include_str!("entry.asm")); fn clear_bss() { extern "C" { @@ -44,17 +42,24 @@ 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] pub fn rust_main() -> ! { clear_bss(); - println!("[kernel] Hello, world!"); mm::init(); - mm::remap_test(); trap::init(); trap::enable_timer_interrupt(); timer::set_next_trigger(); + board::device_init(); fs::list_apps(); task::add_initproc(); + *DEV_NON_BLOCKING_ACCESS.exclusive_access() = true; task::run_tasks(); panic!("Unreachable in rust_main!"); } diff --git a/os/src/mm/frame_allocator.rs b/os/src/mm/frame_allocator.rs index 4bc7db26..3c62324b 100644 --- a/os/src/mm/frame_allocator.rs +++ b/os/src/mm/frame_allocator.rs @@ -1,6 +1,6 @@ use super::{PhysAddr, PhysPageNum}; use crate::config::MEMORY_END; -use crate::sync::UPSafeCell; +use crate::sync::UPIntrFreeCell; use alloc::vec::Vec; use core::fmt::{self, Debug, Formatter}; use lazy_static::*; @@ -83,8 +83,8 @@ impl FrameAllocator for StackFrameAllocator { type FrameAllocatorImpl = StackFrameAllocator; lazy_static! { - pub static ref FRAME_ALLOCATOR: UPSafeCell = - unsafe { UPSafeCell::new(FrameAllocatorImpl::new()) }; + pub static ref FRAME_ALLOCATOR: UPIntrFreeCell = + unsafe { UPIntrFreeCell::new(FrameAllocatorImpl::new()) }; } pub fn init_frame_allocator() { diff --git a/os/src/mm/memory_set.rs b/os/src/mm/memory_set.rs index 0d0b0f1d..0862dc7a 100644 --- a/os/src/mm/memory_set.rs +++ b/os/src/mm/memory_set.rs @@ -3,7 +3,7 @@ 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::UPSafeCell; +use crate::sync::UPIntrFreeCell; use alloc::collections::BTreeMap; use alloc::sync::Arc; use alloc::vec::Vec; @@ -25,8 +25,8 @@ extern "C" { } lazy_static! { - pub static ref KERNEL_SPACE: Arc> = - Arc::new(unsafe { UPSafeCell::new(MemorySet::new_kernel()) }); + pub static ref KERNEL_SPACE: Arc> = + Arc::new(unsafe { UPIntrFreeCell::new(MemorySet::new_kernel()) }); } pub fn kernel_token() -> usize { @@ -351,26 +351,20 @@ pub fn remap_test() { let mid_text: VirtAddr = ((stext as usize + etext as usize) / 2).into(); let mid_rodata: VirtAddr = ((srodata as usize + erodata as usize) / 2).into(); let mid_data: VirtAddr = ((sdata as usize + edata as usize) / 2).into(); - assert!( - !kernel_space - .page_table - .translate(mid_text.floor()) - .unwrap() - .writable(), - ); - assert!( - !kernel_space - .page_table - .translate(mid_rodata.floor()) - .unwrap() - .writable(), - ); - assert!( - !kernel_space - .page_table - .translate(mid_data.floor()) - .unwrap() - .executable(), - ); + assert!(!kernel_space + .page_table + .translate(mid_text.floor()) + .unwrap() + .writable(),); + assert!(!kernel_space + .page_table + .translate(mid_rodata.floor()) + .unwrap() + .writable(),); + assert!(!kernel_space + .page_table + .translate(mid_data.floor()) + .unwrap() + .executable(),); println!("remap_test passed!"); } diff --git a/os/src/sync/condvar.rs b/os/src/sync/condvar.rs index f96cd915..c50a53e2 100644 --- a/os/src/sync/condvar.rs +++ b/os/src/sync/condvar.rs @@ -1,9 +1,9 @@ -use crate::sync::{Mutex, UPSafeCell}; -use crate::task::{add_task, block_current_and_run_next, current_task, TaskControlBlock}; +use crate::sync::{Mutex, UPIntrFreeCell}; +use crate::task::{add_task, block_current_task, block_current_and_run_next, current_task, TaskControlBlock, TaskContext}; use alloc::{collections::VecDeque, sync::Arc}; pub struct Condvar { - pub inner: UPSafeCell, + pub inner: UPIntrFreeCell, } pub struct CondvarInner { @@ -14,7 +14,7 @@ impl Condvar { pub fn new() -> Self { Self { inner: unsafe { - UPSafeCell::new(CondvarInner { + UPIntrFreeCell::new(CondvarInner { wait_queue: VecDeque::new(), }) }, @@ -28,12 +28,28 @@ impl Condvar { } } - pub fn wait(&self, mutex: Arc) { - mutex.unlock(); + /* + 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 7e948aa6..d9a00b5b 100644 --- a/os/src/sync/mod.rs +++ b/os/src/sync/mod.rs @@ -6,4 +6,4 @@ mod up; pub use condvar::Condvar; pub use mutex::{Mutex, MutexBlocking, MutexSpin}; pub use semaphore::Semaphore; -pub use up::UPSafeCell; +pub use up::{UPIntrFreeCell, UPIntrRefMut}; diff --git a/os/src/sync/mutex.rs b/os/src/sync/mutex.rs index be58f795..463638b3 100644 --- a/os/src/sync/mutex.rs +++ b/os/src/sync/mutex.rs @@ -1,4 +1,4 @@ -use super::UPSafeCell; +use super::UPIntrFreeCell; use crate::task::TaskControlBlock; use crate::task::{add_task, current_task}; use crate::task::{block_current_and_run_next, suspend_current_and_run_next}; @@ -10,13 +10,13 @@ pub trait Mutex: Sync + Send { } pub struct MutexSpin { - locked: UPSafeCell, + locked: UPIntrFreeCell, } impl MutexSpin { pub fn new() -> Self { Self { - locked: unsafe { UPSafeCell::new(false) }, + locked: unsafe { UPIntrFreeCell::new(false) }, } } } @@ -43,7 +43,7 @@ impl Mutex for MutexSpin { } pub struct MutexBlocking { - inner: UPSafeCell, + inner: UPIntrFreeCell, } pub struct MutexBlockingInner { @@ -55,7 +55,7 @@ impl MutexBlocking { pub fn new() -> Self { Self { inner: unsafe { - UPSafeCell::new(MutexBlockingInner { + UPIntrFreeCell::new(MutexBlockingInner { locked: false, wait_queue: VecDeque::new(), }) diff --git a/os/src/sync/semaphore.rs b/os/src/sync/semaphore.rs index 7f3870f8..354db29f 100644 --- a/os/src/sync/semaphore.rs +++ b/os/src/sync/semaphore.rs @@ -1,9 +1,9 @@ -use crate::sync::UPSafeCell; +use crate::sync::UPIntrFreeCell; use crate::task::{add_task, block_current_and_run_next, current_task, TaskControlBlock}; use alloc::{collections::VecDeque, sync::Arc}; pub struct Semaphore { - pub inner: UPSafeCell, + pub inner: UPIntrFreeCell, } pub struct SemaphoreInner { @@ -15,7 +15,7 @@ impl Semaphore { pub fn new(res_count: usize) -> Self { Self { inner: unsafe { - UPSafeCell::new(SemaphoreInner { + UPIntrFreeCell::new(SemaphoreInner { count: res_count as isize, wait_queue: VecDeque::new(), }) diff --git a/os/src/sync/up.rs b/os/src/sync/up.rs index c7b2c9ee..55c8d40a 100644 --- a/os/src/sync/up.rs +++ b/os/src/sync/up.rs @@ -1,5 +1,9 @@ -use core::cell::{RefCell, RefMut}; +use core::cell::{RefCell, RefMut, UnsafeCell}; +use core::ops::{Deref, DerefMut}; +use riscv::register::sstatus; +use lazy_static::*; +/* /// Wrap a static data structure inside it so that we are /// able to access it without any `unsafe`. /// @@ -27,3 +31,104 @@ impl UPSafeCell { 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/sync.rs b/os/src/syscall/sync.rs index dd0e856a..e08f3296 100644 --- a/os/src/syscall/sync.rs +++ b/os/src/syscall/sync.rs @@ -129,6 +129,6 @@ pub fn sys_condvar_wait(condvar_id: usize, mutex_id: usize) -> isize { 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(mutex); + condvar.wait_with_mutex(mutex); 0 } diff --git a/os/src/task/id.rs b/os/src/task/id.rs index 178a09f6..e336c500 100644 --- a/os/src/task/id.rs +++ b/os/src/task/id.rs @@ -1,7 +1,7 @@ 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::UPSafeCell; +use crate::sync::UPIntrFreeCell; use alloc::{ sync::{Arc, Weak}, vec::Vec, @@ -40,10 +40,10 @@ impl RecycleAllocator { } lazy_static! { - static ref PID_ALLOCATOR: UPSafeCell = - unsafe { UPSafeCell::new(RecycleAllocator::new()) }; - static ref KSTACK_ALLOCATOR: UPSafeCell = - unsafe { UPSafeCell::new(RecycleAllocator::new()) }; + static ref PID_ALLOCATOR: UPIntrFreeCell = + unsafe { UPIntrFreeCell::new(RecycleAllocator::new()) }; + static ref KSTACK_ALLOCATOR: UPIntrFreeCell = + unsafe { UPIntrFreeCell::new(RecycleAllocator::new()) }; } pub struct PidHandle(pub usize); diff --git a/os/src/task/manager.rs b/os/src/task/manager.rs index 5ed68ae7..168ba32e 100644 --- a/os/src/task/manager.rs +++ b/os/src/task/manager.rs @@ -1,5 +1,5 @@ use super::{ProcessControlBlock, TaskControlBlock}; -use crate::sync::UPSafeCell; +use crate::sync::UPIntrFreeCell; use alloc::collections::{BTreeMap, VecDeque}; use alloc::sync::Arc; use lazy_static::*; @@ -24,10 +24,10 @@ impl TaskManager { } lazy_static! { - pub static ref TASK_MANAGER: UPSafeCell = - unsafe { UPSafeCell::new(TaskManager::new()) }; - pub static ref PID2PCB: UPSafeCell>> = - unsafe { UPSafeCell::new(BTreeMap::new()) }; + 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) { diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index 1bd7b2a7..858848a7 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -43,12 +43,16 @@ pub fn suspend_current_and_run_next() { schedule(task_cx_ptr); } -pub fn block_current_and_run_next() { +/// 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(); - let task_cx_ptr = &mut task_inner.task_cx as *mut TaskContext; task_inner.task_status = TaskStatus::Blocking; - drop(task_inner); + &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); } diff --git a/os/src/task/process.rs b/os/src/task/process.rs index ffff14fe..b3976b7c 100644 --- a/os/src/task/process.rs +++ b/os/src/task/process.rs @@ -5,19 +5,18 @@ 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, UPSafeCell}; +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; -use core::cell::RefMut; pub struct ProcessControlBlock { // immutable pub pid: PidHandle, // mutable - inner: UPSafeCell, + inner: UPIntrFreeCell, } pub struct ProcessControlBlockInner { @@ -68,7 +67,7 @@ impl ProcessControlBlockInner { } impl ProcessControlBlock { - pub fn inner_exclusive_access(&self) -> RefMut<'_, ProcessControlBlockInner> { + pub fn inner_exclusive_access(&self) -> UPIntrRefMut<'_, ProcessControlBlockInner> { self.inner.exclusive_access() } @@ -80,7 +79,7 @@ impl ProcessControlBlock { let process = Arc::new(Self { pid: pid_handle, inner: unsafe { - UPSafeCell::new(ProcessControlBlockInner { + UPIntrFreeCell::new(ProcessControlBlockInner { is_zombie: false, memory_set, parent: None, @@ -206,7 +205,7 @@ impl ProcessControlBlock { let child = Arc::new(Self { pid, inner: unsafe { - UPSafeCell::new(ProcessControlBlockInner { + UPIntrFreeCell::new(ProcessControlBlockInner { is_zombie: false, memory_set, parent: Some(Arc::downgrade(self)), diff --git a/os/src/task/processor.rs b/os/src/task/processor.rs index 3c1a22f6..f196f681 100644 --- a/os/src/task/processor.rs +++ b/os/src/task/processor.rs @@ -1,7 +1,7 @@ use super::__switch; use super::{fetch_task, TaskStatus}; use super::{ProcessControlBlock, TaskContext, TaskControlBlock}; -use crate::sync::UPSafeCell; +use crate::sync::UPIntrFreeCell; use crate::trap::TrapContext; use alloc::sync::Arc; use lazy_static::*; @@ -30,7 +30,7 @@ impl Processor { } lazy_static! { - pub static ref PROCESSOR: UPSafeCell = unsafe { UPSafeCell::new(Processor::new()) }; + pub static ref PROCESSOR: UPIntrFreeCell = unsafe { UPIntrFreeCell::new(Processor::new()) }; } pub fn run_tasks() { @@ -39,11 +39,10 @@ pub fn run_tasks() { 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 + 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); @@ -95,9 +94,9 @@ pub fn current_kstack_top() -> usize { } 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); + 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/task.rs b/os/src/task/task.rs index 99900de3..85d949f8 100644 --- a/os/src/task/task.rs +++ b/os/src/task/task.rs @@ -1,20 +1,19 @@ use super::id::TaskUserRes; use super::{kstack_alloc, KernelStack, ProcessControlBlock, TaskContext}; use crate::trap::TrapContext; -use crate::{mm::PhysPageNum, sync::UPSafeCell}; +use crate::{mm::PhysPageNum, sync::{UPIntrFreeCell, UPIntrRefMut}}; use alloc::sync::{Arc, Weak}; -use core::cell::RefMut; pub struct TaskControlBlock { // immutable pub process: Weak, pub kstack: KernelStack, // mutable - inner: UPSafeCell, + pub inner: UPIntrFreeCell, } impl TaskControlBlock { - pub fn inner_exclusive_access(&self) -> RefMut<'_, TaskControlBlockInner> { + pub fn inner_exclusive_access(&self) -> UPIntrRefMut<'_, TaskControlBlockInner> { self.inner.exclusive_access() } @@ -58,7 +57,7 @@ impl TaskControlBlock { process: Arc::downgrade(&process), kstack, inner: unsafe { - UPSafeCell::new(TaskControlBlockInner { + UPIntrFreeCell::new(TaskControlBlockInner { res: Some(res), trap_cx_ppn, task_cx: TaskContext::goto_trap_return(kstack_top), diff --git a/os/src/timer.rs b/os/src/timer.rs index 3baed0f7..06a70dea 100644 --- a/os/src/timer.rs +++ b/os/src/timer.rs @@ -2,7 +2,7 @@ use core::cmp::Ordering; use crate::config::CLOCK_FREQ; use crate::sbi::set_timer; -use crate::sync::UPSafeCell; +use crate::sync::UPIntrFreeCell; use crate::task::{add_task, TaskControlBlock}; use alloc::collections::BinaryHeap; use alloc::sync::Arc; @@ -50,8 +50,8 @@ impl Ord for TimerCondVar { } lazy_static! { - static ref TIMERS: UPSafeCell> = - unsafe { UPSafeCell::new(BinaryHeap::::new()) }; + static ref TIMERS: UPIntrFreeCell> = + unsafe { UPIntrFreeCell::new(BinaryHeap::::new()) }; } pub fn add_timer(expire_ms: usize, task: Arc) { diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index 6397811a..5eb417dc 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -11,7 +11,7 @@ use core::arch::{asm, global_asm}; use riscv::register::{ mtvec::TrapMode, scause::{self, Exception, Interrupt, Trap}, - sie, stval, stvec, + sie, stval, stvec, sstatus, sscratch, }; global_asm!(include_str!("trap.S")); @@ -21,8 +21,14 @@ pub fn init() { } 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(trap_from_kernel as usize, TrapMode::Direct); + stvec::write(__alltraps_k_va, TrapMode::Direct); + sscratch::write(trap_from_kernel as usize); } } @@ -38,16 +44,32 @@ pub fn enable_timer_interrupt() { } } +fn enable_supervisor_interrupt() { + unsafe { + sstatus::set_sie(); + } +} + +fn disable_supervisor_interrupt() { + unsafe { + sstatus::clear_sie(); + } +} + #[no_mangle] pub fn trap_handler() -> ! { set_kernel_trap_entry(); let scause = scause::read(); let stval = stval::read(); + //println!("into {:?}", scause.cause()); match scause.cause() { Trap::Exception(Exception::UserEnvCall) => { // jump to next instruction anyway let mut cx = current_trap_cx(); cx.sepc += 4; + + enable_supervisor_interrupt(); + // get system call return value let result = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]); // cx is changed during sys_exec, so we have to call it again @@ -78,6 +100,9 @@ pub fn trap_handler() -> ! { check_timer(); suspend_current_and_run_next(); } + Trap::Interrupt(Interrupt::SupervisorExternal) => { + crate::board::irq_handler(); + } _ => { panic!( "Unsupported trap {:?}, stval = {:#x}!", @@ -96,6 +121,7 @@ pub fn trap_handler() -> ! { #[no_mangle] pub fn trap_return() -> ! { + disable_supervisor_interrupt(); set_user_trap_entry(); let trap_cx_user_va = current_trap_cx_user_va(); let user_satp = current_user_token(); @@ -104,6 +130,7 @@ pub fn trap_return() -> ! { fn __restore(); } let restore_va = __restore as usize - __alltraps as usize + TRAMPOLINE; + //println!("before return"); unsafe { asm!( "fence.i", @@ -117,10 +144,26 @@ pub fn trap_return() -> ! { } #[no_mangle] -pub fn trap_from_kernel() -> ! { - use riscv::register::sepc; - println!("stval = {:#x}, sepc = {:#x}", stval::read(), sepc::read()); - panic!("a trap {:?} from kernel!", scause::read().cause()); +pub 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 + ); + }, + } } pub use context::TrapContext; diff --git a/os/src/trap/trap.S b/os/src/trap/trap.S index c0e2d153..407307ca 100644 --- a/os/src/trap/trap.S +++ b/os/src/trap/trap.S @@ -8,6 +8,8 @@ .section .text.trampoline .globl __alltraps .globl __restore + .globl __alltraps_k + .globl __restore_k .align 2 __alltraps: csrrw sp, sscratch, sp @@ -67,3 +69,36 @@ __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/user/src/bin/huge_write.rs b/user/src/bin/huge_write.rs index e93f8b8e..2a977c96 100644 --- a/user/src/bin/huge_write.rs +++ b/user/src/bin/huge_write.rs @@ -24,7 +24,7 @@ pub fn main() -> i32 { } close(f); let time_ms = (get_time() - start) as usize; - let speed_kbs = size_mb * 1000000 / time_ms; + let speed_kbs = (size_mb << 20) / time_ms; println!( "{}MiB written, time cost = {}ms, write speed = {}KiB/s", size_mb, time_ms, speed_kbs diff --git a/user/src/bin/huge_write_mt.rs b/user/src/bin/huge_write_mt.rs new file mode 100644 index 00000000..63146a58 --- /dev/null +++ b/user/src/bin/huge_write_mt.rs @@ -0,0 +1,56 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use alloc::{vec::Vec, string::String, fmt::format}; +use user_lib::{exit, thread_create, waittid}; +use user_lib::{close, get_time, open, write, OpenFlags, gettid}; + +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 +}