chipset_device_resources/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Resource definitions for chipset devices.
5
6#![forbid(unsafe_code)]
7
8use async_trait::async_trait;
9use chipset_device::ChipsetDevice;
10use guestmem::GuestMemory;
11use inspect::InspectMut;
12use std::ops::RangeInclusive;
13use vm_resource::CanResolveTo;
14use vm_resource::kind::ChipsetDeviceHandleKind;
15use vmcore::device_state::ChangeDeviceState;
16use vmcore::line_interrupt::LineInterrupt;
17use vmcore::save_restore::ProtobufSaveRestore;
18use vmcore::vm_task::VmTaskDriverSource;
19use vmcore::vmtime::VmTimeSource;
20
21/// A unique identifier for a line set.
22#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
23pub struct LineSetId(&'static str);
24
25impl LineSetId {
26    /// Returns the name of the line set.
27    pub fn name(&self) -> &str {
28        self.0
29    }
30}
31
32/// Line set for device interrupts connected to the platform interrupt
33/// controller.
34pub const IRQ_LINE_SET: LineSetId = LineSetId("irq");
35/// Line set for ACPI general purpose events.
36pub const GPE0_LINE_SET: LineSetId = LineSetId("gpe0");
37/// Line set for the BSP's local interrupts (LINT0/1) on x86.
38pub const BSP_LINT_LINE_SET: LineSetId = LineSetId("bsp_lint");
39
40impl CanResolveTo<ResolvedChipsetDevice> for ChipsetDeviceHandleKind {
41    type Input<'a> = ResolveChipsetDeviceHandleParams<'a>;
42}
43
44/// Parameters used when resolving a resource with kind
45/// [`ChipsetDeviceHandleKind`].
46pub struct ResolveChipsetDeviceHandleParams<'a> {
47    /// The name of the device.
48    pub device_name: &'a str,
49    /// Guest memory for device DMA operations for untrusted devices.
50    pub guest_memory: &'a GuestMemory,
51    /// Guest memory for device DMA operations for trusted devices, which can
52    /// access encrypted memory on CVMs.
53    ///
54    /// For non-CVMs, this is the same as `guest_memory`.
55    pub encrypted_guest_memory: &'a GuestMemory,
56    /// The VM time source.
57    pub vmtime: &'a VmTimeSource,
58    /// Whether the VM is restoring from a saved state.
59    ///
60    /// FUTURE: remove this once devices have a state transition for "first
61    /// boot". Device authors: try to avoid taking a dependency on this. If
62    /// possible, delay any "first boot" initialization until it's really
63    /// needed.
64    pub is_restoring: bool,
65    /// An object to confiure the chipset device's connection to the platform.
66    pub configure: &'a mut dyn ConfigureChipsetDevice,
67    /// The task driver source for the VM.
68    pub task_driver_source: &'a VmTaskDriverSource,
69    /// Object to register for MMIO intercepts.
70    pub register_mmio: &'a mut (dyn chipset_device::mmio::RegisterMmioIntercept + Send),
71    /// Object to register for PIO intercepts.
72    pub register_pio: &'a mut (dyn chipset_device::pio::RegisterPortIoIntercept + Send),
73}
74
75/// A trait for configuring a chipset device's connection to the platform.
76pub trait ConfigureChipsetDevice: Send {
77    /// Creates a new line interrupt.
78    fn new_line(&mut self, id: LineSetId, name: &str, vector: u32) -> LineInterrupt;
79
80    /// Adds this device as a target for a range of line interrupts.
81    fn add_line_target(
82        &mut self,
83        id: LineSetId,
84        source_range: RangeInclusive<u32>,
85        target_start: u32,
86    );
87
88    /// Tags this device so that its save/restore routines will not be called.
89    fn omit_saved_state(&mut self);
90}
91
92#[async_trait]
93trait DynChipsetDevice: ChipsetDevice + ProtobufSaveRestore + InspectMut {
94    fn start(&mut self);
95    async fn stop(&mut self);
96    async fn reset(&mut self);
97}
98
99#[async_trait]
100impl<T: ChangeDeviceState + ChipsetDevice + ProtobufSaveRestore + InspectMut> DynChipsetDevice
101    for T
102{
103    fn start(&mut self) {
104        self.start()
105    }
106    async fn stop(&mut self) {
107        self.stop().await
108    }
109    async fn reset(&mut self) {
110        self.reset().await
111    }
112}
113
114/// A resolved chipset device resource.
115pub struct ResolvedChipsetDevice(pub ErasedChipsetDevice);
116
117/// A type-erased [`ChipsetDevice`].
118#[derive(InspectMut)]
119#[inspect(transparent(mut))]
120pub struct ErasedChipsetDevice(Box<dyn DynChipsetDevice>);
121
122impl<T: ChangeDeviceState + ChipsetDevice + ProtobufSaveRestore + InspectMut> From<T>
123    for ResolvedChipsetDevice
124{
125    fn from(value: T) -> Self {
126        Self(ErasedChipsetDevice(Box::new(value)))
127    }
128}
129
130impl ChangeDeviceState for ErasedChipsetDevice {
131    fn start(&mut self) {
132        self.0.start()
133    }
134
135    async fn stop(&mut self) {
136        self.0.stop().await
137    }
138
139    async fn reset(&mut self) {
140        self.0.reset().await
141    }
142}
143
144impl ChipsetDevice for ErasedChipsetDevice {
145    fn supports_pio(&mut self) -> Option<&mut dyn chipset_device::pio::PortIoIntercept> {
146        self.0.supports_pio()
147    }
148
149    fn supports_mmio(&mut self) -> Option<&mut dyn chipset_device::mmio::MmioIntercept> {
150        self.0.supports_mmio()
151    }
152
153    fn supports_pci(&mut self) -> Option<&mut dyn chipset_device::pci::PciConfigSpace> {
154        self.0.supports_pci()
155    }
156
157    fn supports_poll_device(&mut self) -> Option<&mut dyn chipset_device::poll_device::PollDevice> {
158        self.0.supports_poll_device()
159    }
160
161    fn supports_line_interrupt_target(
162        &mut self,
163    ) -> Option<&mut dyn chipset_device::interrupt::LineInterruptTarget> {
164        self.0.supports_line_interrupt_target()
165    }
166
167    fn supports_handle_eoi(&mut self) -> Option<&mut dyn chipset_device::interrupt::HandleEoi> {
168        self.0.supports_handle_eoi()
169    }
170
171    fn supports_acknowledge_pic_interrupt(
172        &mut self,
173    ) -> Option<&mut dyn chipset_device::interrupt::AcknowledgePicInterrupt> {
174        self.0.supports_acknowledge_pic_interrupt()
175    }
176}
177
178impl ProtobufSaveRestore for ErasedChipsetDevice {
179    fn save(
180        &mut self,
181    ) -> Result<vmcore::save_restore::SavedStateBlob, vmcore::save_restore::SaveError> {
182        self.0.save()
183    }
184
185    fn restore(
186        &mut self,
187        state: vmcore::save_restore::SavedStateBlob,
188    ) -> Result<(), vmcore::save_restore::RestoreError> {
189        self.0.restore(state)
190    }
191}