lower_vtl_permissions_guard/
lib.rs1#![cfg(target_os = "linux")]
8
9mod device_dma;
10
11pub use device_dma::LowerVtlDmaBuffer;
12
13use anyhow::Context;
14use anyhow::Result;
15use inspect::Inspect;
16use std::sync::Arc;
17use user_driver::DmaClient;
18use user_driver::memory::MemoryBlock;
19use virt::VtlMemoryProtection;
20
21#[derive(Inspect)]
24struct PagesAccessibleToLowerVtl {
25 #[inspect(skip)]
26 vtl_protect: Arc<dyn VtlMemoryProtection + Send + Sync>,
27 #[inspect(hex, iter_by_index)]
28 pages: Vec<u64>,
29}
30
31impl PagesAccessibleToLowerVtl {
32 fn new_from_pages(
35 vtl_protect: Arc<dyn VtlMemoryProtection + Send + Sync>,
36 pages: &[u64],
37 ) -> Result<Self> {
38 for pfn in pages {
39 vtl_protect
40 .modify_vtl_page_setting(*pfn, hvdef::HV_MAP_GPA_PERMISSIONS_ALL)
41 .context("failed to update VTL protections on page")?;
42 }
43 Ok(Self {
44 vtl_protect,
45 pages: pages.to_vec(),
46 })
47 }
48}
49
50impl Drop for PagesAccessibleToLowerVtl {
51 fn drop(&mut self) {
52 if let Err(err) = self
53 .pages
54 .iter()
55 .map(|pfn| {
56 self.vtl_protect
57 .modify_vtl_page_setting(*pfn, hvdef::HV_MAP_GPA_PERMISSIONS_NONE)
58 .context("failed to update VTL protections on page")
59 })
60 .collect::<Result<Vec<_>>>()
61 {
62 panic!(
67 "failed to reset page protections {}",
68 err.as_ref() as &dyn std::error::Error
69 );
70 }
71 }
72}
73
74#[derive(Inspect)]
77pub struct LowerVtlMemorySpawner<T: DmaClient> {
78 #[inspect(skip)]
79 spawner: T,
80 #[inspect(skip)]
81 vtl_protect: Arc<dyn VtlMemoryProtection + Send + Sync>,
82}
83
84impl<T: DmaClient> LowerVtlMemorySpawner<T> {
85 pub fn new(spawner: T, vtl_protect: Arc<dyn VtlMemoryProtection + Send + Sync>) -> Self {
88 Self {
89 spawner,
90 vtl_protect,
91 }
92 }
93}
94
95impl<T: DmaClient> DmaClient for LowerVtlMemorySpawner<T> {
96 fn allocate_dma_buffer(&self, len: usize) -> Result<MemoryBlock> {
97 let mem = self.spawner.allocate_dma_buffer(len)?;
98 let vtl_guard =
99 PagesAccessibleToLowerVtl::new_from_pages(self.vtl_protect.clone(), mem.pfns())
100 .context("failed to lower VTL permissions on memory block")?;
101
102 Ok(MemoryBlock::new(LowerVtlDmaBuffer {
103 block: mem,
104 _vtl_guard: vtl_guard,
105 }))
106 }
107
108 fn attach_pending_buffers(&self) -> Result<Vec<MemoryBlock>> {
109 anyhow::bail!("restore is not supported for LowerVtlMemorySpawner")
110 }
111}