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