os/drivers/block/
virtio_blk.rs1use super::BlockDevice;
2use crate::DEV_NON_BLOCKING_ACCESS;
3use crate::drivers::bus::virtio::VirtioHal;
4use crate::sync::{Condvar, UPIntrFreeCell};
5use crate::task::schedule;
6use alloc::collections::BTreeMap;
7use virtio_drivers::{BlkResp, RespStatus, VirtIOBlk, VirtIOHeader};
8
9#[allow(unused)]
10const VIRTIO0: usize = 0x10008000;
11
12pub struct VirtIOBlock {
13 virtio_blk: UPIntrFreeCell<VirtIOBlk<'static, VirtioHal>>,
14 condvars: BTreeMap<u16, Condvar>,
15}
16
17impl BlockDevice for VirtIOBlock {
18 fn read_block(&self, block_id: usize, buf: &mut [u8]) {
19 let nb = *DEV_NON_BLOCKING_ACCESS.exclusive_access();
20 if nb {
21 let mut resp = BlkResp::default();
22 let task_cx_ptr = self.virtio_blk.exclusive_session(|blk| {
23 let token = unsafe { blk.read_block_nb(block_id, buf, &mut resp).unwrap() };
24 self.condvars.get(&token).unwrap().wait_no_sched()
25 });
26 schedule(task_cx_ptr);
27 assert_eq!(
28 resp.status(),
29 RespStatus::Ok,
30 "Error when reading VirtIOBlk"
31 );
32 } else {
33 self.virtio_blk
34 .exclusive_access()
35 .read_block(block_id, buf)
36 .expect("Error when reading VirtIOBlk");
37 }
38 }
39 fn write_block(&self, block_id: usize, buf: &[u8]) {
40 let nb = *DEV_NON_BLOCKING_ACCESS.exclusive_access();
41 if nb {
42 let mut resp = BlkResp::default();
43 let task_cx_ptr = self.virtio_blk.exclusive_session(|blk| {
44 let token = unsafe { blk.write_block_nb(block_id, buf, &mut resp).unwrap() };
45 self.condvars.get(&token).unwrap().wait_no_sched()
46 });
47 schedule(task_cx_ptr);
48 assert_eq!(
49 resp.status(),
50 RespStatus::Ok,
51 "Error when writing VirtIOBlk"
52 );
53 } else {
54 self.virtio_blk
55 .exclusive_access()
56 .write_block(block_id, buf)
57 .expect("Error when writing VirtIOBlk");
58 }
59 }
60 fn handle_irq(&self) {
61 self.virtio_blk.exclusive_session(|blk| {
62 while let Ok(token) = blk.pop_used() {
63 self.condvars.get(&token).unwrap().signal();
64 }
65 });
66 }
67}
68
69impl VirtIOBlock {
70 pub fn new() -> Self {
71 let virtio_blk = unsafe {
72 UPIntrFreeCell::new(
73 VirtIOBlk::<VirtioHal>::new(&mut *(VIRTIO0 as *mut VirtIOHeader)).unwrap(),
74 )
75 };
76 let mut condvars = BTreeMap::new();
77 let channels = virtio_blk.exclusive_access().virt_queue_size();
78 for i in 0..channels {
79 let condvar = Condvar::new();
80 condvars.insert(i, condvar);
81 }
82 Self {
83 virtio_blk,
84 condvars,
85 }
86 }
87}