1#![expect(unsafe_code)]
8
9use crate::run::RunContext;
10use crate::run::RunnerBuilder;
11use crate::run::TestResult;
12use anyhow::Context as _;
13use futures::executor::block_on;
14use guestmem::GuestMemory;
15use hvdef::Vtl;
16use std::future::Future;
17use std::future::poll_fn;
18use std::pin::pin;
19use std::sync::Arc;
20use std::sync::Weak;
21use std::task::Context;
22use std::task::Waker;
23use virt::BindProcessor;
24use virt::Hypervisor;
25use virt::Partition;
26use virt::PartitionConfig;
27use virt::PartitionMemoryMapper;
28use virt::ProtoPartition;
29use virt::ProtoPartitionConfig;
30use virt::VpIndex;
31
32impl RunContext<'_> {
33 pub async fn run_host_vmm<H: Hypervisor>(
34 &mut self,
35 mut hv: H,
36 test: &crate::load::TestInfo,
37 ) -> anyhow::Result<TestResult>
38 where
39 H::Partition: Partition + PartitionMemoryMapper,
40 {
41 let proto = hv
42 .new_partition(ProtoPartitionConfig {
43 processor_topology: &self.state.processor_topology,
44 hv_config: None,
45 vmtime: self.vmtime_source,
46 isolation: virt::ProtoPartitionIsolation::None,
47 nested_virt: false,
48 #[cfg(guest_arch = "aarch64")]
49 device_assignment_msi_iova_range: None,
50 })
51 .context("failed to create proto partition")?;
52
53 let guest_memory = GuestMemory::allocate(self.state.memory_layout.end_of_ram() as usize);
54
55 let (partition, vps) = proto
56 .build(PartitionConfig {
57 mem_layout: &self.state.memory_layout,
58 guest_memory: &guest_memory,
59 cpuid: &[],
60 vtl0_alias_map: None,
61 fault_resolver: None,
62 })
63 .context("failed to build partition")?;
64
65 let partition = Arc::new(partition);
66
67 for r in self.state.memory_layout.ram() {
69 let range = r.range;
70 unsafe {
73 partition
74 .memory_mapper(Vtl::Vtl0)
75 .map_range(
76 guest_memory.inner_buf().unwrap()
77 [range.start() as usize..range.end() as usize]
78 .as_ptr()
79 .cast_mut()
80 .cast(),
81 range.len() as usize,
82 range.start(),
83 true,
84 true,
85 )
86 .context("failed to map memory")
87 }?;
88 }
89
90 let mut threads = Vec::new();
91 let r = self
92 .run(
93 &guest_memory,
94 partition.caps(),
95 test,
96 async |_this, runner| {
97 let [vp] = vps.try_into().ok().unwrap();
98 threads.push(start_vp(partition.clone(), vp, runner).await?);
99 Ok(())
100 },
101 )
102 .await?;
103 for thread in threads {
104 thread.join().unwrap();
105 }
106
107 Arc::into_inner(partition).expect("partition is no longer referenced");
109
110 Ok(r)
111 }
112}
113
114trait RequestYield: Send + Sync {
115 fn request_yield(&self, vp_index: VpIndex);
118}
119
120impl<T: Partition> RequestYield for T {
121 fn request_yield(&self, vp_index: VpIndex) {
122 self.request_yield(vp_index)
123 }
124}
125
126struct VpWaker {
127 partition: Weak<dyn RequestYield>,
128 vp: VpIndex,
129 inner: Waker,
130}
131
132impl VpWaker {
133 fn new(partition: Weak<dyn RequestYield>, vp: VpIndex, waker: Waker) -> Self {
134 Self {
135 partition,
136 vp,
137 inner: waker,
138 }
139 }
140}
141
142impl std::task::Wake for VpWaker {
143 fn wake_by_ref(self: &Arc<Self>) {
144 if let Some(partition) = self.partition.upgrade() {
145 partition.request_yield(self.vp);
146 }
147 self.inner.wake_by_ref();
148 }
149
150 fn wake(self: Arc<Self>) {
151 self.wake_by_ref()
152 }
153}
154
155async fn start_vp(
156 partition: Arc<dyn RequestYield>,
157 mut vp: impl 'static + BindProcessor + Send,
158 mut runner: RunnerBuilder,
159) -> anyhow::Result<std::thread::JoinHandle<()>> {
160 let (bind_result_send, bind_result_recv) = mesh::oneshot();
161 let vp_thread = std::thread::spawn(move || {
162 let vp_index = VpIndex::BSP;
163 let r = vp
164 .bind()
165 .context("failed to bind vp")
166 .and_then(|vp| runner.build(vp));
167 let (vp, r) = match r {
168 Ok(vp) => (Some(vp), Ok(())),
169 Err(err) => (None, Err(err)),
170 };
171
172 bind_result_send.send(r);
173 let Some(mut vp) = vp else { return };
174 block_on(async {
175 let mut run = pin!(vp.run_vp());
176 poll_fn(|cx| {
177 let waker = Waker::from(Arc::new(VpWaker::new(
178 Arc::downgrade(&partition),
179 vp_index,
180 cx.waker().clone(),
181 )));
182 run.as_mut().poll(&mut Context::from_waker(&waker))
183 })
184 .await
185 })
186 });
187
188 bind_result_recv.await.unwrap()?;
189 Ok(vp_thread)
190}