devices/virtio/queue/
split_queue.rs

1// Copyright 2017 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::num::Wrapping;
6use std::sync::atomic::fence;
7use std::sync::atomic::AtomicU16;
8use std::sync::atomic::Ordering;
9
10use anyhow::bail;
11use anyhow::Context;
12use anyhow::Result;
13use base::error;
14use base::Event;
15use data_model::Le32;
16use serde::Deserialize;
17use serde::Serialize;
18use snapshot::AnySnapshot;
19use virtio_sys::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
20use vm_memory::GuestAddress;
21use vm_memory::GuestMemory;
22use zerocopy::FromBytes;
23use zerocopy::Immutable;
24use zerocopy::IntoBytes;
25use zerocopy::KnownLayout;
26
27use crate::virtio::DescriptorChain;
28use crate::virtio::Interrupt;
29use crate::virtio::QueueConfig;
30use crate::virtio::SplitDescriptorChain;
31
32#[allow(dead_code)]
33const VIRTQ_USED_F_NO_NOTIFY: u16 = 0x1;
34#[allow(dead_code)]
35const VIRTQ_AVAIL_F_NO_INTERRUPT: u16 = 0x1;
36
37/// An activated virtio queue with split queue layout.
38#[derive(Debug)]
39pub struct SplitQueue {
40    mem: GuestMemory,
41
42    event: Event,
43    interrupt: Interrupt,
44
45    /// The queue size in elements the driver selected. This is always guaranteed to be a power of
46    /// two, as required for split virtqueues.
47    size: u16,
48
49    /// MSI-X vector for the queue. Don't care for INTx
50    vector: u16,
51
52    /// Guest physical address of the descriptor table
53    desc_table: GuestAddress,
54
55    /// Guest physical address of the available ring
56    avail_ring: GuestAddress,
57
58    /// Guest physical address of the used ring
59    used_ring: GuestAddress,
60
61    next_avail: Wrapping<u16>,
62    next_used: Wrapping<u16>,
63
64    // Device feature bits accepted by the driver
65    features: u64,
66    last_used: Wrapping<u16>,
67}
68
69#[derive(Serialize, Deserialize)]
70pub struct SplitQueueSnapshot {
71    size: u16,
72    vector: u16,
73    desc_table: GuestAddress,
74    avail_ring: GuestAddress,
75    used_ring: GuestAddress,
76    next_avail: Wrapping<u16>,
77    next_used: Wrapping<u16>,
78    features: u64,
79    last_used: Wrapping<u16>,
80}
81
82#[repr(C)]
83#[derive(FromBytes, Immutable, IntoBytes, KnownLayout)]
84struct virtq_used_elem {
85    id: Le32,
86    len: Le32,
87}
88
89impl SplitQueue {
90    /// Constructs an activated split virtio queue with the given configuration.
91    pub fn new(
92        config: &QueueConfig,
93        mem: &GuestMemory,
94        event: Event,
95        interrupt: Interrupt,
96    ) -> Result<SplitQueue> {
97        let size = config.size();
98        if !size.is_power_of_two() {
99            bail!("split queue size {size} is not a power of 2");
100        }
101
102        let desc_table = config.desc_table();
103        let avail_ring = config.avail_ring();
104        let used_ring = config.used_ring();
105
106        // Validate addresses and queue size to ensure that address calculation won't overflow.
107        let ring_sizes = Self::ring_sizes(size, desc_table, avail_ring, used_ring);
108        let rings = ring_sizes
109            .iter()
110            .zip(vec!["descriptor table", "available ring", "used ring"]);
111
112        for ((addr, size), name) in rings {
113            if addr.checked_add(*size as u64).is_none() {
114                bail!(
115                    "virtio queue {} goes out of bounds: start:0x{:08x} size:0x{:08x}",
116                    name,
117                    addr.offset(),
118                    size,
119                );
120            }
121        }
122
123        Ok(SplitQueue {
124            mem: mem.clone(),
125            event,
126            interrupt,
127            size,
128            vector: config.vector(),
129            desc_table: config.desc_table(),
130            avail_ring: config.avail_ring(),
131            used_ring: config.used_ring(),
132            features: config.acked_features(),
133            next_avail: config.next_avail(),
134            next_used: config.next_used(),
135
136            // WARNING: last_used controls interrupt suppression
137            // (VIRTIO_RING_F_EVENT_IDX). The only safe value initial value is
138            // zero (unless restoring a snapshot and the value that was stored
139            // on the device is known; however we do not bother with that in our
140            // snapshot system since it is much simpler to just use the zero
141            // value and send a potentially spurious interrupt on restore).
142            last_used: Wrapping(0),
143        })
144    }
145
146    pub fn vhost_user_reclaim(&mut self, vring_base: u16) {
147        self.next_avail = Wrapping(vring_base);
148        // The vhost-user spec says:
149        //
150        //     For the Used Ring, the device only needs the next descriptor index at which to put
151        //     new descriptors, which is the value in the vring structure in memory, so this value
152        //     is not covered by this message.
153        //
154        // So, we read the value from guest memory.
155        let used_index_addr = self.used_ring.unchecked_add(2);
156        self.next_used = self
157            .mem
158            .read_obj_from_addr_volatile(used_index_addr)
159            .unwrap();
160
161        // Since the backend has not told us what its actual last_used value
162        // was, we have to assume that an interrupt must be sent when next
163        // available descriptor is used, so we set this to zero.
164        //
165        // But wait, one might ask, why can't we just assume the vhost-user
166        // backend has already sent interrupts for any descriptors it marked
167        // used before it stopped processing the queue? Then we could just
168        // initialize last_used as `last_used == next_used`, which would skip
169        // spurious interrupts and be more efficient. Right?
170        //
171        // If VIRTIO_RING_F_EVENT_IDX is enabled, then no. The reason is the
172        // device could be in an interrupt suppressed state and so it may indeed
173        // have marked some descriptors used, but not yet sent an interrupt for
174        // them. Once we set last_used = next_used, no interrupts will be sent
175        // to the driver until the driver updates next_used (see
176        // queue_wants_interrupt for details), but the driver will
177        // never wake up the device isn't sending any interrupts. Thus, the
178        // device stalls.
179        //
180        // NOTE: this value is not used by the snapshot/restore process, but we
181        // still want to pick a reasonable value here in case it is used in the
182        // future.
183        self.last_used = Wrapping(0);
184    }
185
186    pub fn next_avail_to_process(&self) -> u16 {
187        self.next_avail.0
188    }
189
190    /// Return the actual size of the queue, as the driver may not set up a
191    /// queue as big as the device allows.
192    pub fn size(&self) -> u16 {
193        self.size
194    }
195
196    /// Getter for vector field
197    pub fn vector(&self) -> u16 {
198        self.vector
199    }
200
201    /// Getter for descriptor area
202    pub fn desc_table(&self) -> GuestAddress {
203        self.desc_table
204    }
205
206    /// Getter for driver area
207    pub fn avail_ring(&self) -> GuestAddress {
208        self.avail_ring
209    }
210
211    /// Getter for device area
212    pub fn used_ring(&self) -> GuestAddress {
213        self.used_ring
214    }
215
216    /// Get a reference to the queue's "kick event"
217    pub fn event(&self) -> &Event {
218        &self.event
219    }
220
221    /// Get a reference to the queue's interrupt
222    pub fn interrupt(&self) -> &Interrupt {
223        &self.interrupt
224    }
225
226    // Return `index` modulo the currently configured queue size.
227    fn wrap_queue_index(&self, index: Wrapping<u16>) -> u16 {
228        // We know that `self.size` is a power of two (enforced by `new()`), so the modulus can
229        // be calculated with a bitmask rather than actual division.
230        debug_assert!(self.size.is_power_of_two());
231        index.0 & self.size.wrapping_sub(1)
232    }
233
234    fn ring_sizes(
235        queue_size: u16,
236        desc_table: GuestAddress,
237        avail_ring: GuestAddress,
238        used_ring: GuestAddress,
239    ) -> Vec<(GuestAddress, usize)> {
240        let queue_size = queue_size as usize;
241        vec![
242            (desc_table, 16 * queue_size),
243            (avail_ring, 6 + 2 * queue_size),
244            (used_ring, 6 + 8 * queue_size),
245        ]
246    }
247
248    // Set the `avail_event` field in the used ring.
249    //
250    // This allows the device to inform the driver that driver-to-device notification
251    // (kicking the ring) is not necessary until the driver reaches the `avail_index` descriptor.
252    //
253    // This value is only used if the `VIRTIO_F_EVENT_IDX` feature has been negotiated.
254    fn set_avail_event(&mut self, avail_index: Wrapping<u16>) {
255        fence(Ordering::SeqCst);
256
257        let avail_event_addr = self.used_ring.unchecked_add(4 + 8 * u64::from(self.size));
258        self.mem
259            .write_obj_at_addr_volatile(avail_index.0, avail_event_addr)
260            .unwrap();
261    }
262
263    // Query the value of a single-bit flag in the available ring.
264    //
265    // Returns `true` if `flag` is currently set (by the driver) in the available ring flags.
266    fn get_avail_flag(&self, flag: u16) -> bool {
267        fence(Ordering::SeqCst);
268
269        let avail_flags: u16 = self
270            .mem
271            .read_obj_from_addr_volatile(self.avail_ring)
272            .unwrap();
273
274        avail_flags & flag == flag
275    }
276
277    // Get the `used_event` field in the available ring.
278    //
279    // The returned value is the index of the next descriptor chain entry for which the driver
280    // needs to be notified upon use.  Entries before this index may be used without notifying
281    // the driver.
282    //
283    // This value is only valid if the `VIRTIO_F_EVENT_IDX` feature has been negotiated.
284    fn get_used_event(&self) -> Wrapping<u16> {
285        fence(Ordering::SeqCst);
286
287        let used_event_addr = self.avail_ring.unchecked_add(4 + 2 * u64::from(self.size));
288        let used_event: u16 = self
289            .mem
290            .read_obj_from_addr_volatile(used_event_addr)
291            .unwrap();
292
293        Wrapping(used_event)
294    }
295
296    /// Get the first available descriptor chain without removing it from the queue.
297    /// Call `pop_peeked` to remove the returned descriptor chain from the queue.
298    pub fn peek(&mut self) -> Option<DescriptorChain> {
299        // Get a `VolatileSlice` covering the `struct virtq_avail` fixed header (`flags` and `idx`)
300        // and variable-length `ring`. This ensures that the raw pointers generated below point into
301        // valid `GuestMemory` regions.
302        let avail_ring_size = 2 * size_of::<u16>() + (size_of::<u16>() * usize::from(self.size));
303        let avail_ring_vslice = self
304            .mem
305            .get_slice_at_addr(self.avail_ring, avail_ring_size)
306            .unwrap();
307
308        // SAFETY: offset of `virtq_avail.idx` (2) is always within the `VolatileSlice` bounds.
309        let avail_index_ptr = unsafe { avail_ring_vslice.as_mut_ptr().add(2) } as *mut u16;
310        // SAFETY: `GuestMemory::get_slice_at_addr()` returns a valid `VolatileSlice`, and
311        // `avail_index_ptr` is a valid `*mut u16` contained within that slice.
312        let avail_index_atomic = unsafe { AtomicU16::from_ptr(avail_index_ptr) };
313
314        // Check if the driver has published any new descriptors beyond `self.next_avail`. This uses
315        // a `Relaxed` load because we do not need a memory barrier if there are no new descriptors.
316        // If the ring is not empty, the `fence()` below will provide the necessary ordering,
317        // pairing with the write memory barrier in the driver.
318        let avail_index: u16 = avail_index_atomic.load(Ordering::Relaxed);
319        let next_avail = self.next_avail;
320        if next_avail.0 == avail_index {
321            return None;
322        }
323
324        // This fence ensures that subsequent reads from the descriptor do not
325        // get reordered and happen only after fetching the available_index and
326        // checking that there is a slot available.
327        fence(Ordering::Acquire);
328
329        // Calculate the offset of `ring[next_avail % size]` within `struct virtq_avail`.
330        let ring_offset = 4 + (usize::from(self.wrap_queue_index(next_avail)) * 2);
331        debug_assert!(ring_offset + size_of::<u16>() <= avail_ring_size);
332        // SAFETY: The available ring index was wrapped to fall within the queue size above, so
333        // `ring_offset` is always in bounds.
334        let ring_ptr = unsafe { avail_ring_vslice.as_ptr().add(ring_offset) } as *const u16;
335        // SAFETY: `ring_ptr` is a valid `*const u16` within `avail_ring_vslice`.
336        let descriptor_index: u16 = unsafe { std::ptr::read_volatile(ring_ptr) };
337
338        let chain =
339            SplitDescriptorChain::new(&self.mem, self.desc_table, self.size, descriptor_index);
340        DescriptorChain::new(chain, &self.mem, descriptor_index)
341            .map_err(|e| {
342                error!("{:#}", e);
343                e
344            })
345            .ok()
346    }
347
348    /// Remove the first available descriptor chain from the queue.
349    /// This function should only be called immediately following `peek` and must be passed a
350    /// reference to the same `DescriptorChain` returned by the most recent `peek`.
351    pub(super) fn pop_peeked(&mut self, _descriptor_chain: &DescriptorChain) {
352        self.next_avail += Wrapping(1);
353        if self.features & ((1u64) << VIRTIO_RING_F_EVENT_IDX) != 0 {
354            self.set_avail_event(self.next_avail);
355        }
356    }
357
358    pub(super) fn try_pop_length(&mut self, length: usize) -> Option<Vec<DescriptorChain>> {
359        let mut remain_len = length;
360        let mut descriptors = vec![];
361        while remain_len > 0 {
362            match self.peek() {
363                Some(desc) => {
364                    let available_bytes = desc.writer.available_bytes();
365                    descriptors.push(desc);
366                    self.next_avail += Wrapping(1);
367                    if available_bytes >= remain_len {
368                        if self.features & ((1u64) << VIRTIO_RING_F_EVENT_IDX) != 0 {
369                            self.set_avail_event(self.next_avail);
370                        }
371                        return Some(descriptors);
372                    } else {
373                        remain_len -= available_bytes;
374                    }
375                }
376                None => {
377                    if self.features & ((1u64) << VIRTIO_RING_F_EVENT_IDX) != 0 {
378                        self.set_avail_event(self.next_avail);
379                    }
380                    // Reverse the effect of pop
381                    self.next_avail -= Wrapping(descriptors.len() as u16);
382                    return None;
383                }
384            }
385        }
386        None
387    }
388
389    /// Puts multiple available descriptor heads into the used ring for use by the guest.
390    pub fn add_used_with_bytes_written_batch(
391        &mut self,
392        desc_chains: impl IntoIterator<Item = (DescriptorChain, u32)>,
393    ) {
394        // Get a `VolatileSlice` covering the `struct virtq_used` fixed header (`flags` and `idx`)
395        // and variable-length `ring`. This ensures that the raw pointers generated below point into
396        // valid `GuestMemory` regions.
397        let used_ring_size =
398            2 * size_of::<u16>() + (size_of::<virtq_used_elem>() * usize::from(self.size));
399        let used_ring_vslice = self
400            .mem
401            .get_slice_at_addr(self.used_ring, used_ring_size)
402            .unwrap();
403
404        // SAFETY: `elems_ptr` is always a valid pointer due to `used_ring_vslice()`.
405        let elems_ptr = unsafe { used_ring_vslice.as_mut_ptr().add(4) } as *mut virtq_used_elem;
406
407        // SAFETY: `used_index_ptr` is always a valid pointer due to `used_ring_vslice()`.
408        let used_index_ptr = unsafe { used_ring_vslice.as_mut_ptr().add(2) } as *mut u16;
409
410        // SAFETY: `used_index_ptr` is always a valid pointer
411        let used_index_atomic = unsafe { AtomicU16::from_ptr(used_index_ptr) };
412
413        let mut next_used = self.next_used;
414        for (desc_chain, len) in desc_chains {
415            let desc_index = desc_chain.index();
416            debug_assert!(desc_index < self.size);
417            let id = Le32::from(u32::from(desc_index));
418            let len = Le32::from(len);
419
420            let wrapped_index = usize::from(self.wrap_queue_index(next_used));
421            // SAFETY: `wrapped_index` is always in bounds due to `wrap_queue_index()`.
422            let elem_ptr = unsafe { elems_ptr.add(wrapped_index) };
423
424            // SAFETY: `elem_ptr` is always a valid pointer
425            unsafe {
426                std::ptr::write_volatile(std::ptr::addr_of_mut!((*elem_ptr).id), id);
427                std::ptr::write_volatile(std::ptr::addr_of_mut!((*elem_ptr).len), len);
428            };
429
430            next_used += Wrapping(1);
431        }
432
433        if next_used != self.next_used {
434            fence(Ordering::Release);
435            used_index_atomic.store(next_used.0, Ordering::Relaxed);
436            self.next_used = next_used;
437        }
438    }
439
440    /// Returns if the queue should have an interrupt sent based on its state.
441    ///
442    /// This function implements `VIRTIO_RING_F_EVENT_IDX`, otherwise known as
443    /// interrupt suppression. The virtio spec provides the driver with a field,
444    /// `used_event`, which says that once we write that descriptor (or several
445    /// in the case of a flurry of `add_used` calls), we should send a
446    /// notification. Because the values involved wrap around `u16::MAX`, and to
447    /// avoid checking the condition on every `add_used` call, the math is a
448    /// little complicated.
449    ///
450    /// The critical inequality is:
451    /// ```text
452    ///      (next_used - 1) - used_event < next_used - last_used
453    /// ```
454    ///
455    /// For illustration purposes, we label it as `A < B`, where
456    /// `A = (next_used -1) - used_event`, and `B = next_used - last_used`.
457    ///
458    /// `A` and `B` represent two distances, measured in a wrapping ring of size
459    /// `u16::MAX`. In the "send intr" case, the inequality is true. In the
460    /// "don't send intr" case, the inequality is false. We must be very careful
461    /// in assigning a direction to the ring, so that when we
462    /// graph the subtraction operations, we are measuring the right distance
463    /// (similar to how DC circuits are analyzed).
464    ///
465    /// The two distances are as follows:
466    ///  * `A` is the distance between the driver's requested notification point, and the current
467    ///    position in the ring.
468    ///
469    ///  * `B` is the distance between the last time we notified the guest, and the current position
470    ///    in the ring.
471    ///
472    /// If we graph these distances for the situation where we want to notify
473    /// the guest, and when we don't want to notify the guest, we see that
474    /// `A < B` becomes true the moment `next_used - 1` passes `used_event`. See
475    /// the graphs at the bottom of this comment block for a more visual
476    /// explanation.
477    ///
478    /// Once an interrupt is sent, we have a final useful property: last_used
479    /// moves up next_used, which causes the inequality to be false. Thus, we
480    /// won't send notifications again until `used_event` is moved forward by
481    /// the driver.
482    ///
483    /// Finally, let's talk about a couple of ways to write this inequality
484    /// that don't work, and critically, explain *why*.
485    ///
486    /// First, a naive reading of the virtio spec might lead us to ask: why not
487    /// just use the following inequality:
488    /// ```text
489    ///      next_used - 1 >= used_event
490    /// ```
491    ///
492    /// because that's much simpler, right? The trouble is that the ring wraps,
493    /// so it could be that a smaller index is actually ahead of a larger one.
494    /// That's why we have to use distances in the ring instead.
495    ///
496    /// Second, one might look at the correct inequality:
497    /// ```text
498    ///      (next_used - 1) - used_event < next_used - last_used
499    /// ```
500    ///
501    /// And try to simplify it to:
502    /// ```text
503    ///      last_used - 1 < used_event
504    /// ```
505    ///
506    /// Functionally, this won't work because next_used isn't present at all
507    /// anymore. (Notifications will never be sent.) But why is that? The algebra
508    /// here *appears* to work out, but all semantic meaning is lost. There are
509    /// two explanations for why this happens:
510    /// * The intuitive one: the terms in the inequality are not actually separable; in other words,
511    ///   (next_used - last_used) is an inseparable term, so subtracting next_used from both sides
512    ///   of the original inequality and zeroing them out is semantically invalid. But why aren't
513    ///   they separable? See below.
514    /// * The theoretical one: canceling like terms relies a vector space law: a + x = b + x => a =
515    ///   b (cancellation law). For congruences / equality under modulo, this law is satisfied, but
516    ///   for inequalities under mod, it is not; therefore, we cannot cancel like terms.
517    ///
518    /// ```text
519    /// ┌──────────────────────────────────┐
520    /// │                                  │
521    /// │                                  │
522    /// │                                  │
523    /// │           ┌────────────  next_used - 1
524    /// │           │A                   x
525    /// │           │       ┌────────────x────────────┐
526    /// │           │       │            x            │
527    /// │           │       │                         │
528    /// │           │       │               │         │
529    /// │           │       │               │         │
530    /// │     used_event  xxxx        + ◄───┘       xxxxx last_used
531    /// │                   │                         │      │
532    /// │                   │        Send intr        │      │
533    /// │                   │                         │      │
534    /// │                   └─────────────────────────┘      │
535    /// │                                                    │
536    /// │ B                                                  │
537    /// └────────────────────────────────────────────────────┘
538    ///
539    ///             ┌───────────────────────────────────────────────────┐
540    ///             │                                                 A │
541    ///             │       ┌────────────────────────┐                  │
542    ///             │       │                        │                  │
543    ///             │       │                        │                  │
544    ///             │       │              │         │                  │
545    ///             │       │              │         │                  │
546    ///       used_event  xxxx             │       xxxxx last_used      │
547    ///                     │        + ◄───┘         │       │          │
548    ///                     │                        │       │          │
549    ///                     │     Don't send intr    │       │          │
550    ///                     │                        │       │          │
551    ///                     └───────────x────────────┘       │          │
552    ///                                 x                    │          │
553    ///                              next_used - 1           │          │
554    ///                              │  │                  B │          │
555    ///                              │  └────────────────────┘          │
556    ///                              │                                  │
557    ///                              └──────────────────────────────────┘
558    /// ```
559    fn queue_wants_interrupt(&self) -> bool {
560        if self.features & ((1u64) << VIRTIO_RING_F_EVENT_IDX) != 0 {
561            let used_event = self.get_used_event();
562            self.next_used - used_event - Wrapping(1) < self.next_used - self.last_used
563        } else {
564            !self.get_avail_flag(VIRTQ_AVAIL_F_NO_INTERRUPT)
565        }
566    }
567
568    /// inject interrupt into guest on this queue
569    /// return true: interrupt is injected into guest for this queue
570    ///        false: interrupt isn't injected
571    pub fn trigger_interrupt(&mut self) -> bool {
572        if self.queue_wants_interrupt() {
573            self.last_used = self.next_used;
574            self.interrupt.signal_used_queue(self.vector);
575            true
576        } else {
577            false
578        }
579    }
580
581    pub fn snapshot(&self) -> anyhow::Result<AnySnapshot> {
582        AnySnapshot::to_any(SplitQueueSnapshot {
583            size: self.size,
584            vector: self.vector,
585            desc_table: self.desc_table,
586            avail_ring: self.avail_ring,
587            used_ring: self.used_ring,
588            next_avail: self.next_avail,
589            next_used: self.next_used,
590            features: self.features,
591            last_used: self.last_used,
592        })
593        .context("failed to serialize MsixConfigSnapshot")
594    }
595
596    pub fn restore(
597        queue_value: AnySnapshot,
598        mem: &GuestMemory,
599        event: Event,
600        interrupt: Interrupt,
601    ) -> anyhow::Result<SplitQueue> {
602        let s: SplitQueueSnapshot = AnySnapshot::from_any(queue_value)?;
603        let queue = SplitQueue {
604            mem: mem.clone(),
605            event,
606            interrupt,
607            size: s.size,
608            vector: s.vector,
609            desc_table: s.desc_table,
610            avail_ring: s.avail_ring,
611            used_ring: s.used_ring,
612            next_avail: s.next_avail,
613            next_used: s.next_used,
614            features: s.features,
615            last_used: s.last_used,
616        };
617        Ok(queue)
618    }
619}
620
621#[cfg(test)]
622mod tests {
623    use std::convert::TryInto;
624    use std::mem::offset_of;
625
626    use data_model::Le16;
627    use data_model::Le32;
628    use data_model::Le64;
629    use zerocopy::FromBytes;
630    use zerocopy::Immutable;
631    use zerocopy::IntoBytes;
632    use zerocopy::KnownLayout;
633
634    use super::*;
635    use crate::virtio::create_descriptor_chain;
636    use crate::virtio::Desc;
637    use crate::virtio::Interrupt;
638    use crate::virtio::Queue;
639
640    const GUEST_MEMORY_SIZE: u64 = 0x10000;
641    const DESC_OFFSET: u64 = 0;
642    const AVAIL_OFFSET: u64 = 0x200;
643    const USED_OFFSET: u64 = 0x400;
644    const QUEUE_SIZE: usize = 0x10;
645    const BUFFER_OFFSET: u64 = 0x8000;
646    const BUFFER_LEN: u32 = 0x400;
647
648    #[derive(Copy, Clone, Debug, FromBytes, Immutable, IntoBytes, KnownLayout)]
649    #[repr(C)]
650    struct Avail {
651        flags: Le16,
652        idx: Le16,
653        ring: [Le16; QUEUE_SIZE],
654        used_event: Le16,
655    }
656
657    impl Default for Avail {
658        fn default() -> Self {
659            Avail {
660                flags: Le16::from(0u16),
661                idx: Le16::from(0u16),
662                ring: [Le16::from(0u16); QUEUE_SIZE],
663                used_event: Le16::from(0u16),
664            }
665        }
666    }
667
668    #[derive(Copy, Clone, Debug, FromBytes, Immutable, IntoBytes, KnownLayout)]
669    #[repr(C)]
670    struct UsedElem {
671        id: Le32,
672        len: Le32,
673    }
674
675    impl Default for UsedElem {
676        fn default() -> Self {
677            UsedElem {
678                id: Le32::from(0u32),
679                len: Le32::from(0u32),
680            }
681        }
682    }
683
684    #[derive(Copy, Clone, Debug, FromBytes, Immutable, IntoBytes, KnownLayout)]
685    #[repr(C, packed)]
686    struct Used {
687        flags: Le16,
688        idx: Le16,
689        used_elem_ring: [UsedElem; QUEUE_SIZE],
690        avail_event: Le16,
691    }
692
693    impl Default for Used {
694        fn default() -> Self {
695            Used {
696                flags: Le16::from(0u16),
697                idx: Le16::from(0u16),
698                used_elem_ring: [UsedElem::default(); QUEUE_SIZE],
699                avail_event: Le16::from(0u16),
700            }
701        }
702    }
703
704    fn setup_vq(queue: &mut QueueConfig, mem: &GuestMemory) -> Queue {
705        let desc = Desc {
706            addr: Le64::from(BUFFER_OFFSET),
707            len: Le32::from(BUFFER_LEN),
708            flags: Le16::from(0u16),
709            next: Le16::from(1u16),
710        };
711        let _ = mem.write_obj_at_addr(desc, GuestAddress(DESC_OFFSET));
712
713        let avail = Avail::default();
714        let _ = mem.write_obj_at_addr(avail, GuestAddress(AVAIL_OFFSET));
715
716        let used = Used::default();
717        let _ = mem.write_obj_at_addr(used, GuestAddress(USED_OFFSET));
718
719        queue.set_desc_table(GuestAddress(DESC_OFFSET));
720        queue.set_avail_ring(GuestAddress(AVAIL_OFFSET));
721        queue.set_used_ring(GuestAddress(USED_OFFSET));
722        queue.ack_features((1u64) << VIRTIO_RING_F_EVENT_IDX);
723        queue.set_ready(true);
724
725        queue
726            .activate(mem, Event::new().unwrap(), Interrupt::new_for_test())
727            .expect("QueueConfig::activate failed")
728    }
729
730    fn fake_desc_chain(mem: &GuestMemory) -> DescriptorChain {
731        create_descriptor_chain(mem, GuestAddress(0), GuestAddress(0), Vec::new(), 0)
732            .expect("failed to create descriptor chain")
733    }
734
735    #[test]
736    fn queue_event_id_guest_fast() {
737        let mut queue =
738            QueueConfig::new(QUEUE_SIZE.try_into().unwrap(), 1 << VIRTIO_RING_F_EVENT_IDX);
739        let memory_start_addr = GuestAddress(0x0);
740        let mem = GuestMemory::new(&[(memory_start_addr, GUEST_MEMORY_SIZE)]).unwrap();
741        let mut queue = setup_vq(&mut queue, &mem);
742
743        // Offset of used_event within Avail structure
744        let used_event_offset = offset_of!(Avail, used_event) as u64;
745        let used_event_address = GuestAddress(AVAIL_OFFSET + used_event_offset);
746
747        // Assume driver submit 0x100 req to device,
748        // device has handled them, so increase self.next_used to 0x100
749        let mut device_generate: Wrapping<u16> = Wrapping(0x100);
750        for _ in 0..device_generate.0 {
751            queue.add_used_with_bytes_written(fake_desc_chain(&mem), BUFFER_LEN);
752        }
753
754        // At this moment driver hasn't handled any interrupts yet, so it
755        // should inject interrupt.
756        assert_eq!(queue.trigger_interrupt(), true);
757
758        // Driver handle all the interrupts and update avail.used_event to 0x100
759        let mut driver_handled = device_generate;
760        let _ = mem.write_obj_at_addr(Le16::from(driver_handled.0), used_event_address);
761
762        // At this moment driver have handled all the interrupts, and
763        // device doesn't generate more data, so interrupt isn't needed.
764        assert_eq!(queue.trigger_interrupt(), false);
765
766        // Assume driver submit another u16::MAX - 0x100 req to device,
767        // Device has handled all of them, so increase self.next_used to u16::MAX
768        for _ in device_generate.0..u16::MAX {
769            queue.add_used_with_bytes_written(fake_desc_chain(&mem), BUFFER_LEN);
770        }
771        device_generate = Wrapping(u16::MAX);
772
773        // At this moment driver just handled 0x100 interrupts, so it
774        // should inject interrupt.
775        assert_eq!(queue.trigger_interrupt(), true);
776
777        // driver handle all the interrupts and update avail.used_event to u16::MAX
778        driver_handled = device_generate;
779        let _ = mem.write_obj_at_addr(Le16::from(driver_handled.0), used_event_address);
780
781        // At this moment driver have handled all the interrupts, and
782        // device doesn't generate more data, so interrupt isn't needed.
783        assert_eq!(queue.trigger_interrupt(), false);
784
785        // Assume driver submit another 1 request,
786        // device has handled it, so wrap self.next_used to 0
787        queue.add_used_with_bytes_written(fake_desc_chain(&mem), BUFFER_LEN);
788        device_generate += Wrapping(1);
789
790        // At this moment driver has handled all the previous interrupts, so it
791        // should inject interrupt again.
792        assert_eq!(queue.trigger_interrupt(), true);
793
794        // driver handle that interrupts and update avail.used_event to 0
795        driver_handled = device_generate;
796        let _ = mem.write_obj_at_addr(Le16::from(driver_handled.0), used_event_address);
797
798        // At this moment driver have handled all the interrupts, and
799        // device doesn't generate more data, so interrupt isn't needed.
800        assert_eq!(queue.trigger_interrupt(), false);
801    }
802
803    #[test]
804    fn queue_event_id_guest_slow() {
805        let mut queue =
806            QueueConfig::new(QUEUE_SIZE.try_into().unwrap(), 1 << VIRTIO_RING_F_EVENT_IDX);
807        let memory_start_addr = GuestAddress(0x0);
808        let mem = GuestMemory::new(&[(memory_start_addr, GUEST_MEMORY_SIZE)]).unwrap();
809        let mut queue = setup_vq(&mut queue, &mem);
810
811        // Offset of used_event within Avail structure
812        let used_event_offset = offset_of!(Avail, used_event) as u64;
813        let used_event_address = GuestAddress(AVAIL_OFFSET + used_event_offset);
814
815        // Assume driver submit 0x100 req to device,
816        // device have handled 0x100 req, so increase self.next_used to 0x100
817        let mut device_generate: Wrapping<u16> = Wrapping(0x100);
818        for _ in 0..device_generate.0 {
819            queue.add_used_with_bytes_written(fake_desc_chain(&mem), BUFFER_LEN);
820        }
821
822        // At this moment driver hasn't handled any interrupts yet, so it
823        // should inject interrupt.
824        assert_eq!(queue.trigger_interrupt(), true);
825
826        // Driver handle part of the interrupts and update avail.used_event to 0x80
827        let mut driver_handled = Wrapping(0x80);
828        let _ = mem.write_obj_at_addr(Le16::from(driver_handled.0), used_event_address);
829
830        // At this moment driver hasn't finished last interrupt yet,
831        // so interrupt isn't needed.
832        assert_eq!(queue.trigger_interrupt(), false);
833
834        // Assume driver submit another 1 request,
835        // device has handled it, so increment self.next_used.
836        queue.add_used_with_bytes_written(fake_desc_chain(&mem), BUFFER_LEN);
837        device_generate += Wrapping(1);
838
839        // At this moment driver hasn't finished last interrupt yet,
840        // so interrupt isn't needed.
841        assert_eq!(queue.trigger_interrupt(), false);
842
843        // Assume driver submit another u16::MAX - 0x101 req to device,
844        // Device has handled all of them, so increase self.next_used to u16::MAX
845        for _ in device_generate.0..u16::MAX {
846            queue.add_used_with_bytes_written(fake_desc_chain(&mem), BUFFER_LEN);
847        }
848        device_generate = Wrapping(u16::MAX);
849
850        // At this moment driver hasn't finished last interrupt yet,
851        // so interrupt isn't needed.
852        assert_eq!(queue.trigger_interrupt(), false);
853
854        // driver handle most of the interrupts and update avail.used_event to u16::MAX - 1,
855        driver_handled = device_generate - Wrapping(1);
856        let _ = mem.write_obj_at_addr(Le16::from(driver_handled.0), used_event_address);
857
858        // Assume driver submit another 1 request,
859        // device has handled it, so wrap self.next_used to 0
860        queue.add_used_with_bytes_written(fake_desc_chain(&mem), BUFFER_LEN);
861        device_generate += Wrapping(1);
862
863        // At this moment driver has already finished the last interrupt(0x100),
864        // and device service other request, so new interrupt is needed.
865        assert_eq!(queue.trigger_interrupt(), true);
866
867        // Assume driver submit another 1 request,
868        // device has handled it, so increment self.next_used to 1
869        queue.add_used_with_bytes_written(fake_desc_chain(&mem), BUFFER_LEN);
870        device_generate += Wrapping(1);
871
872        // At this moment driver hasn't finished last interrupt((Wrapping(0)) yet,
873        // so interrupt isn't needed.
874        assert_eq!(queue.trigger_interrupt(), false);
875
876        // driver handle all the remain interrupts and wrap avail.used_event to 0x1.
877        driver_handled = device_generate;
878        let _ = mem.write_obj_at_addr(Le16::from(driver_handled.0), used_event_address);
879
880        // At this moment driver has handled all the interrupts, and
881        // device doesn't generate more data, so interrupt isn't needed.
882        assert_eq!(queue.trigger_interrupt(), false);
883
884        // Assume driver submit another 1 request,
885        // device has handled it, so increase self.next_used.
886        queue.add_used_with_bytes_written(fake_desc_chain(&mem), BUFFER_LEN);
887        device_generate += Wrapping(1);
888
889        // At this moment driver has finished all the previous interrupts, so it
890        // should inject interrupt again.
891        assert_eq!(queue.trigger_interrupt(), true);
892    }
893}