/rust/registry/src/index.crates.io-1949cf8c6b5b557f/virtio-queue-0.16.0/src/state.rs
Line | Count | Source |
1 | | use crate::{Error, Queue, QueueT}; |
2 | | use vm_memory::GuestAddress; |
3 | | |
4 | | /// Representation of the `Queue` state. |
5 | | /// |
6 | | /// The `QueueState` represents the pure state of the `queue` without tracking any implementation |
7 | | /// details of the queue. The goal with this design is to minimize the changes required to the |
8 | | /// state, and thus the required transitions between states when upgrading or downgrading. |
9 | | /// |
10 | | /// In practice this means that the `QueueState` consists solely of POD (Plain Old Data). |
11 | | /// |
12 | | /// As this structure has all the fields public it is consider to be untrusted. A validated |
13 | | /// queue can be created from the state by calling the associated `try_from` function. |
14 | | #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] |
15 | | pub struct QueueState { |
16 | | /// The maximum size in elements offered by the device. |
17 | | pub max_size: u16, |
18 | | /// Tail position of the available ring. |
19 | | pub next_avail: u16, |
20 | | /// Head position of the used ring. |
21 | | pub next_used: u16, |
22 | | /// VIRTIO_F_RING_EVENT_IDX negotiated. |
23 | | pub event_idx_enabled: bool, |
24 | | /// The queue size in elements the driver selected. |
25 | | pub size: u16, |
26 | | /// Indicates if the queue is finished with configuration. |
27 | | pub ready: bool, |
28 | | /// Guest physical address of the descriptor table. |
29 | | pub desc_table: u64, |
30 | | /// Guest physical address of the available ring. |
31 | | pub avail_ring: u64, |
32 | | /// Guest physical address of the used ring. |
33 | | pub used_ring: u64, |
34 | | } |
35 | | |
36 | | impl TryFrom<QueueState> for Queue { |
37 | | type Error = Error; |
38 | | |
39 | 0 | fn try_from(q_state: QueueState) -> Result<Self, Self::Error> { |
40 | 0 | let mut q = Queue::new(q_state.max_size)?; |
41 | | |
42 | 0 | q.set_next_avail(q_state.next_avail); |
43 | 0 | q.set_next_used(q_state.next_used); |
44 | 0 | q.set_event_idx(q_state.event_idx_enabled); |
45 | 0 | q.try_set_size(q_state.size)?; |
46 | 0 | q.set_ready(q_state.ready); |
47 | 0 | q.try_set_desc_table_address(GuestAddress(q_state.desc_table))?; |
48 | 0 | q.try_set_avail_ring_address(GuestAddress(q_state.avail_ring))?; |
49 | 0 | q.try_set_used_ring_address(GuestAddress(q_state.used_ring))?; |
50 | | |
51 | 0 | Ok(q) |
52 | 0 | } |
53 | | } |
54 | | |
55 | | #[cfg(test)] |
56 | | mod tests { |
57 | | use super::*; |
58 | | |
59 | | fn create_valid_queue_state() -> QueueState { |
60 | | let queue = Queue::new(16).unwrap(); |
61 | | queue.state() |
62 | | } |
63 | | |
64 | | #[test] |
65 | | fn test_empty_queue_state() { |
66 | | let max_size = 16; |
67 | | let queue = Queue::new(max_size).unwrap(); |
68 | | |
69 | | // Saving the state of a queue on which we didn't do any operation is ok. |
70 | | // Same for restore. |
71 | | let queue_state = queue.state(); |
72 | | let restored_q = Queue::try_from(queue_state).unwrap(); |
73 | | assert_eq!(queue, restored_q); |
74 | | } |
75 | | |
76 | | #[test] |
77 | | fn test_invalid_queue_state() { |
78 | | // Let's generate a state that we know is valid so we can just alter one field at a time. |
79 | | let mut q_state = create_valid_queue_state(); |
80 | | |
81 | | // Test invalid max_size. |
82 | | // Size too small. |
83 | | q_state.max_size = 0; |
84 | | assert!(Queue::try_from(q_state).is_err()); |
85 | | // Size too big. |
86 | | q_state.max_size = u16::MAX; |
87 | | assert!(Queue::try_from(q_state).is_err()); |
88 | | // Size not a power of 2. |
89 | | q_state.max_size = 15; |
90 | | assert!(Queue::try_from(q_state).is_err()); |
91 | | |
92 | | // Test invalid size. |
93 | | let mut q_state = create_valid_queue_state(); |
94 | | // Size too small. |
95 | | q_state.size = 0; |
96 | | assert!(Queue::try_from(q_state).is_err()); |
97 | | // Size too big. |
98 | | q_state.size = u16::MAX; |
99 | | assert!(Queue::try_from(q_state).is_err()); |
100 | | // Size not a power of 2. |
101 | | q_state.size = 15; |
102 | | assert!(Queue::try_from(q_state).is_err()); |
103 | | |
104 | | // Test invalid desc_table. |
105 | | let mut q_state = create_valid_queue_state(); |
106 | | q_state.desc_table = 0xf; |
107 | | assert!(Queue::try_from(q_state).is_err()); |
108 | | |
109 | | // Test invalid avail_ring. |
110 | | let mut q_state = create_valid_queue_state(); |
111 | | q_state.avail_ring = 0x1; |
112 | | assert!(Queue::try_from(q_state).is_err()); |
113 | | |
114 | | // Test invalid used_ring. |
115 | | let mut q_state = create_valid_queue_state(); |
116 | | q_state.used_ring = 0x3; |
117 | | assert!(Queue::try_from(q_state).is_err()); |
118 | | } |
119 | | } |