os/drivers/block/
virtio_blk.rs

1use super::BlockDevice;
2use crate::mm::{
3    FrameTracker, PageTable, PhysAddr, PhysPageNum, StepByOne, VirtAddr, frame_alloc,
4    frame_dealloc, kernel_token,
5};
6use crate::sync::UPSafeCell;
7use alloc::vec::Vec;
8use lazy_static::*;
9use virtio_drivers::{Hal, VirtIOBlk, VirtIOHeader};
10
11#[allow(unused)]
12const VIRTIO0: usize = 0x10001000;
13
14pub struct VirtIOBlock(UPSafeCell<VirtIOBlk<'static, VirtioHal>>);
15
16lazy_static! {
17    static ref QUEUE_FRAMES: UPSafeCell<Vec<FrameTracker>> = unsafe { UPSafeCell::new(Vec::new()) };
18}
19
20impl BlockDevice for VirtIOBlock {
21    fn read_block(&self, block_id: usize, buf: &mut [u8]) {
22        self.0
23            .exclusive_access()
24            .read_block(block_id, buf)
25            .expect("Error when reading VirtIOBlk");
26    }
27    fn write_block(&self, block_id: usize, buf: &[u8]) {
28        self.0
29            .exclusive_access()
30            .write_block(block_id, buf)
31            .expect("Error when writing VirtIOBlk");
32    }
33}
34
35impl VirtIOBlock {
36    #[allow(unused)]
37    pub fn new() -> Self {
38        unsafe {
39            Self(UPSafeCell::new(
40                VirtIOBlk::<VirtioHal>::new(&mut *(VIRTIO0 as *mut VirtIOHeader)).unwrap(),
41            ))
42        }
43    }
44}
45
46pub struct VirtioHal;
47
48impl Hal for VirtioHal {
49    fn dma_alloc(pages: usize) -> usize {
50        let mut ppn_base = PhysPageNum(0);
51        for i in 0..pages {
52            let frame = frame_alloc().unwrap();
53            if i == 0 {
54                ppn_base = frame.ppn;
55            }
56            assert_eq!(frame.ppn.0, ppn_base.0 + i);
57            QUEUE_FRAMES.exclusive_access().push(frame);
58        }
59        let pa: PhysAddr = ppn_base.into();
60        pa.0
61    }
62
63    fn dma_dealloc(pa: usize, pages: usize) -> i32 {
64        let pa = PhysAddr::from(pa);
65        let mut ppn_base: PhysPageNum = pa.into();
66        for _ in 0..pages {
67            frame_dealloc(ppn_base);
68            ppn_base.step();
69        }
70        0
71    }
72
73    fn phys_to_virt(addr: usize) -> usize {
74        addr
75    }
76
77    fn virt_to_phys(vaddr: usize) -> usize {
78        PageTable::from_token(kernel_token())
79            .translate_va(VirtAddr::from(vaddr))
80            .unwrap()
81            .0
82    }
83}