1#![forbid(unsafe_code)]
11
12mod configure;
13
14use crate::RemoteDynamicResolvers;
15use crate::guestmem::GuestMemoryRemoteBuilder;
16use crate::protocol::*;
17use anyhow::Context;
18use chipset_device::ChipsetDevice;
19use chipset_device::io::IoResult;
20use chipset_device::io::deferred::DeferredToken;
21use chipset_device::pci::ByteEnabledDwordRead;
22use chipset_device::pci::ByteEnabledDwordWrite;
23use chipset_device_resources::ErasedChipsetDevice;
24use chipset_device_resources::ResolveChipsetDeviceHandleParams;
25use mesh::MeshPayload;
26use mesh::error::RemoteError;
27use mesh_worker::Worker;
28use mesh_worker::WorkerId;
29use mesh_worker::WorkerRpc;
30use pal_async::DefaultPool;
31use std::task::Poll;
32use vm_resource::Resource;
33use vm_resource::ResourceResolver;
34use vm_resource::kind::ChipsetDeviceHandleKind;
35use vmcore::device_state::ChangeDeviceState;
36use vmcore::save_restore::AsyncProtobufSaveRestore;
37
38pub(crate) const fn remote_chipset_device_worker_id<T: RemoteDynamicResolvers>()
40-> WorkerId<RemoteChipsetDeviceWorkerParameters<T>> {
41 WorkerId::new(T::WORKER_ID_STR)
42}
43
44#[derive(MeshPayload)]
46pub struct RemoteChipsetDeviceWorkerParameters<T> {
47 pub(crate) device: Resource<ChipsetDeviceHandleKind>,
48 pub(crate) dyn_resolvers: T,
49 pub(crate) inputs: RemoteChipsetDeviceHandleParams,
50
51 pub(crate) req_recv: mesh::Receiver<DeviceRequest>,
52 pub(crate) resp_send: mesh::Sender<DeviceResponse>,
53 pub(crate) cap_send: mesh::OneshotSender<DeviceInit>,
54}
55
56#[derive(MeshPayload)]
57pub(crate) struct RemoteChipsetDeviceHandleParams {
58 pub device_name: String,
59 pub is_restoring: bool,
60 pub vmtime: vmcore::vmtime::VmTimeSourceBuilder,
61 pub guest_memory: GuestMemoryRemoteBuilder,
62 pub encrypted_guest_memory: GuestMemoryRemoteBuilder,
63}
64
65pub struct RemoteChipsetDeviceWorker<T> {
70 running: bool,
71 device: ErasedChipsetDevice,
72 pool: Option<DefaultPool>,
73 req_recv: mesh::Receiver<DeviceRequest>,
74 resp_send: mesh::Sender<DeviceResponse>,
75 deferred_reads: Vec<DeferredRead>,
76 deferred_writes: Vec<DeferredWrite>,
77
78 _phantom_resolvers: std::marker::PhantomData<T>,
79}
80
81struct DeferredRead {
82 id: usize,
83 token: DeferredToken,
84 size: usize,
85}
86
87struct DeferredWrite {
88 id: usize,
89 token: DeferredToken,
90}
91
92impl<T: RemoteDynamicResolvers> Worker for RemoteChipsetDeviceWorker<T> {
93 type Parameters = RemoteChipsetDeviceWorkerParameters<T>;
94 type State = ();
95 const ID: WorkerId<Self::Parameters> = remote_chipset_device_worker_id();
96
97 fn new(params: Self::Parameters) -> anyhow::Result<Self> {
98 let mut pool = DefaultPool::new();
99
100 let RemoteChipsetDeviceWorkerParameters {
101 device,
102 dyn_resolvers,
103 inputs,
104
105 req_recv,
106 resp_send,
107 cap_send,
108 } = params;
109
110 let mut resolver = ResourceResolver::new();
111
112 let driver = pool.driver();
113 let mut device = pool
114 .run_until(async move {
115 dyn_resolvers
116 .register_remote_dynamic_resolvers(&mut resolver)
117 .await?;
118 resolver
119 .resolve(
120 device,
121 ResolveChipsetDeviceHandleParams {
122 device_name: &inputs.device_name,
123 guest_memory: &inputs.guest_memory.build("remote_gm"),
124 encrypted_guest_memory: &inputs
125 .encrypted_guest_memory
126 .build("remote_enc_gm"),
127 vmtime: &inputs
128 .vmtime
129 .build(&driver)
130 .await
131 .context("failed to build vmtime source")?,
132 is_restoring: inputs.is_restoring,
133 task_driver_source: &vmcore::vm_task::VmTaskDriverSource::new(
134 vmcore::vm_task::thread::ThreadDriverBackend::new(driver),
135 ),
136 configure: &mut configure::RemoteConfigureChipsetDevice {},
138 register_mmio: &mut configure::RemoteRegisterMmio {},
139 register_pio: &mut configure::RemoteRegisterPio {},
140 },
141 )
142 .await
143 .context("failed to resolve device")
144 })?
145 .0;
146
147 if device.supports_acknowledge_pic_interrupt().is_some()
148 || device.supports_handle_eoi().is_some()
149 || device.supports_line_interrupt_target().is_some()
150 || device.supports_tdisp_host().is_some()
151 {
152 anyhow::bail!("remote device requires unimplemented functionality");
153 }
154
155 cap_send.send(DeviceInit {
156 mmio: device.supports_mmio().map(|m| MmioInit {
157 static_regions: m
158 .get_static_regions()
159 .iter()
160 .map(|(name, range)| ((*name).into(), *range.start(), *range.end()))
161 .collect(),
162 }),
163 pio: device.supports_pio().map(|p| PioInit {
164 static_regions: p
165 .get_static_regions()
166 .iter()
167 .map(|(name, range)| ((*name).into(), *range.start(), *range.end()))
168 .collect(),
169 }),
170 pci: device.supports_pci().map(|pci| PciInit {
171 suggested_bdf: pci.suggested_bdf(),
172 }),
173 });
174
175 Ok(Self {
176 running: false,
177 device,
178 pool: Some(pool),
179 req_recv,
180 resp_send,
181 deferred_reads: Vec::new(),
182 deferred_writes: Vec::new(),
183 _phantom_resolvers: std::marker::PhantomData,
184 })
185 }
186
187 fn restart(_state: Self::State) -> anyhow::Result<Self> {
188 todo!()
189 }
190
191 fn run(mut self, mut rpc_recv: mesh::Receiver<WorkerRpc<Self::State>>) -> anyhow::Result<()> {
192 self.pool.take().unwrap().run_until(async move {
193 loop {
194 enum WorkerEvent {
195 Rpc(WorkerRpc<()>),
196 DeviceRequest(DeviceRequest),
197 }
198
199 let event = std::future::poll_fn(|cx| {
200 if self.running
201 && let Some(poll_device) = self.device.supports_poll_device()
202 {
203 poll_device.poll_device(cx);
204 }
205
206 self.deferred_reads
207 .extract_if(.., |read| {
208 let mut data = vec![0; read.size];
209 match read.token.poll_read(cx, &mut data) {
210 Poll::Ready(r) => {
211 self.resp_send.send(DeviceResponse::Read {
212 id: read.id,
213 result: r.map(|_| data),
214 });
215 true
216 }
217 Poll::Pending => false,
218 }
219 })
220 .for_each(|_| ());
221
222 self.deferred_writes
223 .extract_if(.., |write| match write.token.poll_write(cx) {
224 Poll::Ready(r) => {
225 self.resp_send.send(DeviceResponse::Write {
226 id: write.id,
227 result: r,
228 });
229 true
230 }
231 Poll::Pending => false,
232 })
233 .for_each(|_| ());
234
235 if let Poll::Ready(r) = rpc_recv.poll_recv(cx) {
237 return Poll::Ready(r.map(WorkerEvent::Rpc));
238 }
239 if let Poll::Ready(r) = self.req_recv.poll_recv(cx) {
240 return Poll::Ready(r.map(WorkerEvent::DeviceRequest));
241 }
242 Poll::Pending
243 })
244 .await?;
245
246 match event {
247 WorkerEvent::Rpc(rpc) => match rpc {
248 WorkerRpc::Inspect(deferred) => {
249 deferred.inspect(&mut self.device);
250 }
251 WorkerRpc::Stop => {
252 if self.running {
253 self.device.stop().await;
254 self.running = false;
255 }
256 self.device.teardown().await;
257 return Ok(());
258 }
259 WorkerRpc::Restart(rpc) => {
260 rpc.complete(Err(RemoteError::new(anyhow::anyhow!("not supported"))));
261 }
262 },
263 WorkerEvent::DeviceRequest(req) => match req {
264 DeviceRequest::Start => {
265 self.device.start();
266 self.running = true;
267 }
268 DeviceRequest::Teardown(rpc) => {
269 assert!(
270 !self.running,
271 "remote device must be stopped before teardown"
272 );
273 self.device.teardown().await;
274 drop(self.deferred_reads);
275 drop(self.deferred_writes);
276 rpc.complete(());
277 return Ok(());
278 }
279 DeviceRequest::Stop(rpc) => {
280 self.device.stop().await;
281 self.running = false;
282 rpc.complete(());
283 }
284 DeviceRequest::Reset(rpc) => {
285 self.deferred_reads.clear();
286 self.deferred_writes.clear();
287 rpc.handle(async |()| self.device.reset().await).await
288 }
289 DeviceRequest::MmioRead(ReadRequest { id, address, size }) => {
290 let mut data = vec![0; size];
291 let result = self
292 .device
293 .supports_mmio()
294 .unwrap()
295 .mmio_read(address, &mut data);
296 self.handle_read_result(id, result, data);
297 }
298 DeviceRequest::MmioWrite(WriteRequest { id, address, data }) => {
299 let result = self
300 .device
301 .supports_mmio()
302 .unwrap()
303 .mmio_write(address, &data);
304 self.handle_write_result(id, result);
305 }
306 DeviceRequest::PioRead(ReadRequest { id, address, size }) => {
307 let mut data = vec![0; size];
308 let result = self
309 .device
310 .supports_pio()
311 .unwrap()
312 .io_read(address, &mut data);
313 self.handle_read_result(id, result, data);
314 }
315 DeviceRequest::PioWrite(WriteRequest { id, address, data }) => {
316 let result =
317 self.device.supports_pio().unwrap().io_write(address, &data);
318 self.handle_write_result(id, result);
319 }
320 DeviceRequest::PciConfigRead(
321 ReadRequest { id, address, size },
322 byte_enable,
323 ) => {
324 assert_eq!(size, 4);
325 let mut data_u32 = 0;
326 let mut value = ByteEnabledDwordRead::new(&mut data_u32, byte_enable);
327 let result = self
328 .device
329 .supports_pci()
330 .unwrap()
331 .pci_cfg_read(address, value.reborrow());
332 self.handle_read_result(id, result, data_u32.to_ne_bytes().to_vec());
333 }
334 DeviceRequest::PciConfigWrite(
335 WriteRequest { id, address, data },
336 byte_enable,
337 ) => {
338 let value = ByteEnabledDwordWrite::new(data, byte_enable);
339 let result = self
340 .device
341 .supports_pci()
342 .unwrap()
343 .pci_cfg_write(address, value);
344 self.handle_write_result(id, result);
345 }
346 DeviceRequest::Save(rpc) => {
347 rpc.handle_failable(async |()| self.device.save().await)
348 .await
349 }
350 DeviceRequest::Restore(rpc) => {
351 rpc.handle_failable(async |state| self.device.restore(state).await)
352 .await
353 }
354 },
355 }
356 }
357 })
358 }
359}
360
361impl<T> RemoteChipsetDeviceWorker<T> {
362 fn handle_read_result(&mut self, id: usize, result: IoResult, data: Vec<u8>) {
363 match result {
364 IoResult::Ok => self.resp_send.send(DeviceResponse::Read {
365 id,
366 result: Ok(data),
367 }),
368 IoResult::Err(io_error) => self.resp_send.send(DeviceResponse::Read {
369 id,
370 result: Err(io_error),
371 }),
372 IoResult::Defer(token) => self.deferred_reads.push(DeferredRead {
373 id,
374 token,
375 size: data.len(),
376 }),
377 }
378 }
379
380 fn handle_write_result(&mut self, id: usize, result: IoResult) {
381 match result {
382 IoResult::Ok => self
383 .resp_send
384 .send(DeviceResponse::Write { id, result: Ok(()) }),
385 IoResult::Err(io_error) => self.resp_send.send(DeviceResponse::Write {
386 id,
387 result: Err(io_error),
388 }),
389 IoResult::Defer(token) => self.deferred_writes.push(DeferredWrite { id, token }),
390 }
391 }
392}