Skip to main content

os/drivers/block/
virtio_blk.rs

1use 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}