hermit/drivers/vsock/
pci.rs

1use crate::arch::pci::PciConfigRegion;
2use crate::drivers::pci::PciDevice;
3use crate::drivers::virtio::error::{self, VirtioError};
4use crate::drivers::virtio::transport::pci;
5use crate::drivers::virtio::transport::pci::{PciCap, UniCapsColl};
6use crate::drivers::vsock::{EventQueue, RxQueue, TxQueue, VirtioVsockDriver, VsockDevCfg};
7
8/// Virtio's socket device configuration structure.
9/// See specification v1.1. - 5.11.4
10///
11#[derive(Debug, Copy, Clone)]
12#[repr(C)]
13pub(crate) struct VsockDevCfgRaw {
14	/// The guest_cid field contains the guest’s context ID, which uniquely identifies the device
15	/// for its lifetime. The upper 32 bits of the CID are reserved and zeroed.
16	pub guest_cid: u64,
17}
18
19impl VirtioVsockDriver {
20	fn map_cfg(cap: &PciCap) -> Option<VsockDevCfg> {
21		let dev_cfg = pci::map_dev_cfg::<VsockDevCfgRaw>(cap)?;
22
23		Some(VsockDevCfg {
24			raw: dev_cfg,
25			dev_id: cap.dev_id(),
26			features: virtio::vsock::F::empty(),
27		})
28	}
29
30	/// Instantiates a new VirtioVsockDriver struct, by checking the available
31	/// configuration structures and moving them into the struct.
32	pub fn new(
33		caps_coll: UniCapsColl,
34		device: &PciDevice<PciConfigRegion>,
35	) -> Result<Self, error::VirtioVsockError> {
36		let device_id = device.device_id();
37
38		let UniCapsColl {
39			com_cfg,
40			notif_cfg,
41			isr_cfg,
42			dev_cfg_list,
43			..
44		} = caps_coll;
45
46		let Some(dev_cfg) = dev_cfg_list.iter().find_map(VirtioVsockDriver::map_cfg) else {
47			error!("No dev config. Aborting!");
48			return Err(error::VirtioVsockError::NoDevCfg(device_id));
49		};
50
51		Ok(VirtioVsockDriver {
52			dev_cfg,
53			com_cfg,
54			isr_stat: isr_cfg,
55			notif_cfg,
56			irq: device.get_irq().unwrap(),
57			event_vq: EventQueue::new(),
58			recv_vq: RxQueue::new(),
59			send_vq: TxQueue::new(),
60		})
61	}
62
63	/// Initializes virtio socket device
64	///
65	/// Returns a driver instance of VirtioVsockDriver.
66	pub(crate) fn init(
67		device: &PciDevice<PciConfigRegion>,
68	) -> Result<VirtioVsockDriver, VirtioError> {
69		let mut drv = match pci::map_caps(device) {
70			Ok(caps) => match VirtioVsockDriver::new(caps, device) {
71				Ok(driver) => driver,
72				Err(vsock_err) => {
73					error!("Initializing new virtio socket device driver failed. Aborting!");
74					return Err(VirtioError::VsockDriver(vsock_err));
75				}
76			},
77			Err(err) => {
78				error!("Mapping capabilities failed. Aborting!");
79				return Err(err);
80			}
81		};
82
83		match drv.init_dev() {
84			Ok(()) => {
85				info!(
86					"Socket device with cid {:x}, has been initialized by driver!",
87					drv.dev_cfg.raw.guest_cid
88				);
89
90				Ok(drv)
91			}
92			Err(fs_err) => {
93				drv.set_failed();
94				Err(VirtioError::VsockDriver(fs_err))
95			}
96		}
97	}
98}