Skip to main content

chipset_resources/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Resource definitions for core chipset devices.
5
6#![forbid(unsafe_code)]
7
8use local_clock::InspectableLocalClock;
9use vm_resource::CanResolveTo;
10use vm_resource::ResourceKind;
11
12/// The PCI bus name used by the Gen1 (i440BX + PIIX4) chipset.
13pub const LEGACY_CHIPSET_PCI_BUS_NAME: &str = "i440bx";
14
15/// Resource kind for CMOS RTC time-source handles.
16pub enum CmosRtcTimeSourceHandleKind {}
17
18impl ResourceKind for CmosRtcTimeSourceHandleKind {
19    const NAME: &'static str = "cmos_rtc_time_source";
20}
21
22/// Resolved runtime time source for CMOS RTC devices.
23pub struct ResolvedCmosRtcTimeSource(pub Box<dyn InspectableLocalClock>);
24
25impl CanResolveTo<ResolvedCmosRtcTimeSource> for CmosRtcTimeSourceHandleKind {
26    type Input<'a> = ();
27}
28
29pub mod ipmi_kcs {
30    //! Resource definitions for the IPMI KCS virtual BMC.
31
32    use super::CmosRtcTimeSourceHandleKind;
33    use ipmi_protocol::SelRecord;
34    use mesh::MeshPayload;
35    use vm_resource::CanResolveTo;
36    use vm_resource::Resource;
37    use vm_resource::ResourceId;
38    use vm_resource::ResourceKind;
39    use vm_resource::kind::ChipsetDeviceHandleKind;
40
41    /// AMD64 KCS data-register port.
42    pub const IPMI_KCS_DATA_PORT: u16 = 0xca2;
43    /// AMD64 KCS status-read/command-write port.
44    pub const IPMI_KCS_STATUS_COMMAND_PORT: u16 = IPMI_KCS_DATA_PORT + 1;
45    /// ARM64 KCS MMIO page base address.
46    pub const IPMI_KCS_MMIO_BASE_ADDRESS_AARCH64: u64 = 0xeffe_7000;
47    /// ARM64 KCS MMIO register spacing.
48    pub const IPMI_KCS_MMIO_REGISTER_SPACING_AARCH64: u64 = 4;
49    /// ARM64 KCS data-register address.
50    pub const IPMI_KCS_MMIO_DATA_ADDRESS_AARCH64: u64 = IPMI_KCS_MMIO_BASE_ADDRESS_AARCH64;
51    /// ARM64 KCS status-read/command-write address.
52    pub const IPMI_KCS_MMIO_STATUS_COMMAND_ADDRESS_AARCH64: u64 =
53        IPMI_KCS_MMIO_BASE_ADDRESS_AARCH64 + IPMI_KCS_MMIO_REGISTER_SPACING_AARCH64;
54    /// Size of the ARM64 KCS MMIO aperture.
55    pub const IPMI_KCS_MMIO_REGION_SIZE_AARCH64: u64 = 0x1000;
56
57    /// Non-blocking sink for completed IPMI SEL records.
58    pub trait SelEventSink: Send {
59        /// Attempts to forward a completed SEL record, returning whether it was accepted.
60        fn try_send(&mut self, record_id: u16, record: SelRecord) -> bool;
61    }
62
63    /// Resource kind for IPMI SEL event sinks.
64    pub enum IpmiSelEventSinkHandleKind {}
65
66    impl ResourceKind for IpmiSelEventSinkHandleKind {
67        const NAME: &'static str = "ipmi_sel_event_sink";
68    }
69
70    /// Resolved runtime IPMI SEL event sink.
71    pub struct ResolvedIpmiSelEventSink(pub Box<dyn SelEventSink>);
72
73    impl CanResolveTo<ResolvedIpmiSelEventSink> for IpmiSelEventSinkHandleKind {
74        type Input<'a> = ();
75    }
76
77    /// A handle to an AMD64 IPMI KCS virtual BMC.
78    #[derive(MeshPayload)]
79    pub struct IpmiKcsDeviceHandleX64 {
80        /// Non-blocking sink for completed SEL records.
81        pub event_sink: Resource<IpmiSelEventSinkHandleKind>,
82        /// Wall-clock source used for Unix-epoch SEL timestamps.
83        ///
84        /// This resource supplies time to UEFI and is not dependent on a
85        /// guest-visible CMOS device.
86        pub time_source: Resource<CmosRtcTimeSourceHandleKind>,
87    }
88
89    impl ResourceId<ChipsetDeviceHandleKind> for IpmiKcsDeviceHandleX64 {
90        const ID: &'static str = "ipmi-kcs-x64";
91    }
92
93    /// A handle to an ARM64 IPMI KCS virtual BMC.
94    #[derive(MeshPayload)]
95    pub struct IpmiKcsDeviceHandleAArch64 {
96        /// Non-blocking sink for completed SEL records.
97        pub event_sink: Resource<IpmiSelEventSinkHandleKind>,
98        /// Wall-clock source used for Unix-epoch SEL timestamps.
99        ///
100        /// This resource supplies time to UEFI and is not dependent on a
101        /// guest-visible CMOS device.
102        pub time_source: Resource<CmosRtcTimeSourceHandleKind>,
103    }
104
105    impl ResourceId<ChipsetDeviceHandleKind> for IpmiKcsDeviceHandleAArch64 {
106        const ID: &'static str = "ipmi-kcs-aarch64";
107    }
108}
109
110pub mod cmos_rtc_time_source {
111    //! Resource definitions and resolvers for CMOS RTC time sources.
112
113    use super::CmosRtcTimeSourceHandleKind;
114    use super::ResolvedCmosRtcTimeSource;
115    use local_clock::LocalClockDelta;
116    use local_clock::SystemTimeClock;
117    use mesh::MeshPayload;
118    use vm_resource::ResolveResource;
119    use vm_resource::ResourceId;
120    use vm_resource::declare_static_resolver;
121
122    /// A time source backed by the host system clock with a configurable
123    /// millisecond delta.
124    #[derive(MeshPayload)]
125    pub struct SystemTimeClockHandle {
126        /// Offset from system time in milliseconds.
127        pub delta_milliseconds: i64,
128    }
129
130    impl ResourceId<CmosRtcTimeSourceHandleKind> for SystemTimeClockHandle {
131        const ID: &'static str = "system_time_clock";
132    }
133
134    /// Resolver for [`SystemTimeClockHandle`].
135    pub struct SystemTimeClockResolver;
136
137    declare_static_resolver! {
138        SystemTimeClockResolver,
139        (CmosRtcTimeSourceHandleKind, SystemTimeClockHandle),
140    }
141
142    impl ResolveResource<CmosRtcTimeSourceHandleKind, SystemTimeClockHandle>
143        for SystemTimeClockResolver
144    {
145        type Output = ResolvedCmosRtcTimeSource;
146        type Error = std::convert::Infallible;
147
148        fn resolve(
149            &self,
150            resource: SystemTimeClockHandle,
151            (): (),
152        ) -> Result<Self::Output, Self::Error> {
153            Ok(ResolvedCmosRtcTimeSource(Box::new(SystemTimeClock::new(
154                LocalClockDelta::from_millis(resource.delta_milliseconds),
155            ))))
156        }
157    }
158}
159
160pub mod i8042 {
161    //! Resource definitions for the i8042 PS2 keyboard/mouse controller.
162
163    use mesh::MeshPayload;
164    use vm_resource::Resource;
165    use vm_resource::ResourceId;
166    use vm_resource::kind::ChipsetDeviceHandleKind;
167    use vm_resource::kind::KeyboardInputHandleKind;
168
169    /// A handle to an i8042 PS2 keyboard/mouse controller controller.
170    #[derive(MeshPayload)]
171    pub struct I8042DeviceHandle {
172        /// The keyboard input.
173        pub keyboard_input: Resource<KeyboardInputHandleKind>,
174    }
175
176    impl ResourceId<ChipsetDeviceHandleKind> for I8042DeviceHandle {
177        const ID: &'static str = "i8042";
178    }
179}
180
181pub mod isa_dma {
182    //! Resource definitions for the generic ISA DMA controller.
183
184    use mesh::MeshPayload;
185    use vm_resource::ResourceId;
186    use vm_resource::kind::IsaDmaControllerHandleKind;
187
188    /// A handle to a generic dual 8237 ISA DMA controller.
189    #[derive(MeshPayload)]
190    pub struct GenericIsaDmaDeviceHandle;
191
192    impl ResourceId<IsaDmaControllerHandleKind> for GenericIsaDmaDeviceHandle {
193        const ID: &'static str = "genericIsaDma";
194    }
195}
196
197pub mod pic {
198    //! Resource definitions for the PIC (dual 8259 Programmable Interrupt Controller).
199
200    use mesh::MeshPayload;
201    use vm_resource::ResourceId;
202    use vm_resource::kind::ChipsetDeviceHandleKind;
203
204    /// A handle to a dual 8259 PIC (Programmable Interrupt Controller) device.
205    #[derive(MeshPayload)]
206    pub struct PicDeviceHandle;
207
208    impl ResourceId<ChipsetDeviceHandleKind> for PicDeviceHandle {
209        const ID: &'static str = "pic";
210    }
211}
212
213pub mod pit {
214    //! Resource definitions for the PIT (Programmable Interval Timer).
215
216    use mesh::MeshPayload;
217    use vm_resource::ResourceId;
218    use vm_resource::kind::ChipsetDeviceHandleKind;
219
220    /// A handle to a PIT (Intel 8253/8254 Programmable Interval Timer) device.
221    #[derive(MeshPayload)]
222    pub struct PitDeviceHandle;
223
224    impl ResourceId<ChipsetDeviceHandleKind> for PitDeviceHandle {
225        const ID: &'static str = "pit";
226    }
227}
228
229pub mod battery {
230    //! Resource definitions for the battery device
231
232    #[cfg(feature = "arbitrary")]
233    use arbitrary::Arbitrary;
234    use inspect::Inspect;
235    use mesh::MeshPayload;
236    use vm_resource::ResourceId;
237    use vm_resource::kind::ChipsetDeviceHandleKind;
238    /// A handle to a battery device for x64
239    #[derive(MeshPayload)]
240    pub struct BatteryDeviceHandleX64 {
241        /// Channel to receive updated state
242        pub battery_status_recv: mesh::Receiver<HostBatteryUpdate>,
243    }
244
245    impl ResourceId<ChipsetDeviceHandleKind> for BatteryDeviceHandleX64 {
246        const ID: &'static str = "batteryX64";
247    }
248
249    /// A handle to a battery device for aarch64
250    #[derive(MeshPayload)]
251    pub struct BatteryDeviceHandleAArch64 {
252        /// Channel to receive updated state
253        pub battery_status_recv: mesh::Receiver<HostBatteryUpdate>,
254    }
255
256    impl ResourceId<ChipsetDeviceHandleKind> for BatteryDeviceHandleAArch64 {
257        const ID: &'static str = "batteryAArch64";
258    }
259
260    /// Updated battery state from the host
261    #[derive(Debug, Clone, Copy, Inspect, PartialEq, Eq, MeshPayload, Default)]
262    #[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
263    pub struct HostBatteryUpdate {
264        /// Is the battery present?
265        pub battery_present: bool,
266        /// Is the battery charging?
267        pub charging: bool,
268        /// Is the battery discharging?
269        pub discharging: bool,
270        /// Provides the current rate of drain in milliwatts from the battery.
271        pub rate: u32,
272        /// Provides the remaining battery capacity in milliwatt-hours.
273        pub remaining_capacity: u32,
274        /// Provides the max capacity of the battery in `milliwatt-hours`
275        pub max_capacity: u32,
276        /// Is ac online?
277        pub ac_online: bool,
278    }
279
280    impl HostBatteryUpdate {
281        /// Returns a default `HostBatteryUpdate` with the battery present and charging.
282        pub fn default_present() -> Self {
283            Self {
284                battery_present: true,
285                charging: true,
286                discharging: false,
287                rate: 1,
288                remaining_capacity: 950,
289                max_capacity: 1000,
290                ac_online: true,
291            }
292        }
293    }
294}
295
296pub mod piix4_pci_isa_bridge {
297    //! Resource definitions for the PIIX4 PCI-ISA bridge device.
298
299    use mesh::MeshPayload;
300    use vm_resource::ResourceId;
301    use vm_resource::kind::ChipsetDeviceHandleKind;
302
303    /// A handle to the PIIX4 PCI-to-ISA bridge (PCI device function 0).
304    #[derive(MeshPayload)]
305    pub struct Piix4PciIsaBridgeDeviceHandle;
306
307    /// The fixed BDF used by the PIIX4 PCI-ISA bridge in the Gen1 chipset.
308    pub const PIIX4_PCI_ISA_BRIDGE_BDF: (u8, u8, u8) = (0, 7, 0);
309
310    impl ResourceId<ChipsetDeviceHandleKind> for Piix4PciIsaBridgeDeviceHandle {
311        const ID: &'static str = "piix4PciIsaBridge";
312    }
313}
314
315pub mod ioapic {
316    //! Resource definitions for the generic IO-APIC device.
317
318    use mesh::MeshPayload;
319    use std::fmt;
320    use std::fmt::Debug;
321    use vm_resource::CanResolveTo;
322    use vm_resource::Resource;
323    use vm_resource::ResourceId;
324    use vm_resource::ResourceKind;
325    use vm_resource::kind::ChipsetDeviceHandleKind;
326
327    /// The number of IO-APIC entries used by the platform.
328    pub const IOAPIC_NUM_ENTRIES: u8 = 24;
329
330    /// Trait allowing the IO-APIC device to assert VM interrupts.
331    pub trait IoApicRouting: Send + Sync {
332        /// Asserts virtual interrupt line `irq`.
333        fn assert(&self, irq: u8);
334        /// Sets the MSI parameters to use when virtual interrupt line `irq` is
335        /// asserted.
336        fn set_route(&self, irq: u8, request: Option<(u64, u32)>);
337    }
338
339    impl Debug for dyn IoApicRouting {
340        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
341            f.pad("IoApicRouting")
342        }
343    }
344
345    /// Resource kind for resolving IO-APIC routing implementations.
346    pub enum IoApicRoutingHandleKind {}
347
348    impl ResourceKind for IoApicRoutingHandleKind {
349        const NAME: &'static str = "ioapic_routing";
350    }
351
352    /// Resolved IO-APIC routing implementation.
353    ///
354    /// Wraps `Box<dyn IoApicRouting>` in a newtype to avoid lifetime issues
355    /// with `async_trait` and `CanResolveTo`.
356    pub struct ResolvedIoApicRouting(pub Box<dyn IoApicRouting>);
357
358    impl CanResolveTo<ResolvedIoApicRouting> for IoApicRoutingHandleKind {
359        type Input<'a> = ();
360    }
361
362    /// A handle to a generic IO-APIC device.
363    #[derive(MeshPayload)]
364    pub struct GenericIoApicDeviceHandle {
365        /// Resource for resolving the IoApicRouting implementation.
366        pub routing: Resource<IoApicRoutingHandleKind>,
367    }
368
369    impl ResourceId<ChipsetDeviceHandleKind> for GenericIoApicDeviceHandle {
370        const ID: &'static str = "generic-ioapic";
371    }
372}
373
374pub mod piix4_uhci {
375    //! Resource definitions for the PIIX4 USB UHCI stub device.
376
377    use mesh::MeshPayload;
378    use vm_resource::ResourceId;
379    use vm_resource::kind::ChipsetDeviceHandleKind;
380
381    /// A handle to the PIIX4 USB UHCI stub controller.
382    #[derive(MeshPayload)]
383    pub struct Piix4PciUsbUhciStubDeviceHandle;
384
385    /// The fixed BDF used by the PIIX4 USB UHCI stub in the Gen1 chipset.
386    pub const PIIX4_PCI_USB_UHCI_STUB_BDF: (u8, u8, u8) = (0, 7, 2);
387
388    impl ResourceId<ChipsetDeviceHandleKind> for Piix4PciUsbUhciStubDeviceHandle {
389        const ID: &'static str = "piix4PciUsbUhciStub";
390    }
391}
392
393pub mod hyperv_guest_watchdog {
394    //! Resource definitions for the Hyper-V guest watchdog device.
395
396    use mesh::MeshPayload;
397    use vm_resource::ResourceId;
398    use vm_resource::kind::ChipsetDeviceHandleKind;
399
400    /// Default base port IO address for the Hyper-V guest watchdog register window.
401    pub const DEFAULT_WDAT_PORT_BASE: u16 = 0x30;
402
403    /// A handle to the Hyper-V guest watchdog device.
404    #[derive(MeshPayload)]
405    pub struct HyperVGuestWatchdogDeviceHandle {
406        /// Base port IO address for the watchdog register window.
407        pub port_base: u16,
408    }
409
410    impl ResourceId<ChipsetDeviceHandleKind> for HyperVGuestWatchdogDeviceHandle {
411        const ID: &'static str = "hyperv_guest_watchdog";
412    }
413}
414
415pub mod pm {
416    //! Resource definitions for power management devices.
417
418    use mesh::MeshPayload;
419    use vm_resource::CanResolveTo;
420    use vm_resource::Resource;
421    use vm_resource::ResourceId;
422    use vm_resource::ResourceKind;
423    use vm_resource::kind::ChipsetDeviceHandleKind;
424
425    /// Interface to enable/disable hypervisor PM timer assist.
426    pub trait PmTimerAssist: Send + Sync {
427        /// Sets the port of the PM timer assist, or disables it if `None`.
428        fn set(&self, port: Option<u16>);
429    }
430
431    /// Resolved PM timer assist, wrapping a boxed trait object.
432    pub struct ResolvedPmTimerAssist(pub Box<dyn PmTimerAssist>);
433
434    /// Resource kind for PM timer assist implementations.
435    pub enum PmTimerAssistHandleKind {}
436
437    impl ResourceKind for PmTimerAssistHandleKind {
438        const NAME: &'static str = "pm_timer_assist";
439    }
440
441    impl CanResolveTo<ResolvedPmTimerAssist> for PmTimerAssistHandleKind {
442        type Input<'a> = ();
443    }
444
445    /// A handle to the Hyper-V power management device (non-PCI, ACPI/PIO).
446    #[derive(MeshPayload)]
447    pub struct HyperVPowerManagementDeviceHandle {
448        /// IRQ line triggered on ACPI power event.
449        pub acpi_irq: u32,
450        /// Base port IO address of the device's dynamic register region.
451        pub pio_base: u16,
452        /// Optional PM timer assist resource.
453        pub pm_timer_assist: Option<Resource<PmTimerAssistHandleKind>>,
454    }
455
456    impl ResourceId<ChipsetDeviceHandleKind> for HyperVPowerManagementDeviceHandle {
457        const ID: &'static str = "hyperv_power_management";
458    }
459
460    /// A handle to the PIIX4 power management device (PCI function 3).
461    #[derive(MeshPayload)]
462    pub struct Piix4PowerManagementDeviceHandle {
463        /// Optional PM timer assist resource.
464        pub pm_timer_assist: Option<Resource<PmTimerAssistHandleKind>>,
465    }
466
467    /// The fixed BDF used by the PIIX4 PM device in the Gen1 chipset.
468    pub const PIIX4_PM_BDF: (u8, u8, u8) = (0, 7, 3);
469
470    /// Default PIO base address for the PM dynamic register region.
471    ///
472    /// This value must match what is reported by the firmware (FADT).
473    pub const DEFAULT_PM_PIO_BASE: u16 = 0x400;
474
475    /// Default ACPI IRQ line for the Hyper-V power management device.
476    pub const DEFAULT_ACPI_IRQ: u32 = 9;
477
478    impl ResourceId<ChipsetDeviceHandleKind> for Piix4PowerManagementDeviceHandle {
479        const ID: &'static str = "piix4_power_management";
480    }
481}
482
483pub mod i440bx_host_pci_bridge {
484    //! Resource definitions for the i440BX Host-PCI Bridge.
485
486    use memory_range::MemoryRange;
487    use mesh::MeshPayload;
488    use vm_resource::CanResolveTo;
489    use vm_resource::Resource;
490    use vm_resource::ResourceId;
491    use vm_resource::ResourceKind;
492    use vm_resource::kind::ChipsetDeviceHandleKind;
493
494    /// Memory mapping state for a GPA range managed by the i440BX PAM registers.
495    #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
496    pub enum GpaState {
497        /// Reads and writes go to RAM.
498        #[default]
499        Writable,
500        /// Reads go to RAM, writes go to MMIO.
501        WriteProtected,
502        /// Reads go to ROM, writes go to RAM.
503        WriteOnly,
504        /// Reads and writes go to MMIO.
505        Mmio,
506    }
507
508    /// A trait to adjust GPA memory range mappings.
509    ///
510    /// This is called when the i440BX PAM (Physical Address Management) PCI
511    /// configuration registers are modified, or for VGA memory.
512    pub trait AdjustGpaRange: Send {
513        /// Adjusts a memory range's mapping state.
514        fn adjust_gpa_range(&mut self, range: MemoryRange, state: GpaState);
515    }
516
517    /// Resolved platform-specific [`AdjustGpaRange`] implementation.
518    pub struct ResolvedAdjustGpaRange(pub Box<dyn AdjustGpaRange>);
519
520    /// Resource kind for platform-specific [`AdjustGpaRange`] implementations.
521    pub enum AdjustGpaRangeHandleKind {}
522
523    impl ResourceKind for AdjustGpaRangeHandleKind {
524        const NAME: &'static str = "i440bx_adjust_gpa_range";
525    }
526
527    impl CanResolveTo<ResolvedAdjustGpaRange> for AdjustGpaRangeHandleKind {
528        type Input<'a> = ();
529    }
530
531    /// A handle to an i440BX Host-PCI Bridge device.
532    #[derive(MeshPayload)]
533    pub struct I440BxHostPciBridgeDeviceHandle {
534        /// Platform-specific implementation of GPA range adjustment.
535        pub adjust_gpa_range: Resource<AdjustGpaRangeHandleKind>,
536    }
537
538    /// The fixed BDF used by the i440BX Host-PCI Bridge in the Gen1 chipset.
539    pub const I440BX_HOST_PCI_BRIDGE_BDF: (u8, u8, u8) = (0, 0, 0);
540
541    impl ResourceId<ChipsetDeviceHandleKind> for I440BxHostPciBridgeDeviceHandle {
542        const ID: &'static str = "i440bx-host-pci-bridge";
543    }
544}