hermit/drivers/vsock/
mod.rs

1#![allow(dead_code)]
2
3#[cfg(feature = "pci")]
4pub mod pci;
5
6use alloc::boxed::Box;
7use alloc::vec::Vec;
8use core::mem;
9
10use pci_types::InterruptLine;
11use smallvec::SmallVec;
12use virtio::FeatureBits;
13use virtio::vsock::Hdr;
14
15use super::virtio::virtqueue::VirtQueue;
16use crate::config::VIRTIO_MAX_QUEUE_SIZE;
17use crate::drivers::Driver;
18use crate::drivers::virtio::error::VirtioVsockError;
19#[cfg(feature = "pci")]
20use crate::drivers::virtio::transport::pci::{ComCfg, IsrStatus, NotifCfg};
21use crate::drivers::virtio::virtqueue::split::SplitVq;
22use crate::drivers::virtio::virtqueue::{
23	AvailBufferToken, BufferElem, BufferType, UsedBufferToken, Virtq, VqIndex, VqSize,
24};
25#[cfg(feature = "pci")]
26use crate::drivers::vsock::pci::VsockDevCfgRaw;
27use crate::mm::device_alloc::DeviceAlloc;
28
29fn fill_queue(vq: &mut VirtQueue, num_packets: u16, packet_size: u32) {
30	for _ in 0..num_packets {
31		let buff_tkn = match AvailBufferToken::new(
32			SmallVec::new(),
33			SmallVec::from_buf([
34				BufferElem::Sized(Box::<Hdr, _>::new_uninit_in(DeviceAlloc)),
35				BufferElem::Vector(Vec::with_capacity_in(
36					packet_size.try_into().unwrap(),
37					DeviceAlloc,
38				)),
39			]),
40		) {
41			Ok(tkn) => tkn,
42			Err(_vq_err) => {
43				error!("Setup of network queue failed, which should not happen!");
44				panic!("setup of network queue failed!");
45			}
46		};
47
48		// BufferTokens are directly provided to the queue
49		// TransferTokens are directly dispatched
50		// Transfers will be awaited at the queue
51		if let Err(err) = vq.dispatch(buff_tkn, false, BufferType::Direct) {
52			error!("{err:#?}");
53			break;
54		}
55	}
56}
57
58pub(crate) struct RxQueue {
59	vq: Option<VirtQueue>,
60	packet_size: u32,
61}
62
63impl RxQueue {
64	pub fn new() -> Self {
65		Self {
66			vq: None,
67
68			packet_size: crate::VSOCK_PACKET_SIZE,
69		}
70	}
71
72	pub fn add(&mut self, mut vq: VirtQueue) {
73		const BUFF_PER_PACKET: u16 = 2;
74		let num_packets: u16 = u16::from(vq.size()) / BUFF_PER_PACKET;
75		info!("num_packets {num_packets}");
76		fill_queue(&mut vq, num_packets, self.packet_size);
77
78		self.vq = Some(vq);
79	}
80
81	pub fn enable_notifs(&mut self) {
82		if let Some(ref mut vq) = self.vq {
83			vq.enable_notifs();
84		}
85	}
86
87	pub fn disable_notifs(&mut self) {
88		if let Some(ref mut vq) = self.vq {
89			vq.disable_notifs();
90		}
91	}
92
93	fn get_next(&mut self) -> Option<UsedBufferToken> {
94		self.vq.as_mut().unwrap().try_recv().ok()
95	}
96
97	pub fn process_packet<F>(&mut self, mut f: F)
98	where
99		F: FnMut(&Hdr, &[u8]),
100	{
101		while let Some(mut buffer_tkn) = self.get_next() {
102			let header = unsafe {
103				buffer_tkn
104					.used_recv_buff
105					.pop_front_downcast::<Hdr>()
106					.unwrap()
107			};
108			let packet = buffer_tkn.used_recv_buff.pop_front_vec().unwrap();
109
110			if let Some(ref mut vq) = self.vq {
111				f(&header, &packet[..]);
112
113				fill_queue(vq, 1, self.packet_size);
114			} else {
115				panic!("Invalid length of receive queue");
116			}
117		}
118	}
119}
120
121pub(crate) struct TxQueue {
122	vq: Option<VirtQueue>,
123	/// Indicates, whether the Driver/Device are using multiple
124	/// queues for communication.
125	packet_length: u32,
126}
127
128impl TxQueue {
129	pub fn new() -> Self {
130		Self {
131			vq: None,
132			packet_length: crate::VSOCK_PACKET_SIZE + mem::size_of::<Hdr>() as u32,
133		}
134	}
135
136	pub fn add(&mut self, vq: VirtQueue) {
137		self.vq = Some(vq);
138	}
139
140	pub fn enable_notifs(&mut self) {
141		if let Some(ref mut vq) = self.vq {
142			vq.enable_notifs();
143		}
144	}
145
146	pub fn disable_notifs(&mut self) {
147		if let Some(ref mut vq) = self.vq {
148			vq.disable_notifs();
149		}
150	}
151
152	fn poll(&mut self) {
153		if let Some(ref mut vq) = self.vq {
154			while vq.try_recv().is_ok() {}
155		}
156	}
157
158	/// Provides a slice to copy the packet and transfer the packet
159	/// to the send queue. The caller has to create the header
160	/// for the vsock interface.
161	pub fn send_packet<R, F>(&mut self, len: usize, f: F) -> R
162	where
163		F: FnOnce(&mut [u8]) -> R,
164	{
165		// We need to poll to get the queue to remove elements from the table and make space for
166		// what we are about to add
167		self.poll();
168		if let Some(ref mut vq) = self.vq {
169			assert!(len < usize::try_from(self.packet_length).unwrap());
170			let mut packet = Vec::with_capacity_in(len, DeviceAlloc);
171			let result = unsafe {
172				let result = f(packet.spare_capacity_mut().assume_init_mut());
173				packet.set_len(len);
174				result
175			};
176
177			let buff_tkn = AvailBufferToken::new(
178				{
179					let mut vec = SmallVec::new();
180					vec.push(BufferElem::Vector(packet));
181					vec
182				},
183				SmallVec::new(),
184			)
185			.unwrap();
186
187			vq.dispatch(buff_tkn, false, BufferType::Direct).unwrap();
188
189			result
190		} else {
191			panic!("Unable to get send queue");
192		}
193	}
194}
195
196pub(crate) struct EventQueue {
197	vq: Option<VirtQueue>,
198	packet_size: u32,
199}
200
201impl EventQueue {
202	pub fn new() -> Self {
203		Self {
204			vq: None,
205			packet_size: 128u32,
206		}
207	}
208
209	/// Adds a given queue to the underlying vector and populates the queue with RecvBuffers.
210	///
211	/// Queues are all populated according to Virtio specification v1.1. - 5.1.6.3.1
212	fn add(&mut self, mut vq: VirtQueue) {
213		const BUFF_PER_PACKET: u16 = 2;
214		let num_packets: u16 = u16::from(vq.size()) / BUFF_PER_PACKET;
215		fill_queue(&mut vq, num_packets, self.packet_size);
216		self.vq = Some(vq);
217	}
218
219	pub fn enable_notifs(&mut self) {
220		if let Some(ref mut vq) = self.vq {
221			vq.enable_notifs();
222		}
223	}
224
225	pub fn disable_notifs(&mut self) {
226		if let Some(ref mut vq) = self.vq {
227			vq.disable_notifs();
228		}
229	}
230}
231
232/// A wrapper struct for the raw configuration structure.
233/// Handling the right access to fields, as some are read-only
234/// for the driver.
235pub(crate) struct VsockDevCfg {
236	pub raw: &'static VsockDevCfgRaw,
237	pub dev_id: u16,
238	pub features: virtio::vsock::F,
239}
240
241pub(crate) struct VirtioVsockDriver {
242	pub(super) dev_cfg: VsockDevCfg,
243	pub(super) com_cfg: ComCfg,
244	pub(super) isr_stat: IsrStatus,
245	pub(super) notif_cfg: NotifCfg,
246	pub(super) irq: InterruptLine,
247
248	pub(super) event_vq: EventQueue,
249	pub(super) recv_vq: RxQueue,
250	pub(super) send_vq: TxQueue,
251}
252
253impl Driver for VirtioVsockDriver {
254	fn get_interrupt_number(&self) -> InterruptLine {
255		self.irq
256	}
257
258	fn get_name(&self) -> &'static str {
259		"virtio"
260	}
261}
262
263impl VirtioVsockDriver {
264	#[cfg(feature = "pci")]
265	pub fn get_dev_id(&self) -> u16 {
266		self.dev_cfg.dev_id
267	}
268
269	#[inline]
270	pub fn get_cid(&self) -> u64 {
271		self.dev_cfg.raw.guest_cid
272	}
273
274	#[cfg(feature = "pci")]
275	pub fn set_failed(&mut self) {
276		self.com_cfg.set_failed();
277	}
278
279	pub fn disable_interrupts(&mut self) {
280		// For send and receive queues?
281		// Only for receive? Because send is off anyway?
282		self.recv_vq.disable_notifs();
283	}
284
285	pub fn enable_interrupts(&mut self) {
286		// For send and receive queues?
287		// Only for receive? Because send is off anyway?
288		self.recv_vq.enable_notifs();
289	}
290
291	pub fn handle_interrupt(&mut self) {
292		let status = self.isr_stat.is_queue_interrupt();
293
294		#[cfg(not(feature = "pci"))]
295		if status.contains(virtio::mmio::InterruptStatus::CONFIGURATION_CHANGE_NOTIFICATION) {
296			info!("Configuration changes are not possible! Aborting");
297			todo!("Implement possibility to change config on the fly...")
298		}
299
300		#[cfg(feature = "pci")]
301		if status.contains(virtio::pci::IsrStatus::DEVICE_CONFIGURATION_INTERRUPT) {
302			info!("Configuration changes are not possible! Aborting");
303			todo!("Implement possibility to change config on the fly...")
304		}
305
306		self.isr_stat.acknowledge();
307	}
308
309	/// Negotiates a subset of features, understood and wanted by both the OS
310	/// and the device.
311	fn negotiate_features(
312		&mut self,
313		driver_features: virtio::vsock::F,
314	) -> Result<(), VirtioVsockError> {
315		let device_features = virtio::vsock::F::from(self.com_cfg.dev_features());
316
317		if device_features.requirements_satisfied() {
318			info!("Feature set wanted by vsock driver are in conformance with specification.");
319		} else {
320			return Err(VirtioVsockError::FeatureRequirementsNotMet(device_features));
321		}
322
323		if device_features.contains(driver_features) {
324			// If device supports subset of features write feature set to common config
325			self.com_cfg.set_drv_features(driver_features.into());
326			Ok(())
327		} else {
328			Err(VirtioVsockError::IncompatibleFeatureSets(
329				driver_features,
330				device_features,
331			))
332		}
333	}
334
335	/// Initializes the device in adherence to specification. Returns Some(VirtioVsockError)
336	/// upon failure and None in case everything worked as expected.
337	///
338	/// See Virtio specification v1.1. - 3.1.1.
339	///                      and v1.1. - 5.10.6
340	pub fn init_dev(&mut self) -> Result<(), VirtioVsockError> {
341		// Reset
342		self.com_cfg.reset_dev();
343
344		// Indicate device, that OS noticed it
345		self.com_cfg.ack_dev();
346
347		// Indicate device, that driver is able to handle it
348		self.com_cfg.set_drv();
349
350		let features = virtio::vsock::F::VERSION_1;
351		self.negotiate_features(features)?;
352
353		// Indicates the device, that the current feature set is final for the driver
354		// and will not be changed.
355		self.com_cfg.features_ok();
356
357		// Checks if the device has accepted final set. This finishes feature negotiation.
358		if self.com_cfg.check_features() {
359			info!(
360				"Features have been negotiated between virtio socket device {:x} and driver.",
361				self.dev_cfg.dev_id
362			);
363			// Set feature set in device config fur future use.
364			self.dev_cfg.features = features;
365		} else {
366			return Err(VirtioVsockError::FailFeatureNeg(self.dev_cfg.dev_id));
367		}
368
369		// create the queues and tell device about them
370		self.recv_vq.add(VirtQueue::Split(
371			SplitVq::new(
372				&mut self.com_cfg,
373				&self.notif_cfg,
374				VqSize::from(VIRTIO_MAX_QUEUE_SIZE),
375				VqIndex::from(0u16),
376				self.dev_cfg.features.into(),
377			)
378			.unwrap(),
379		));
380		// Interrupt for receiving packets is wanted
381		self.recv_vq.enable_notifs();
382
383		self.send_vq.add(VirtQueue::Split(
384			SplitVq::new(
385				&mut self.com_cfg,
386				&self.notif_cfg,
387				VqSize::from(VIRTIO_MAX_QUEUE_SIZE),
388				VqIndex::from(1u16),
389				self.dev_cfg.features.into(),
390			)
391			.unwrap(),
392		));
393		// Interrupt for communicating that a sent packet left, is not needed
394		self.send_vq.disable_notifs();
395
396		// create the queues and tell device about them
397		self.event_vq.add(VirtQueue::Split(
398			SplitVq::new(
399				&mut self.com_cfg,
400				&self.notif_cfg,
401				VqSize::from(VIRTIO_MAX_QUEUE_SIZE),
402				VqIndex::from(2u16),
403				self.dev_cfg.features.into(),
404			)
405			.unwrap(),
406		));
407		// Interrupt for event packets is wanted
408		self.event_vq.enable_notifs();
409
410		// At this point the device is "live"
411		self.com_cfg.drv_ok();
412
413		Ok(())
414	}
415
416	#[inline]
417	pub fn process_packet<F>(&mut self, f: F)
418	where
419		F: FnMut(&Hdr, &[u8]),
420	{
421		self.recv_vq.process_packet(f);
422	}
423
424	/// Provides a slice to copy the packet and transfer the packet
425	/// to the send queue. The caller has to creatde the header
426	/// for the vsock interface.
427	#[inline]
428	pub fn send_packet<R, F>(&mut self, len: usize, f: F) -> R
429	where
430		F: FnOnce(&mut [u8]) -> R,
431	{
432		self.send_vq.send_packet(len, f)
433	}
434}
435
436/// Error module of virtio socket device driver.
437pub mod error {
438	/// Virtio socket device error enum.
439	#[derive(Debug, Copy, Clone)]
440	pub enum VirtioVsockError {
441		NoDevCfg(u16),
442		NoComCfg(u16),
443		NoIsrCfg(u16),
444		NoNotifCfg(u16),
445		FailFeatureNeg(u16),
446		/// Set of features does not adhere to the requirements of features
447		/// indicated by the specification
448		FeatureRequirementsNotMet(virtio::vsock::F),
449		/// The first u64 contains the feature bits wanted by the driver.
450		/// but which are incompatible with the device feature set, second u64.
451		IncompatibleFeatureSets(virtio::vsock::F, virtio::vsock::F),
452	}
453}