1use crate::queue::QueueCompletion;
5use crate::queue::QueueCoreCompleteWork;
6use crate::queue::QueueCoreGetWork;
7use crate::queue::QueueError;
8use crate::queue::QueueParams;
9use crate::queue::QueueState;
10use crate::queue::VirtioQueuePayload;
11use crate::queue::new_queue;
12use crate::spec::VirtioDeviceFeatures;
13use crate::spec::VirtioDeviceType;
14use futures::FutureExt;
15use futures::Stream;
16use guestmem::DoorbellRegistration;
17use guestmem::GuestMemory;
18use guestmem::GuestMemoryError;
19use inspect::Inspect;
20use pal_async::wait::PolledWait;
21use pal_event::Event;
22use std::io::Error;
23use std::pin::Pin;
24use std::sync::Arc;
25use std::task::Context;
26use std::task::Poll;
27use std::task::ready;
28use thiserror::Error;
29use vmcore::interrupt::Interrupt;
30
31fn read_from_payload(
33 payload: &[VirtioQueuePayload],
34 mem: &GuestMemory,
35 target: &mut [u8],
36) -> Result<usize, GuestMemoryError> {
37 let mut remaining = target;
38 let mut read_bytes: usize = 0;
39 for payload in payload {
40 if payload.writeable {
41 continue;
42 }
43 let size = std::cmp::min(payload.length as usize, remaining.len());
44 let (current, next) = remaining.split_at_mut(size);
45 mem.read_at(payload.address, current)?;
46 read_bytes += size;
47 if next.is_empty() {
48 break;
49 }
50 remaining = next;
51 }
52 Ok(read_bytes)
53}
54
55fn readable_payload_length(payload: &[VirtioQueuePayload]) -> u64 {
57 payload
58 .iter()
59 .filter(|p| !p.writeable)
60 .fold(0, |acc, p| acc + p.length as u64)
61}
62
63fn read_from_payload_at_offset(
66 payload: &[VirtioQueuePayload],
67 offset: u64,
68 mem: &GuestMemory,
69 target: &mut [u8],
70) -> Result<usize, GuestMemoryError> {
71 let mut skip = offset;
72 let mut remaining = target;
73 let mut read_bytes: usize = 0;
74 for payload in payload {
75 if payload.writeable {
76 continue;
77 }
78 let payload_len = payload.length as u64;
79 if skip >= payload_len {
80 skip -= payload_len;
81 continue;
82 }
83 let usable = (payload_len - skip) as usize;
84 let size = std::cmp::min(usable, remaining.len());
85 let (current, next) = remaining.split_at_mut(size);
86 mem.read_at(payload.address.saturating_add(skip), current)?;
90 read_bytes += size;
91 skip = 0;
92 if next.is_empty() {
93 break;
94 }
95 remaining = next;
96 }
97 Ok(read_bytes)
98}
99
100#[must_use]
106pub struct VirtioQueueCallbackWork {
107 completion: QueueCompletion,
108 pub payload: Vec<VirtioQueuePayload>,
109}
110
111impl VirtioQueueCallbackWork {
112 pub(crate) fn from_parts(
113 completion: QueueCompletion,
114 payload: Vec<VirtioQueuePayload>,
115 ) -> Self {
116 Self {
117 completion,
118 payload,
119 }
120 }
121
122 pub(crate) fn completion(&self) -> &QueueCompletion {
125 &self.completion
126 }
127
128 pub fn descriptor_index(&self) -> u16 {
129 self.completion.descriptor_index()
130 }
131
132 pub fn into_completion(self) -> QueueCompletion {
139 self.completion
140 }
141
142 pub fn get_payload_length(&self, writeable: bool) -> u64 {
144 self.payload
145 .iter()
146 .filter(|x| x.writeable == writeable)
147 .fold(0, |acc, x| acc + x.length as u64)
148 }
149
150 pub fn read(&self, mem: &GuestMemory, target: &mut [u8]) -> Result<usize, GuestMemoryError> {
152 read_from_payload(&self.payload, mem, target)
153 }
154
155 pub fn read_at_offset(
158 &self,
159 offset: u64,
160 mem: &GuestMemory,
161 target: &mut [u8],
162 ) -> Result<usize, GuestMemoryError> {
163 read_from_payload_at_offset(&self.payload, offset, mem, target)
164 }
165
166 pub fn write_at_offset(
168 &self,
169 offset: u64,
170 mem: &GuestMemory,
171 source: &[u8],
172 ) -> Result<(), VirtioWriteError> {
173 let mut skip_bytes = offset;
174 let mut remaining = source;
175 for payload in &self.payload {
176 if !payload.writeable {
177 continue;
178 }
179
180 let payload_length = payload.length as u64;
181 if skip_bytes >= payload_length {
182 skip_bytes -= payload_length;
183 continue;
184 }
185
186 let size = std::cmp::min(
187 payload_length as usize - skip_bytes as usize,
188 remaining.len(),
189 );
190 let (current, next) = remaining.split_at(size);
191 mem.write_at(payload.address.saturating_add(skip_bytes), current)?;
194 remaining = next;
195 if remaining.is_empty() {
196 break;
197 }
198 skip_bytes = 0;
199 }
200
201 if !remaining.is_empty() {
202 return Err(VirtioWriteError::NotAllWritten(source.len()));
203 }
204
205 Ok(())
206 }
207
208 pub fn write(&self, mem: &GuestMemory, source: &[u8]) -> Result<(), VirtioWriteError> {
209 self.write_at_offset(0, mem, source)
210 }
211}
212
213#[derive(Debug, Error)]
214pub enum VirtioWriteError {
215 #[error(transparent)]
216 Memory(#[from] GuestMemoryError),
217 #[error("{0:#x} bytes not written")]
218 NotAllWritten(usize),
219}
220
221pub struct PeekedWork<'a> {
231 queue: &'a mut VirtioQueue,
232 work: VirtioQueueCallbackWork,
233}
234
235impl<'a> PeekedWork<'a> {
236 fn new(queue: &'a mut VirtioQueue, work: VirtioQueueCallbackWork) -> Self {
237 Self { queue, work }
238 }
239
240 pub fn payload(&self) -> &[VirtioQueuePayload] {
242 &self.work.payload
243 }
244
245 pub fn readable_length(&self) -> u64 {
247 readable_payload_length(&self.work.payload)
248 }
249
250 pub fn read(&self, mem: &GuestMemory, target: &mut [u8]) -> Result<usize, GuestMemoryError> {
252 read_from_payload(&self.work.payload, mem, target)
253 }
254
255 pub fn read_at_offset(
258 &self,
259 offset: u64,
260 mem: &GuestMemory,
261 target: &mut [u8],
262 ) -> Result<usize, GuestMemoryError> {
263 read_from_payload_at_offset(&self.work.payload, offset, mem, target)
264 }
265
266 pub fn consume(self) -> VirtioQueueCallbackWork {
271 self.queue.core.advance(self.work.completion());
272 self.work
273 }
274}
275
276#[derive(Debug, Inspect)]
277pub struct VirtioQueue {
278 #[inspect(flatten)]
279 core: QueueCoreGetWork,
280 #[inspect(flatten)]
281 complete: QueueCoreCompleteWork,
282 #[inspect(skip)]
283 notify_guest: Interrupt,
284 #[inspect(skip)]
285 queue_event: PolledWait<Event>,
286}
287
288impl VirtioQueue {
289 pub fn new(
290 features: VirtioDeviceFeatures,
291 params: QueueParams,
292 mem: GuestMemory,
293 notify: Interrupt,
294 queue_event: PolledWait<Event>,
295 initial_state: Option<QueueState>,
296 ) -> Result<Self, QueueError> {
297 let (get_work, complete_work) = new_queue(features, mem, params, initial_state)?;
298 Ok(Self {
299 core: get_work,
300 complete: complete_work,
301 notify_guest: notify,
302 queue_event,
303 })
304 }
305
306 pub fn queue_state(&self) -> QueueState {
308 QueueState {
309 avail_index: self.core.avail_index(),
310 used_index: self.complete.used_index(),
311 }
312 }
313
314 pub fn poll_kick(&mut self, cx: &mut Context<'_>) -> Poll<()> {
326 if self.core.failed() {
327 return Poll::Pending;
328 }
329 if self.core.arm_for_kick() {
330 ready!(self.queue_event.wait().poll_unpin(cx)).expect("waits on Event cannot fail");
331 }
332 Poll::Ready(())
333 }
334
335 pub fn try_next(&mut self) -> Result<Option<VirtioQueueCallbackWork>, Error> {
343 self.core.try_next_work().map_err(Error::other)
344 }
345
346 pub fn try_peek(&mut self) -> Result<Option<PeekedWork<'_>>, Error> {
362 let work = self.core.try_peek_work().map_err(Error::other)?;
363 Ok(work.map(|w| PeekedWork::new(self, w)))
364 }
365
366 pub async fn peek(&mut self) -> Result<PeekedWork<'_>, Error> {
374 let work = loop {
375 if let Some(work) = self.core.try_peek_work().map_err(Error::other)? {
376 break work;
377 }
378 std::future::poll_fn(|cx| self.poll_kick(cx)).await;
379 };
380 Ok(PeekedWork::new(self, work))
381 }
382
383 pub fn complete(&mut self, work: VirtioQueueCallbackWork, bytes_written: u32) {
391 self.complete_prepared(work.into_completion(), bytes_written);
392 }
393
394 pub fn complete_prepared(&mut self, completion: QueueCompletion, bytes_written: u32) {
401 self.core.work_completed(&completion);
404 match self
405 .complete
406 .complete_descriptor(&completion, bytes_written)
407 {
408 Ok(true) => {
409 self.notify_guest.deliver();
410 }
411 Ok(false) => {}
412 Err(err) => {
413 tracelimit::error_ratelimited!(
414 error = &err as &dyn std::error::Error,
415 "failed to complete descriptor"
416 );
417 }
418 }
419 }
420
421 fn poll_next_buffer(
422 &mut self,
423 cx: &mut Context<'_>,
424 ) -> Poll<Result<VirtioQueueCallbackWork, Error>> {
425 loop {
426 if let Some(work) = self.try_next()? {
427 return Poll::Ready(Ok(work));
428 }
429 ready!(self.poll_kick(cx));
430 }
431 }
432}
433
434impl Stream for VirtioQueue {
442 type Item = Result<VirtioQueueCallbackWork, Error>;
443
444 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
445 Some(ready!(self.get_mut().poll_next_buffer(cx))).into()
446 }
447}
448
449pub(crate) struct VirtioDoorbells {
450 registration: Option<Arc<dyn DoorbellRegistration>>,
451 doorbells: Vec<Box<dyn Send + Sync>>,
452}
453
454impl VirtioDoorbells {
455 pub fn new(registration: Option<Arc<dyn DoorbellRegistration>>) -> Self {
456 Self {
457 registration,
458 doorbells: Vec::new(),
459 }
460 }
461
462 pub fn add(&mut self, address: u64, value: Option<u64>, length: Option<u32>, event: &Event) {
463 if let Some(registration) = &mut self.registration {
464 let doorbell = registration.register_doorbell(address, value, length, event);
465 if let Ok(doorbell) = doorbell {
466 self.doorbells.push(doorbell);
467 }
468 }
469 }
470
471 pub fn clear(&mut self) {
472 self.doorbells.clear();
473 }
474}
475
476#[derive(Copy, Clone, Debug, Default)]
477pub struct DeviceTraitsSharedMemory {
478 pub id: u8,
479 pub size: u64,
480}
481
482#[derive(Clone, Debug)]
483pub struct DeviceTraits {
484 pub device_id: VirtioDeviceType,
485 pub device_features: VirtioDeviceFeatures,
486 pub max_queues: u16,
487 pub device_register_length: u32,
488 pub shared_memory: DeviceTraitsSharedMemory,
489}
490
491impl Default for DeviceTraits {
492 fn default() -> Self {
493 Self {
494 device_id: VirtioDeviceType(0),
495 device_features: Default::default(),
496 max_queues: 0,
497 device_register_length: 0,
498 shared_memory: Default::default(),
499 }
500 }
501}
502
503pub struct QueueResources {
504 pub params: QueueParams,
505 pub notify: Interrupt,
506 pub event: Event,
507 pub guest_memory: GuestMemory,
508}