xref: /DragonOS/kernel/src/driver/virtio/virtio.rs (revision f049d1af01da7b92f312245ed411b22475b76065)
1 use super::transport_pci::PciTransport;
2 use super::virtio_impl::HalImpl;
3 use crate::driver::base::device::DeviceId;
4 use crate::driver::net::virtio_net::virtio_net;
5 use crate::driver::pci::pci::{
6     get_pci_device_structure_mut, PciDeviceStructure, PciDeviceStructureGeneralDevice,
7     PCI_DEVICE_LINKEDLIST,
8 };
9 use crate::libs::rwlock::RwLockWriteGuard;
10 use crate::{kdebug, kerror, kwarn};
11 use alloc::sync::Arc;
12 use alloc::{boxed::Box, collections::LinkedList};
13 use virtio_drivers::transport::{DeviceType, Transport};
14 const NETWORK_CLASS: u8 = 0x2;
15 const ETHERNET_SUBCLASS: u8 = 0x0;
16 
17 //Virtio设备寻找过程中出现的问题
18 enum VirtioError {
19     VirtioNetNotFound,
20     NetDeviceNotFound,
21 }
22 
23 ///@brief 寻找并加载所有virtio设备的驱动(目前只有virtio-net,但其他virtio设备也可添加)
24 pub fn virtio_probe() {
25     let mut list = PCI_DEVICE_LINKEDLIST.write();
26     if let Ok(virtio_list) = virtio_device_search(&mut list) {
27         for virtio_device in virtio_list {
28             let dev_id = virtio_device.common_header.device_id;
29             let dev_id = DeviceId::new(None, Some(format!("virtio_{}", dev_id))).unwrap();
30             match PciTransport::new::<HalImpl>(virtio_device, dev_id.clone()) {
31                 Ok(mut transport) => {
32                     kdebug!(
33                         "Detected virtio PCI device with device type {:?}, features {:#018x}",
34                         transport.device_type(),
35                         transport.read_device_features(),
36                     );
37                     virtio_device_init(transport, dev_id);
38                 }
39                 Err(err) => {
40                     kerror!("Pci transport create failed because of error: {}", err);
41                 }
42             }
43         }
44     } else {
45         kerror!("Error occured when finding virtio device!");
46     }
47 }
48 
49 ///@brief 为virtio设备寻找对应的驱动进行初始化
50 fn virtio_device_init(transport: impl Transport + 'static, dev_id: Arc<DeviceId>) {
51     match transport.device_type() {
52         DeviceType::Block => {
53             kwarn!("Not support virtio_block device for now");
54         }
55         DeviceType::GPU => {
56             kwarn!("Not support virtio_gpu device for now");
57         }
58         DeviceType::Input => {
59             kwarn!("Not support virtio_input device for now");
60         }
61         DeviceType::Network => virtio_net(transport, dev_id),
62         t => {
63             kwarn!("Unrecognized virtio device: {:?}", t);
64         }
65     }
66 }
67 
68 /// @brief 寻找所有的virtio设备
69 /// @param list 链表的写锁
70 /// @return Result<LinkedList<&'a mut Pci_Device_Structure_General_Device>, VirtioError>  成功则返回包含所有virtio设备结构体的可变引用的链表,失败则返回err
71 /// 该函数主要是为其他virtio设备预留支持
72 fn virtio_device_search<'a>(
73     list: &'a mut RwLockWriteGuard<'_, LinkedList<Box<dyn PciDeviceStructure>>>,
74 ) -> Result<LinkedList<&'a mut PciDeviceStructureGeneralDevice>, VirtioError> {
75     let mut virtio_list: LinkedList<&mut PciDeviceStructureGeneralDevice> = LinkedList::new();
76     let virtio_net_device = get_virtio_net_device(list)?;
77     virtio_list.push_back(virtio_net_device);
78     Ok(virtio_list)
79 }
80 
81 /// @brief 寻找virtio-net设备
82 /// @param list 链表的写锁
83 /// @return Result<&'a mut Pci_Device_Structure_General_Device, VirtioError> 成功则返回virtio设备结构体的可变引用,失败则返回err
84 fn get_virtio_net_device<'a>(
85     list: &'a mut RwLockWriteGuard<'_, LinkedList<Box<dyn PciDeviceStructure>>>,
86 ) -> Result<&'a mut PciDeviceStructureGeneralDevice, VirtioError> {
87     let result = get_pci_device_structure_mut(list, NETWORK_CLASS, ETHERNET_SUBCLASS);
88     if result.is_empty() {
89         return Err(VirtioError::NetDeviceNotFound);
90     }
91     for device in result {
92         let standard_device = device.as_standard_device_mut().unwrap();
93         let header = &standard_device.common_header;
94         if header.vendor_id == 0x1AF4
95             && header.device_id >= 0x1000
96             && header.device_id <= 0x103F
97             && standard_device.subsystem_id == 1
98         {
99             return Ok(standard_device);
100         }
101     }
102     Err(VirtioError::VirtioNetNotFound)
103 }
104