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