hvlite_defs/
config.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Configuration for the VM worker.
5
6use guid::Guid;
7use hvlite_pcat_locator::RomFileLocation;
8use input_core::InputData;
9use memory_range::MemoryRange;
10use mesh::MeshPayload;
11use mesh::payload::Protobuf;
12use net_backend_resources::mac_address::MacAddress;
13use std::fmt;
14use std::fs::File;
15use vm_resource::Resource;
16use vm_resource::kind::PciDeviceHandleKind;
17use vm_resource::kind::VirtioDeviceHandle;
18use vm_resource::kind::VmbusDeviceHandleKind;
19use vmgs_resources::VmgsResource;
20use vmotherboard::ChipsetDeviceHandle;
21use vmotherboard::options::BaseChipsetManifest;
22
23#[derive(MeshPayload, Debug)]
24pub struct Config {
25    pub load_mode: LoadMode,
26    pub floppy_disks: Vec<floppy_resources::FloppyDiskConfig>,
27    pub ide_disks: Vec<ide_resources::IdeDeviceConfig>,
28    pub pcie_root_complexes: Vec<PcieRootComplexConfig>,
29    pub vpci_devices: Vec<VpciDeviceConfig>,
30    pub memory: MemoryConfig,
31    pub processor_topology: ProcessorTopologyConfig,
32    pub hypervisor: HypervisorConfig,
33    pub chipset: BaseChipsetManifest,
34    pub vmbus: Option<VmbusConfig>,
35    pub vtl2_vmbus: Option<VmbusConfig>,
36    #[cfg(windows)]
37    pub kernel_vmnics: Vec<KernelVmNicConfig>,
38    pub input: mesh::Receiver<InputData>,
39    pub framebuffer: Option<framebuffer::Framebuffer>,
40    pub vga_firmware: Option<RomFileLocation>,
41    pub vtl2_gfx: bool,
42    pub virtio_console_pci: bool,
43    pub virtio_serial: Option<SerialPipes>,
44    pub virtio_devices: Vec<(VirtioBus, Resource<VirtioDeviceHandle>)>,
45    #[cfg(windows)]
46    pub vpci_resources: Vec<virt_whp::device::DeviceHandle>,
47    pub vmgs: Option<VmgsResource>,
48    pub secure_boot_enabled: bool,
49    pub custom_uefi_vars: firmware_uefi_custom_vars::CustomVars,
50    // TODO: move FirmwareEvent somewhere not GED-specific.
51    pub firmware_event_send: Option<mesh::Sender<get_resources::ged::FirmwareEvent>>,
52    pub debugger_rpc: Option<mesh::Receiver<vmm_core_defs::debug_rpc::DebugRequest>>,
53    pub vmbus_devices: Vec<(DeviceVtl, Resource<VmbusDeviceHandleKind>)>,
54    pub chipset_devices: Vec<ChipsetDeviceHandle>,
55    pub generation_id_recv: Option<mesh::Receiver<[u8; 16]>>,
56    // This is used for testing. TODO: resourcify, and also store this in VMGS.
57    pub rtc_delta_milliseconds: i64,
58    /// allow the guest to reset without notifying the client
59    pub automatic_guest_reset: bool,
60}
61
62// ARM64 needs a larger low gap.
63const DEFAULT_LOW_MMAP_GAP_SIZE_X86: u64 = 1024 * 1024 * 128;
64const DEFAULT_LOW_MMAP_GAP_SIZE_AARCH64: u64 = 1024 * 1024 * 512;
65
66/// Default mmio gaps for an x86 partition.
67pub const DEFAULT_MMIO_GAPS_X86: [MemoryRange; 2] = [
68    MemoryRange::new(0x1_0000_0000 - DEFAULT_LOW_MMAP_GAP_SIZE_X86..0x1_0000_0000), // nMB just below 4GB
69    MemoryRange::new(0xF_E000_0000..0x10_0000_0000), // 512MB just below 64GB, then up to 64GB
70];
71
72/// Default mmio gaps for x86 if VTL2 is enabled.
73pub const DEFAULT_MMIO_GAPS_X86_WITH_VTL2: [MemoryRange; 3] = [
74    MemoryRange::new(0x1_0000_0000 - DEFAULT_LOW_MMAP_GAP_SIZE_X86..0x1_0000_0000), // nMB just below 4GB
75    MemoryRange::new(0xF_E000_0000..0x20_0000_0000), // 512MB just below 64GB, then up to 128GB
76    MemoryRange::new(0x20_0000_0000..0x20_4000_0000), // 128GB to 129 GB
77];
78
79/// Default mmio gaps for an aarch64 partition.
80pub const DEFAULT_MMIO_GAPS_AARCH64: [MemoryRange; 2] = [
81    MemoryRange::new(0x1_0000_0000 - DEFAULT_LOW_MMAP_GAP_SIZE_AARCH64..0x1_0000_0000), // nMB just below 4GB
82    MemoryRange::new(0xF_E000_0000..0x10_0000_0000), // 512MB just below 64GB, then up to 64GB
83];
84
85/// Default mmio gaps for aarch64 if VTL2 is enabled.
86pub const DEFAULT_MMIO_GAPS_AARCH64_WITH_VTL2: [MemoryRange; 3] = [
87    MemoryRange::new(0x1_0000_0000 - DEFAULT_LOW_MMAP_GAP_SIZE_AARCH64..0x1_0000_0000), // nMB just below 4GB
88    MemoryRange::new(0xF_E000_0000..0x20_0000_0000), // 512MB just below 64GB, then up to 128GB
89    MemoryRange::new(0x20_0000_0000..0x20_4000_0000), // 128GB to 129 GB
90];
91
92pub const DEFAULT_GIC_DISTRIBUTOR_BASE: u64 = 0xFFFF_0000;
93// The KVM in-kernel vGICv3 requires the distributor and redistributor bases be 64KiB aligned.
94pub const DEFAULT_GIC_REDISTRIBUTORS_BASE: u64 = if cfg!(target_os = "linux") {
95    0xEFFF_0000
96} else {
97    0xEFFE_E000
98};
99
100pub const DEFAULT_PCIE_ECAM_BASE: u64 = 0x8_0000_0000; // 32GB, size depends on configuration
101
102#[derive(MeshPayload, Debug)]
103pub enum LoadMode {
104    Linux {
105        kernel: File,
106        initrd: Option<File>,
107        cmdline: String,
108        enable_serial: bool,
109        custom_dsdt: Option<Vec<u8>>,
110    },
111    Uefi {
112        firmware: File,
113        enable_debugging: bool,
114        enable_memory_protections: bool,
115        disable_frontpage: bool,
116        enable_tpm: bool,
117        enable_battery: bool,
118        enable_serial: bool,
119        enable_vpci_boot: bool,
120        uefi_console_mode: Option<UefiConsoleMode>,
121        default_boot_always_attempt: bool,
122    },
123    Pcat {
124        firmware: RomFileLocation,
125        boot_order: [PcatBootDevice; 4],
126    },
127    Igvm {
128        file: File,
129        cmdline: String,
130        vtl2_base_address: Vtl2BaseAddressType,
131        com_serial: Option<SerialInformation>,
132    },
133    None,
134}
135
136#[derive(Debug, Clone, Copy, MeshPayload)]
137pub struct SerialInformation {
138    pub io_port: u16,
139    pub irq: u32,
140}
141
142/// Different types to specify the base address for the VTL2 region of the IGVM
143/// file.
144#[derive(Debug, Clone, Copy, MeshPayload)]
145pub enum Vtl2BaseAddressType {
146    /// Use the addresses specified in the file. The IGVM file does not need to
147    /// support relocations.
148    File,
149    /// Put VTL2 at the specified address. The IGVM file must support
150    /// relocations.
151    Absolute(u64),
152    /// Use the specified range in the supplied MemoryLayout, as the caller has
153    /// created a specific range for VTL2. The IGVM file must support
154    /// relocations.
155    ///
156    /// An optional size may be specified to override the size describing VTL2
157    /// provided in the IGVM file. It must be larger than the IGVM file provided
158    /// size.
159    MemoryLayout { size: Option<u64> },
160    /// Tell VTL2 to allocate out it's own memory. This will load the file at
161    /// the base address specified in the file, and the host will tell VTL2 the
162    /// size of memory to allocate for itself.
163    ///
164    /// An optional size may be specified to override the size describing VTL2
165    /// provided in the IGVM file. It must be larger than the IGVM file provided
166    /// size.
167    Vtl2Allocate { size: Option<u64> },
168}
169
170#[derive(Debug, MeshPayload)]
171pub struct PcieRootComplexConfig {
172    pub index: u32,
173    pub name: String,
174    pub segment: u16,
175    pub start_bus: u8,
176    pub end_bus: u8,
177    pub low_mmio_size: u32,
178    pub high_mmio_size: u64,
179    pub ports: Vec<PcieRootPortConfig>,
180}
181
182#[derive(Debug, MeshPayload)]
183pub struct PcieRootPortConfig {
184    pub name: String,
185}
186
187#[derive(Debug, MeshPayload)]
188pub struct VpciDeviceConfig {
189    pub vtl: DeviceVtl,
190    /// The ID of the device. Vpci devices are identified by a portion of `data2` and `data3` of the
191    /// instance ID, which is used to generate the guest-visible device ID.
192    pub instance_id: Guid,
193    pub resource: Resource<PciDeviceHandleKind>,
194}
195
196#[derive(Debug, Protobuf)]
197pub struct ProcessorTopologyConfig {
198    pub proc_count: u32,
199    pub vps_per_socket: Option<u32>,
200    pub enable_smt: Option<bool>,
201    pub arch: Option<ArchTopologyConfig>,
202}
203
204#[derive(Debug, Protobuf, Default, Clone)]
205pub struct X86TopologyConfig {
206    pub apic_id_offset: u32,
207    pub x2apic: X2ApicConfig,
208}
209
210#[derive(Debug, Default, Copy, Clone, Protobuf)]
211pub enum X2ApicConfig {
212    #[default]
213    /// Support the X2APIC if recommended by the hypervisor or if needed by the
214    /// topology configuration.
215    Auto,
216    /// Support the X2APIC, and automatically enable it if needed to address all
217    /// processors.
218    Supported,
219    /// Do not support the X2APIC.
220    Unsupported,
221    /// Support and enable the X2APIC.
222    Enabled,
223}
224
225#[derive(Debug, Protobuf, Default, Clone)]
226pub enum PmuGsivConfig {
227    #[default]
228    /// Use the hypervisor's platform GSIV value for the PMU.
229    Platform,
230    /// Use the specified GSIV value for the PMU.
231    Gsiv(u32),
232}
233
234#[derive(Debug, Protobuf, Default, Clone)]
235pub struct Aarch64TopologyConfig {
236    pub gic_config: Option<GicConfig>,
237    pub pmu_gsiv: PmuGsivConfig,
238}
239
240#[derive(Debug, Protobuf, Clone)]
241pub struct GicConfig {
242    pub gic_distributor_base: u64,
243    pub gic_redistributors_base: u64,
244}
245
246#[derive(Debug, Protobuf, Clone)]
247pub enum ArchTopologyConfig {
248    X86(X86TopologyConfig),
249    Aarch64(Aarch64TopologyConfig),
250}
251
252#[derive(Debug, MeshPayload)]
253pub struct MemoryConfig {
254    pub mem_size: u64,
255    pub mmio_gaps: Vec<MemoryRange>,
256    pub prefetch_memory: bool,
257    pub pcie_ecam_base: u64,
258}
259
260#[derive(Debug, MeshPayload, Default)]
261pub struct VmbusConfig {
262    pub vsock_listener: Option<unix_socket::UnixListener>,
263    pub vsock_path: Option<String>,
264    pub vmbus_max_version: Option<u32>,
265    #[cfg(windows)]
266    pub vmbusproxy_handle: Option<vmbus_proxy::ProxyHandle>,
267    pub vtl2_redirect: bool,
268}
269
270#[derive(Debug, MeshPayload, Default)]
271pub struct HypervisorConfig {
272    pub with_hv: bool,
273    pub user_mode_hv_enlightenments: bool,
274    pub user_mode_apic: bool,
275    pub with_vtl2: Option<Vtl2Config>,
276    pub with_isolation: Option<IsolationType>,
277}
278
279#[derive(Debug, Copy, Clone, MeshPayload)]
280pub enum Hypervisor {
281    Kvm,
282    MsHv,
283    Whp,
284    Hvf,
285}
286
287impl fmt::Display for Hypervisor {
288    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
289        f.pad(match self {
290            Self::Kvm => "kvm",
291            Self::MsHv => "mshv",
292            Self::Whp => "whp",
293            Self::Hvf => "hvf",
294        })
295    }
296}
297
298/// Input and output for a connected serial port.
299#[derive(Debug, MeshPayload)]
300pub struct SerialPipes {
301    /// Input for a serial port.
302    ///
303    /// If the file reaches EOF, then the serial port will report carrier drop
304    /// to the guest. Use `None` when the port should remain connected
305    /// indefinitely.
306    pub input: Option<File>,
307    /// Output for a serial port.
308    ///
309    /// If the file write fails with [`std::io::ErrorKind::BrokenPipe`], then
310    /// the serial port will report carrier drop to the guest.
311    ///
312    /// `None` is equivalent to `/dev/null`--it will silently succeed all
313    /// writes.
314    pub output: Option<File>,
315}
316
317impl SerialPipes {
318    pub fn try_clone(&self) -> std::io::Result<Self> {
319        Ok(Self {
320            input: self.input.as_ref().map(File::try_clone).transpose()?,
321            output: self.output.as_ref().map(File::try_clone).transpose()?,
322        })
323    }
324}
325
326#[derive(Debug, MeshPayload)]
327pub struct KernelVmNicConfig {
328    pub instance_id: Guid,
329    pub mac_address: MacAddress,
330    pub switch_port_id: SwitchPortId,
331}
332
333#[derive(Clone, Debug, MeshPayload)]
334pub struct SwitchPortId {
335    pub switch: Guid,
336    pub port: Guid,
337}
338
339pub const DEFAULT_PCAT_BOOT_ORDER: [PcatBootDevice; 4] = [
340    PcatBootDevice::Optical,
341    PcatBootDevice::HardDrive,
342    PcatBootDevice::Network,
343    PcatBootDevice::Floppy,
344];
345
346#[derive(MeshPayload, Debug, Clone, Copy, PartialEq)]
347pub enum PcatBootDevice {
348    Floppy,
349    HardDrive,
350    Optical,
351    Network,
352}
353
354#[derive(Eq, PartialEq, Debug, Copy, Clone, MeshPayload)]
355pub enum VirtioBus {
356    Mmio,
357    Pci,
358}
359
360/// Policy for the partition when mapping VTL0 memory late.
361#[derive(Eq, PartialEq, Debug, Copy, Clone, MeshPayload)]
362pub enum LateMapVtl0MemoryPolicy {
363    /// Halt execution of the VP if VTL0 memory is accessed.
364    Halt,
365    /// Log the error but emulate the access with the instruction emulator.
366    Log,
367    /// Inject an exception into the guest.
368    InjectException,
369}
370
371impl From<LateMapVtl0MemoryPolicy> for virt::LateMapVtl0MemoryPolicy {
372    fn from(value: LateMapVtl0MemoryPolicy) -> Self {
373        match value {
374            LateMapVtl0MemoryPolicy::Halt => virt::LateMapVtl0MemoryPolicy::Halt,
375            LateMapVtl0MemoryPolicy::Log => virt::LateMapVtl0MemoryPolicy::Log,
376            LateMapVtl0MemoryPolicy::InjectException => {
377                virt::LateMapVtl0MemoryPolicy::InjectException
378            }
379        }
380    }
381}
382
383/// Configuration for VTL2.
384///
385/// NOTE: This is distinct from `virt::Vtl2Config` to keep an abstraction
386/// between the virt crate and this crate. Users should not be specifying
387/// virt crate configuration directly.
388#[derive(Debug, Clone, MeshPayload)]
389pub struct Vtl2Config {
390    /// Enable the VTL0 alias map. This maps VTL0's view of memory in VTL2 at
391    /// the highest legal physical address bit.
392    pub vtl0_alias_map: bool,
393    /// If set, map VTL0 memory late after VTL2 has started. The current
394    /// heuristic is to defer mapping VTL0 memory until the first
395    /// `HvModifyVtlProtectionMask` hypercall is made.
396    pub late_map_vtl0_memory: Option<LateMapVtl0MemoryPolicy>,
397}
398
399// Isolation type for a partition.
400#[derive(Eq, PartialEq, Debug, Copy, Clone, MeshPayload)]
401pub enum IsolationType {
402    Vbs,
403}
404
405impl From<IsolationType> for virt::IsolationType {
406    fn from(value: IsolationType) -> Self {
407        match value {
408            IsolationType::Vbs => Self::Vbs,
409        }
410    }
411}
412
413/// Which VTL to assign a particular device to.
414#[derive(Copy, Clone, Debug, PartialEq, Eq, MeshPayload)]
415pub enum DeviceVtl {
416    Vtl0,
417    Vtl1,
418    Vtl2,
419}
420
421#[derive(Copy, Clone, Debug, MeshPayload)]
422pub enum UefiConsoleMode {
423    Default,
424    Com1,
425    Com2,
426    None,
427}