Skip to main content

tmk_vmm/
paravisor_vmm.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Support for running as a paravisor VMM.
5
6#![cfg(target_os = "linux")]
7
8use crate::run::RunContext;
9use crate::run::RunnerBuilder;
10use crate::run::TestResult;
11use guestmem::GuestMemory;
12use std::sync::Arc;
13use virt::Partition;
14use virt_mshv_vtl::UhLateParams;
15use virt_mshv_vtl::UhPartitionNewParams;
16use virt_mshv_vtl::UhProcessorBox;
17
18impl RunContext<'_> {
19    pub async fn run_paravisor_vmm(
20        &mut self,
21        isolation: virt::IsolationType,
22        test: &crate::load::TestInfo,
23    ) -> anyhow::Result<TestResult> {
24        let params = UhPartitionNewParams {
25            isolation,
26            hide_isolation: false,
27            lower_vtl_memory_layout: &self.state.memory_layout,
28            topology: &self.state.processor_topology,
29            cvm_cpuid_info: None,
30            snp_secrets: None,
31            vtom: None,
32            handle_synic: true,
33            no_sidecar_hotplug: false,
34            use_mmio_hypercalls: false,
35            intercept_debug_exceptions: false,
36            disable_proxy_redirect: false,
37            // TODO: match openhcl defaults when TDX is supported.
38            disable_lower_vtl_timer_virt: true,
39        };
40        let p = virt_mshv_vtl::UhProtoPartition::new(&params, |_| self.state.driver.clone())?;
41
42        let m = underhill_mem::init(&underhill_mem::Init {
43            processor_topology: &self.state.processor_topology,
44            isolation,
45            vtl0_alias_map_bit: None,
46            vtom: p.get_vtom(),
47            mem_layout: &self.state.memory_layout,
48            complete_memory_layout: &self.state.memory_layout,
49            boot_init: None,
50            shared_pool: &[],
51            maximum_vtl: hvdef::Vtl::Vtl0,
52        })
53        .await?;
54
55        let cvm_params = if isolation == virt::IsolationType::Cca {
56            let cvm_memory = m.cvm_memory().unwrap();
57            Some(virt_mshv_vtl::CvmLateParams {
58                shared_gm: cvm_memory.shared_gm.clone(),
59                isolated_memory_protector: cvm_memory.protector.clone(),
60                shared_dma_client: Arc::new(user_driver::lockmem::LockedMemorySpawner),
61                private_dma_client: self.state.cca_private_dma_client(),
62            })
63        } else {
64            None
65        };
66
67        let (partition, vps) = p
68            .build(UhLateParams {
69                gm: [
70                    m.vtl0().clone(),
71                    m.vtl1().cloned().unwrap_or(GuestMemory::empty()),
72                ]
73                .into(),
74                vtl0_kernel_exec_gm: m.vtl0().clone(),
75                vtl0_user_exec_gm: m.vtl0().clone(),
76                #[cfg(guest_arch = "x86_64")]
77                cpuid: Vec::new(),
78                crash_notification_send: mesh::channel().0,
79                vmtime: self.vmtime_source,
80                cvm_params,
81                vmbus_relay: false,
82            })
83            .await?;
84
85        let partition = Arc::new(partition);
86
87        let mut threads = Vec::new();
88        let r = self
89            .run(m.vtl0(), partition.caps(), test, async |_this, runner| {
90                let [vp] = vps.try_into().ok().unwrap();
91                threads.push(start_vp(vp, runner, isolation).await?);
92                Ok(())
93            })
94            .await?;
95
96        for thread in threads {
97            thread.join().unwrap();
98        }
99
100        // Ensure the partition has not leaked.
101        Arc::into_inner(partition).expect("partition is no longer referenced");
102
103        Ok(r)
104    }
105}
106
107async fn start_vp(
108    mut vp: UhProcessorBox,
109    mut runner: RunnerBuilder,
110    isolation: virt::IsolationType,
111) -> anyhow::Result<std::thread::JoinHandle<()>> {
112    let vp_thread = std::thread::spawn(move || {
113        let pool = pal_uring::IoUringPool::new("vp", 256).unwrap();
114        let driver = pool.client().initiator().clone();
115        match isolation {
116            #[cfg(guest_arch = "aarch64")]
117            virt::IsolationType::Cca => pool.client().set_idle_task(async move |mut control| {
118                let vp = vp
119                    .bind_processor::<virt_mshv_vtl::CcaBacked>(&driver, Some(&mut control))
120                    .unwrap();
121                runner.build(vp).unwrap().run_vp().await;
122            }),
123            _ => pool.client().set_idle_task(async move |mut control| {
124                let vp = vp
125                    .bind_processor::<virt_mshv_vtl::HypervisorBacked>(&driver, Some(&mut control))
126                    .unwrap();
127                runner.build(vp).unwrap().run_vp().await;
128            }),
129        }
130        pool.run()
131    });
132    Ok(vp_thread)
133}