182464347SSamuel Ortiz // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 282464347SSamuel Ortiz // 382464347SSamuel Ortiz // Portions Copyright 2017 The Chromium OS Authors. All rights reserved. 482464347SSamuel Ortiz // Use of this source code is governed by a BSD-style license that can be 5040ea543SSamuel Ortiz // found in the LICENSE-BSD-3-Clause file. 6040ea543SSamuel Ortiz // 7040ea543SSamuel Ortiz // Copyright © 2019 Intel Corporation 8040ea543SSamuel Ortiz // 9040ea543SSamuel Ortiz // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause 1082464347SSamuel Ortiz 112a6eb31dSRob Bradford pub mod testing { 1282464347SSamuel Ortiz use std::marker::PhantomData; 1382464347SSamuel Ortiz use std::mem; 1488a9f799SRob Bradford 15*190d9019SJinank Jain use virtio_queue::desc::split::VirtqUsedElem; 16*190d9019SJinank Jain use virtio_queue::{Queue, QueueT}; 1761e57e1cSRuoqing He use vm_memory::bitmap::AtomicBitmap; 1861e57e1cSRuoqing He use vm_memory::{Address, Bytes, GuestAddress, GuestUsize}; 19b5bcdbafSBo Chen 20b5bcdbafSBo Chen type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>; 2182464347SSamuel Ortiz 2282464347SSamuel Ortiz // Represents a location in GuestMemoryMmap which holds a given type. 2382464347SSamuel Ortiz pub struct SomeplaceInMemory<'a, T> { 2482464347SSamuel Ortiz pub location: GuestAddress, 2582464347SSamuel Ortiz mem: &'a GuestMemoryMmap, 2682464347SSamuel Ortiz phantom: PhantomData<*const T>, 2782464347SSamuel Ortiz } 2882464347SSamuel Ortiz 2982464347SSamuel Ortiz // The ByteValued trait is required to use mem.read_obj and write_obj. 3082464347SSamuel Ortiz impl<'a, T> SomeplaceInMemory<'a, T> 3182464347SSamuel Ortiz where 3282464347SSamuel Ortiz T: vm_memory::ByteValued, 3382464347SSamuel Ortiz { new(location: GuestAddress, mem: &'a GuestMemoryMmap) -> Self3482464347SSamuel Ortiz fn new(location: GuestAddress, mem: &'a GuestMemoryMmap) -> Self { 3582464347SSamuel Ortiz SomeplaceInMemory { 3682464347SSamuel Ortiz location, 3782464347SSamuel Ortiz mem, 3882464347SSamuel Ortiz phantom: PhantomData, 3982464347SSamuel Ortiz } 4082464347SSamuel Ortiz } 4182464347SSamuel Ortiz 4282464347SSamuel Ortiz // Reads from the actual memory location. get(&self) -> T4382464347SSamuel Ortiz pub fn get(&self) -> T { 4482464347SSamuel Ortiz self.mem.read_obj(self.location).unwrap() 4582464347SSamuel Ortiz } 4682464347SSamuel Ortiz 4782464347SSamuel Ortiz // Writes to the actual memory location. set(&self, val: T)4882464347SSamuel Ortiz pub fn set(&self, val: T) { 4982464347SSamuel Ortiz self.mem.write_obj(val, self.location).unwrap() 5082464347SSamuel Ortiz } 5182464347SSamuel Ortiz 5282464347SSamuel Ortiz // This function returns a place in memory which holds a value of type U, and starts 5382464347SSamuel Ortiz // offset bytes after the current location. map_offset<U>(&self, offset: GuestUsize) -> SomeplaceInMemory<'a, U>5482464347SSamuel Ortiz fn map_offset<U>(&self, offset: GuestUsize) -> SomeplaceInMemory<'a, U> { 5582464347SSamuel Ortiz SomeplaceInMemory { 5682464347SSamuel Ortiz location: self.location.checked_add(offset).unwrap(), 5782464347SSamuel Ortiz mem: self.mem, 5882464347SSamuel Ortiz phantom: PhantomData, 5982464347SSamuel Ortiz } 6082464347SSamuel Ortiz } 6182464347SSamuel Ortiz 6282464347SSamuel Ortiz // This function returns a place in memory which holds a value of type U, and starts 6382464347SSamuel Ortiz // immediately after the end of self (which is location + sizeof(T)). next_place<U>(&self) -> SomeplaceInMemory<'a, U>6482464347SSamuel Ortiz fn next_place<U>(&self) -> SomeplaceInMemory<'a, U> { 6582464347SSamuel Ortiz self.map_offset::<U>(mem::size_of::<T>() as u64) 6682464347SSamuel Ortiz } 6782464347SSamuel Ortiz end(&self) -> GuestAddress6882464347SSamuel Ortiz fn end(&self) -> GuestAddress { 6982464347SSamuel Ortiz self.location 7082464347SSamuel Ortiz .checked_add(mem::size_of::<T>() as u64) 7182464347SSamuel Ortiz .unwrap() 7282464347SSamuel Ortiz } 7382464347SSamuel Ortiz } 7482464347SSamuel Ortiz 7582464347SSamuel Ortiz // Represents a virtio descriptor in guest memory. 7682464347SSamuel Ortiz pub struct VirtqDesc<'a> { 7782464347SSamuel Ortiz pub addr: SomeplaceInMemory<'a, u64>, 7882464347SSamuel Ortiz pub len: SomeplaceInMemory<'a, u32>, 7982464347SSamuel Ortiz pub flags: SomeplaceInMemory<'a, u16>, 8082464347SSamuel Ortiz pub next: SomeplaceInMemory<'a, u16>, 8182464347SSamuel Ortiz } 8282464347SSamuel Ortiz 8382464347SSamuel Ortiz impl<'a> VirtqDesc<'a> { new(start: GuestAddress, mem: &'a GuestMemoryMmap) -> Self842a6eb31dSRob Bradford pub fn new(start: GuestAddress, mem: &'a GuestMemoryMmap) -> Self { 8582464347SSamuel Ortiz assert_eq!(start.0 & 0xf, 0); 8682464347SSamuel Ortiz 8782464347SSamuel Ortiz let addr = SomeplaceInMemory::new(start, mem); 8882464347SSamuel Ortiz let len = addr.next_place(); 8982464347SSamuel Ortiz let flags = len.next_place(); 9082464347SSamuel Ortiz let next = flags.next_place(); 9182464347SSamuel Ortiz 9282464347SSamuel Ortiz VirtqDesc { 9382464347SSamuel Ortiz addr, 9482464347SSamuel Ortiz len, 9582464347SSamuel Ortiz flags, 9682464347SSamuel Ortiz next, 9782464347SSamuel Ortiz } 9882464347SSamuel Ortiz } 9982464347SSamuel Ortiz start(&self) -> GuestAddress10082464347SSamuel Ortiz fn start(&self) -> GuestAddress { 10182464347SSamuel Ortiz self.addr.location 10282464347SSamuel Ortiz } 10382464347SSamuel Ortiz end(&self) -> GuestAddress10482464347SSamuel Ortiz fn end(&self) -> GuestAddress { 10582464347SSamuel Ortiz self.next.end() 10682464347SSamuel Ortiz } 10782464347SSamuel Ortiz set(&self, addr: u64, len: u32, flags: u16, next: u16)10882464347SSamuel Ortiz pub fn set(&self, addr: u64, len: u32, flags: u16, next: u16) { 10982464347SSamuel Ortiz self.addr.set(addr); 11082464347SSamuel Ortiz self.len.set(len); 11182464347SSamuel Ortiz self.flags.set(flags); 11282464347SSamuel Ortiz self.next.set(next); 11382464347SSamuel Ortiz } 11482464347SSamuel Ortiz } 11582464347SSamuel Ortiz 11682464347SSamuel Ortiz // Represents a virtio queue ring. The only difference between the used and available rings, 11782464347SSamuel Ortiz // is the ring element type. 11882464347SSamuel Ortiz pub struct VirtqRing<'a, T> { 11982464347SSamuel Ortiz pub flags: SomeplaceInMemory<'a, u16>, 12082464347SSamuel Ortiz pub idx: SomeplaceInMemory<'a, u16>, 12182464347SSamuel Ortiz pub ring: Vec<SomeplaceInMemory<'a, T>>, 12282464347SSamuel Ortiz pub event: SomeplaceInMemory<'a, u16>, 12382464347SSamuel Ortiz } 12482464347SSamuel Ortiz 12582464347SSamuel Ortiz impl<'a, T> VirtqRing<'a, T> 12682464347SSamuel Ortiz where 12782464347SSamuel Ortiz T: vm_memory::ByteValued, 12882464347SSamuel Ortiz { new( start: GuestAddress, mem: &'a GuestMemoryMmap, qsize: u16, alignment: GuestUsize, ) -> Self12982464347SSamuel Ortiz fn new( 13082464347SSamuel Ortiz start: GuestAddress, 13182464347SSamuel Ortiz mem: &'a GuestMemoryMmap, 13282464347SSamuel Ortiz qsize: u16, 13382464347SSamuel Ortiz alignment: GuestUsize, 13482464347SSamuel Ortiz ) -> Self { 13582464347SSamuel Ortiz assert_eq!(start.0 & (alignment - 1), 0); 13682464347SSamuel Ortiz 13782464347SSamuel Ortiz let flags = SomeplaceInMemory::new(start, mem); 13882464347SSamuel Ortiz let idx = flags.next_place(); 13982464347SSamuel Ortiz 14082464347SSamuel Ortiz let mut ring = Vec::with_capacity(qsize as usize); 14182464347SSamuel Ortiz 14282464347SSamuel Ortiz ring.push(idx.next_place()); 14382464347SSamuel Ortiz 14482464347SSamuel Ortiz for _ in 1..qsize as usize { 14582464347SSamuel Ortiz let x = ring.last().unwrap().next_place(); 14682464347SSamuel Ortiz ring.push(x) 14782464347SSamuel Ortiz } 14882464347SSamuel Ortiz 14982464347SSamuel Ortiz let event = ring.last().unwrap().next_place(); 15082464347SSamuel Ortiz 15182464347SSamuel Ortiz flags.set(0); 15282464347SSamuel Ortiz idx.set(0); 15382464347SSamuel Ortiz event.set(0); 15482464347SSamuel Ortiz 15582464347SSamuel Ortiz VirtqRing { 15682464347SSamuel Ortiz flags, 15782464347SSamuel Ortiz idx, 15882464347SSamuel Ortiz ring, 15982464347SSamuel Ortiz event, 16082464347SSamuel Ortiz } 16182464347SSamuel Ortiz } 16282464347SSamuel Ortiz end(&self) -> GuestAddress16382464347SSamuel Ortiz pub fn end(&self) -> GuestAddress { 16482464347SSamuel Ortiz self.event.end() 16582464347SSamuel Ortiz } 16682464347SSamuel Ortiz } 16782464347SSamuel Ortiz 16882464347SSamuel Ortiz pub type VirtqAvail<'a> = VirtqRing<'a, u16>; 16982464347SSamuel Ortiz pub type VirtqUsed<'a> = VirtqRing<'a, VirtqUsedElem>; 17082464347SSamuel Ortiz 17182464347SSamuel Ortiz pub struct VirtQueue<'a> { 17282464347SSamuel Ortiz pub dtable: Vec<VirtqDesc<'a>>, 17382464347SSamuel Ortiz pub avail: VirtqAvail<'a>, 17482464347SSamuel Ortiz pub used: VirtqUsed<'a>, 1750249e864SSebastien Boeuf pub mem: &'a GuestMemoryMmap, 17682464347SSamuel Ortiz } 17782464347SSamuel Ortiz 17882464347SSamuel Ortiz impl<'a> VirtQueue<'a> { 17982464347SSamuel Ortiz // We try to make sure things are aligned properly :-s new(start: GuestAddress, mem: &'a GuestMemoryMmap, qsize: u16) -> Self18082464347SSamuel Ortiz pub fn new(start: GuestAddress, mem: &'a GuestMemoryMmap, qsize: u16) -> Self { 18182464347SSamuel Ortiz // power of 2? 182b41daddcSRuoqing He assert!(qsize.is_power_of_two()); 18382464347SSamuel Ortiz 18482464347SSamuel Ortiz let mut dtable = Vec::with_capacity(qsize as usize); 18582464347SSamuel Ortiz 18682464347SSamuel Ortiz let mut end = start; 18782464347SSamuel Ortiz 18882464347SSamuel Ortiz for _ in 0..qsize { 18982464347SSamuel Ortiz let d = VirtqDesc::new(end, mem); 19082464347SSamuel Ortiz end = d.end(); 19182464347SSamuel Ortiz dtable.push(d); 19282464347SSamuel Ortiz } 19382464347SSamuel Ortiz 19482464347SSamuel Ortiz const AVAIL_ALIGN: u64 = 2; 19582464347SSamuel Ortiz 19682464347SSamuel Ortiz let avail = VirtqAvail::new(end, mem, qsize, AVAIL_ALIGN); 19782464347SSamuel Ortiz 19882464347SSamuel Ortiz const USED_ALIGN: u64 = 4; 19982464347SSamuel Ortiz 20082464347SSamuel Ortiz let mut x = avail.end().0; 20182464347SSamuel Ortiz x = (x + USED_ALIGN - 1) & !(USED_ALIGN - 1); 20282464347SSamuel Ortiz 20382464347SSamuel Ortiz let used = VirtqUsed::new(GuestAddress(x), mem, qsize, USED_ALIGN); 20482464347SSamuel Ortiz 20582464347SSamuel Ortiz VirtQueue { 20682464347SSamuel Ortiz dtable, 20782464347SSamuel Ortiz avail, 20882464347SSamuel Ortiz used, 2090249e864SSebastien Boeuf mem, 21082464347SSamuel Ortiz } 21182464347SSamuel Ortiz } 21282464347SSamuel Ortiz size(&self) -> u1621382464347SSamuel Ortiz fn size(&self) -> u16 { 21482464347SSamuel Ortiz self.dtable.len() as u16 21582464347SSamuel Ortiz } 21682464347SSamuel Ortiz dtable_start(&self) -> GuestAddress2172a6eb31dSRob Bradford pub fn dtable_start(&self) -> GuestAddress { 21882464347SSamuel Ortiz self.dtable.first().unwrap().start() 21982464347SSamuel Ortiz } 22082464347SSamuel Ortiz avail_start(&self) -> GuestAddress2212a6eb31dSRob Bradford pub fn avail_start(&self) -> GuestAddress { 22282464347SSamuel Ortiz self.avail.flags.location 22382464347SSamuel Ortiz } 22482464347SSamuel Ortiz used_start(&self) -> GuestAddress2252a6eb31dSRob Bradford pub fn used_start(&self) -> GuestAddress { 22682464347SSamuel Ortiz self.used.flags.location 22782464347SSamuel Ortiz } 22882464347SSamuel Ortiz 22982464347SSamuel Ortiz // Creates a new Queue, using the underlying memory regions represented by the VirtQueue. create_queue(&self) -> Queue230a423bf13SSebastien Boeuf pub fn create_queue(&self) -> Queue { 231a423bf13SSebastien Boeuf let mut q = Queue::new(self.size()).unwrap(); 23282464347SSamuel Ortiz 233a423bf13SSebastien Boeuf q.set_size(self.size()); 234a423bf13SSebastien Boeuf q.set_ready(true); 235a423bf13SSebastien Boeuf q.try_set_desc_table_address(self.dtable_start()).unwrap(); 236a423bf13SSebastien Boeuf q.try_set_avail_ring_address(self.avail_start()).unwrap(); 237a423bf13SSebastien Boeuf q.try_set_used_ring_address(self.used_start()).unwrap(); 23882464347SSamuel Ortiz 23982464347SSamuel Ortiz q 24082464347SSamuel Ortiz } 24182464347SSamuel Ortiz start(&self) -> GuestAddress24282464347SSamuel Ortiz pub fn start(&self) -> GuestAddress { 24382464347SSamuel Ortiz self.dtable_start() 24482464347SSamuel Ortiz } 24582464347SSamuel Ortiz end(&self) -> GuestAddress24682464347SSamuel Ortiz pub fn end(&self) -> GuestAddress { 24782464347SSamuel Ortiz self.used.end() 24882464347SSamuel Ortiz } 24982464347SSamuel Ortiz } 2502a6eb31dSRob Bradford } 251