Alioth Code Coverage

iommu.rs0.00%

1// Copyright 2024 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fs::File;
16use std::mem::size_of;
17use std::os::fd::AsRawFd;
18use std::path::Path;
19use std::sync::Arc;
20
21use snafu::ResultExt;
22
23use crate::errors::BoxTrace;
24use crate::mem::mapped::ArcMemPages;
25use crate::mem::{self, LayoutChanged};
26use crate::sys::vfio::{
27 IommuDestroy, IommuIoasAlloc, IommuIoasMap, IommuIoasMapFlag, IommuIoasUnmap, iommu_destroy,
28 iommu_ioas_alloc, iommu_ioas_map, iommu_ioas_unmap,
29};
30use crate::vfio::{Result, error};
31
32#[derive(Debug)]
33pub struct Iommu {
34 pub(super) fd: File,
35}
36
37impl Iommu {
38 pub fn new(path: impl AsRef<Path>) -> Result<Self> {
39 let fd = File::open(&path).context(error::AccessDevice {
40 path: path.as_ref(),
41 })?;
42 Ok(Iommu { fd })
43 }
44}
45
46#[derive(Debug)]
47pub struct Ioas {
48 pub(super) iommu: Arc<Iommu>,
49 pub(super) id: u32,
50}
51
52impl Drop for Ioas {
53 fn drop(&mut self) {
54 if let Err(e) = self.reset() {
55 log::error!("Removing mappings from ioas id {:#x}: {e}", self.id)
56 }
57 let destroy = IommuDestroy {
58 size: size_of::<IommuDestroy>() as u32,
59 id: self.id,
60 };
61 let ret = unsafe { iommu_destroy(&self.iommu.fd, &destroy) };
62 if let Err(e) = ret {
63 log::error!("Destroying ioas id {:#x}: {e}", self.id)
64 }
65 }
66}
67
68impl Ioas {
69 pub fn alloc_on(iommu: Arc<Iommu>) -> Result<Self> {
70 let mut alloc: IommuIoasAlloc = IommuIoasAlloc {
71 size: size_of::<IommuIoasAlloc>() as u32,
72 ..Default::default()
73 };
74 unsafe { iommu_ioas_alloc(&iommu.fd, &mut alloc) }?;
75 Ok(Ioas {
76 iommu,
77 id: alloc.out_ioas_id,
78 })
79 }
80
81 pub fn map(&self, user_va: usize, iova: u64, len: u64) -> Result<()> {
82 let flags =
83 IommuIoasMapFlag::READABLE | IommuIoasMapFlag::WRITEABLE | IommuIoasMapFlag::FIXED_IOVA;
84 let ioas_map = IommuIoasMap {
85 size: size_of::<IommuIoasMap>() as u32,
86 flags,
87 ioas_id: self.id,
88 user_va: user_va as u64,
89 length: len,
90 iova,
91 ..Default::default()
92 };
93 unsafe { iommu_ioas_map(&self.iommu.fd, &ioas_map) }?;
94 log::debug!(
95 "ioas-{}-{}: mapped: {iova:#018x} -> {user_va:#018x}, size = {len:#x}",
96 self.iommu.fd.as_raw_fd(),
97 self.id
98 );
99 Ok(())
100 }
101
102 pub fn unmap(&self, iova: u64, len: u64) -> Result<()> {
103 let ioas_unmap = IommuIoasUnmap {
104 size: size_of::<IommuIoasUnmap>() as u32,
105 ioas_id: self.id,
106 iova,
107 length: len,
108 };
109 unsafe { iommu_ioas_unmap(&self.iommu.fd, &ioas_unmap) }?;
110 log::debug!(
111 "ioas-{}-{}: unmapped: {iova:#018x}, size = {len:#x}",
112 self.iommu.fd.as_raw_fd(),
113 self.id,
114 );
115 Ok(())
116 }
117
118 pub fn reset(&self) -> Result<()> {
119 self.unmap(0, u64::MAX)
120 }
121}
122
123#[derive(Debug)]
124pub struct UpdateIommuIoas {
125 pub ioas: Arc<Ioas>,
126}
127
128impl LayoutChanged for UpdateIommuIoas {
129 fn ram_added(&self, gpa: u64, pages: &ArcMemPages) -> mem::Result<()> {
130 let ret = self.ioas.map(pages.addr(), gpa, pages.size());
131 ret.box_trace(mem::error::ChangeLayout)?;
132 Ok(())
133 }
134
135 fn ram_removed(&self, gpa: u64, pages: &ArcMemPages) -> mem::Result<()> {
136 let ret = self.ioas.unmap(gpa, pages.size());
137 ret.box_trace(mem::error::ChangeLayout)?;
138 Ok(())
139 }
140}
141