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 user_mode_apic: self.state.opts.disable_offloads,
47 isolation: virt::IsolationType::None,
48 })
49 .context("failed to create proto partition")?;
50
51 let guest_memory = GuestMemory::allocate(self.state.memory_layout.end_of_ram() as usize);
52
53 let (partition, vps) = proto
54 .build(PartitionConfig {
55 mem_layout: &self.state.memory_layout,
56 guest_memory: &guest_memory,
57 cpuid: &[],
58 vtl0_alias_map: None,
59 })
60 .context("failed to build partition")?;
61
62 let partition = Arc::new(partition);
63
64 for r in self.state.memory_layout.ram() {
66 let range = r.range;
67 unsafe {
70 partition
71 .memory_mapper(Vtl::Vtl0)
72 .map_range(
73 guest_memory.inner_buf().unwrap()
74 [range.start() as usize..range.end() as usize]
75 .as_ptr()
76 .cast_mut()
77 .cast(),
78 range.len() as usize,
79 range.start(),
80 true,
81 true,
82 )
83 .context("failed to map memory")
84 }?;
85 }
86
87 let mut threads = Vec::new();
88 let r = self
89 .run(
90 &guest_memory,
91 partition.caps(),
92 test,
93 async |_this, runner| {
94 let [vp] = vps.try_into().ok().unwrap();
95 threads.push(start_vp(partition.clone(), vp, runner).await?);
96 Ok(())
97 },
98 )
99 .await?;
100 for thread in threads {
101 thread.join().unwrap();
102 }
103
104 Arc::into_inner(partition).expect("partition is no longer referenced");
106
107 Ok(r)
108 }
109}
110
111trait RequestYield: Send + Sync {
112 fn request_yield(&self, vp_index: VpIndex);
115}
116
117impl<T: Partition> RequestYield for T {
118 fn request_yield(&self, vp_index: VpIndex) {
119 self.request_yield(vp_index)
120 }
121}
122
123struct VpWaker {
124 partition: Weak<dyn RequestYield>,
125 vp: VpIndex,
126 inner: Waker,
127}
128
129impl VpWaker {
130 fn new(partition: Weak<dyn RequestYield>, vp: VpIndex, waker: Waker) -> Self {
131 Self {
132 partition,
133 vp,
134 inner: waker,
135 }
136 }
137}
138
139impl std::task::Wake for VpWaker {
140 fn wake_by_ref(self: &Arc<Self>) {
141 if let Some(partition) = self.partition.upgrade() {
142 partition.request_yield(self.vp);
143 }
144 self.inner.wake_by_ref();
145 }
146
147 fn wake(self: Arc<Self>) {
148 self.wake_by_ref()
149 }
150}
151
152async fn start_vp(
153 partition: Arc<dyn RequestYield>,
154 mut vp: impl 'static + BindProcessor + Send,
155 mut runner: RunnerBuilder,
156) -> anyhow::Result<std::thread::JoinHandle<()>> {
157 let (bind_result_send, bind_result_recv) = mesh::oneshot();
158 let vp_thread = std::thread::spawn(move || {
159 let vp_index = VpIndex::BSP;
160 let r = vp
161 .bind()
162 .context("failed to bind vp")
163 .and_then(|vp| runner.build(vp));
164 let (vp, r) = match r {
165 Ok(vp) => (Some(vp), Ok(())),
166 Err(err) => (None, Err(err)),
167 };
168
169 bind_result_send.send(r);
170 let Some(mut vp) = vp else { return };
171 block_on(async {
172 let mut run = pin!(vp.run_vp());
173 poll_fn(|cx| {
174 let waker = Waker::from(Arc::new(VpWaker::new(
175 Arc::downgrade(&partition),
176 vp_index,
177 cx.waker().clone(),
178 )));
179 run.as_mut().poll(&mut Context::from_waker(&waker))
180 })
181 .await
182 })
183 });
184
185 bind_result_recv.await.unwrap()?;
186 Ok(vp_thread)
187}