1 // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 // 3 // Portions Copyright 2017 The Chromium OS Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE-BSD-3-Clause file. 6 // 7 // Copyright © 2019 Intel Corporation 8 // 9 // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause 10 11 pub mod testing { 12 use std::marker::PhantomData; 13 use std::mem; 14 15 use virtio_queue::desc::split::VirtqUsedElem; 16 use virtio_queue::{Queue, QueueT}; 17 use vm_memory::bitmap::AtomicBitmap; 18 use vm_memory::{Address, Bytes, GuestAddress, GuestUsize}; 19 20 type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>; 21 22 // Represents a location in GuestMemoryMmap which holds a given type. 23 pub struct SomeplaceInMemory<'a, T> { 24 pub location: GuestAddress, 25 mem: &'a GuestMemoryMmap, 26 phantom: PhantomData<*const T>, 27 } 28 29 // The ByteValued trait is required to use mem.read_obj and write_obj. 30 impl<'a, T> SomeplaceInMemory<'a, T> 31 where 32 T: vm_memory::ByteValued, 33 { new(location: GuestAddress, mem: &'a GuestMemoryMmap) -> Self34 fn new(location: GuestAddress, mem: &'a GuestMemoryMmap) -> Self { 35 SomeplaceInMemory { 36 location, 37 mem, 38 phantom: PhantomData, 39 } 40 } 41 42 // Reads from the actual memory location. get(&self) -> T43 pub fn get(&self) -> T { 44 self.mem.read_obj(self.location).unwrap() 45 } 46 47 // Writes to the actual memory location. set(&self, val: T)48 pub fn set(&self, val: T) { 49 self.mem.write_obj(val, self.location).unwrap() 50 } 51 52 // This function returns a place in memory which holds a value of type U, and starts 53 // offset bytes after the current location. map_offset<U>(&self, offset: GuestUsize) -> SomeplaceInMemory<'a, U>54 fn map_offset<U>(&self, offset: GuestUsize) -> SomeplaceInMemory<'a, U> { 55 SomeplaceInMemory { 56 location: self.location.checked_add(offset).unwrap(), 57 mem: self.mem, 58 phantom: PhantomData, 59 } 60 } 61 62 // This function returns a place in memory which holds a value of type U, and starts 63 // immediately after the end of self (which is location + sizeof(T)). next_place<U>(&self) -> SomeplaceInMemory<'a, U>64 fn next_place<U>(&self) -> SomeplaceInMemory<'a, U> { 65 self.map_offset::<U>(mem::size_of::<T>() as u64) 66 } 67 end(&self) -> GuestAddress68 fn end(&self) -> GuestAddress { 69 self.location 70 .checked_add(mem::size_of::<T>() as u64) 71 .unwrap() 72 } 73 } 74 75 // Represents a virtio descriptor in guest memory. 76 pub struct VirtqDesc<'a> { 77 pub addr: SomeplaceInMemory<'a, u64>, 78 pub len: SomeplaceInMemory<'a, u32>, 79 pub flags: SomeplaceInMemory<'a, u16>, 80 pub next: SomeplaceInMemory<'a, u16>, 81 } 82 83 impl<'a> VirtqDesc<'a> { new(start: GuestAddress, mem: &'a GuestMemoryMmap) -> Self84 pub fn new(start: GuestAddress, mem: &'a GuestMemoryMmap) -> Self { 85 assert_eq!(start.0 & 0xf, 0); 86 87 let addr = SomeplaceInMemory::new(start, mem); 88 let len = addr.next_place(); 89 let flags = len.next_place(); 90 let next = flags.next_place(); 91 92 VirtqDesc { 93 addr, 94 len, 95 flags, 96 next, 97 } 98 } 99 start(&self) -> GuestAddress100 fn start(&self) -> GuestAddress { 101 self.addr.location 102 } 103 end(&self) -> GuestAddress104 fn end(&self) -> GuestAddress { 105 self.next.end() 106 } 107 set(&self, addr: u64, len: u32, flags: u16, next: u16)108 pub fn set(&self, addr: u64, len: u32, flags: u16, next: u16) { 109 self.addr.set(addr); 110 self.len.set(len); 111 self.flags.set(flags); 112 self.next.set(next); 113 } 114 } 115 116 // Represents a virtio queue ring. The only difference between the used and available rings, 117 // is the ring element type. 118 pub struct VirtqRing<'a, T> { 119 pub flags: SomeplaceInMemory<'a, u16>, 120 pub idx: SomeplaceInMemory<'a, u16>, 121 pub ring: Vec<SomeplaceInMemory<'a, T>>, 122 pub event: SomeplaceInMemory<'a, u16>, 123 } 124 125 impl<'a, T> VirtqRing<'a, T> 126 where 127 T: vm_memory::ByteValued, 128 { new( start: GuestAddress, mem: &'a GuestMemoryMmap, qsize: u16, alignment: GuestUsize, ) -> Self129 fn new( 130 start: GuestAddress, 131 mem: &'a GuestMemoryMmap, 132 qsize: u16, 133 alignment: GuestUsize, 134 ) -> Self { 135 assert_eq!(start.0 & (alignment - 1), 0); 136 137 let flags = SomeplaceInMemory::new(start, mem); 138 let idx = flags.next_place(); 139 140 let mut ring = Vec::with_capacity(qsize as usize); 141 142 ring.push(idx.next_place()); 143 144 for _ in 1..qsize as usize { 145 let x = ring.last().unwrap().next_place(); 146 ring.push(x) 147 } 148 149 let event = ring.last().unwrap().next_place(); 150 151 flags.set(0); 152 idx.set(0); 153 event.set(0); 154 155 VirtqRing { 156 flags, 157 idx, 158 ring, 159 event, 160 } 161 } 162 end(&self) -> GuestAddress163 pub fn end(&self) -> GuestAddress { 164 self.event.end() 165 } 166 } 167 168 pub type VirtqAvail<'a> = VirtqRing<'a, u16>; 169 pub type VirtqUsed<'a> = VirtqRing<'a, VirtqUsedElem>; 170 171 pub struct VirtQueue<'a> { 172 pub dtable: Vec<VirtqDesc<'a>>, 173 pub avail: VirtqAvail<'a>, 174 pub used: VirtqUsed<'a>, 175 pub mem: &'a GuestMemoryMmap, 176 } 177 178 impl<'a> VirtQueue<'a> { 179 // We try to make sure things are aligned properly :-s new(start: GuestAddress, mem: &'a GuestMemoryMmap, qsize: u16) -> Self180 pub fn new(start: GuestAddress, mem: &'a GuestMemoryMmap, qsize: u16) -> Self { 181 // power of 2? 182 assert!(qsize.is_power_of_two()); 183 184 let mut dtable = Vec::with_capacity(qsize as usize); 185 186 let mut end = start; 187 188 for _ in 0..qsize { 189 let d = VirtqDesc::new(end, mem); 190 end = d.end(); 191 dtable.push(d); 192 } 193 194 const AVAIL_ALIGN: u64 = 2; 195 196 let avail = VirtqAvail::new(end, mem, qsize, AVAIL_ALIGN); 197 198 const USED_ALIGN: u64 = 4; 199 200 let mut x = avail.end().0; 201 x = (x + USED_ALIGN - 1) & !(USED_ALIGN - 1); 202 203 let used = VirtqUsed::new(GuestAddress(x), mem, qsize, USED_ALIGN); 204 205 VirtQueue { 206 dtable, 207 avail, 208 used, 209 mem, 210 } 211 } 212 size(&self) -> u16213 fn size(&self) -> u16 { 214 self.dtable.len() as u16 215 } 216 dtable_start(&self) -> GuestAddress217 pub fn dtable_start(&self) -> GuestAddress { 218 self.dtable.first().unwrap().start() 219 } 220 avail_start(&self) -> GuestAddress221 pub fn avail_start(&self) -> GuestAddress { 222 self.avail.flags.location 223 } 224 used_start(&self) -> GuestAddress225 pub fn used_start(&self) -> GuestAddress { 226 self.used.flags.location 227 } 228 229 // Creates a new Queue, using the underlying memory regions represented by the VirtQueue. create_queue(&self) -> Queue230 pub fn create_queue(&self) -> Queue { 231 let mut q = Queue::new(self.size()).unwrap(); 232 233 q.set_size(self.size()); 234 q.set_ready(true); 235 q.try_set_desc_table_address(self.dtable_start()).unwrap(); 236 q.try_set_avail_ring_address(self.avail_start()).unwrap(); 237 q.try_set_used_ring_address(self.used_start()).unwrap(); 238 239 q 240 } 241 start(&self) -> GuestAddress242 pub fn start(&self) -> GuestAddress { 243 self.dtable_start() 244 } 245 end(&self) -> GuestAddress246 pub fn end(&self) -> GuestAddress { 247 self.used.end() 248 } 249 } 250 } 251