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