1use hvdef::HvError;
11use hvdef::HvResult;
12use hvdef::Vtl;
13use inspect::Inspect;
14use parking_lot::Mutex;
15use std::collections::HashMap;
16use std::collections::hash_map;
17use std::fmt::Debug;
18use std::sync::Arc;
19use std::sync::Weak;
20use std::task::Context;
21use std::task::Poll;
22use vm_topology::processor::VpIndex;
23use vmcore::monitor::MonitorId;
24use vmcore::synic::EventPort;
25use vmcore::synic::GuestEventPort;
26use vmcore::synic::GuestMessagePort;
27use vmcore::synic::MessagePort;
28use vmcore::synic::MonitorInfo;
29use vmcore::synic::MonitorPageGpas;
30use vmcore::synic::SynicMonitorAccess;
31use vmcore::synic::SynicPortAccess;
32
33#[derive(Inspect, Debug, Default)]
42pub struct SynicPortMap {
43 #[inspect(with = "|x| inspect::adhoc(|req| inspect::iter_by_key(&*x.lock()).inspect(req))")]
44 ports: Mutex<HashMap<u32, Port>>,
45}
46
47impl SynicPortMap {
48 pub fn handle_post_message(
50 &self,
51 vtl: Vtl,
52 connection_id: u32,
53 secure: bool,
54 message: &[u8],
55 ) -> HvResult<()> {
56 let port = self.ports.lock().get(&connection_id).cloned();
57 if let Some(Port {
58 port_type: PortType::Message(port),
59 minimum_vtl,
60 }) = port
61 {
62 if vtl < minimum_vtl {
63 Err(HvError::OperationDenied)
64 } else if port.poll_handle_message(
65 &mut Context::from_waker(std::task::Waker::noop()),
66 message,
67 secure,
68 ) == Poll::Ready(())
69 {
70 Ok(())
71 } else {
72 Err(HvError::InsufficientBuffers)
76 }
77 } else {
78 Err(HvError::InvalidConnectionId)
79 }
80 }
81
82 pub fn handle_signal_event(
84 &self,
85 vtl: Vtl,
86 connection_id: u32,
87 flag_number: u16,
88 ) -> HvResult<()> {
89 let port = self.ports.lock().get(&connection_id).cloned();
90 if let Some(Port {
91 port_type: PortType::Event(port),
92 minimum_vtl,
93 }) = port
94 {
95 if vtl < minimum_vtl {
96 Err(HvError::OperationDenied)
97 } else {
98 port.handle_event(flag_number);
99 Ok(())
100 }
101 } else {
102 Err(HvError::InvalidConnectionId)
103 }
104 }
105
106 fn add_message_port(
107 &self,
108 connection_id: u32,
109 minimum_vtl: Vtl,
110 port: Arc<dyn MessagePort>,
111 ) -> Result<(), vmcore::synic::Error> {
112 match self.ports.lock().entry(connection_id) {
113 hash_map::Entry::Occupied(_) => {
114 Err(vmcore::synic::Error::ConnectionIdInUse(connection_id))
115 }
116 hash_map::Entry::Vacant(e) => {
117 e.insert(Port {
118 port_type: PortType::Message(port),
119 minimum_vtl,
120 });
121 Ok(())
122 }
123 }
124 }
125
126 fn add_event_port(
127 &self,
128 connection_id: u32,
129 minimum_vtl: Vtl,
130 port: Arc<dyn EventPort>,
131 ) -> Result<(), vmcore::synic::Error> {
132 match self.ports.lock().entry(connection_id) {
133 hash_map::Entry::Occupied(_) => {
134 Err(vmcore::synic::Error::ConnectionIdInUse(connection_id))
135 }
136 hash_map::Entry::Vacant(e) => {
137 e.insert(Port {
138 port_type: PortType::Event(port),
139 minimum_vtl,
140 });
141 Ok(())
142 }
143 }
144 }
145}
146
147pub trait Synic: 'static + Send + Sync {
148 fn port_map(&self) -> &SynicPortMap;
151
152 fn new_host_event_port(
157 self: Arc<Self>,
158 connection_id: u32,
159 minimum_vtl: Vtl,
160 event: &pal_event::Event,
161 ) -> Result<Option<Box<dyn Sync + Send>>, vmcore::synic::Error> {
162 let _ = (connection_id, minimum_vtl, event);
163 Ok(None)
164 }
165
166 fn post_message(&self, vtl: Vtl, vp: VpIndex, sint: u8, typ: u32, payload: &[u8]);
168
169 fn new_guest_event_port(
171 self: Arc<Self>,
172 vtl: Vtl,
173 vp: u32,
174 sint: u8,
175 flag: u16,
176 ) -> Box<dyn GuestEventPort>;
177
178 fn prefer_os_events(&self) -> bool;
185
186 fn monitor_support(&self) -> Option<&dyn SynicMonitor> {
189 None
190 }
191}
192
193pub trait SynicMonitor: Synic {
195 fn register_monitor(&self, monitor_id: MonitorId, connection_id: u32) -> Box<dyn Sync + Send>;
201
202 fn set_monitor_page(&self, vtl: Vtl, gpa: Option<u64>) -> anyhow::Result<()>;
204
205 fn allocate_monitor_page(&self, vtl: Vtl) -> anyhow::Result<Option<u64>> {
211 let _ = vtl;
212 Ok(None)
213 }
214}
215
216#[derive(Debug)]
221pub struct SynicPorts<T> {
222 synic: Arc<T>,
223}
224
225impl<T: Synic> SynicPorts<T> {
226 pub fn new(synic: Arc<T>) -> Self {
228 Self { synic }
229 }
230}
231
232impl<T: Synic> SynicPortAccess for SynicPorts<T> {
233 fn add_message_port(
234 &self,
235 connection_id: u32,
236 minimum_vtl: Vtl,
237 port: Arc<dyn MessagePort>,
238 ) -> Result<Box<dyn Sync + Send>, vmcore::synic::Error> {
239 self.synic
240 .port_map()
241 .add_message_port(connection_id, minimum_vtl, port)?;
242 Ok(Box::new(PortHandle {
243 synic: Arc::downgrade(&self.synic),
244 connection_id,
245 _inner_handle: None,
246 _monitor: None,
247 }))
248 }
249
250 fn add_event_port(
251 &self,
252 connection_id: u32,
253 minimum_vtl: Vtl,
254 port: Arc<dyn EventPort>,
255 monitor_info: Option<MonitorInfo>,
256 ) -> Result<Box<dyn Sync + Send>, vmcore::synic::Error> {
257 let inner_handle = if let Some(event) = port.os_event() {
259 self.synic
260 .clone()
261 .new_host_event_port(connection_id, minimum_vtl, event)?
262 } else {
263 None
264 };
265
266 self.synic
267 .port_map()
268 .add_event_port(connection_id, minimum_vtl, port)?;
269
270 let monitor = monitor_info.as_ref().and_then(|info| {
271 self.synic
272 .monitor_support()
273 .map(|monitor| monitor.register_monitor(info.monitor_id, connection_id))
274 });
275
276 Ok(Box::new(PortHandle {
277 synic: Arc::downgrade(&self.synic),
278 connection_id,
279 _inner_handle: inner_handle,
280 _monitor: monitor,
281 }))
282 }
283
284 fn new_guest_message_port(
285 &self,
286 vtl: Vtl,
287 vp: u32,
288 sint: u8,
289 ) -> Result<Box<dyn GuestMessagePort>, vmcore::synic::HypervisorError> {
290 Ok(Box::new(DirectGuestMessagePort {
291 partition: Arc::clone(&self.synic),
292 vtl,
293 vp: VpIndex::new(vp),
294 sint,
295 }))
296 }
297
298 fn new_guest_event_port(
299 &self,
300 _port_id: u32,
301 vtl: Vtl,
302 vp: u32,
303 sint: u8,
304 flag: u16,
305 _monitor_info: Option<MonitorInfo>,
306 ) -> Result<Box<dyn GuestEventPort>, vmcore::synic::HypervisorError> {
307 Ok(self.synic.clone().new_guest_event_port(vtl, vp, sint, flag))
308 }
309
310 fn prefer_os_events(&self) -> bool {
311 self.synic.prefer_os_events()
312 }
313
314 fn monitor_support(&self) -> Option<&dyn SynicMonitorAccess> {
315 self.synic.monitor_support().and(Some(self))
316 }
317}
318
319impl<T: Synic> SynicMonitorAccess for SynicPorts<T> {
320 fn set_monitor_page(&self, vtl: Vtl, gpa: Option<MonitorPageGpas>) -> anyhow::Result<()> {
321 self.synic
322 .monitor_support()
323 .unwrap()
324 .set_monitor_page(vtl, gpa.map(|mp| mp.child_to_parent))
325 }
326
327 fn allocate_monitor_page(&self, vtl: Vtl) -> anyhow::Result<Option<MonitorPageGpas>> {
328 self.synic
329 .monitor_support()
330 .unwrap()
331 .allocate_monitor_page(vtl)
332 .map(|gpa| {
333 gpa.map(|child_to_parent| MonitorPageGpas {
334 parent_to_child: 0,
335 child_to_parent,
336 })
337 })
338 }
339}
340
341struct PortHandle<T: Synic> {
342 synic: Weak<T>,
343 connection_id: u32,
344 _inner_handle: Option<Box<dyn Sync + Send>>,
345 _monitor: Option<Box<dyn Sync + Send>>,
346}
347
348impl<T: Synic> Drop for PortHandle<T> {
349 fn drop(&mut self) {
350 if let Some(synic) = self.synic.upgrade() {
351 let entry = synic.port_map().ports.lock().remove(&self.connection_id);
352 entry.expect("port was previously added");
353 }
354 }
355}
356
357#[derive(Debug, Clone, Inspect)]
358struct Port {
359 port_type: PortType,
360 #[inspect(with = "|&x| x as u8")]
361 minimum_vtl: Vtl,
362}
363
364#[derive(Clone, Inspect)]
365#[inspect(external_tag)]
366enum PortType {
367 Message(#[inspect(skip)] Arc<dyn MessagePort>),
368 Event(#[inspect(skip)] Arc<dyn EventPort>),
369}
370
371impl Debug for PortType {
372 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
373 f.pad(match self {
374 Self::Message(_) => "Port::Message",
375 Self::Event(_) => "Port::Event",
376 })
377 }
378}
379
380#[derive(Inspect)]
381#[inspect(bound = "")]
382struct DirectGuestMessagePort<T> {
383 #[inspect(skip)]
384 partition: Arc<T>,
385 #[inspect(with = "|&x| x as u8")]
386 vtl: Vtl,
387 vp: VpIndex,
388 sint: u8,
389}
390
391impl<T: Synic> GuestMessagePort for DirectGuestMessagePort<T> {
392 fn poll_post_message(&mut self, _cx: &mut Context<'_>, typ: u32, payload: &[u8]) -> Poll<()> {
393 self.partition
394 .post_message(self.vtl, self.vp, self.sint, typ, payload);
395 Poll::Ready(())
396 }
397
398 fn set_target_vp(&mut self, vp: u32) -> Result<(), vmcore::synic::HypervisorError> {
399 self.vp = VpIndex::new(vp);
400 Ok(())
401 }
402}