From 6ef566faacbb2117b2acf863a84a0213fc503a6c Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Mon, 7 Feb 2022 14:13:30 -0800 Subject: [PATCH] IRQ-based VirtIOBlk Access. Plz wait for the virtio-drivers crate to be updated. --- easy-fs-fuse/src/main.rs | 2 + easy-fs/src/block_dev.rs | 1 + os/Cargo.toml | 5 +- os/src/boards/k210.rs | 7 ++ os/src/boards/qemu.rs | 39 ++++++++- os/src/drivers/block/sdcard.rs | 1 + os/src/drivers/block/virtio_blk.rs | 68 +++++++++++---- os/src/drivers/mod.rs | 1 + os/src/drivers/plic.rs | 127 +++++++++++++++++++++++++++++ os/src/main.rs | 15 +++- os/src/sync/condvar.rs | 9 +- os/src/syscall/sync.rs | 2 +- os/src/trap/mod.rs | 3 + 13 files changed, 258 insertions(+), 22 deletions(-) create mode 100644 os/src/drivers/plic.rs 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..18d68849 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -12,7 +12,8 @@ lazy_static = { version = "1.4.0", features = ["spin_no_std"] } buddy_system_allocator = "0.6" bitflags = "1.2.1" xmas-elf = "0.7.0" -virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers" } +#virtio-drivers = { git = "https://github.com/wyfcyx/virtio-drivers" } +virtio-drivers = { path = "../../virtio-drivers" } k210-pac = { git = "https://github.com/wyfcyx/k210-pac" } k210-hal = { git = "https://github.com/wyfcyx/k210-hal" } k210-soc = { git = "https://github.com/wyfcyx/k210-soc" } @@ -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/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..bf5841b5 100644 --- a/os/src/boards/qemu.rs +++ b/os/src/boards/qemu.rs @@ -1,6 +1,43 @@ pub const CLOCK_FREQ: usize = 12500000; -pub const MMIO: &[(usize, usize)] = &[(0x10001000, 0x1000)]; +pub const MMIO: &[(usize, usize)] = &[ + (0x10001000, 0x1000), + (0xC00_0000, 0x40_0000), +]; pub type BlockDeviceImpl = crate::drivers::block::VirtIOBlock; +pub const VIRT_PLIC: usize = 0xC00_0000; + +use crate::drivers::plic::{PLIC, IntrTargetPriority}; + +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); + } + crate::println!("Hart0M threshold = {}", plic.get_threshold(hart_id, IntrTargetPriority::Machine)); + crate::println!("Hart0S threshold = {}", plic.get_threshold(hart_id, IntrTargetPriority::Supervisor)); + crate::println!("1 prio = {}", plic.get_priority(1)); + crate::println!("10 prio = {}", plic.get_priority(10)); + unsafe { sie::set_sext(); } +} + +use crate::drivers::block::BLOCK_DEVICE; + +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(), + _ => panic!("unsupported IRQ {}", intr_src_id), + } + plic.complete(0, IntrTargetPriority::Supervisor, intr_src_id); +} diff --git a/os/src/drivers/block/sdcard.rs b/os/src/drivers/block/sdcard.rs index a74acccc..f7c640b1 100644 --- a/os/src/drivers/block/sdcard.rs +++ b/os/src/drivers/block/sdcard.rs @@ -761,4 +761,5 @@ 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..170416c4 100644 --- a/os/src/drivers/block/virtio_blk.rs +++ b/os/src/drivers/block/virtio_blk.rs @@ -3,15 +3,20 @@ use crate::mm::{ frame_alloc, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum, StepByOne, VirtAddr, }; -use crate::sync::UPSafeCell; -use alloc::vec::Vec; +use crate::sync::{UPSafeCell, Condvar}; use lazy_static::*; use virtio_drivers::{VirtIOBlk, VirtIOHeader}; +use crate::DEV_NON_BLOCKING_ACCESS; +use alloc::collections::BTreeMap; +use alloc::vec::Vec; #[allow(unused)] const VIRTIO0: usize = 0x10001000; -pub struct VirtIOBlock(UPSafeCell>); +pub struct VirtIOBlock { + virtio_blk: UPSafeCell>, + condvars: BTreeMap, +} lazy_static! { static ref QUEUE_FRAMES: UPSafeCell> = unsafe { UPSafeCell::new(Vec::new()) }; @@ -19,26 +24,61 @@ lazy_static! { 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 blk = self.virtio_blk.exclusive_access(); + let mut resp = 0xffu8; + let token = blk.read_block_nb(block_id, buf, &mut resp).unwrap(); + drop(blk); + self.condvars.get(&token).unwrap().wait(); + assert_eq!(resp, 0x0, "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 blk = self.virtio_blk.exclusive_access(); + let mut resp = 0xffu8; + let token = blk.write_block_nb(block_id, buf, &mut resp).unwrap(); + drop(blk); + self.condvars.get(&token).unwrap().wait(); + assert_eq!(resp, 0x0, "Error when reading VirtIOBlk"); + } else { + self.virtio_blk + .exclusive_access() + .write_block(block_id, buf) + .expect("Error when writing VirtIOBlk"); + } + } + fn handle_irq(&self) { + let mut blk = self.virtio_blk.exclusive_access(); + 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( + let virtio_blk = UPSafeCell::new( VirtIOBlk::new(&mut *(VIRTIO0 as *mut VirtIOHeader)).unwrap(), - )) + ); + let mut condvars = BTreeMap::new(); + let channels = virtio_blk.exclusive_access().virt_queue_size(); + for i in 0..channels { + let condvar = Condvar::new(); + condvars.insert(i, condvar); + } + Self { + virtio_blk, + condvars, + } } } } diff --git a/os/src/drivers/mod.rs b/os/src/drivers/mod.rs index c2dea36b..7a2e4fba 100644 --- a/os/src/drivers/mod.rs +++ b/os/src/drivers/mod.rs @@ -1,3 +1,4 @@ pub mod block; +pub mod plic; pub use block::BLOCK_DEVICE; diff --git a/os/src/drivers/plic.rs b/os/src/drivers/plic.rs new file mode 100644 index 00000000..fd6aefc3 --- /dev/null +++ b/os/src/drivers/plic.rs @@ -0,0 +1,127 @@ +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); + } + } + 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); + } + } + 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); } + } + 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/main.rs b/os/src/main.rs index cbc4ab40..a506d1a1 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,6 +42,15 @@ fn clear_bss() { } } +use lazy_static::*; +use sync::UPSafeCell; + +lazy_static! { + pub static ref DEV_NON_BLOCKING_ACCESS: UPSafeCell = unsafe { + UPSafeCell::new(false) + }; +} + #[no_mangle] pub fn rust_main() -> ! { clear_bss(); @@ -53,8 +60,10 @@ pub fn rust_main() -> ! { 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/sync/condvar.rs b/os/src/sync/condvar.rs index f96cd915..fc3f586b 100644 --- a/os/src/sync/condvar.rs +++ b/os/src/sync/condvar.rs @@ -28,7 +28,14 @@ impl Condvar { } } - pub fn wait(&self, mutex: Arc) { + 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_with_mutex(&self, mutex: Arc) { mutex.unlock(); let mut inner = self.inner.exclusive_access(); inner.wait_queue.push_back(current_task().unwrap()); 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/trap/mod.rs b/os/src/trap/mod.rs index 6397811a..287afd3e 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -78,6 +78,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}!",