IRQ-based VirtIOBlk Access. Plz wait for the virtio-drivers crate to be updated.

This commit is contained in:
Yifan Wu 2022-02-07 14:13:30 -08:00
parent f0f7f6fcaa
commit 6ef566faac
13 changed files with 258 additions and 22 deletions

View File

@ -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() {

View File

@ -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);
}

View File

@ -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 = []
board_k210 = []

View File

@ -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!();
}

View File

@ -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);
}

View File

@ -761,4 +761,5 @@ impl BlockDevice for SDCardWrapper {
.write_sector(buf, block_id as u32)
.unwrap();
}
fn handle_irq(&self) { unimplemented!(); }
}

View File

@ -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<VirtIOBlk<'static>>);
pub struct VirtIOBlock {
virtio_blk: UPSafeCell<VirtIOBlk<'static>>,
condvars: BTreeMap<u16, Condvar>,
}
lazy_static! {
static ref QUEUE_FRAMES: UPSafeCell<Vec<FrameTracker>> = 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,
}
}
}
}

View File

@ -1,3 +1,4 @@
pub mod block;
pub mod plic;
pub use block::BLOCK_DEVICE;

127
os/src/drivers/plic.rs Normal file
View File

@ -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); }
}
}

View File

@ -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<bool> = 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!");
}

View File

@ -28,7 +28,14 @@ impl Condvar {
}
}
pub fn wait(&self, mutex: Arc<dyn Mutex>) {
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<dyn Mutex>) {
mutex.unlock();
let mut inner = self.inner.exclusive_access();
inner.wait_queue.push_back(current_task().unwrap());

View File

@ -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
}

View File

@ -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}!",