1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
// SPDX-License-Identifier: MPL-2.0
//! MMIO device common definitions or functions.
use int_to_c_enum::TryFromInt;
use log::info;
use super::VIRTIO_MMIO_MAGIC;
use crate::{
io_mem::IoMem,
mm::{paddr_to_vaddr, Paddr, VmIo},
trap::IrqLine,
};
/// MMIO Common device.
#[derive(Debug)]
pub struct MmioCommonDevice {
io_mem: IoMem,
irq: IrqLine,
}
impl MmioCommonDevice {
pub(super) fn new(paddr: Paddr, handle: IrqLine) -> Self {
// TODO: Implement universal access to MMIO devices since we are temporarily
// using specific virtio device as implementation of CommonDevice.
// Read magic value
// SAFETY: It only read the value and judge if the magic value fit 0x74726976
unsafe {
debug_assert_eq!(*(paddr_to_vaddr(paddr) as *const u32), VIRTIO_MMIO_MAGIC);
}
// SAFETY: This range is virtio-mmio device space.
let io_mem = unsafe { IoMem::new(paddr..paddr + 0x200) };
let res = Self {
io_mem,
irq: handle,
};
info!(
"[Virtio]: Found Virtio mmio device, device id:{:?}, irq number:{:?}",
res.device_id(),
res.irq.num()
);
res
}
/// Base address
pub fn address(&self) -> Paddr {
self.io_mem.paddr()
}
/// Grants access to the MMIO
pub fn io_mem(&self) -> &IoMem {
&self.io_mem
}
/// Device ID
pub fn device_id(&self) -> u32 {
self.io_mem.read_val::<u32>(8).unwrap()
}
/// Version of the MMIO device.
pub fn version(&self) -> VirtioMmioVersion {
VirtioMmioVersion::try_from(self.io_mem.read_val::<u32>(4).unwrap()).unwrap()
}
/// Interrupt line
pub fn irq(&self) -> &IrqLine {
&self.irq
}
/// Mutable Interrupt line
pub fn irq_mut(&mut self) -> &mut IrqLine {
&mut self.irq
}
}
/// Virtio MMIO version
#[derive(Debug, Clone, Copy, TryFromInt, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u32)]
pub enum VirtioMmioVersion {
/// Legacy
Legacy = 1,
/// Modern
Modern = 2,
}