container.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::os::fd::AsRawFd;17
use std::path::Path;18
use std::sync::Arc;19
20
use parking_lot::Mutex;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
VfioDmaMapFlag, VfioDmaUnmapFlag, VfioIommu, VfioIommuType1DmaMap, VfioIommuType1DmaUnmap,28
vfio_iommu_map_dma, vfio_iommu_unmap_dma, vfio_set_iommu,29
};30
use crate::vfio::{Result, error};31
32
#[derive(Debug)]33
pub struct Container {34
fd: File,35
iommu: Mutex<Option<VfioIommu>>,36
}37
38
impl Container {39
pub fn new(vfio_dev: impl AsRef<Path>) -> Result<Self> {40
let fd = File::open(&vfio_dev).context(error::AccessDevice {41
path: vfio_dev.as_ref(),42
})?;43
Ok(Container {44
fd,45
iommu: Mutex::new(None),46
})47
}48
49
pub fn fd(&self) -> &File {50
&self.fd51
}52
53
pub fn set_iommu(&self, iommu: VfioIommu) -> Result<()> {54
let current = &mut *self.iommu.lock();55
if let Some(current_iommu) = current {56
if *current_iommu == iommu {57
Ok(())58
} else {59
error::SetContainerIommu {60
current: *current_iommu,61
new: iommu,62
}63
.fail()64
}65
} else {66
unsafe { vfio_set_iommu(&self.fd, iommu) }?;67
current.replace(iommu);68
Ok(())69
}70
}71
72
fn map(&self, hva: usize, iova: u64, size: u64) -> Result<()> {73
let flags = VfioDmaMapFlag::READ | VfioDmaMapFlag::WRITE;74
let dma_map = VfioIommuType1DmaMap {75
argsz: size_of::<VfioIommuType1DmaMap>() as u32,76
flags,77
vaddr: hva as u64,78
iova,79
size,80
};81
unsafe { vfio_iommu_map_dma(&self.fd, &dma_map) }?;82
log::debug!(83
"container-{}: mapped: {iova:#018x} -> {hva:#018x}, size = {size:#x}",84
self.fd.as_raw_fd()85
);86
Ok(())87
}88
89
fn unmap(&self, iova: u64, size: u64) -> Result<()> {90
let mut dma_unmap = VfioIommuType1DmaUnmap {91
argsz: size_of::<VfioIommuType1DmaUnmap>() as u32,92
flags: VfioDmaUnmapFlag::empty(),93
iova,94
size,95
};96
unsafe { vfio_iommu_unmap_dma(&self.fd, &mut dma_unmap) }?;97
log::debug!(98
"container-{}: unmapped: {iova:#018x}, size = {size:#x}",99
self.fd.as_raw_fd(),100
);101
Ok(())102
}103
}104
105
#[derive(Debug)]106
pub struct UpdateContainerMapping {107
pub container: Arc<Container>,108
}109
110
impl LayoutChanged for UpdateContainerMapping {111
fn ram_added(&self, gpa: u64, pages: &ArcMemPages) -> mem::Result<()> {112
let ret = self.container.map(pages.addr(), gpa, pages.size());113
ret.box_trace(mem::error::ChangeLayout)?;114
Ok(())115
}116
117
fn ram_removed(&self, gpa: u64, pages: &ArcMemPages) -> mem::Result<()> {118
let ret = self.container.unmap(gpa, pages.size());119
ret.box_trace(mem::error::ChangeLayout)?;120
Ok(())121
}122
}123