1 // Portions Copyright 2017 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE-BSD-3-Clause file. 4 // 5 // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 // 7 // Copyright © 2019 Intel Corporation 8 // 9 // Copyright (C) 2020-2021 Alibaba Cloud. All rights reserved. 10 // 11 // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause 12 13 use vm_memory::{ByteValued, GuestAddress, Le16, Le32, Le64}; 14 15 use virtio_bindings::bindings::virtio_ring::{ 16 VRING_DESC_F_INDIRECT, VRING_DESC_F_NEXT, VRING_DESC_F_WRITE, 17 }; 18 19 /// A virtio descriptor constraints with C representation. 20 /// 21 /// # Example 22 /// 23 /// ```rust 24 /// # use virtio_bindings::bindings::virtio_ring::{VRING_DESC_F_NEXT, VRING_DESC_F_WRITE}; 25 /// # use virtio_queue::mock::MockSplitQueue; 26 /// use virtio_queue::{Descriptor, Queue, QueueOwnedT}; 27 /// use vm_memory::{GuestAddress, GuestMemoryMmap}; 28 /// 29 /// # fn populate_queue(m: &GuestMemoryMmap) -> Queue { 30 /// # let vq = MockSplitQueue::new(m, 16); 31 /// # let mut q = vq.create_queue().unwrap(); 32 /// # 33 /// # // We have only one chain: (0, 1). 34 /// # let desc = Descriptor::new(0x1000, 0x1000, VRING_DESC_F_NEXT as u16, 1); 35 /// # vq.desc_table().store(0, desc); 36 /// # let desc = Descriptor::new(0x2000, 0x1000, VRING_DESC_F_WRITE as u16, 0); 37 /// # vq.desc_table().store(1, desc); 38 /// # 39 /// # vq.avail().ring().ref_at(0).unwrap().store(u16::to_le(0)); 40 /// # vq.avail().idx().store(u16::to_le(1)); 41 /// # q 42 /// # } 43 /// let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap(); 44 /// // Populate the queue with descriptor chains and update the available ring accordingly. 45 /// let mut queue = populate_queue(m); 46 /// let mut i = queue.iter(m).unwrap(); 47 /// let mut c = i.next().unwrap(); 48 /// 49 /// // Get the first descriptor and access its fields. 50 /// let desc = c.next().unwrap(); 51 /// let _addr = desc.addr(); 52 /// let _len = desc.len(); 53 /// let _flags = desc.flags(); 54 /// let _next = desc.next(); 55 /// let _is_write_only = desc.is_write_only(); 56 /// let _has_next = desc.has_next(); 57 /// let _refers_to_ind_table = desc.refers_to_indirect_table(); 58 /// ``` 59 // Note that the `ByteValued` implementation of this structure expects the `Descriptor` to store 60 // only plain old data types. 61 #[repr(C)] 62 #[derive(Default, Clone, Copy, Debug)] 63 pub struct Descriptor { 64 /// Guest physical address of device specific data. 65 addr: Le64, 66 67 /// Length of device specific data. 68 len: Le32, 69 70 /// Includes next, write, and indirect bits. 71 flags: Le16, 72 73 /// Index into the descriptor table of the next descriptor if flags has the `next` bit set. 74 next: Le16, 75 } 76 77 #[allow(clippy::len_without_is_empty)] 78 impl Descriptor { 79 /// Return the guest physical address of the descriptor buffer. addr(&self) -> GuestAddress80 pub fn addr(&self) -> GuestAddress { 81 GuestAddress(self.addr.into()) 82 } 83 84 /// Return the length of the descriptor buffer. len(&self) -> u3285 pub fn len(&self) -> u32 { 86 self.len.into() 87 } 88 89 /// Return the flags for this descriptor, including next, write and indirect bits. flags(&self) -> u1690 pub fn flags(&self) -> u16 { 91 self.flags.into() 92 } 93 94 /// Return the value stored in the `next` field of the descriptor. next(&self) -> u1695 pub fn next(&self) -> u16 { 96 self.next.into() 97 } 98 99 /// Check whether this descriptor refers to a buffer containing an indirect descriptor table. refers_to_indirect_table(&self) -> bool100 pub fn refers_to_indirect_table(&self) -> bool { 101 self.flags() & VRING_DESC_F_INDIRECT as u16 != 0 102 } 103 104 /// Check whether the `VIRTQ_DESC_F_NEXT` is set for the descriptor. has_next(&self) -> bool105 pub fn has_next(&self) -> bool { 106 self.flags() & VRING_DESC_F_NEXT as u16 != 0 107 } 108 109 /// Check if the driver designated this as a write only descriptor. 110 /// 111 /// If this is false, this descriptor is read only. 112 /// Write only means the the emulated device can write and the driver can read. is_write_only(&self) -> bool113 pub fn is_write_only(&self) -> bool { 114 self.flags() & VRING_DESC_F_WRITE as u16 != 0 115 } 116 } 117 118 #[cfg(any(test, feature = "test-utils"))] 119 impl Descriptor { 120 /// Create a new descriptor. 121 /// 122 /// # Arguments 123 /// * `addr` - the guest physical address of the descriptor buffer. 124 /// * `len` - the length of the descriptor buffer. 125 /// * `flags` - the `flags` for the descriptor. 126 /// * `next` - the `next` field of the descriptor. new(addr: u64, len: u32, flags: u16, next: u16) -> Self127 pub fn new(addr: u64, len: u32, flags: u16, next: u16) -> Self { 128 Descriptor { 129 addr: addr.into(), 130 len: len.into(), 131 flags: flags.into(), 132 next: next.into(), 133 } 134 } 135 136 /// Set the guest physical address of the descriptor buffer. set_addr(&mut self, addr: u64)137 pub fn set_addr(&mut self, addr: u64) { 138 self.addr = addr.into(); 139 } 140 141 /// Set the length of the descriptor buffer. set_len(&mut self, len: u32)142 pub fn set_len(&mut self, len: u32) { 143 self.len = len.into(); 144 } 145 146 /// Set the flags for this descriptor. set_flags(&mut self, flags: u16)147 pub fn set_flags(&mut self, flags: u16) { 148 self.flags = flags.into(); 149 } 150 151 /// Set the value stored in the `next` field of the descriptor. set_next(&mut self, next: u16)152 pub fn set_next(&mut self, next: u16) { 153 self.next = next.into(); 154 } 155 } 156 157 // SAFETY: This is safe because `Descriptor` contains only wrappers over POD types and 158 // all accesses through safe `vm-memory` API will validate any garbage that could be 159 // included in there. 160 unsafe impl ByteValued for Descriptor {} 161 162 /// Represents the contents of an element from the used virtqueue ring. 163 // Note that the `ByteValued` implementation of this structure expects the `VirtqUsedElem` to store 164 // only plain old data types. 165 #[repr(C)] 166 #[derive(Clone, Copy, Default, Debug)] 167 pub struct VirtqUsedElem { 168 id: Le32, 169 len: Le32, 170 } 171 172 impl VirtqUsedElem { 173 /// Create a new `VirtqUsedElem` instance. 174 /// 175 /// # Arguments 176 /// * `id` - the index of the used descriptor chain. 177 /// * `len` - the total length of the descriptor chain which was used (written to). new(id: u32, len: u32) -> Self178 pub(crate) fn new(id: u32, len: u32) -> Self { 179 VirtqUsedElem { 180 id: id.into(), 181 len: len.into(), 182 } 183 } 184 } 185 186 #[cfg(any(test, feature = "test-utils"))] 187 #[allow(clippy::len_without_is_empty)] 188 impl VirtqUsedElem { 189 /// Get the index of the used descriptor chain. id(&self) -> u32190 pub fn id(&self) -> u32 { 191 self.id.into() 192 } 193 194 /// Get `length` field of the used ring entry. len(&self) -> u32195 pub fn len(&self) -> u32 { 196 self.len.into() 197 } 198 } 199 200 // SAFETY: This is safe because `VirtqUsedElem` contains only wrappers over POD types 201 // and all accesses through safe `vm-memory` API will validate any garbage that could be 202 // included in there. 203 unsafe impl ByteValued for VirtqUsedElem {} 204 205 #[cfg(test)] 206 mod tests { 207 use super::*; 208 use memoffset::offset_of; 209 use std::mem::{align_of, size_of}; 210 211 #[test] test_descriptor_offset()212 fn test_descriptor_offset() { 213 assert_eq!(size_of::<Descriptor>(), 16); 214 assert_eq!(offset_of!(Descriptor, addr), 0); 215 assert_eq!(offset_of!(Descriptor, len), 8); 216 assert_eq!(offset_of!(Descriptor, flags), 12); 217 assert_eq!(offset_of!(Descriptor, next), 14); 218 assert!(align_of::<Descriptor>() <= 16); 219 } 220 221 #[test] test_descriptor_getter_setter()222 fn test_descriptor_getter_setter() { 223 let mut desc = Descriptor::new(0, 0, 0, 0); 224 225 desc.set_addr(0x1000); 226 assert_eq!(desc.addr(), GuestAddress(0x1000)); 227 desc.set_len(0x2000); 228 assert_eq!(desc.len(), 0x2000); 229 desc.set_flags(VRING_DESC_F_NEXT as u16); 230 assert_eq!(desc.flags(), VRING_DESC_F_NEXT as u16); 231 assert!(desc.has_next()); 232 assert!(!desc.is_write_only()); 233 assert!(!desc.refers_to_indirect_table()); 234 desc.set_flags(VRING_DESC_F_WRITE as u16); 235 assert_eq!(desc.flags(), VRING_DESC_F_WRITE as u16); 236 assert!(!desc.has_next()); 237 assert!(desc.is_write_only()); 238 assert!(!desc.refers_to_indirect_table()); 239 desc.set_flags(VRING_DESC_F_INDIRECT as u16); 240 assert_eq!(desc.flags(), VRING_DESC_F_INDIRECT as u16); 241 assert!(!desc.has_next()); 242 assert!(!desc.is_write_only()); 243 assert!(desc.refers_to_indirect_table()); 244 desc.set_next(3); 245 assert_eq!(desc.next(), 3); 246 } 247 248 #[test] test_descriptor_copy()249 fn test_descriptor_copy() { 250 let e1 = Descriptor::new(1, 2, VRING_DESC_F_NEXT as u16, 3); 251 let mut e2 = Descriptor::default(); 252 253 e2.as_mut_slice().copy_from_slice(e1.as_slice()); 254 assert_eq!(e1.addr(), e2.addr()); 255 assert_eq!(e1.len(), e2.len()); 256 assert_eq!(e1.flags(), e2.flags()); 257 assert_eq!(e1.next(), e2.next()); 258 } 259 260 #[test] test_used_elem_offset()261 fn test_used_elem_offset() { 262 assert_eq!(offset_of!(VirtqUsedElem, id), 0); 263 assert_eq!(offset_of!(VirtqUsedElem, len), 4); 264 assert_eq!(size_of::<VirtqUsedElem>(), 8); 265 } 266 267 #[test] test_used_elem_copy()268 fn test_used_elem_copy() { 269 let e1 = VirtqUsedElem::new(3, 15); 270 let mut e2 = VirtqUsedElem::new(0, 0); 271 272 e2.as_mut_slice().copy_from_slice(e1.as_slice()); 273 assert_eq!(e1.id, e2.id); 274 assert_eq!(e1.len, e2.len); 275 } 276 } 277