iommu.rs0.00%
1
// Copyright 2024 Google LLC2
//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 at6
//7
// https://www.apache.org/licenses/LICENSE-2.08
//9
// Unless required by applicable law or agreed to in writing, software10
// 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 and13
// limitations under the License.14
15
use std::fs::File;16
use std::mem::size_of;17
use std::os::fd::AsRawFd;18
use std::path::Path;19
use std::sync::Arc;20
21
use snafu::ResultExt;22
23
use crate::errors::BoxTrace;24
use crate::mem::mapped::ArcMemPages;25
use crate::mem::{self, LayoutChanged};26
use crate::sys::vfio::{27
IommuDestroy, IommuIoasAlloc, IommuIoasMap, IommuIoasMapFlag, IommuIoasUnmap, iommu_destroy,28
iommu_ioas_alloc, iommu_ioas_map, iommu_ioas_unmap,29
};30
use crate::vfio::{Result, error};31
32
#[derive(Debug)]33
pub struct Iommu {34
pub(super) fd: File,35
}36
37
impl 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)]47
pub struct Ioas {48
pub(super) iommu: Arc<Iommu>,49
pub(super) id: u32,50
}51
52
impl 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
68
impl 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.id98
);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)]124
pub struct UpdateIommuIoas {125
pub ioas: Arc<Ioas>,126
}127
128
impl 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