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