Skip to main content

chipset_legacy/
piix4_uhci.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! PIIX4 - USB configuration
5
6use chipset_device::ChipsetDevice;
7use chipset_device::io::IoResult;
8use chipset_device::pci::ByteEnabledDwordRead;
9use chipset_device::pci::ByteEnabledDwordWrite;
10use chipset_device::pci::PciConfigSpace;
11use chipset_resources::piix4_uhci::PIIX4_PCI_USB_UHCI_STUB_BDF;
12use inspect::InspectMut;
13use vmcore::device_state::ChangeDeviceState;
14
15pub mod resolver;
16
17/// PIIX4 (PCI device function 2) - USB configuration (stub)
18///
19/// See section 3.3 in the PIIX4 data sheet.
20///
21/// We only minimally support the UHCI controller because it is part of the
22/// chipset that we emulate.
23///
24/// If we wanted to support USB in the future, it is highly unlikely that we
25/// would implement it as part of the legacy chipset.
26#[derive(Debug, InspectMut)]
27#[non_exhaustive] // force the use of `new`
28pub struct Piix4UsbUhciStub {}
29
30impl Piix4UsbUhciStub {
31    pub fn new() -> Self {
32        Self {}
33    }
34}
35
36impl ChangeDeviceState for Piix4UsbUhciStub {
37    fn start(&mut self) {}
38
39    async fn stop(&mut self) {}
40
41    async fn reset(&mut self) {}
42}
43
44impl ChipsetDevice for Piix4UsbUhciStub {
45    fn supports_pci(&mut self) -> Option<&mut dyn PciConfigSpace> {
46        Some(self)
47    }
48}
49
50/// Sidestep the config space emulator, and match legacy stub behavior directly
51impl PciConfigSpace for Piix4UsbUhciStub {
52    fn pci_cfg_read(&mut self, offset: u16, mut value: ByteEnabledDwordRead<'_>) -> IoResult {
53        use pci_core::spec::cfg_space::HeaderType00;
54        value.set(match HeaderType00(offset) {
55            HeaderType00::BIST_HEADER => 0,
56            HeaderType00::BAR4 => 0,
57            HeaderType00::STATUS_COMMAND => 0x02800000,
58            // Always return the default value, which indicates
59            // that the controller is hardwired to PCI IRQ Lane D (i.e: 4).
60            HeaderType00::LATENCY_INTERRUPT => 0x000000FF | (4 << 8),
61            // Return an invalid value so UHCI controller is ignored by the BIOS and
62            // the OS. On a real implementation, the correct value would be 0x71128086.
63            HeaderType00::DEVICE_VENDOR => 0xFFFFFFFF,
64            // Return zero so UHCI controller is ignored by the BIOS and the OS.
65            // On a real implementation, the correct value would be 0x0C030008.
66            HeaderType00::CLASS_REVISION => 0x00000000,
67            _ if offset < 0x40 => 0, // stub-out all other standard cfg regs
68            _ => {
69                tracing::debug!(?offset, "unimplemented config space read");
70                // stub-out all other registers as well, since this is just a stub device
71                0
72            }
73        });
74
75        IoResult::Ok
76    }
77
78    fn pci_cfg_write(&mut self, offset: u16, value: ByteEnabledDwordWrite) -> IoResult {
79        use pci_core::spec::cfg_space::HeaderType00;
80        match HeaderType00(offset) {
81            HeaderType00::BIST_HEADER => {}
82            HeaderType00::BAR4 => {}
83            HeaderType00::STATUS_COMMAND => {}
84            HeaderType00::LATENCY_INTERRUPT => {}
85            HeaderType00::DEVICE_VENDOR => {}
86            _ => {
87                tracing::debug!(?offset, ?value, "unimplemented config space write");
88                // stub-out all other registers as well, since this is just a stub device
89            }
90        }
91
92        IoResult::Ok
93    }
94
95    fn suggested_bdf(&mut self) -> Option<(u8, u8, u8)> {
96        Some(PIIX4_PCI_USB_UHCI_STUB_BDF) // as per PIIX4 spec
97    }
98}
99
100mod save_restore {
101    use super::*;
102    use vmcore::save_restore::NoSavedState;
103    use vmcore::save_restore::RestoreError;
104    use vmcore::save_restore::SaveError;
105    use vmcore::save_restore::SaveRestore;
106
107    // This is a stub device, with no saved state
108    impl SaveRestore for Piix4UsbUhciStub {
109        type SavedState = NoSavedState;
110
111        fn save(&mut self) -> Result<Self::SavedState, SaveError> {
112            Ok(NoSavedState)
113        }
114
115        fn restore(&mut self, NoSavedState: Self::SavedState) -> Result<(), RestoreError> {
116            Ok(())
117        }
118    }
119}