1#![expect(missing_docs)]
7#![forbid(unsafe_code)]
8
9use chipset_device::ChipsetDevice;
10use chipset_device::io::IoError;
11use chipset_device::io::IoResult;
12use chipset_device::io::deferred::DeferredRead;
13use chipset_device::io::deferred::DeferredWrite;
14use chipset_device::io::deferred::defer_read;
15use chipset_device::io::deferred::defer_write;
16use chipset_device::pci::PciConfigSpace;
17use chipset_device::pio::PortIoIntercept;
18use chipset_device::poll_device::PollDevice;
19use inspect::InspectMut;
20use std::future::Future;
21use std::ops::RangeInclusive;
22use std::pin::Pin;
23use std::sync::Arc;
24use std::task::Poll;
25use std::task::Waker;
26use vmcore::device_state::ChangeDeviceState;
27
28pub struct VgaProxyDevice {
29 pci_cfg_proxy: Arc<dyn ProxyVgaPciCfgAccess>,
30 pending_actions: Vec<DeferredAction>,
31 waker: Option<Waker>,
32 _host_port_handles: Vec<Box<dyn Send>>,
33}
34
35enum DeferredAction {
36 Read(DeferredRead, Pin<Box<dyn Future<Output = u32> + Send>>),
37 Write(DeferredWrite, Pin<Box<dyn Future<Output = ()> + Send>>),
38}
39
40static PORTS: &[(&str, RangeInclusive<u16>)] = &[
41 ("s3", 0x4ae8..=0x4ae9),
42 ("mda", 0x3b0..=0x3bf),
43 ("vga", 0x3c0..=0x3cf),
44 ("cga", 0x3d0..=0x3df),
45];
46
47impl VgaProxyDevice {
48 pub fn new(
49 pci_cfg_proxy: Arc<dyn ProxyVgaPciCfgAccess>,
50 register: &dyn RegisterHostIoPortFastPath,
51 ) -> Self {
52 let host_port_handles = PORTS
55 .iter()
56 .map(|(_, range)| register.register(range.clone()))
57 .collect();
58
59 Self {
60 pci_cfg_proxy,
61 pending_actions: Vec::new(),
62 waker: None,
63 _host_port_handles: host_port_handles,
64 }
65 }
66}
67
68pub trait RegisterHostIoPortFastPath {
70 #[must_use]
74 fn register(&self, range: RangeInclusive<u16>) -> Box<dyn Send>;
75}
76
77#[async_trait::async_trait]
78pub trait ProxyVgaPciCfgAccess: Send + Sync {
79 async fn vga_proxy_pci_read(&self, offset: u16) -> u32;
80 async fn vga_proxy_pci_write(&self, offset: u16, value: u32);
81}
82
83impl ChangeDeviceState for VgaProxyDevice {
84 fn start(&mut self) {}
85
86 async fn stop(&mut self) {}
87
88 async fn reset(&mut self) {
89 }
92}
93
94impl ChipsetDevice for VgaProxyDevice {
95 fn supports_pci(&mut self) -> Option<&mut dyn PciConfigSpace> {
96 Some(self)
97 }
98
99 fn supports_pio(&mut self) -> Option<&mut dyn PortIoIntercept> {
100 Some(self)
101 }
102
103 fn supports_poll_device(&mut self) -> Option<&mut dyn PollDevice> {
104 Some(self)
105 }
106}
107
108impl PciConfigSpace for VgaProxyDevice {
109 fn pci_cfg_read(&mut self, offset: u16, _value: &mut u32) -> IoResult {
110 tracing::trace!(?offset, "VGA proxy read");
111 let (read, token) = defer_read();
112
113 let fut = {
114 let proxy = self.pci_cfg_proxy.clone();
115 async move { proxy.vga_proxy_pci_read(offset).await }
116 };
117
118 self.pending_actions
119 .push(DeferredAction::Read(read, Box::pin(fut)));
120 if let Some(waker) = self.waker.take() {
121 waker.wake();
122 }
123 IoResult::Defer(token)
124 }
125
126 fn pci_cfg_write(&mut self, offset: u16, value: u32) -> IoResult {
127 tracing::trace!(?offset, ?value, "VGA proxy write");
128 let (write, token) = defer_write();
129
130 let fut = {
131 let proxy = self.pci_cfg_proxy.clone();
132 async move { proxy.vga_proxy_pci_write(offset, value).await }
133 };
134
135 self.pending_actions
136 .push(DeferredAction::Write(write, Box::pin(fut)));
137 if let Some(waker) = self.waker.take() {
138 waker.wake();
139 }
140 IoResult::Defer(token)
141 }
142
143 fn suggested_bdf(&mut self) -> Option<(u8, u8, u8)> {
144 Some((0, 8, 0)) }
146}
147
148impl PortIoIntercept for VgaProxyDevice {
149 fn io_read(&mut self, io_port: u16, _data: &mut [u8]) -> IoResult {
150 tracelimit::warn_ratelimited!(io_port, "invalid straddling vga write");
153 IoResult::Err(IoError::InvalidAccessSize)
154 }
155
156 fn io_write(&mut self, io_port: u16, data: &[u8]) -> IoResult {
157 tracelimit::warn_ratelimited!(io_port, ?data, "invalid straddling vga write");
160 IoResult::Err(IoError::InvalidAccessSize)
161 }
162
163 fn get_static_regions(&mut self) -> &[(&str, RangeInclusive<u16>)] {
164 PORTS
165 }
166}
167
168impl PollDevice for VgaProxyDevice {
169 fn poll_device(&mut self, cx: &mut std::task::Context<'_>) {
170 self.waker = Some(cx.waker().clone());
171 self.pending_actions = std::mem::take(&mut self.pending_actions)
172 .into_iter()
173 .filter_map(|action| match action {
174 DeferredAction::Read(dr, mut fut) => {
175 if let Poll::Ready(value) = fut.as_mut().poll(cx) {
176 tracing::trace!(value, "VGA proxy read complete");
177 dr.complete(&value.to_ne_bytes());
178 None
179 } else {
180 Some(DeferredAction::Read(dr, fut))
181 }
182 }
183 DeferredAction::Write(dw, mut fut) => {
184 if let Poll::Ready(()) = fut.as_mut().poll(cx) {
185 tracing::trace!("VGA proxy write complete");
186 dw.complete();
187 None
188 } else {
189 Some(DeferredAction::Write(dw, fut))
190 }
191 }
192 })
193 .collect();
194 }
195}
196
197impl InspectMut for VgaProxyDevice {
198 fn inspect_mut(&mut self, req: inspect::Request<'_>) {
199 req.respond();
200 }
201}
202
203mod save_restore {
204 use super::*;
205 use vmcore::save_restore::NoSavedState;
206 use vmcore::save_restore::RestoreError;
207 use vmcore::save_restore::SaveError;
208 use vmcore::save_restore::SaveRestore;
209
210 impl SaveRestore for VgaProxyDevice {
216 type SavedState = NoSavedState;
217
218 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
219 Ok(NoSavedState)
220 }
221
222 fn restore(&mut self, NoSavedState: Self::SavedState) -> Result<(), RestoreError> {
223 Ok(())
224 }
225 }
226}