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 //! Implements virtio queues 12 13 use std::fmt::{self, Debug}; 14 use std::sync::Arc; 15 16 use virtio_queue::{Queue, QueueT}; 17 use vm_memory::GuestAddress; 18 19 pub mod queue; 20 pub use queue::*; 21 22 pub const VIRTIO_MSI_NO_VECTOR: u16 = 0xffff; 23 24 // Types taken from linux/virtio_ids.h 25 #[derive(Copy, Clone, Debug)] 26 #[allow(dead_code)] 27 #[allow(non_camel_case_types)] 28 #[repr(C)] 29 pub enum VirtioDeviceType { 30 Net = 1, 31 Block = 2, 32 Console = 3, 33 Rng = 4, 34 Balloon = 5, 35 Fs9P = 9, 36 Gpu = 16, 37 Input = 18, 38 Vsock = 19, 39 Iommu = 23, 40 Mem = 24, 41 Fs = 26, 42 Pmem = 27, 43 Watchdog = 35, // Temporary until official number allocated 44 Unknown = 0xFF, 45 } 46 47 impl From<u32> for VirtioDeviceType { 48 fn from(t: u32) -> Self { 49 match t { 50 1 => VirtioDeviceType::Net, 51 2 => VirtioDeviceType::Block, 52 3 => VirtioDeviceType::Console, 53 4 => VirtioDeviceType::Rng, 54 5 => VirtioDeviceType::Balloon, 55 9 => VirtioDeviceType::Fs9P, 56 16 => VirtioDeviceType::Gpu, 57 18 => VirtioDeviceType::Input, 58 19 => VirtioDeviceType::Vsock, 59 23 => VirtioDeviceType::Iommu, 60 24 => VirtioDeviceType::Mem, 61 26 => VirtioDeviceType::Fs, 62 27 => VirtioDeviceType::Pmem, 63 35 => VirtioDeviceType::Watchdog, 64 _ => VirtioDeviceType::Unknown, 65 } 66 } 67 } 68 69 // In order to use the `{}` marker, the trait `fmt::Display` must be implemented 70 // manually for the type VirtioDeviceType. 71 impl fmt::Display for VirtioDeviceType { 72 // This trait requires `fmt` with this exact signature. 73 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 74 let output = match *self { 75 VirtioDeviceType::Net => "net", 76 VirtioDeviceType::Block => "block", 77 VirtioDeviceType::Console => "console", 78 VirtioDeviceType::Rng => "rng", 79 VirtioDeviceType::Balloon => "balloon", 80 VirtioDeviceType::Gpu => "gpu", 81 VirtioDeviceType::Fs9P => "9p", 82 VirtioDeviceType::Input => "input", 83 VirtioDeviceType::Vsock => "vsock", 84 VirtioDeviceType::Iommu => "iommu", 85 VirtioDeviceType::Mem => "mem", 86 VirtioDeviceType::Fs => "fs", 87 VirtioDeviceType::Pmem => "pmem", 88 VirtioDeviceType::Watchdog => "watchdog", 89 VirtioDeviceType::Unknown => "UNKNOWN", 90 }; 91 write!(f, "{output}") 92 } 93 } 94 95 /// Trait for devices with access to data in memory being limited and/or 96 /// translated. 97 pub trait AccessPlatform: Send + Sync + Debug { 98 /// Provide a way to translate GVA address ranges into GPAs. 99 fn translate_gva(&self, base: u64, size: u64) -> std::result::Result<u64, std::io::Error>; 100 /// Provide a way to translate GPA address ranges into GVAs. 101 fn translate_gpa(&self, base: u64, size: u64) -> std::result::Result<u64, std::io::Error>; 102 } 103 104 pub trait Translatable { 105 fn translate_gva(&self, access_platform: Option<&Arc<dyn AccessPlatform>>, len: usize) -> Self; 106 fn translate_gpa(&self, access_platform: Option<&Arc<dyn AccessPlatform>>, len: usize) -> Self; 107 } 108 109 impl Translatable for GuestAddress { 110 fn translate_gva(&self, access_platform: Option<&Arc<dyn AccessPlatform>>, len: usize) -> Self { 111 GuestAddress(self.0.translate_gva(access_platform, len)) 112 } 113 fn translate_gpa(&self, access_platform: Option<&Arc<dyn AccessPlatform>>, len: usize) -> Self { 114 GuestAddress(self.0.translate_gpa(access_platform, len)) 115 } 116 } 117 118 impl Translatable for u64 { 119 fn translate_gva(&self, access_platform: Option<&Arc<dyn AccessPlatform>>, len: usize) -> Self { 120 if let Some(access_platform) = access_platform { 121 access_platform.translate_gva(*self, len as u64).unwrap() 122 } else { 123 *self 124 } 125 } 126 fn translate_gpa(&self, access_platform: Option<&Arc<dyn AccessPlatform>>, len: usize) -> Self { 127 if let Some(access_platform) = access_platform { 128 access_platform.translate_gpa(*self, len as u64).unwrap() 129 } else { 130 *self 131 } 132 } 133 } 134 135 /// Helper for cloning a Queue since QueueState doesn't derive Clone 136 pub fn clone_queue(queue: &Queue) -> Queue { 137 let mut q = Queue::new(queue.max_size()).unwrap(); 138 139 q.set_next_avail(queue.next_avail()); 140 q.set_next_used(queue.next_used()); 141 q.set_event_idx(queue.event_idx_enabled()); 142 q.set_size(queue.size()); 143 q.set_ready(queue.ready()); 144 q.try_set_desc_table_address(GuestAddress(queue.desc_table())) 145 .unwrap(); 146 q.try_set_avail_ring_address(GuestAddress(queue.avail_ring())) 147 .unwrap(); 148 q.try_set_used_ring_address(GuestAddress(queue.used_ring())) 149 .unwrap(); 150 151 q 152 } 153