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