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