mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-28 20:03:22 +00:00
Impl virtio-mmio transport
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
4d927fed19
commit
0c7df54513
@ -19,6 +19,7 @@ const VIRTIO_MMIO_MAGIC: u32 = 0x74726976;
|
|||||||
|
|
||||||
pub static MMIO_BUS: SpinLock<MmioBus> = SpinLock::new(MmioBus::new());
|
pub static MMIO_BUS: SpinLock<MmioBus> = SpinLock::new(MmioBus::new());
|
||||||
static IRQS: SpinLock<Vec<IrqLine>> = SpinLock::new(Vec::new());
|
static IRQS: SpinLock<Vec<IrqLine>> = SpinLock::new(Vec::new());
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
// FIXME: The address 0xFEB0_0000 is obtained from an instance of microvm, and it may not work in other architecture.
|
// FIXME: The address 0xFEB0_0000 is obtained from an instance of microvm, and it may not work in other architecture.
|
||||||
iter_range(0xFEB0_0000..0xFEB0_4000);
|
iter_range(0xFEB0_0000..0xFEB0_4000);
|
||||||
|
@ -14,19 +14,19 @@ pub static DEVICE_NAME: &str = "Virtio-Block";
|
|||||||
bitflags! {
|
bitflags! {
|
||||||
/// features for virtio block device
|
/// features for virtio block device
|
||||||
pub(crate) struct BlkFeatures : u64{
|
pub(crate) struct BlkFeatures : u64{
|
||||||
|
const BARRIER = 1 << 0;
|
||||||
const SIZE_MAX = 1 << 1;
|
const SIZE_MAX = 1 << 1;
|
||||||
const SEG_MAX = 1 << 2;
|
const SEG_MAX = 1 << 2;
|
||||||
const GEOMETRY = 1 << 4;
|
const GEOMETRY = 1 << 4;
|
||||||
const RO = 1 << 5;
|
const RO = 1 << 5;
|
||||||
const BLK_SIZE = 1 << 6;
|
const BLK_SIZE = 1 << 6;
|
||||||
|
const SCSI = 1 << 7;
|
||||||
const FLUSH = 1 << 9;
|
const FLUSH = 1 << 9;
|
||||||
const TOPOLOGY = 1 << 10;
|
const TOPOLOGY = 1 << 10;
|
||||||
const CONFIG_WCE = 1 << 11;
|
const CONFIG_WCE = 1 << 11;
|
||||||
const DISCARD = 1 << 13;
|
const DISCARD = 1 << 13;
|
||||||
const WRITE_ZEROES = 1 << 14;
|
const WRITE_ZEROES = 1 << 14;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -185,7 +185,9 @@ impl jinux_input::InputDevice for InputDevice {
|
|||||||
fn handle_irq(&self) -> Option<()> {
|
fn handle_irq(&self) -> Option<()> {
|
||||||
// one interrupt may contains serval input, so it should loop
|
// one interrupt may contains serval input, so it should loop
|
||||||
loop {
|
loop {
|
||||||
let event = self.pop_pending_event()?;
|
let Some(event) = self.pop_pending_event() else {
|
||||||
|
return Some(());
|
||||||
|
};
|
||||||
let dtype = match Decoder::decode(
|
let dtype = match Decoder::decode(
|
||||||
event.event_type as usize,
|
event.event_type as usize,
|
||||||
event.code as usize,
|
event.code as usize,
|
||||||
|
@ -16,7 +16,7 @@ use device::{
|
|||||||
VirtioDeviceType,
|
VirtioDeviceType,
|
||||||
};
|
};
|
||||||
use log::{error, warn};
|
use log::{error, warn};
|
||||||
use transport::{pci::VIRTIO_PCI_DRIVER, DeviceStatus};
|
use transport::{mmio::VIRTIO_MMIO_DRIVER, pci::VIRTIO_PCI_DRIVER, DeviceStatus};
|
||||||
|
|
||||||
use crate::transport::VirtioTransport;
|
use crate::transport::VirtioTransport;
|
||||||
|
|
||||||
@ -28,8 +28,7 @@ mod transport;
|
|||||||
fn virtio_component_init() -> Result<(), ComponentInitError> {
|
fn virtio_component_init() -> Result<(), ComponentInitError> {
|
||||||
// Find all devices and register them to the corresponding crate
|
// Find all devices and register them to the corresponding crate
|
||||||
transport::init();
|
transport::init();
|
||||||
let pci_driver = VIRTIO_PCI_DRIVER.get().unwrap();
|
while let Some(mut transport) = pop_device_transport() {
|
||||||
while let Some(mut transport) = pci_driver.pop_device_tranport() {
|
|
||||||
// Reset device
|
// Reset device
|
||||||
transport.set_device_status(DeviceStatus::empty()).unwrap();
|
transport.set_device_status(DeviceStatus::empty()).unwrap();
|
||||||
// Set to acknowledge
|
// Set to acknowledge
|
||||||
@ -45,7 +44,6 @@ fn virtio_component_init() -> Result<(), ComponentInitError> {
|
|||||||
DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER | DeviceStatus::FEATURES_OK,
|
DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER | DeviceStatus::FEATURES_OK,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let transport = Box::new(transport);
|
|
||||||
let device_type = transport.device_type();
|
let device_type = transport.device_type();
|
||||||
let res = match transport.device_type() {
|
let res = match transport.device_type() {
|
||||||
VirtioDeviceType::Block => BlockDevice::init(transport),
|
VirtioDeviceType::Block => BlockDevice::init(transport),
|
||||||
@ -66,9 +64,18 @@ fn virtio_component_init() -> Result<(), ComponentInitError> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn negotiate_features(transport: &mut dyn VirtioTransport) {
|
fn pop_device_transport() -> Option<Box<dyn VirtioTransport>> {
|
||||||
let features = transport.device_features();
|
if let Some(device) = VIRTIO_PCI_DRIVER.get().unwrap().pop_device_transport() {
|
||||||
|
return Some(Box::new(device));
|
||||||
|
}
|
||||||
|
if let Some(device) = VIRTIO_MMIO_DRIVER.get().unwrap().pop_device_transport() {
|
||||||
|
return Some(Box::new(device));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn negotiate_features(transport: &mut Box<dyn VirtioTransport>) {
|
||||||
|
let features = transport.device_features();
|
||||||
let mask = ((1u64 << 24) - 1) | (((1u64 << 24) - 1) << 50);
|
let mask = ((1u64 << 24) - 1) | (((1u64 << 24) - 1) << 50);
|
||||||
let device_specified_features = features & mask;
|
let device_specified_features = features & mask;
|
||||||
let device_support_features = match transport.device_type() {
|
let device_support_features = match transport.device_type() {
|
||||||
@ -105,5 +112,7 @@ bitflags! {
|
|||||||
const ORDER_PLATFORM = 1 << 36;
|
const ORDER_PLATFORM = 1 << 36;
|
||||||
const SR_IOV = 1 << 37;
|
const SR_IOV = 1 << 37;
|
||||||
const NOTIFICATION_DATA = 1 << 38;
|
const NOTIFICATION_DATA = 1 << 38;
|
||||||
|
const NOTIF_CONFIG_DATA = 1 << 39;
|
||||||
|
const RING_RESET = 1 << 40;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,14 @@ use crate::transport::VirtioTransport;
|
|||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use core::sync::atomic::{fence, Ordering};
|
use core::{
|
||||||
|
mem::size_of,
|
||||||
|
sync::atomic::{fence, Ordering},
|
||||||
|
};
|
||||||
use jinux_frame::{
|
use jinux_frame::{
|
||||||
io_mem::IoMem,
|
io_mem::IoMem,
|
||||||
offset_of,
|
offset_of,
|
||||||
vm::{VmAllocOptions, VmFrame, VmFrameVec},
|
vm::{HasPaddr, VmAllocOptions, VmFrame, VmFrameVec},
|
||||||
};
|
};
|
||||||
use jinux_rights::{Dup, TRightSet, TRights, Write};
|
use jinux_rights::{Dup, TRightSet, TRights, Write};
|
||||||
use jinux_util::{field_ptr, safe_ptr::SafePtr};
|
use jinux_util::{field_ptr, safe_ptr::SafePtr};
|
||||||
@ -66,40 +69,73 @@ impl VirtQueue {
|
|||||||
return Err(QueueError::InvalidArgs);
|
return Err(QueueError::InvalidArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
let descriptor_ptr: SafePtr<Descriptor, VmFrame> = SafePtr::new(
|
let (descriptor_ptr, avail_ring_ptr, used_ring_ptr) = if transport.is_legacy_version() {
|
||||||
|
// FIXME: How about pci legacy?
|
||||||
|
// Currently, we use one VmFrame to place the descriptors and avaliable rings, one VmFrame to place used rings
|
||||||
|
// because the virtio-mmio legacy required the address to be continuous. The max queue size is 128.
|
||||||
|
if size > 128 {
|
||||||
|
return Err(QueueError::InvalidArgs);
|
||||||
|
}
|
||||||
|
let desc_size = size_of::<Descriptor>() * size as usize;
|
||||||
|
|
||||||
|
let (page1, page2) = {
|
||||||
|
let mut continue_pages = VmFrameVec::allocate(
|
||||||
|
VmAllocOptions::new(2)
|
||||||
|
.uninit(false)
|
||||||
|
.can_dma(true)
|
||||||
|
.is_contiguous(true),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let page1 = continue_pages.pop().unwrap();
|
||||||
|
let page2 = continue_pages.pop().unwrap();
|
||||||
|
if page1.paddr() > page2.paddr() {
|
||||||
|
(page2, page1)
|
||||||
|
} else {
|
||||||
|
(page1, page2)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let desc_frame_ptr: SafePtr<Descriptor, VmFrame> = SafePtr::new(page1, 0);
|
||||||
|
let mut avail_frame_ptr: SafePtr<AvailRing, VmFrame> = desc_frame_ptr.clone().cast();
|
||||||
|
avail_frame_ptr.byte_add(desc_size);
|
||||||
|
let used_frame_ptr: SafePtr<UsedRing, VmFrame> = SafePtr::new(page2, 0);
|
||||||
|
(desc_frame_ptr, avail_frame_ptr, used_frame_ptr)
|
||||||
|
} else {
|
||||||
|
if size > 256 {
|
||||||
|
return Err(QueueError::InvalidArgs);
|
||||||
|
}
|
||||||
|
(
|
||||||
|
SafePtr::new(
|
||||||
VmFrameVec::allocate(VmAllocOptions::new(1).uninit(false).can_dma(true))
|
VmFrameVec::allocate(VmAllocOptions::new(1).uninit(false).can_dma(true))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.pop()
|
.pop()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
0,
|
0,
|
||||||
);
|
),
|
||||||
let avail_ring_ptr: SafePtr<AvailRing, VmFrame> = SafePtr::new(
|
SafePtr::new(
|
||||||
VmFrameVec::allocate(VmAllocOptions::new(1).uninit(false).can_dma(true))
|
VmFrameVec::allocate(VmAllocOptions::new(1).uninit(false).can_dma(true))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.pop()
|
.pop()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
0,
|
0,
|
||||||
);
|
),
|
||||||
let used_ring_ptr: SafePtr<UsedRing, VmFrame> = SafePtr::new(
|
SafePtr::new(
|
||||||
VmFrameVec::allocate(VmAllocOptions::new(1).uninit(false).can_dma(true))
|
VmFrameVec::allocate(VmAllocOptions::new(1).uninit(false).can_dma(true))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.pop()
|
.pop()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
0,
|
0,
|
||||||
);
|
),
|
||||||
|
)
|
||||||
|
};
|
||||||
debug!("queue_desc start paddr:{:x?}", descriptor_ptr.paddr());
|
debug!("queue_desc start paddr:{:x?}", descriptor_ptr.paddr());
|
||||||
debug!("queue_driver start paddr:{:x?}", avail_ring_ptr.paddr());
|
debug!("queue_driver start paddr:{:x?}", avail_ring_ptr.paddr());
|
||||||
debug!("queue_device start paddr:{:x?}", used_ring_ptr.paddr());
|
debug!("queue_device start paddr:{:x?}", used_ring_ptr.paddr());
|
||||||
|
|
||||||
transport
|
|
||||||
.set_queue(idx, size, &descriptor_ptr, &avail_ring_ptr, &used_ring_ptr)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut descs = Vec::with_capacity(size as usize);
|
let mut descs = Vec::with_capacity(size as usize);
|
||||||
descs.push(descriptor_ptr);
|
descs.push(descriptor_ptr.clone());
|
||||||
for i in 0..size as usize {
|
for i in 0..size as usize {
|
||||||
let mut desc = descs.get(i).unwrap().clone();
|
let mut desc = descs.get(i).unwrap().clone();
|
||||||
desc.offset(1);
|
desc.add(1);
|
||||||
descs.push(desc);
|
descs.push(desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,6 +148,9 @@ impl VirtQueue {
|
|||||||
field_ptr!(&avail_ring_ptr, AvailRing, flags)
|
field_ptr!(&avail_ring_ptr, AvailRing, flags)
|
||||||
.write(&(0u16))
|
.write(&(0u16))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
transport
|
||||||
|
.set_queue(idx, size, &descriptor_ptr, &avail_ring_ptr, &used_ring_ptr)
|
||||||
|
.unwrap();
|
||||||
Ok(VirtQueue {
|
Ok(VirtQueue {
|
||||||
descs,
|
descs,
|
||||||
avail: avail_ring_ptr,
|
avail: avail_ring_ptr,
|
||||||
|
291
services/comps/virtio/src/transport/mmio/device.rs
Normal file
291
services/comps/virtio/src/transport/mmio/device.rs
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
use alloc::{boxed::Box, sync::Arc};
|
||||||
|
use core::mem::size_of;
|
||||||
|
use jinux_frame::{
|
||||||
|
bus::mmio::{
|
||||||
|
bus::MmioDevice,
|
||||||
|
device::{MmioCommonDevice, VirtioMmioVersion},
|
||||||
|
},
|
||||||
|
config::PAGE_SIZE,
|
||||||
|
io_mem::IoMem,
|
||||||
|
offset_of,
|
||||||
|
sync::RwLock,
|
||||||
|
trap::IrqCallbackFunction,
|
||||||
|
vm::VmFrame,
|
||||||
|
};
|
||||||
|
use jinux_rights::{ReadOp, WriteOp};
|
||||||
|
use jinux_util::{field_ptr, safe_ptr::SafePtr};
|
||||||
|
use log::warn;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
queue::{AvailRing, Descriptor, UsedRing},
|
||||||
|
transport::{DeviceStatus, VirtioTransport, VirtioTransportError},
|
||||||
|
VirtioDeviceType,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{layout::VirtioMmioLayout, multiplex::MultiplexIrq};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct VirtioMmioDevice {
|
||||||
|
device_id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct VirtioMmioTransport {
|
||||||
|
layout: SafePtr<VirtioMmioLayout, IoMem>,
|
||||||
|
device: Arc<VirtioMmioDevice>,
|
||||||
|
common_device: jinux_frame::bus::mmio::device::MmioCommonDevice,
|
||||||
|
multiplex: Arc<RwLock<MultiplexIrq>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MmioDevice for VirtioMmioDevice {
|
||||||
|
fn device_id(&self) -> u32 {
|
||||||
|
self.device_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MmioDevice for VirtioMmioTransport {
|
||||||
|
fn device_id(&self) -> u32 {
|
||||||
|
self.common_device.device_id()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VirtioMmioTransport {
|
||||||
|
pub(super) fn mmio_device(&self) -> &Arc<VirtioMmioDevice> {
|
||||||
|
&self.device
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn new(device: MmioCommonDevice) -> Self {
|
||||||
|
let irq = device.irq().clone();
|
||||||
|
let layout = SafePtr::new(device.io_mem().clone(), 0);
|
||||||
|
let device_id = device.device_id();
|
||||||
|
let (interrupt_ack, interrupt_status) = {
|
||||||
|
let interrupt_ack_offset = offset_of!(VirtioMmioLayout, interrupt_ack);
|
||||||
|
let interrupt_status_offset = offset_of!(VirtioMmioLayout, interrupt_status);
|
||||||
|
let mut interrupt_ack = layout.clone();
|
||||||
|
interrupt_ack.byte_add(interrupt_ack_offset as usize);
|
||||||
|
let mut interrupt_status = layout.clone();
|
||||||
|
interrupt_status.byte_add(interrupt_status_offset as usize);
|
||||||
|
(
|
||||||
|
interrupt_ack.cast::<u32>().restrict::<WriteOp>(),
|
||||||
|
interrupt_status.cast::<u32>().restrict::<ReadOp>(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let device = Self {
|
||||||
|
layout,
|
||||||
|
common_device: device,
|
||||||
|
multiplex: MultiplexIrq::new(irq, interrupt_ack, interrupt_status),
|
||||||
|
device: Arc::new(VirtioMmioDevice { device_id }),
|
||||||
|
};
|
||||||
|
if device.common_device.version() == VirtioMmioVersion::Legacy {
|
||||||
|
field_ptr!(&device.layout, VirtioMmioLayout, legacy_guest_page_size)
|
||||||
|
.write(&(PAGE_SIZE as u32))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
device
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VirtioTransport for VirtioMmioTransport {
|
||||||
|
fn device_type(&self) -> VirtioDeviceType {
|
||||||
|
VirtioDeviceType::try_from(self.common_device.device_id() as u8).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_queue(
|
||||||
|
&mut self,
|
||||||
|
idx: u16,
|
||||||
|
queue_size: u16,
|
||||||
|
descriptor_ptr: &SafePtr<Descriptor, VmFrame>,
|
||||||
|
driver_ptr: &SafePtr<AvailRing, VmFrame>,
|
||||||
|
device_ptr: &SafePtr<UsedRing, VmFrame>,
|
||||||
|
) -> Result<(), VirtioTransportError> {
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, queue_sel)
|
||||||
|
.write(&(idx as u32))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let queue_num_max: u32 = field_ptr!(&self.layout, VirtioMmioLayout, queue_num_max)
|
||||||
|
.read()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if queue_size as u32 > queue_num_max {
|
||||||
|
warn!("Set queue failed, queue size is bigger than maximum virtual queue size.");
|
||||||
|
return Err(VirtioTransportError::InvalidArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
let descriptor_paddr = descriptor_ptr.paddr();
|
||||||
|
let driver_paddr = driver_ptr.paddr();
|
||||||
|
let device_paddr = device_ptr.paddr();
|
||||||
|
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, queue_num)
|
||||||
|
.write(&(queue_size as u32))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
match self.common_device.version() {
|
||||||
|
VirtioMmioVersion::Legacy => {
|
||||||
|
// The area should be continuous
|
||||||
|
assert_eq!(
|
||||||
|
driver_paddr - descriptor_paddr,
|
||||||
|
size_of::<Descriptor>() * queue_size as usize
|
||||||
|
);
|
||||||
|
// Descriptor paddr should align
|
||||||
|
assert_eq!(descriptor_paddr % PAGE_SIZE, 0);
|
||||||
|
let pfn = (descriptor_paddr / PAGE_SIZE) as u32;
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, legacy_queue_align)
|
||||||
|
.write(&(PAGE_SIZE as u32))
|
||||||
|
.unwrap();
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, legacy_queue_pfn)
|
||||||
|
.write(&pfn)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
VirtioMmioVersion::Modern => {
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, queue_desc_low)
|
||||||
|
.write(&(descriptor_paddr as u32))
|
||||||
|
.unwrap();
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, queue_desc_high)
|
||||||
|
.write(&((descriptor_paddr >> 32) as u32))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, queue_driver_low)
|
||||||
|
.write(&(driver_paddr as u32))
|
||||||
|
.unwrap();
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, queue_driver_high)
|
||||||
|
.write(&((driver_paddr >> 32) as u32))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, queue_device_low)
|
||||||
|
.write(&(device_paddr as u32))
|
||||||
|
.unwrap();
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, queue_device_high)
|
||||||
|
.write(&((device_paddr >> 32) as u32))
|
||||||
|
.unwrap();
|
||||||
|
// enable queue
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, queue_sel)
|
||||||
|
.write(&(idx as u32))
|
||||||
|
.unwrap();
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, queue_ready)
|
||||||
|
.write(&1u32)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_notify_ptr(&self, _idx: u16) -> Result<SafePtr<u32, IoMem>, VirtioTransportError> {
|
||||||
|
let offset = offset_of!(VirtioMmioLayout, queue_notify) as usize;
|
||||||
|
Ok(SafePtr::new(self.common_device.io_mem().clone(), offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn num_queues(&self) -> u16 {
|
||||||
|
// We use the field `queue_num_max` to get queue size.
|
||||||
|
// If the queue is not exists, the field should be zero
|
||||||
|
let mut num_queues = 0;
|
||||||
|
const MAX_QUEUES: u32 = 512;
|
||||||
|
while num_queues < MAX_QUEUES {
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, queue_sel)
|
||||||
|
.write(&num_queues)
|
||||||
|
.unwrap();
|
||||||
|
if field_ptr!(&self.layout, VirtioMmioLayout, queue_num_max)
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
== 0u32
|
||||||
|
{
|
||||||
|
return num_queues as u16;
|
||||||
|
}
|
||||||
|
num_queues += 1;
|
||||||
|
}
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn device_config_memory(&self) -> IoMem {
|
||||||
|
// offset: 0x100~0x200
|
||||||
|
let mut io_mem = self.common_device.io_mem().clone();
|
||||||
|
let paddr = io_mem.paddr();
|
||||||
|
io_mem.resize((paddr + 0x100)..(paddr + 0x200)).unwrap();
|
||||||
|
io_mem
|
||||||
|
}
|
||||||
|
|
||||||
|
fn device_features(&self) -> u64 {
|
||||||
|
// select low
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, device_features_select)
|
||||||
|
.write(&0u32)
|
||||||
|
.unwrap();
|
||||||
|
let device_feature_low = field_ptr!(&self.layout, VirtioMmioLayout, device_features)
|
||||||
|
.read()
|
||||||
|
.unwrap();
|
||||||
|
// select high
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, device_features_select)
|
||||||
|
.write(&1u32)
|
||||||
|
.unwrap();
|
||||||
|
let device_feature_high = field_ptr!(&self.layout, VirtioMmioLayout, device_features)
|
||||||
|
.read()
|
||||||
|
.unwrap() as u64;
|
||||||
|
device_feature_high << 32 | device_feature_low as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_driver_features(&mut self, features: u64) -> Result<(), VirtioTransportError> {
|
||||||
|
let low = features as u32;
|
||||||
|
let high = (features >> 32) as u32;
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, driver_features_select)
|
||||||
|
.write(&0u32)
|
||||||
|
.unwrap();
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, driver_features)
|
||||||
|
.write(&low)
|
||||||
|
.unwrap();
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, driver_features_select)
|
||||||
|
.write(&1u32)
|
||||||
|
.unwrap();
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, driver_features)
|
||||||
|
.write(&high)
|
||||||
|
.unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn device_status(&self) -> DeviceStatus {
|
||||||
|
DeviceStatus::from_bits(
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, status)
|
||||||
|
.read()
|
||||||
|
.unwrap() as u8,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_device_status(&mut self, status: DeviceStatus) -> Result<(), VirtioTransportError> {
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, status)
|
||||||
|
.write(&(status.bits() as u32))
|
||||||
|
.unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_legacy_version(&self) -> bool {
|
||||||
|
self.common_device.version() == VirtioMmioVersion::Legacy
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max_queue_size(&self, idx: u16) -> Result<u16, VirtioTransportError> {
|
||||||
|
field_ptr!(&self.layout, VirtioMmioLayout, queue_sel)
|
||||||
|
.write(&(idx as u32))
|
||||||
|
.unwrap();
|
||||||
|
Ok(field_ptr!(&self.layout, VirtioMmioLayout, queue_num_max)
|
||||||
|
.read()
|
||||||
|
.unwrap() as u16)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_queue_callback(
|
||||||
|
&mut self,
|
||||||
|
_index: u16,
|
||||||
|
func: Box<IrqCallbackFunction>,
|
||||||
|
single_interrupt: bool,
|
||||||
|
) -> Result<(), VirtioTransportError> {
|
||||||
|
if single_interrupt {
|
||||||
|
return Err(VirtioTransportError::NotEnoughResources);
|
||||||
|
}
|
||||||
|
self.multiplex.write().register_queue_callback(func);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_cfg_callback(
|
||||||
|
&mut self,
|
||||||
|
func: Box<IrqCallbackFunction>,
|
||||||
|
) -> Result<(), VirtioTransportError> {
|
||||||
|
self.multiplex.write().register_cfg_callback(func);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
46
services/comps/virtio/src/transport/mmio/driver.rs
Normal file
46
services/comps/virtio/src/transport/mmio/driver.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
use alloc::{sync::Arc, vec::Vec};
|
||||||
|
use jinux_frame::{
|
||||||
|
bus::{
|
||||||
|
mmio::{
|
||||||
|
bus::{MmioDevice, MmioDriver},
|
||||||
|
device::MmioCommonDevice,
|
||||||
|
},
|
||||||
|
BusProbeError,
|
||||||
|
},
|
||||||
|
sync::SpinLock,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::device::VirtioMmioTransport;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct VirtioMmioDriver {
|
||||||
|
devices: SpinLock<Vec<VirtioMmioTransport>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VirtioMmioDriver {
|
||||||
|
pub fn num_devices(&self) -> usize {
|
||||||
|
self.devices.lock().len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_device_transport(&self) -> Option<VirtioMmioTransport> {
|
||||||
|
self.devices.lock().pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn new() -> Self {
|
||||||
|
VirtioMmioDriver {
|
||||||
|
devices: SpinLock::new(Vec::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MmioDriver for VirtioMmioDriver {
|
||||||
|
fn probe(
|
||||||
|
&self,
|
||||||
|
device: MmioCommonDevice,
|
||||||
|
) -> Result<Arc<dyn MmioDevice>, (BusProbeError, MmioCommonDevice)> {
|
||||||
|
let device = VirtioMmioTransport::new(device);
|
||||||
|
let mmio_device = device.mmio_device().clone();
|
||||||
|
self.devices.lock().push(device);
|
||||||
|
Ok(mmio_device)
|
||||||
|
}
|
||||||
|
}
|
143
services/comps/virtio/src/transport/mmio/layout.rs
Normal file
143
services/comps/virtio/src/transport/mmio/layout.rs
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
use core::fmt::Debug;
|
||||||
|
|
||||||
|
use pod::Pod;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Pod)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct VirtioMmioLayout {
|
||||||
|
/// Magic value: 0x74726976. **Read-only**
|
||||||
|
pub magic_value: u32,
|
||||||
|
/// Device version. 1 => Legacy, 2 => Normal. **Read-only**
|
||||||
|
pub version: u32,
|
||||||
|
/// Virtio Subsystem Device ID. **Read-only**
|
||||||
|
pub device_id: u32,
|
||||||
|
/// Virtio Subsystem Vendor ID. **Read-only**
|
||||||
|
pub vendor_id: u32,
|
||||||
|
|
||||||
|
/// Flags representing features the device supports.
|
||||||
|
/// Bits 0-31 if `device_features_sel`is 0,
|
||||||
|
/// bits 32-63 if `device_features_sel` is 1.
|
||||||
|
/// **Read-only**
|
||||||
|
pub device_features: u32,
|
||||||
|
/// **Write-only**
|
||||||
|
pub device_features_select: u32,
|
||||||
|
|
||||||
|
__r1: [u8; 8],
|
||||||
|
|
||||||
|
/// Flags representing device features understood and activated by the driver.
|
||||||
|
/// Bits 0-31 if `driver_features_sel`is 0,
|
||||||
|
/// bits 32-63 if `driver_features_sel` is 1.
|
||||||
|
/// **Write-only**
|
||||||
|
pub driver_features: u32,
|
||||||
|
/// **Write-only**
|
||||||
|
pub driver_features_select: u32,
|
||||||
|
|
||||||
|
/// Guest page size.
|
||||||
|
///
|
||||||
|
/// The driver writes the guest page size in bytes
|
||||||
|
/// to the register during initialization, before any queues are used.
|
||||||
|
///
|
||||||
|
/// This value should be a power of 2 and is used by the device to
|
||||||
|
/// calculate the Guest address of the first queue page (see legacy_queue_pfn).
|
||||||
|
/// **Write-only**
|
||||||
|
pub legacy_guest_page_size: u32,
|
||||||
|
|
||||||
|
__r2: [u8; 4],
|
||||||
|
|
||||||
|
/// Selected queue. **Write-only**
|
||||||
|
pub queue_sel: u32,
|
||||||
|
/// Maximum virtual queue size. **Read-only**
|
||||||
|
pub queue_num_max: u32,
|
||||||
|
/// Virtual queue size. **Write-only**
|
||||||
|
pub queue_num: u32,
|
||||||
|
|
||||||
|
pub legacy_queue_align: u32,
|
||||||
|
|
||||||
|
pub legacy_queue_pfn: u32,
|
||||||
|
|
||||||
|
/// Virtual queue ready bit.
|
||||||
|
///
|
||||||
|
/// Write 1 to notifies the device that it can execute requests from this virtual queue.
|
||||||
|
/// **Read-Write**
|
||||||
|
pub queue_ready: u32,
|
||||||
|
|
||||||
|
__r3: [u8; 8],
|
||||||
|
|
||||||
|
/// Queue notifier.
|
||||||
|
///
|
||||||
|
/// Writing a value to this register notifies the device
|
||||||
|
/// that there are new buffers to process in a queue. **Write-only**
|
||||||
|
pub queue_notify: u32,
|
||||||
|
|
||||||
|
__r4: [u8; 12],
|
||||||
|
|
||||||
|
/// Interrupt status.
|
||||||
|
///
|
||||||
|
/// bit0 => Used Buffer Notification;
|
||||||
|
/// bit1 => Configuration Change Notification
|
||||||
|
/// **Read-only**
|
||||||
|
pub interrupt_status: u32,
|
||||||
|
/// Interrupt acknowledge. **Write-only**
|
||||||
|
pub interrupt_ack: u32,
|
||||||
|
|
||||||
|
__r5: [u8; 8],
|
||||||
|
|
||||||
|
/// Device status. **Read-Write**
|
||||||
|
pub status: u32,
|
||||||
|
|
||||||
|
__r6: [u8; 12],
|
||||||
|
|
||||||
|
/// Virtual queue’s Descriptor Area 64 bit long physical address. **Write-only**
|
||||||
|
pub queue_desc_low: u32,
|
||||||
|
pub queue_desc_high: u32,
|
||||||
|
|
||||||
|
__r7: [u8; 8],
|
||||||
|
|
||||||
|
/// Virtual queue’s Driver Area 64 bit long physical address. **Write-only**
|
||||||
|
pub queue_driver_low: u32,
|
||||||
|
pub queue_driver_high: u32,
|
||||||
|
|
||||||
|
__r8: [u8; 8],
|
||||||
|
|
||||||
|
/// Virtual queue’s Device Area 64 bit long physical address. **Write-only**
|
||||||
|
pub queue_device_low: u32,
|
||||||
|
pub queue_device_high: u32,
|
||||||
|
|
||||||
|
__r9: [u8; 84],
|
||||||
|
|
||||||
|
/// Configuration atomicity value. **Read-only**
|
||||||
|
pub config_generation: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for VirtioMmioLayout {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
f.debug_struct("VirtioMmioLayout")
|
||||||
|
.field("magic_value", &self.magic_value)
|
||||||
|
.field("version", &self.version)
|
||||||
|
.field("device_id", &self.device_id)
|
||||||
|
.field("vendor_id", &self.vendor_id)
|
||||||
|
.field("device_features", &self.device_features)
|
||||||
|
.field("device_features_sel", &self.device_features_select)
|
||||||
|
.field("driver_features", &self.driver_features)
|
||||||
|
.field("driver_features_sel", &self.driver_features_select)
|
||||||
|
.field("legacy_guest_page_size", &self.legacy_guest_page_size)
|
||||||
|
.field("queue_sel", &self.queue_sel)
|
||||||
|
.field("queue_num_max", &self.queue_num_max)
|
||||||
|
.field("queue_num", &self.queue_num)
|
||||||
|
.field("legacy_queue_align", &self.legacy_queue_align)
|
||||||
|
.field("legacy_queue_pfn", &self.legacy_queue_pfn)
|
||||||
|
.field("queue_ready", &self.queue_ready)
|
||||||
|
.field("queue_notify", &self.queue_notify)
|
||||||
|
.field("interrupt_status", &self.interrupt_status)
|
||||||
|
.field("interrupt_ack", &self.interrupt_ack)
|
||||||
|
.field("status", &self.status)
|
||||||
|
.field("queue_desc_low", &self.queue_desc_low)
|
||||||
|
.field("queue_desc_high", &self.queue_desc_high)
|
||||||
|
.field("queue_driver_low", &self.queue_driver_low)
|
||||||
|
.field("queue_driver_high", &self.queue_driver_high)
|
||||||
|
.field("queue_device_low", &self.queue_device_low)
|
||||||
|
.field("queue_device_high", &self.queue_device_high)
|
||||||
|
.field("config_generation", &self.config_generation)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
18
services/comps/virtio/src/transport/mmio/mod.rs
Normal file
18
services/comps/virtio/src/transport/mmio/mod.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use alloc::sync::Arc;
|
||||||
|
use jinux_frame::bus::mmio::MMIO_BUS;
|
||||||
|
use spin::Once;
|
||||||
|
|
||||||
|
use self::driver::VirtioMmioDriver;
|
||||||
|
|
||||||
|
pub mod device;
|
||||||
|
pub mod driver;
|
||||||
|
pub mod layout;
|
||||||
|
pub mod multiplex;
|
||||||
|
|
||||||
|
pub static VIRTIO_MMIO_DRIVER: Once<Arc<VirtioMmioDriver>> = Once::new();
|
||||||
|
pub fn virtio_mmio_init() {
|
||||||
|
VIRTIO_MMIO_DRIVER.call_once(|| Arc::new(VirtioMmioDriver::new()));
|
||||||
|
MMIO_BUS
|
||||||
|
.lock()
|
||||||
|
.register_driver(VIRTIO_MMIO_DRIVER.get().unwrap().clone());
|
||||||
|
}
|
80
services/comps/virtio/src/transport/mmio/multiplex.rs
Normal file
80
services/comps/virtio/src/transport/mmio/multiplex.rs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
use core::fmt::Debug;
|
||||||
|
|
||||||
|
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||||
|
use jinux_frame::{
|
||||||
|
io_mem::IoMem,
|
||||||
|
sync::RwLock,
|
||||||
|
trap::{IrqCallbackFunction, IrqLine, TrapFrame},
|
||||||
|
};
|
||||||
|
use jinux_rights::{ReadOp, TRightSet, WriteOp};
|
||||||
|
use jinux_util::safe_ptr::SafePtr;
|
||||||
|
|
||||||
|
/// Multiplexing Irqs. The two interrupt types (configuration space change and queue interrupt)
|
||||||
|
/// of the virtio-mmio device share the same IRQ, so `MultiplexIrq` are used to distinguish them.
|
||||||
|
/// Besides, virtio-mmio requires ack_interrupt after interrupt is handled.
|
||||||
|
pub struct MultiplexIrq {
|
||||||
|
irq: IrqLine,
|
||||||
|
queue_callbacks: Vec<Box<IrqCallbackFunction>>,
|
||||||
|
cfg_callbacks: Vec<Box<IrqCallbackFunction>>,
|
||||||
|
interrupt_ack: SafePtr<u32, IoMem, TRightSet<WriteOp>>,
|
||||||
|
interrupt_status: SafePtr<u32, IoMem, TRightSet<ReadOp>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MultiplexIrq {
|
||||||
|
pub fn new(
|
||||||
|
irq: IrqLine,
|
||||||
|
interrupt_ack: SafePtr<u32, IoMem, TRightSet<WriteOp>>,
|
||||||
|
interrupt_status: SafePtr<u32, IoMem, TRightSet<ReadOp>>,
|
||||||
|
) -> Arc<RwLock<Self>> {
|
||||||
|
let irq = Arc::new(RwLock::new(Self {
|
||||||
|
irq,
|
||||||
|
queue_callbacks: Vec::new(),
|
||||||
|
cfg_callbacks: Vec::new(),
|
||||||
|
interrupt_ack,
|
||||||
|
interrupt_status,
|
||||||
|
}));
|
||||||
|
// Holding a weak reference to prevent memory leakage due to
|
||||||
|
// circular reference.
|
||||||
|
let weak = Arc::downgrade(&irq);
|
||||||
|
let mut lock = irq.write();
|
||||||
|
let callback = move |trap_frame: &TrapFrame| {
|
||||||
|
let Some(multiplex_irq) = weak.upgrade() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let irq = multiplex_irq.read();
|
||||||
|
let interrupt_status = irq.interrupt_status.read().unwrap();
|
||||||
|
let callbacks = if interrupt_status & 0x01 == 1 {
|
||||||
|
// Used buffer notification
|
||||||
|
&irq.queue_callbacks
|
||||||
|
} else {
|
||||||
|
// Configuration Change Notification
|
||||||
|
&irq.cfg_callbacks
|
||||||
|
};
|
||||||
|
for callback in callbacks.iter() {
|
||||||
|
callback.call((trap_frame,));
|
||||||
|
}
|
||||||
|
irq.interrupt_ack.write(&interrupt_status).unwrap();
|
||||||
|
};
|
||||||
|
lock.irq.on_active(callback);
|
||||||
|
drop(lock);
|
||||||
|
irq
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_queue_callback(&mut self, func: Box<IrqCallbackFunction>) {
|
||||||
|
self.queue_callbacks.push(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_cfg_callback(&mut self, func: Box<IrqCallbackFunction>) {
|
||||||
|
self.cfg_callbacks.push(func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for MultiplexIrq {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
f.debug_struct("MultiplexIrq")
|
||||||
|
.field("irq", &self.irq)
|
||||||
|
.field("interrupt_ack", &self.interrupt_ack)
|
||||||
|
.field("interrupt_status", &self.interrupt_status)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use jinux_frame::{io_mem::IoMem, trap::TrapFrame, vm::VmFrame};
|
use jinux_frame::{io_mem::IoMem, trap::IrqCallbackFunction, vm::VmFrame};
|
||||||
use jinux_util::safe_ptr::SafePtr;
|
use jinux_util::safe_ptr::SafePtr;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -9,8 +9,9 @@ use crate::{
|
|||||||
VirtioDeviceType,
|
VirtioDeviceType,
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::pci::virtio_pci_init;
|
use self::{mmio::virtio_mmio_init, pci::virtio_pci_init};
|
||||||
|
|
||||||
|
pub mod mmio;
|
||||||
pub mod pci;
|
pub mod pci;
|
||||||
|
|
||||||
/// The transport of virtio device. Virtio device can use this transport to:
|
/// The transport of virtio device. Virtio device can use this transport to:
|
||||||
@ -72,6 +73,8 @@ pub trait VirtioTransport: Sync + Send + Debug {
|
|||||||
/// after it add buffers into the corresponding virtqueue.
|
/// after it add buffers into the corresponding virtqueue.
|
||||||
fn get_notify_ptr(&self, idx: u16) -> Result<SafePtr<u32, IoMem>, VirtioTransportError>;
|
fn get_notify_ptr(&self, idx: u16) -> Result<SafePtr<u32, IoMem>, VirtioTransportError>;
|
||||||
|
|
||||||
|
fn is_legacy_version(&self) -> bool;
|
||||||
|
|
||||||
// ====================Device interrupt APIs=====================
|
// ====================Device interrupt APIs=====================
|
||||||
|
|
||||||
/// Register queue interrupt callback. The transport will try to allocate single IRQ line if
|
/// Register queue interrupt callback. The transport will try to allocate single IRQ line if
|
||||||
@ -79,14 +82,14 @@ pub trait VirtioTransport: Sync + Send + Debug {
|
|||||||
fn register_queue_callback(
|
fn register_queue_callback(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: u16,
|
index: u16,
|
||||||
func: Box<dyn Fn(&TrapFrame) + Send + Sync>,
|
func: Box<IrqCallbackFunction>,
|
||||||
single_interrupt: bool,
|
single_interrupt: bool,
|
||||||
) -> Result<(), VirtioTransportError>;
|
) -> Result<(), VirtioTransportError>;
|
||||||
|
|
||||||
/// Register configuration space change interrupt callback.
|
/// Register configuration space change interrupt callback.
|
||||||
fn register_cfg_callback(
|
fn register_cfg_callback(
|
||||||
&mut self,
|
&mut self,
|
||||||
func: Box<dyn Fn(&TrapFrame) + Send + Sync>,
|
func: Box<IrqCallbackFunction>,
|
||||||
) -> Result<(), VirtioTransportError>;
|
) -> Result<(), VirtioTransportError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,4 +131,5 @@ bitflags::bitflags! {
|
|||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
virtio_pci_init();
|
virtio_pci_init();
|
||||||
|
virtio_mmio_init();
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
use jinux_frame::{
|
use jinux_frame::{
|
||||||
bus::pci::{
|
bus::{
|
||||||
bus::{PciDevice, PciDriverProbeError},
|
pci::{
|
||||||
capability::CapabilityData,
|
bus::PciDevice, capability::CapabilityData, common_device::PciCommonDevice, PciDeviceId,
|
||||||
common_device::PciCommonDevice,
|
},
|
||||||
PciDeviceId,
|
BusProbeError,
|
||||||
},
|
},
|
||||||
io_mem::IoMem,
|
io_mem::IoMem,
|
||||||
offset_of,
|
offset_of,
|
||||||
trap::TrapFrame,
|
trap::IrqCallbackFunction,
|
||||||
vm::VmFrame,
|
vm::VmFrame,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -206,7 +206,7 @@ impl VirtioTransport for VirtioPciTransport {
|
|||||||
fn register_queue_callback(
|
fn register_queue_callback(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: u16,
|
index: u16,
|
||||||
func: Box<dyn Fn(&TrapFrame) + Send + Sync>,
|
func: Box<IrqCallbackFunction>,
|
||||||
single_interrupt: bool,
|
single_interrupt: bool,
|
||||||
) -> Result<(), VirtioTransportError> {
|
) -> Result<(), VirtioTransportError> {
|
||||||
if index >= self.num_queues() {
|
if index >= self.num_queues() {
|
||||||
@ -237,12 +237,17 @@ impl VirtioTransport for VirtioPciTransport {
|
|||||||
|
|
||||||
fn register_cfg_callback(
|
fn register_cfg_callback(
|
||||||
&mut self,
|
&mut self,
|
||||||
func: Box<dyn Fn(&TrapFrame) + Send + Sync>,
|
func: Box<IrqCallbackFunction>,
|
||||||
) -> Result<(), VirtioTransportError> {
|
) -> Result<(), VirtioTransportError> {
|
||||||
let (_, irq) = self.msix_manager.config_msix_irq();
|
let (_, irq) = self.msix_manager.config_msix_irq();
|
||||||
irq.on_active(func);
|
irq.on_active(func);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_legacy_version(&self) -> bool {
|
||||||
|
// TODO: Support legacy version
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VirtioPciTransport {
|
impl VirtioPciTransport {
|
||||||
@ -253,7 +258,7 @@ impl VirtioPciTransport {
|
|||||||
#[allow(clippy::result_large_err)]
|
#[allow(clippy::result_large_err)]
|
||||||
pub(super) fn new(
|
pub(super) fn new(
|
||||||
common_device: PciCommonDevice,
|
common_device: PciCommonDevice,
|
||||||
) -> Result<Self, (PciDriverProbeError, PciCommonDevice)> {
|
) -> Result<Self, (BusProbeError, PciCommonDevice)> {
|
||||||
let device_type = match common_device.device_id().device_id {
|
let device_type = match common_device.device_id().device_id {
|
||||||
0x1000 => VirtioDeviceType::Network,
|
0x1000 => VirtioDeviceType::Network,
|
||||||
0x1001 => VirtioDeviceType::Block,
|
0x1001 => VirtioDeviceType::Block,
|
||||||
@ -268,7 +273,7 @@ impl VirtioPciTransport {
|
|||||||
"Unrecognized virtio-pci device id:{:x?}",
|
"Unrecognized virtio-pci device id:{:x?}",
|
||||||
common_device.device_id().device_id
|
common_device.device_id().device_id
|
||||||
);
|
);
|
||||||
return Err((PciDriverProbeError::ConfigurationSpaceError, common_device));
|
return Err((BusProbeError::ConfigurationSpaceError, common_device));
|
||||||
}
|
}
|
||||||
let id = id - 0x1040;
|
let id = id - 0x1040;
|
||||||
match VirtioDeviceType::try_from(id as u8) {
|
match VirtioDeviceType::try_from(id as u8) {
|
||||||
@ -278,7 +283,7 @@ impl VirtioPciTransport {
|
|||||||
"Unrecognized virtio-pci device id:{:x?}",
|
"Unrecognized virtio-pci device id:{:x?}",
|
||||||
common_device.device_id().device_id
|
common_device.device_id().device_id
|
||||||
);
|
);
|
||||||
return Err((PciDriverProbeError::ConfigurationSpaceError, common_device));
|
return Err((BusProbeError::ConfigurationSpaceError, common_device));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
use alloc::{sync::Arc, vec::Vec};
|
use alloc::{sync::Arc, vec::Vec};
|
||||||
use jinux_frame::{
|
use jinux_frame::{
|
||||||
bus::pci::{
|
bus::{
|
||||||
bus::{PciDevice, PciDriver, PciDriverProbeError},
|
pci::{
|
||||||
|
bus::{PciDevice, PciDriver},
|
||||||
common_device::PciCommonDevice,
|
common_device::PciCommonDevice,
|
||||||
},
|
},
|
||||||
|
BusProbeError,
|
||||||
|
},
|
||||||
sync::SpinLock,
|
sync::SpinLock,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -19,7 +22,7 @@ impl VirtioPciDriver {
|
|||||||
self.devices.lock().len()
|
self.devices.lock().len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop_device_tranport(&self) -> Option<VirtioPciTransport> {
|
pub fn pop_device_transport(&self) -> Option<VirtioPciTransport> {
|
||||||
self.devices.lock().pop()
|
self.devices.lock().pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,10 +37,10 @@ impl PciDriver for VirtioPciDriver {
|
|||||||
fn probe(
|
fn probe(
|
||||||
&self,
|
&self,
|
||||||
device: PciCommonDevice,
|
device: PciCommonDevice,
|
||||||
) -> Result<Arc<dyn PciDevice>, (PciDriverProbeError, PciCommonDevice)> {
|
) -> Result<Arc<dyn PciDevice>, (BusProbeError, PciCommonDevice)> {
|
||||||
const VIRTIO_DEVICE_VENDOR_ID: u16 = 0x1af4;
|
const VIRTIO_DEVICE_VENDOR_ID: u16 = 0x1af4;
|
||||||
if device.device_id().vendor_id != VIRTIO_DEVICE_VENDOR_ID {
|
if device.device_id().vendor_id != VIRTIO_DEVICE_VENDOR_ID {
|
||||||
return Err((PciDriverProbeError::DeviceNotMatch, device));
|
return Err((BusProbeError::DeviceNotMatch, device));
|
||||||
}
|
}
|
||||||
let transport = VirtioPciTransport::new(device)?;
|
let transport = VirtioPciTransport::new(device)?;
|
||||||
let device = transport.pci_device().clone();
|
let device = transport.pci_device().clone();
|
||||||
|
Reference in New Issue
Block a user