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}