1#![forbid(unsafe_code)]
11
12use chipset_device::ChipsetDevice;
13use chipset_device::io::IoResult;
14use chipset_device::mmio::ControlMmioIntercept;
15use chipset_device::mmio::MmioIntercept;
16use chipset_device::mmio::RegisterMmioIntercept;
17use chipset_device::pci::PciConfigSpace;
18use chipset_device::pio::ControlPortIoIntercept;
19use chipset_device::pio::PortIoIntercept;
20use chipset_device::pio::RegisterPortIoIntercept;
21use inspect::Inspect;
22use inspect::InspectMut;
23use pci_core::spec::hwid::ProgrammingInterface;
24use std::ops::RangeInclusive;
25use vmcore::device_state::ChangeDeviceState;
26use vmcore::save_restore::RestoreError;
27use vmcore::save_restore::SaveError;
28use vmcore::save_restore::SaveRestore;
29use vmcore::save_restore::SavedStateNotSupported;
30
31#[derive(Default, Inspect)]
32struct MissingDevPciMetadata {
33 #[inspect(debug)]
34 bdf: (u8, u8, u8),
35 #[inspect(hex)]
36 vendor_id: u16,
37 #[inspect(hex)]
38 device_id: u16,
39}
40
41#[derive(Default, InspectMut)]
43pub struct MissingDev {
44 #[inspect(with = "inspect_helpers::io_ranges")]
45 pio: Vec<(Box<str>, RangeInclusive<u16>)>,
46 #[inspect(with = "inspect_helpers::io_ranges")]
47 mmio: Vec<(Box<str>, RangeInclusive<u64>)>,
48 pci: Option<MissingDevPciMetadata>,
49
50 #[inspect(skip)]
51 _mmio_control: Box<[Box<dyn ControlMmioIntercept>]>,
52 #[inspect(skip)]
53 _pio_control: Box<[Box<dyn ControlPortIoIntercept>]>,
54}
55
56impl MissingDev {
57 pub fn from_manifest(
60 manifest: MissingDevManifest,
61 register_mmio: &mut dyn RegisterMmioIntercept,
62 register_pio: &mut dyn RegisterPortIoIntercept,
63 ) -> MissingDev {
64 let MissingDevManifest { pio, mmio, pci } = manifest;
65
66 let pio_control = pio
67 .iter()
68 .map(|(name, range)| {
69 let mut control = register_pio.new_io_region(name, range.end() - range.start() + 1);
70 control.map(*range.start());
71 control
72 })
73 .collect();
74
75 let mmio_control = mmio
76 .iter()
77 .map(|(name, range)| {
78 let mut control =
79 register_mmio.new_io_region(name, range.end() - range.start() + 1);
80 control.map(*range.start());
81 control
82 })
83 .collect();
84
85 MissingDev {
86 pio,
87 mmio,
88 pci,
89
90 _pio_control: pio_control,
91 _mmio_control: mmio_control,
92 }
93 }
94}
95
96mod inspect_helpers {
97 use super::*;
98
99 pub(crate) fn io_ranges<T>(ranges: &[(Box<str>, RangeInclusive<T>)]) -> impl Inspect + '_
100 where
101 T: std::fmt::LowerHex,
102 {
103 inspect::adhoc(|req| {
104 let mut res = req.respond();
105 for (label, range) in ranges.iter() {
106 let width = size_of::<T>() * 2 + 2;
107 res.field(
108 &format!("{:#0width$x}-{:#0width$x}", range.start(), range.end()),
109 label,
110 );
111 }
112 })
113 }
114}
115
116impl ChangeDeviceState for MissingDev {
117 fn start(&mut self) {}
118
119 async fn stop(&mut self) {}
120
121 async fn reset(&mut self) {}
122}
123
124impl ChipsetDevice for MissingDev {
125 fn supports_pio(&mut self) -> Option<&mut dyn PortIoIntercept> {
126 Some(self)
127 }
128
129 fn supports_mmio(&mut self) -> Option<&mut dyn MmioIntercept> {
130 Some(self)
131 }
132
133 fn supports_pci(&mut self) -> Option<&mut dyn PciConfigSpace> {
134 if self.pci.is_some() { Some(self) } else { None }
136 }
137}
138
139impl SaveRestore for MissingDev {
140 type SavedState = SavedStateNotSupported;
142
143 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
144 Err(SaveError::NotSupported)
145 }
146
147 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
148 match state {}
149 }
150}
151
152impl MmioIntercept for MissingDev {
153 fn mmio_read(&mut self, _addr: u64, data: &mut [u8]) -> IoResult {
154 data.fill(!0);
155 IoResult::Ok
156 }
157
158 fn mmio_write(&mut self, _addr: u64, _data: &[u8]) -> IoResult {
159 IoResult::Ok
160 }
161}
162
163impl PortIoIntercept for MissingDev {
164 fn io_read(&mut self, _addr: u16, data: &mut [u8]) -> IoResult {
165 data.fill(!0);
166 IoResult::Ok
167 }
168
169 fn io_write(&mut self, _addr: u16, _data: &[u8]) -> IoResult {
170 IoResult::Ok
171 }
172}
173
174impl PciConfigSpace for MissingDev {
175 fn pci_cfg_read(&mut self, offset: u16, value: &mut u32) -> IoResult {
176 let pci = self.pci.as_ref().unwrap();
177
178 pci_core::cfg_space_emu::ConfigSpaceType0Emulator::new(
179 pci_core::spec::hwid::HardwareIds {
180 vendor_id: pci.vendor_id,
181 device_id: pci.device_id,
182 revision_id: 0,
183 prog_if: ProgrammingInterface::NONE,
184 sub_class: pci_core::spec::hwid::Subclass::NONE,
185 base_class: pci_core::spec::hwid::ClassCode::UNCLASSIFIED,
186 type0_sub_vendor_id: 0,
187 type0_sub_system_id: 0,
188 },
189 vec![],
190 pci_core::cfg_space_emu::DeviceBars::new(),
191 )
192 .read_u32(offset, value)
193 }
194
195 fn pci_cfg_write(&mut self, _offset: u16, _value: u32) -> IoResult {
196 IoResult::Ok
197 }
198
199 fn suggested_bdf(&mut self) -> Option<(u8, u8, u8)> {
200 let pci = self.pci.as_ref().unwrap();
201 Some(pci.bdf)
202 }
203}
204
205#[derive(Default)]
207pub struct MissingDevManifest {
208 pio: Vec<(Box<str>, RangeInclusive<u16>)>,
209 mmio: Vec<(Box<str>, RangeInclusive<u64>)>,
210 pci: Option<MissingDevPciMetadata>,
211}
212
213impl MissingDevManifest {
214 pub fn new() -> Self {
216 Default::default()
217 }
218
219 pub fn claim_pio(mut self, region_name: &str, range: RangeInclusive<u16>) -> Self {
221 self.pio.push((region_name.into(), range));
222 self
223 }
224
225 pub fn claim_mmio(mut self, region_name: &str, range: RangeInclusive<u64>) -> Self {
227 self.mmio.push((region_name.into(), range));
228 self
229 }
230
231 pub fn claim_pci(mut self, bdf: (u8, u8, u8), vendor_id: u16, device_id: u16) -> Self {
233 self.pci = Some(MissingDevPciMetadata {
234 bdf,
235 vendor_id,
236 device_id,
237 });
238 self
239 }
240}
241
242pub mod resolver {
243 use crate::MissingDev;
246 use crate::MissingDevManifest;
247 use chipset_device_resources::ResolveChipsetDeviceHandleParams;
248 use chipset_device_resources::ResolvedChipsetDevice;
249 use missing_dev_resources::MissingDevHandle;
250 use std::convert::Infallible;
251 use vm_resource::ResolveResource;
252 use vm_resource::declare_static_resolver;
253 use vm_resource::kind::ChipsetDeviceHandleKind;
254
255 pub struct MissingDevResolver;
257
258 declare_static_resolver!(
259 MissingDevResolver,
260 (ChipsetDeviceHandleKind, MissingDevHandle)
261 );
262
263 impl ResolveResource<ChipsetDeviceHandleKind, MissingDevHandle> for MissingDevResolver {
264 type Output = ResolvedChipsetDevice;
265 type Error = Infallible;
266
267 fn resolve(
268 &self,
269 resource: MissingDevHandle,
270 input: ResolveChipsetDeviceHandleParams<'_>,
271 ) -> Result<Self::Output, Self::Error> {
272 input.configure.omit_saved_state();
273 let dev = MissingDev::from_manifest(
274 MissingDevManifest {
275 pio: resource
276 .pio
277 .into_iter()
278 .map(|(name, start, end)| (name.into(), start..=end))
279 .collect(),
280 mmio: resource
281 .mmio
282 .into_iter()
283 .map(|(name, start, end)| (name.into(), start..=end))
284 .collect(),
285 pci: None,
286 },
287 input.register_mmio,
288 input.register_pio,
289 );
290 Ok(dev.into())
291 }
292 }
293}