Alioth Code Coverage

container.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::os::fd::AsRawFd;
17use std::path::Path;
18use std::sync::Arc;
19
20use parking_lot::Mutex;
21use snafu::ResultExt;
22
23use crate::errors::BoxTrace;
24use crate::mem::mapped::ArcMemPages;
25use crate::mem::{self, LayoutChanged};
26use crate::sys::vfio::{
27 VfioDmaMapFlag, VfioDmaUnmapFlag, VfioIommu, VfioIommuType1DmaMap, VfioIommuType1DmaUnmap,
28 vfio_iommu_map_dma, vfio_iommu_unmap_dma, vfio_set_iommu,
29};
30use crate::vfio::{Result, error};
31
32#[derive(Debug)]
33pub struct Container {
34 fd: File,
35 iommu: Mutex<Option<VfioIommu>>,
36}
37
38impl 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.fd
51 }
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)]
106pub struct UpdateContainerMapping {
107 pub container: Arc<Container>,
108}
109
110impl 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