vfio_ioctls/lib.rs
1// Copyright © 2019 Intel Corporation
2//
3// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
4
5//! [Virtual Function I/O (VFIO) API](https://www.kernel.org/doc/Documentation/vfio.txt)
6//!
7//! Many modern system now provide DMA and interrupt remapping facilities to help ensure I/O
8//! devices behave within the boundaries they've been allotted. This includes x86 hardware with
9//! AMD-Vi and Intel VT-d, POWER systems with Partitionable Endpoints (PEs) and embedded PowerPC
10//! systems such as Freescale PAMU. The VFIO driver is an IOMMU/device agnostic framework for
11//! exposing direct device access to userspace, in a secure, IOMMU protected environment.
12//! In other words, the VFIO framework allows safe, non-privileged, userspace drivers.
13//!
14//! Why do we want that? Virtual machines often make use of direct device access ("device
15//! assignment") when configured for the highest possible I/O performance. From a device and host
16//! perspective, this simply turns the VM into a userspace driver, with the benefits of
17//! significantly reduced latency, higher bandwidth, and direct use of bare-metal device drivers.
18//!
19//! Devices are the main target of any I/O driver. Devices typically create a programming
20//! interface made up of I/O access, interrupts, and DMA. Without going into the details of each
21//! of these, DMA is by far the most critical aspect for maintaining a secure environment as
22//! allowing a device read-write access to system memory imposes the greatest risk to the overall
23//! system integrity.
24//!
25//! To help mitigate this risk, many modern IOMMUs now incorporate isolation properties into what
26//! was, in many cases, an interface only meant for translation (ie. solving the addressing
27//! problems of devices with limited address spaces). With this, devices can now be isolated
28//! from each other and from arbitrary memory access, thus allowing things like secure direct
29//! assignment of devices into virtual machines.
30//!
31//! While for the most part an IOMMU may have device level granularity, any system is susceptible
32//! to reduced granularity. The IOMMU API therefore supports a notion of IOMMU groups. A group is
33//! a set of devices which is isolatable from all other devices in the system. Groups are therefore
34//! the unit of ownership used by VFIO.
35//!
36//! While the group is the minimum granularity that must be used to ensure secure user access, it's
37//! not necessarily the preferred granularity. In IOMMUs which make use of page tables, it may be
38//! possible to share a set of page tables between different groups, reducing the overhead both to
39//! the platform (reduced TLB thrashing, reduced duplicate page tables), and to the user
40//! (programming only a single set of translations). For this reason, VFIO makes use of a container
41//! class, which may hold one or more groups. A container is created by simply opening the
42//! /dev/vfio/vfio character device.
43//!
44//! This crate is a safe wrapper around the Linux kernel's VFIO interfaces, which offering safe
45//! wrappers for:
46//! - [VFIO Container](struct.VfioContainer.html) using the `VfioContainer` structure
47//! - [VFIO Device](struct.VfioDevice.html) using the `VfioDevice` structure
48//!
49//! # Platform support
50//!
51//! - x86_64
52//!
53//! **NOTE:** The list of available ioctls is not exhaustive.
54
55#![deny(missing_docs)]
56
57#[macro_use]
58extern crate vmm_sys_util;
59
60use std::io;
61use thiserror::Error;
62use vmm_sys_util::errno::Error as SysError;
63
64mod fam;
65mod vfio_device;
66mod vfio_ioctls;
67
68pub use vfio_device::{
69 VfioContainer, VfioDevice, VfioDeviceFd, VfioGroup, VfioIrq, VfioOps, VfioRegion,
70 VfioRegionInfoCap, VfioRegionInfoCapNvlink2Lnkspd, VfioRegionInfoCapNvlink2Ssatgt,
71 VfioRegionInfoCapSparseMmap, VfioRegionInfoCapType, VfioRegionSparseMmapArea,
72};
73
74/// Error codes for VFIO operations.
75#[derive(Debug, Error)]
76#[allow(missing_docs)]
77pub enum VfioError {
78 #[error("failed to open /dev/vfio/vfio container: {0}")]
79 OpenContainer(#[source] io::Error),
80 #[error("failed to open /dev/vfio/{1} group: {0}")]
81 OpenGroup(#[source] io::Error, String),
82 #[error("failed to get Group Status")]
83 GetGroupStatus,
84 #[error("group is not viable")]
85 GroupViable,
86 #[error("vfio API version doesn't match with VFIO_API_VERSION defined in vfio-bindings")]
87 VfioApiVersion,
88 #[error("failed to check VFIO extension")]
89 VfioExtension,
90 #[error("invalid VFIO type")]
91 VfioInvalidType,
92 #[error("container doesn't support VfioType1V2 IOMMU driver type")]
93 VfioType1V2,
94 #[error("failed to add vfio group into vfio container")]
95 GroupSetContainer,
96 #[error("failed to unset vfio container")]
97 UnsetContainer,
98 #[error("failed to set container's IOMMU driver type as VfioType1V2: {0}")]
99 ContainerSetIOMMU(#[source] SysError),
100 #[error("failed to get vfio device fd: {0}")]
101 GroupGetDeviceFD(#[source] SysError),
102 #[error("failed to set vfio device's attribute: {0}")]
103 SetDeviceAttr(#[source] SysError),
104 #[error("failed to get vfio device's info: {0}")]
105 VfioDeviceGetInfo(#[source] SysError),
106 #[error("vfio PCI device info doesn't match")]
107 VfioDeviceGetInfoPCI,
108 #[error("unsupported vfio device type")]
109 VfioDeviceGetInfoOther,
110 #[error("failed to get vfio device's region info: {0}")]
111 VfioDeviceGetRegionInfo(#[source] SysError),
112 #[error("invalid file path")]
113 InvalidPath,
114 #[error("failed to add guest memory map into iommu table: {0}")]
115 IommuDmaMap(#[source] SysError),
116 #[error("failed to remove guest memory map from iommu table: {0}")]
117 IommuDmaUnmap(#[source] SysError),
118 #[error("failed to get vfio device irq info")]
119 VfioDeviceGetIrqInfo,
120 #[error("failed to set vfio device irq")]
121 VfioDeviceSetIrq,
122 #[error("failed to enable vfio device irq")]
123 VfioDeviceEnableIrq,
124 #[error("failed to disable vfio device irq")]
125 VfioDeviceDisableIrq,
126 #[error("failed to unmask vfio device irq")]
127 VfioDeviceUnmaskIrq,
128 #[error("failed to trigger vfio device irq")]
129 VfioDeviceTriggerIrq,
130 #[error("failed to set vfio device irq resample fd")]
131 VfioDeviceSetIrqResampleFd,
132 #[error("failed to duplicate fd")]
133 VfioDeviceDupFd,
134 #[error("wrong device fd type")]
135 VfioDeviceFdWrongType,
136 #[error("failed to get host address")]
137 GetHostAddress,
138 #[error("invalid dma unmap size")]
139 InvalidDmaUnmapSize,
140 #[error("failed to downcast VfioOps")]
141 DowncastVfioOps,
142}
143
144/// Specialized version of `Result` for VFIO subsystem.
145pub type Result<T> = std::result::Result<T, VfioError>;
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150 use std::error::Error;
151
152 #[test]
153 fn test_vfio_error_fmt() {
154 let e = VfioError::GetGroupStatus;
155 let e2 = VfioError::OpenContainer(std::io::Error::from(std::io::ErrorKind::Other));
156 let str = format!("{e}");
157
158 assert_eq!(&str, "failed to get Group Status");
159 assert!(e2.source().is_some());
160 assert!(e.source().is_none());
161 }
162}