mirror of
https://github.com/rcore-os/rCore-Tutorial-v3.git
synced 2025-01-18 21:17:14 +04:00
IRQ-based VirtIOBlk Access. Plz wait for the virtio-drivers crate to be updated.
This commit is contained in:
parent
f0f7f6fcaa
commit
6ef566faac
@ -23,6 +23,8 @@ impl BlockDevice for BlockFile {
|
|||||||
.expect("Error when seeking!");
|
.expect("Error when seeking!");
|
||||||
assert_eq!(file.write(buf).unwrap(), BLOCK_SZ, "Not a complete block!");
|
assert_eq!(file.write(buf).unwrap(), BLOCK_SZ, "Not a complete block!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_irq(&self) { unimplemented!(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -3,4 +3,5 @@ use core::any::Any;
|
|||||||
pub trait BlockDevice: Send + Sync + Any {
|
pub trait BlockDevice: Send + Sync + Any {
|
||||||
fn read_block(&self, block_id: usize, buf: &mut [u8]);
|
fn read_block(&self, block_id: usize, buf: &mut [u8]);
|
||||||
fn write_block(&self, block_id: usize, buf: &[u8]);
|
fn write_block(&self, block_id: usize, buf: &[u8]);
|
||||||
|
fn handle_irq(&self);
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,8 @@ lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
|
|||||||
buddy_system_allocator = "0.6"
|
buddy_system_allocator = "0.6"
|
||||||
bitflags = "1.2.1"
|
bitflags = "1.2.1"
|
||||||
xmas-elf = "0.7.0"
|
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-pac = { git = "https://github.com/wyfcyx/k210-pac" }
|
||||||
k210-hal = { git = "https://github.com/wyfcyx/k210-hal" }
|
k210-hal = { git = "https://github.com/wyfcyx/k210-hal" }
|
||||||
k210-soc = { git = "https://github.com/wyfcyx/k210-soc" }
|
k210-soc = { git = "https://github.com/wyfcyx/k210-soc" }
|
||||||
@ -20,4 +21,4 @@ easy-fs = { path = "../easy-fs" }
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
board_qemu = []
|
board_qemu = []
|
||||||
board_k210 = []
|
board_k210 = []
|
||||||
|
@ -21,3 +21,10 @@ pub const MMIO: &[(usize, usize)] = &[
|
|||||||
|
|
||||||
pub type BlockDeviceImpl = crate::drivers::block::SDCardWrapper;
|
pub type BlockDeviceImpl = crate::drivers::block::SDCardWrapper;
|
||||||
|
|
||||||
|
pub fn device_init() {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn irq_handler() {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
@ -1,6 +1,43 @@
|
|||||||
pub const CLOCK_FREQ: usize = 12500000;
|
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 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);
|
||||||
|
}
|
||||||
|
@ -761,4 +761,5 @@ impl BlockDevice for SDCardWrapper {
|
|||||||
.write_sector(buf, block_id as u32)
|
.write_sector(buf, block_id as u32)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
fn handle_irq(&self) { unimplemented!(); }
|
||||||
}
|
}
|
||||||
|
@ -3,15 +3,20 @@ use crate::mm::{
|
|||||||
frame_alloc, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum,
|
frame_alloc, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum,
|
||||||
StepByOne, VirtAddr,
|
StepByOne, VirtAddr,
|
||||||
};
|
};
|
||||||
use crate::sync::UPSafeCell;
|
use crate::sync::{UPSafeCell, Condvar};
|
||||||
use alloc::vec::Vec;
|
|
||||||
use lazy_static::*;
|
use lazy_static::*;
|
||||||
use virtio_drivers::{VirtIOBlk, VirtIOHeader};
|
use virtio_drivers::{VirtIOBlk, VirtIOHeader};
|
||||||
|
use crate::DEV_NON_BLOCKING_ACCESS;
|
||||||
|
use alloc::collections::BTreeMap;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
const VIRTIO0: usize = 0x10001000;
|
const VIRTIO0: usize = 0x10001000;
|
||||||
|
|
||||||
pub struct VirtIOBlock(UPSafeCell<VirtIOBlk<'static>>);
|
pub struct VirtIOBlock {
|
||||||
|
virtio_blk: UPSafeCell<VirtIOBlk<'static>>,
|
||||||
|
condvars: BTreeMap<u16, Condvar>,
|
||||||
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref QUEUE_FRAMES: UPSafeCell<Vec<FrameTracker>> = unsafe { UPSafeCell::new(Vec::new()) };
|
static ref QUEUE_FRAMES: UPSafeCell<Vec<FrameTracker>> = unsafe { UPSafeCell::new(Vec::new()) };
|
||||||
@ -19,26 +24,61 @@ lazy_static! {
|
|||||||
|
|
||||||
impl BlockDevice for VirtIOBlock {
|
impl BlockDevice for VirtIOBlock {
|
||||||
fn read_block(&self, block_id: usize, buf: &mut [u8]) {
|
fn read_block(&self, block_id: usize, buf: &mut [u8]) {
|
||||||
self.0
|
let nb = *DEV_NON_BLOCKING_ACCESS.exclusive_access();
|
||||||
.exclusive_access()
|
if nb {
|
||||||
.read_block(block_id, buf)
|
let mut blk = self.virtio_blk.exclusive_access();
|
||||||
.expect("Error when reading VirtIOBlk");
|
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]) {
|
fn write_block(&self, block_id: usize, buf: &[u8]) {
|
||||||
self.0
|
let nb = *DEV_NON_BLOCKING_ACCESS.exclusive_access();
|
||||||
.exclusive_access()
|
if nb {
|
||||||
.write_block(block_id, buf)
|
let mut blk = self.virtio_blk.exclusive_access();
|
||||||
.expect("Error when writing VirtIOBlk");
|
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 {
|
impl VirtIOBlock {
|
||||||
#[allow(unused)]
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
Self(UPSafeCell::new(
|
let virtio_blk = UPSafeCell::new(
|
||||||
VirtIOBlk::new(&mut *(VIRTIO0 as *mut VirtIOHeader)).unwrap(),
|
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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
pub mod block;
|
pub mod block;
|
||||||
|
pub mod plic;
|
||||||
|
|
||||||
pub use block::BLOCK_DEVICE;
|
pub use block::BLOCK_DEVICE;
|
||||||
|
127
os/src/drivers/plic.rs
Normal file
127
os/src/drivers/plic.rs
Normal 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); }
|
||||||
|
}
|
||||||
|
}
|
@ -29,9 +29,7 @@ mod task;
|
|||||||
mod timer;
|
mod timer;
|
||||||
mod trap;
|
mod trap;
|
||||||
|
|
||||||
use core::arch::global_asm;
|
core::arch::global_asm!(include_str!("entry.asm"));
|
||||||
|
|
||||||
global_asm!(include_str!("entry.asm"));
|
|
||||||
|
|
||||||
fn clear_bss() {
|
fn clear_bss() {
|
||||||
extern "C" {
|
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]
|
#[no_mangle]
|
||||||
pub fn rust_main() -> ! {
|
pub fn rust_main() -> ! {
|
||||||
clear_bss();
|
clear_bss();
|
||||||
@ -53,8 +60,10 @@ pub fn rust_main() -> ! {
|
|||||||
trap::init();
|
trap::init();
|
||||||
trap::enable_timer_interrupt();
|
trap::enable_timer_interrupt();
|
||||||
timer::set_next_trigger();
|
timer::set_next_trigger();
|
||||||
|
board::device_init();
|
||||||
fs::list_apps();
|
fs::list_apps();
|
||||||
task::add_initproc();
|
task::add_initproc();
|
||||||
|
*DEV_NON_BLOCKING_ACCESS.exclusive_access() = true;
|
||||||
task::run_tasks();
|
task::run_tasks();
|
||||||
panic!("Unreachable in rust_main!");
|
panic!("Unreachable in rust_main!");
|
||||||
}
|
}
|
||||||
|
@ -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();
|
mutex.unlock();
|
||||||
let mut inner = self.inner.exclusive_access();
|
let mut inner = self.inner.exclusive_access();
|
||||||
inner.wait_queue.push_back(current_task().unwrap());
|
inner.wait_queue.push_back(current_task().unwrap());
|
||||||
|
@ -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 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());
|
let mutex = Arc::clone(process_inner.mutex_list[mutex_id].as_ref().unwrap());
|
||||||
drop(process_inner);
|
drop(process_inner);
|
||||||
condvar.wait(mutex);
|
condvar.wait_with_mutex(mutex);
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,9 @@ pub fn trap_handler() -> ! {
|
|||||||
check_timer();
|
check_timer();
|
||||||
suspend_current_and_run_next();
|
suspend_current_and_run_next();
|
||||||
}
|
}
|
||||||
|
Trap::Interrupt(Interrupt::SupervisorExternal) => {
|
||||||
|
crate::board::irq_handler();
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
panic!(
|
panic!(
|
||||||
"Unsupported trap {:?}, stval = {:#x}!",
|
"Unsupported trap {:?}, stval = {:#x}!",
|
||||||
|
Loading…
Reference in New Issue
Block a user