arch/
lib.rs

1// Copyright 2018 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Virtual machine architecture support code.
6
7pub mod android;
8pub mod fdt;
9pub mod pstore;
10pub mod serial;
11
12pub mod sys;
13
14use std::collections::BTreeMap;
15use std::error::Error as StdError;
16use std::fs::File;
17use std::io;
18use std::ops::Deref;
19use std::path::PathBuf;
20use std::str::FromStr;
21use std::sync::mpsc;
22use std::sync::mpsc::SendError;
23use std::sync::Arc;
24
25use acpi_tables::sdt::SDT;
26use base::syslog;
27use base::AsRawDescriptors;
28use base::FileGetLen;
29use base::FileReadWriteAtVolatile;
30use base::RecvTube;
31use base::SendTube;
32use base::Tube;
33use devices::virtio::VirtioDevice;
34use devices::BarRange;
35use devices::Bus;
36use devices::BusDevice;
37use devices::BusDeviceObj;
38use devices::BusError;
39use devices::BusResumeDevice;
40use devices::FwCfgParameters;
41use devices::GpeScope;
42use devices::HotPlugBus;
43use devices::IrqChip;
44use devices::IrqEventSource;
45use devices::PciAddress;
46use devices::PciBus;
47use devices::PciDevice;
48use devices::PciDeviceError;
49use devices::PciInterruptPin;
50use devices::PciRoot;
51use devices::PciRootCommand;
52use devices::PreferredIrq;
53#[cfg(any(target_os = "android", target_os = "linux"))]
54use devices::ProxyDevice;
55use devices::SerialHardware;
56use devices::SerialParameters;
57pub use fdt::apply_device_tree_overlays;
58pub use fdt::DtbOverlay;
59#[cfg(feature = "gdb")]
60use gdbstub::arch::Arch;
61pub use hypervisor::CpuConfigArch;
62pub use hypervisor::HypervisorArch;
63use hypervisor::MemCacheType;
64pub use hypervisor::VcpuArch;
65pub use hypervisor::VcpuInitArch;
66use hypervisor::Vm;
67pub use hypervisor::VmArch;
68#[cfg(windows)]
69use jail::FakeMinijailStub as Minijail;
70#[cfg(any(target_os = "android", target_os = "linux"))]
71use minijail::Minijail;
72use remain::sorted;
73use resources::SystemAllocator;
74use resources::SystemAllocatorConfig;
75use serde::de::Visitor;
76use serde::Deserialize;
77use serde::Serialize;
78use serde_keyvalue::FromKeyValues;
79pub use serial::add_serial_devices;
80pub use serial::get_serial_cmdline;
81pub use serial::set_default_serial_parameters;
82pub use serial::GetSerialCmdlineError;
83pub use serial::SERIAL_ADDR;
84use sync::Condvar;
85use sync::Mutex;
86use thiserror::Error;
87use uuid::Uuid;
88use vm_control::BatControl;
89use vm_control::BatteryType;
90use vm_control::PmResource;
91use vm_memory::GuestAddress;
92use vm_memory::GuestMemory;
93use vm_memory::GuestMemoryError;
94use vm_memory::MemoryRegionInformation;
95use vm_memory::MemoryRegionOptions;
96
97cfg_if::cfg_if! {
98    if #[cfg(target_arch = "aarch64")] {
99        pub use devices::IrqChipAArch64 as IrqChipArch;
100        #[cfg(feature = "gdb")]
101        pub use gdbstub_arch::aarch64::AArch64 as GdbArch;
102    } else if #[cfg(target_arch = "riscv64")] {
103        pub use devices::IrqChipRiscv64 as IrqChipArch;
104        #[cfg(feature = "gdb")]
105        pub use gdbstub_arch::riscv::Riscv64 as GdbArch;
106    } else if #[cfg(target_arch = "x86_64")] {
107        pub use devices::IrqChipX86_64 as IrqChipArch;
108        #[cfg(feature = "gdb")]
109        pub use gdbstub_arch::x86::X86_64_SSE as GdbArch;
110    }
111}
112
113pub enum VmImage {
114    Kernel(File),
115    Bios(File),
116}
117
118#[derive(Clone, Debug, Deserialize, Serialize, FromKeyValues, PartialEq, Eq)]
119#[serde(deny_unknown_fields, rename_all = "kebab-case")]
120pub struct Pstore {
121    pub path: PathBuf,
122    pub size: u32,
123}
124
125#[derive(Clone, Copy, Debug, Serialize, Deserialize, FromKeyValues)]
126#[serde(deny_unknown_fields, rename_all = "kebab-case")]
127pub enum FdtPosition {
128    /// At the start of RAM.
129    Start,
130    /// Near the end of RAM.
131    End,
132    /// After the payload, with some padding for alignment.
133    AfterPayload,
134}
135
136/// Set of CPU cores.
137#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
138pub struct CpuSet(Vec<usize>);
139
140impl CpuSet {
141    pub fn new<I: IntoIterator<Item = usize>>(cpus: I) -> Self {
142        CpuSet(cpus.into_iter().collect())
143    }
144
145    pub fn iter(&self) -> std::slice::Iter<'_, usize> {
146        self.0.iter()
147    }
148}
149
150impl FromIterator<usize> for CpuSet {
151    fn from_iter<T>(iter: T) -> Self
152    where
153        T: IntoIterator<Item = usize>,
154    {
155        CpuSet::new(iter)
156    }
157}
158
159#[cfg(target_arch = "aarch64")]
160fn sve_auto_default() -> bool {
161    true
162}
163
164/// The SVE config for Vcpus.
165#[cfg(target_arch = "aarch64")]
166#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
167#[serde(deny_unknown_fields, rename_all = "kebab-case")]
168pub struct SveConfig {
169    /// Detect if SVE is available and enable accordingly. `enable` is ignored if auto is true
170    #[serde(default = "sve_auto_default")]
171    pub auto: bool,
172}
173
174#[cfg(target_arch = "aarch64")]
175impl Default for SveConfig {
176    fn default() -> Self {
177        SveConfig {
178            auto: sve_auto_default(),
179        }
180    }
181}
182
183/// FFA config
184// For now this is limited to android, will be opened to other aarch64 based pVMs after
185// corresponding kernel APIs are upstreamed.
186#[cfg(all(target_os = "android", target_arch = "aarch64"))]
187#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize, FromKeyValues)]
188#[serde(deny_unknown_fields, rename_all = "kebab-case")]
189pub struct FfaConfig {
190    /// Just enable FFA, don't care about the negotiated version.
191    #[serde(default)]
192    pub auto: bool,
193}
194
195fn parse_cpu_range(s: &str, cpuset: &mut Vec<usize>) -> Result<(), String> {
196    fn parse_cpu(s: &str) -> Result<usize, String> {
197        s.parse()
198            .map_err(|_| format!("invalid CPU index {s} - index must be a non-negative integer"))
199    }
200
201    let (first_cpu, last_cpu) = match s.split_once('-') {
202        Some((first_cpu, last_cpu)) => {
203            let first_cpu = parse_cpu(first_cpu)?;
204            let last_cpu = parse_cpu(last_cpu)?;
205
206            if last_cpu < first_cpu {
207                return Err(format!(
208                    "invalid CPU range {s} - ranges must be from low to high"
209                ));
210            }
211            (first_cpu, last_cpu)
212        }
213        None => {
214            let cpu = parse_cpu(s)?;
215            (cpu, cpu)
216        }
217    };
218
219    cpuset.extend(first_cpu..=last_cpu);
220
221    Ok(())
222}
223
224impl FromStr for CpuSet {
225    type Err = String;
226
227    fn from_str(s: &str) -> Result<Self, Self::Err> {
228        let mut cpuset = Vec::new();
229        for part in s.split(',') {
230            parse_cpu_range(part, &mut cpuset)?;
231        }
232        Ok(CpuSet::new(cpuset))
233    }
234}
235
236impl Deref for CpuSet {
237    type Target = Vec<usize>;
238
239    fn deref(&self) -> &Self::Target {
240        &self.0
241    }
242}
243
244impl IntoIterator for CpuSet {
245    type Item = usize;
246    type IntoIter = std::vec::IntoIter<Self::Item>;
247
248    fn into_iter(self) -> Self::IntoIter {
249        self.0.into_iter()
250    }
251}
252
253/// Selects the interface for guest-controlled power management of assigned devices.
254#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize)]
255pub enum DevicePowerManagerConfig {
256    /// Uses the protected KVM hypercall interface.
257    /// This feature is currently only present in Android AArch64 kernels.
258    PkvmHvc,
259}
260
261impl FromStr for DevicePowerManagerConfig {
262    type Err = String;
263
264    fn from_str(s: &str) -> Result<Self, Self::Err> {
265        match s {
266            "pkvm-hvc" => Ok(Self::PkvmHvc),
267            _ => Err(format!("DevicePowerManagerConfig '{s}' not supported")),
268        }
269    }
270}
271
272/// Deserializes a `CpuSet` from a sequence which elements can either be integers, or strings
273/// representing CPU ranges (e.g. `5-8`).
274impl<'de> Deserialize<'de> for CpuSet {
275    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
276    where
277        D: serde::Deserializer<'de>,
278    {
279        struct CpuSetVisitor;
280        impl<'de> Visitor<'de> for CpuSetVisitor {
281            type Value = CpuSet;
282
283            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
284                formatter.write_str("CpuSet")
285            }
286
287            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
288            where
289                A: serde::de::SeqAccess<'de>,
290            {
291                #[derive(Deserialize)]
292                #[serde(untagged)]
293                enum CpuSetValue<'a> {
294                    Single(usize),
295                    Range(&'a str),
296                }
297
298                let mut cpus = Vec::new();
299                while let Some(cpuset) = seq.next_element::<CpuSetValue>()? {
300                    match cpuset {
301                        CpuSetValue::Single(cpu) => cpus.push(cpu),
302                        CpuSetValue::Range(range) => {
303                            parse_cpu_range(range, &mut cpus).map_err(serde::de::Error::custom)?;
304                        }
305                    }
306                }
307
308                Ok(CpuSet::new(cpus))
309            }
310        }
311
312        deserializer.deserialize_seq(CpuSetVisitor)
313    }
314}
315
316/// Serializes a `CpuSet` into a sequence of integers and strings representing CPU ranges.
317impl Serialize for CpuSet {
318    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
319    where
320        S: serde::Serializer,
321    {
322        use serde::ser::SerializeSeq;
323
324        let mut seq = serializer.serialize_seq(None)?;
325
326        // Factorize ranges into "a-b" strings.
327        let mut serialize_range = |start: usize, end: usize| -> Result<(), S::Error> {
328            if start == end {
329                seq.serialize_element(&start)?;
330            } else {
331                seq.serialize_element(&format!("{start}-{end}"))?;
332            }
333
334            Ok(())
335        };
336
337        // Current range.
338        let mut range = None;
339        for core in &self.0 {
340            range = match range {
341                None => Some((core, core)),
342                Some((start, end)) if *end == *core - 1 => Some((start, core)),
343                Some((start, end)) => {
344                    serialize_range(*start, *end)?;
345                    Some((core, core))
346                }
347            };
348        }
349
350        if let Some((start, end)) = range {
351            serialize_range(*start, *end)?;
352        }
353
354        seq.end()
355    }
356}
357
358/// Mapping of guest VCPU threads to host CPU cores.
359#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
360pub enum VcpuAffinity {
361    /// All VCPU threads will be pinned to the same set of host CPU cores.
362    Global(CpuSet),
363    /// Each VCPU may be pinned to a set of host CPU cores.
364    /// The map key is a guest VCPU index, and the corresponding value is the set of
365    /// host CPU indices that the VCPU thread will be allowed to run on.
366    /// If a VCPU index is not present in the map, its affinity will not be set.
367    PerVcpu(BTreeMap<usize, CpuSet>),
368}
369
370/// Memory region with optional size.
371#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, FromKeyValues)]
372pub struct MemoryRegionConfig {
373    pub start: u64,
374    pub size: Option<u64>,
375}
376
377/// General PCI config.
378#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize, FromKeyValues)]
379pub struct PciConfig {
380    /// region for PCI Configuration Access Mechanism
381    #[cfg(target_arch = "aarch64")]
382    pub cam: Option<MemoryRegionConfig>,
383    /// region for PCIe Enhanced Configuration Access Mechanism
384    #[cfg(target_arch = "x86_64")]
385    pub ecam: Option<MemoryRegionConfig>,
386    /// region for non-prefetchable PCI device memory below 4G
387    pub mem: Option<MemoryRegionConfig>,
388}
389
390pub const DEFAULT_CPU_CAPACITY: u32 = 1024;
391
392#[sorted]
393#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
394pub struct VcpuProperties {
395    pub capacity: Option<u32>,
396    pub dynamic_power_coefficient: Option<u32>,
397    pub frequencies: Vec<u32>,
398    #[cfg(all(
399        target_arch = "aarch64",
400        any(target_os = "android", target_os = "linux")
401    ))]
402    pub normalized_cpu_ipc_ratio: Option<u32>,
403    #[cfg(all(
404        target_arch = "aarch64",
405        any(target_os = "android", target_os = "linux")
406    ))]
407    pub vcpu_domain: Option<u32>,
408    #[cfg(all(
409        target_arch = "aarch64",
410        any(target_os = "android", target_os = "linux")
411    ))]
412    pub vcpu_domain_path: Option<PathBuf>,
413}
414
415/// Derives base VCPU properties from various config fields.
416pub fn derive_vcpu_properties(
417    vcpu_count: usize,
418    vcpu_capacity: &std::collections::BTreeMap<usize, u32>,
419    dynamic_power_coefficient: &std::collections::BTreeMap<usize, u32>,
420    vcpu_frequencies: &std::collections::BTreeMap<usize, Vec<u32>>,
421    #[cfg(all(
422        target_arch = "aarch64",
423        any(target_os = "android", target_os = "linux")
424    ))]
425    normalized_cpu_ipc_ratio: &std::collections::BTreeMap<usize, u32>,
426    #[cfg(all(
427        target_arch = "aarch64",
428        any(target_os = "android", target_os = "linux")
429    ))]
430    vcpu_domain: &std::collections::BTreeMap<usize, u32>,
431    #[cfg(all(
432        target_arch = "aarch64",
433        any(target_os = "android", target_os = "linux")
434    ))]
435    vcpu_domain_path: &std::collections::BTreeMap<usize, std::path::PathBuf>,
436) -> std::collections::BTreeMap<usize, VcpuProperties> {
437    let mut vcpu_properties = std::collections::BTreeMap::new();
438    for vcpu_id in 0..vcpu_count {
439        let vcpu_prop_capacity = vcpu_capacity.get(&vcpu_id).copied();
440
441        vcpu_properties.insert(
442            vcpu_id,
443            VcpuProperties {
444                capacity: vcpu_prop_capacity,
445                frequencies: vcpu_frequencies.get(&vcpu_id).cloned().unwrap_or_default(),
446                dynamic_power_coefficient: dynamic_power_coefficient.get(&vcpu_id).copied(),
447                #[cfg(all(
448                    target_arch = "aarch64",
449                    any(target_os = "android", target_os = "linux")
450                ))]
451                normalized_cpu_ipc_ratio: normalized_cpu_ipc_ratio.get(&vcpu_id).copied(),
452                #[cfg(all(
453                    target_arch = "aarch64",
454                    any(target_os = "android", target_os = "linux")
455                ))]
456                vcpu_domain: vcpu_domain.get(&vcpu_id).copied(),
457                #[cfg(all(
458                    target_arch = "aarch64",
459                    any(target_os = "android", target_os = "linux")
460                ))]
461                vcpu_domain_path: vcpu_domain_path.get(&vcpu_id).cloned(),
462            },
463        );
464    }
465    vcpu_properties
466}
467
468/// Holds the pieces needed to build a VM. Passed to `build_vm` in the `LinuxArch` trait below to
469/// create a `RunnableLinuxVm`.
470#[sorted]
471pub struct VmComponents {
472    pub acpi_sdts: Vec<SDT>,
473    pub android_fstab: Option<File>,
474    pub boot_cpu: usize,
475    pub bootorder_fw_cfg_blob: Vec<u8>,
476    #[cfg(target_arch = "x86_64")]
477    pub break_linux_pci_config_io: bool,
478
479    pub delay_rt: bool,
480    pub dev_pm: Option<DevicePowerManagerConfig>,
481    pub extra_kernel_params: Vec<String>,
482    #[cfg(target_arch = "x86_64")]
483    pub force_s2idle: bool,
484    pub fw_cfg_enable: bool,
485    pub fw_cfg_parameters: Vec<FwCfgParameters>,
486    pub host_cpu_topology: bool,
487    pub hugepages: bool,
488    pub hv_cfg: hypervisor::Config,
489    pub initrd_image: Option<File>,
490    pub itmt: bool,
491    pub memory_size: u64,
492    #[cfg(target_arch = "aarch64")]
493    pub nested: hypervisor::NestedMode,
494    pub no_i8042: bool,
495    pub no_rtc: bool,
496    pub no_smt: bool,
497
498    pub pci_config: PciConfig,
499    pub pflash_block_size: u32,
500    pub pflash_image: Option<File>,
501    pub pstore: Option<Pstore>,
502    /// A file to load as pVM firmware. Must be `Some` iff
503    /// `hv_cfg.protection_type == ProtectionType::UnprotectedWithFirmware`.
504    pub pvm_fw: Option<File>,
505    pub rt_cpus: CpuSet,
506    #[cfg(target_arch = "x86_64")]
507    pub smbios: SmbiosOptions,
508    pub smccc_trng: bool,
509    #[cfg(target_arch = "aarch64")]
510    pub sve_config: SveConfig,
511    pub swiotlb: Option<u64>,
512    pub vcpu_affinity: Option<VcpuAffinity>,
513    /// List of vCPU clusters, mapped from pCPU clusters.
514    pub vcpu_clusters: Vec<CpuSet>,
515    pub vcpu_properties: BTreeMap<usize, VcpuProperties>,
516    #[cfg(any(target_os = "android", target_os = "linux"))]
517    pub vfio_platform_pm: bool,
518    #[cfg(all(
519        target_arch = "aarch64",
520        any(target_os = "android", target_os = "linux")
521    ))]
522    pub virt_cpufreq_v2: bool,
523    pub vm_image: VmImage,
524}
525
526/// Holds the elements needed to run a Linux VM. Created by `build_vm`.
527#[sorted]
528pub struct RunnableLinuxVm {
529    pub bat_control: Option<BatControl>,
530    pub delay_rt: bool,
531    pub devices_thread: Option<std::thread::JoinHandle<()>>,
532    pub hotplug_bus: BTreeMap<u8, Arc<Mutex<dyn HotPlugBus>>>,
533    pub hypercall_bus: Arc<Bus>,
534    pub io_bus: Arc<Bus>,
535    pub irq_chip: Arc<dyn IrqChipArch>,
536    pub mmio_bus: Arc<Bus>,
537    pub no_smt: bool,
538    pub pid_debug_label_map: BTreeMap<u32, String>,
539    #[cfg(any(target_os = "android", target_os = "linux"))]
540    pub platform_devices: Vec<Arc<Mutex<dyn BusDevice>>>,
541    pub pm: Option<Arc<Mutex<dyn PmResource + Send>>>,
542    /// Devices to be notified before the system resumes from the S3 suspended state.
543    pub resume_notify_devices: Vec<Arc<Mutex<dyn BusResumeDevice>>>,
544    pub root_config: Arc<Mutex<PciRoot>>,
545    pub rt_cpus: CpuSet,
546    pub suspend_tube: (Arc<Mutex<SendTube>>, RecvTube),
547    pub vcpu_affinity: Option<VcpuAffinity>,
548    pub vcpu_count: usize,
549    pub vcpu_init: Vec<VcpuInitArch>,
550    /// If vcpus is None, then it's the responsibility of the vcpu thread to create vcpus.
551    /// If it's Some, then `build_vm` already created the vcpus.
552    pub vcpus: Option<Vec<Arc<dyn VcpuArch>>>,
553    pub vm: Arc<dyn VmArch>,
554    pub vm_request_tubes: Vec<Tube>,
555}
556
557/// The device and optional jail.
558pub struct VirtioDeviceStub {
559    pub dev: Box<dyn VirtioDevice>,
560    pub jail: Option<Minijail>,
561}
562
563/// Trait which is implemented for each Linux Architecture in order to
564/// set up the memory, cpus, and system devices and to boot the kernel.
565pub trait LinuxArch {
566    type Error: StdError;
567    type ArchMemoryLayout;
568
569    /// Decide architecture specific memory layout details to be used by later stages of the VM
570    /// setup.
571    fn arch_memory_layout(
572        components: &VmComponents,
573    ) -> std::result::Result<Self::ArchMemoryLayout, Self::Error>;
574
575    /// Returns a Vec of the valid memory addresses as pairs of address and length. These should be
576    /// used to configure the `GuestMemory` structure for the platform.
577    ///
578    /// # Arguments
579    ///
580    /// * `components` - Parts used to determine the memory layout.
581    fn guest_memory_layout(
582        components: &VmComponents,
583        arch_memory_layout: &Self::ArchMemoryLayout,
584        hypervisor: &impl hypervisor::Hypervisor,
585    ) -> std::result::Result<Vec<(GuestAddress, u64, MemoryRegionOptions)>, Self::Error>;
586
587    /// Gets the configuration for a new `SystemAllocator` that fits the given `Vm`'s memory layout.
588    ///
589    /// This is the per-architecture template for constructing the `SystemAllocator`. Platform
590    /// agnostic modifications may be made to this configuration, but the final `SystemAllocator`
591    /// will be at least as strict as this configuration.
592    ///
593    /// # Arguments
594    ///
595    /// * `vm` - The virtual machine to be used as a template for the `SystemAllocator`.
596    fn get_system_allocator_config(
597        vm: &dyn Vm,
598        arch_memory_layout: &Self::ArchMemoryLayout,
599    ) -> SystemAllocatorConfig;
600
601    /// Takes `VmComponents` and generates a `RunnableLinuxVm`.
602    ///
603    /// # Arguments
604    ///
605    /// * `components` - Parts to use to build the VM.
606    /// * `vm_evt_wrtube` - Tube used by sub-devices to request that crosvm exit because guest wants
607    ///   to stop/shut down or requested reset.
608    /// * `system_allocator` - Allocator created by this trait's implementation of
609    ///   `get_system_allocator_config`.
610    /// * `serial_parameters` - Definitions for how the serial devices should be configured.
611    /// * `serial_jail` - Jail used for serial devices created here.
612    /// * `battery` - Defines what battery device will be created.
613    /// * `vm` - A VM implementation to build upon.
614    /// * `ramoops_region` - Region allocated for ramoops.
615    /// * `devices` - The devices to be built into the VM.
616    /// * `irq_chip` - The IRQ chip implemention for the VM.
617    /// * `debugcon_jail` - Jail used for debugcon devices created here.
618    /// * `pflash_jail` - Jail used for pflash device created here.
619    /// * `fw_cfg_jail` - Jail used for fw_cfg device created here.
620    /// * `device_tree_overlays` - Device tree overlay binaries
621    fn build_vm(
622        components: VmComponents,
623        arch_memory_layout: &Self::ArchMemoryLayout,
624        vm_evt_wrtube: &SendTube,
625        system_allocator: &mut SystemAllocator,
626        serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>,
627        serial_jail: Option<Minijail>,
628        battery: (Option<BatteryType>, Option<Minijail>),
629        vm: Arc<dyn VmArch>,
630        ramoops_region: Option<pstore::RamoopsRegion>,
631        devices: Vec<(Box<dyn BusDeviceObj>, Option<Minijail>)>,
632        irq_chip: Arc<dyn IrqChipArch>,
633        vcpu_ids: &mut Vec<usize>,
634        dump_device_tree_blob: Option<PathBuf>,
635        debugcon_jail: Option<Minijail>,
636        #[cfg(target_arch = "x86_64")] pflash_jail: Option<Minijail>,
637        #[cfg(target_arch = "x86_64")] fw_cfg_jail: Option<Minijail>,
638        #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
639        guest_suspended_cvar: Option<Arc<(Mutex<bool>, Condvar)>>,
640        device_tree_overlays: Vec<DtbOverlay>,
641        fdt_position: Option<FdtPosition>,
642        no_pmu: bool,
643    ) -> std::result::Result<RunnableLinuxVm, Self::Error>;
644
645    /// Configures the vcpu and should be called once per vcpu from the vcpu's thread.
646    ///
647    /// # Arguments
648    ///
649    /// * `vm` - The virtual machine object.
650    /// * `hypervisor` - The `Hypervisor` that created the vcpu.
651    /// * `irq_chip` - The `IrqChip` associated with this vm.
652    /// * `vcpu` - The VCPU object to configure.
653    /// * `vcpu_init` - The data required to initialize VCPU registers and other state.
654    /// * `vcpu_id` - The id of the given `vcpu`.
655    /// * `num_vcpus` - Number of virtual CPUs the guest will have.
656    /// * `cpu_config` - CPU feature configurations.
657    fn configure_vcpu(
658        vm: &dyn Vm,
659        hypervisor: &dyn HypervisorArch,
660        irq_chip: &dyn IrqChipArch,
661        vcpu: &dyn VcpuArch,
662        vcpu_init: VcpuInitArch,
663        vcpu_id: usize,
664        num_vcpus: usize,
665        cpu_config: Option<CpuConfigArch>,
666    ) -> Result<(), Self::Error>;
667
668    /// Configures and add a pci device into vm
669    fn register_pci_device(
670        linux: &mut RunnableLinuxVm,
671        device: Box<dyn PciDevice>,
672        #[cfg(any(target_os = "android", target_os = "linux"))] minijail: Option<Minijail>,
673        resources: &mut SystemAllocator,
674        hp_control_tube: &mpsc::Sender<PciRootCommand>,
675        #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
676    ) -> Result<PciAddress, Self::Error>;
677
678    /// Returns frequency map for each of the host's logical cores.
679    fn get_host_cpu_frequencies_khz() -> Result<BTreeMap<usize, Vec<u32>>, Self::Error>;
680
681    /// Returns max-freq map of the host's logical cores.
682    fn get_host_cpu_max_freq_khz() -> Result<BTreeMap<usize, u32>, Self::Error>;
683
684    /// Returns capacity map of the host's logical cores.
685    fn get_host_cpu_capacity() -> Result<BTreeMap<usize, u32>, Self::Error>;
686
687    /// Returns cluster masks for each of the host's logical cores.
688    fn get_host_cpu_clusters() -> Result<Vec<CpuSet>, Self::Error>;
689}
690
691#[cfg(feature = "gdb")]
692pub trait GdbOps {
693    type Error: StdError;
694
695    /// Reads vCPU's registers.
696    fn read_registers(vcpu: &dyn VcpuArch) -> Result<<GdbArch as Arch>::Registers, Self::Error>;
697
698    /// Writes vCPU's registers.
699    fn write_registers(
700        vcpu: &dyn VcpuArch,
701        regs: &<GdbArch as Arch>::Registers,
702    ) -> Result<(), Self::Error>;
703
704    /// Reads bytes from the guest memory.
705    fn read_memory(
706        vcpu: &dyn VcpuArch,
707        guest_mem: &GuestMemory,
708        vaddr: GuestAddress,
709        len: usize,
710    ) -> Result<Vec<u8>, Self::Error>;
711
712    /// Writes bytes to the specified guest memory.
713    fn write_memory(
714        vcpu: &dyn VcpuArch,
715        guest_mem: &GuestMemory,
716        vaddr: GuestAddress,
717        buf: &[u8],
718    ) -> Result<(), Self::Error>;
719
720    /// Reads bytes from the guest register.
721    ///
722    /// Returns an empty vector if `reg_id` is valid but the register is not available.
723    fn read_register(
724        vcpu: &dyn VcpuArch,
725        reg_id: <GdbArch as Arch>::RegId,
726    ) -> Result<Vec<u8>, Self::Error>;
727
728    /// Writes bytes to the specified guest register.
729    fn write_register(
730        vcpu: &dyn VcpuArch,
731        reg_id: <GdbArch as Arch>::RegId,
732        data: &[u8],
733    ) -> Result<(), Self::Error>;
734
735    /// Make the next vCPU's run single-step.
736    fn enable_singlestep(vcpu: &dyn VcpuArch) -> Result<(), Self::Error>;
737
738    /// Get maximum number of hardware breakpoints.
739    fn get_max_hw_breakpoints(vcpu: &dyn VcpuArch) -> Result<usize, Self::Error>;
740
741    /// Set hardware breakpoints at the given addresses.
742    fn set_hw_breakpoints(
743        vcpu: &dyn VcpuArch,
744        breakpoints: &[GuestAddress],
745    ) -> Result<(), Self::Error>;
746}
747
748/// Errors for device manager.
749#[sorted]
750#[derive(Error, Debug)]
751pub enum DeviceRegistrationError {
752    /// No more MMIO space available.
753    #[error("no more addresses are available")]
754    AddrsExhausted,
755    /// Could not allocate device address space for the device.
756    #[error("Allocating device addresses: {0}")]
757    AllocateDeviceAddrs(PciDeviceError),
758    /// Could not allocate IO space for the device.
759    #[error("Allocating IO addresses: {0}")]
760    AllocateIoAddrs(PciDeviceError),
761    /// Could not allocate MMIO or IO resource for the device.
762    #[error("Allocating IO resource: {0}")]
763    AllocateIoResource(resources::Error),
764    /// Could not allocate an IRQ number.
765    #[error("Allocating IRQ number")]
766    AllocateIrq,
767    /// Could not allocate IRQ resource for the device.
768    #[cfg(any(target_os = "android", target_os = "linux"))]
769    #[error("Allocating IRQ resource: {0}")]
770    AllocateIrqResource(devices::vfio::VfioError),
771    #[error("failed to attach the device to its power domain: {0}")]
772    AttachDevicePowerDomain(anyhow::Error),
773    /// Broken pci topology
774    #[error("pci topology is broken")]
775    BrokenPciTopology,
776    /// Unable to clone a jail for the device.
777    #[cfg(any(target_os = "android", target_os = "linux"))]
778    #[error("failed to clone jail: {0}")]
779    CloneJail(minijail::Error),
780    /// Appending to kernel command line failed.
781    #[error("unable to add device to kernel command line: {0}")]
782    Cmdline(kernel_cmdline::Error),
783    /// Configure window size failed.
784    #[error("failed to configure window size: {0}")]
785    ConfigureWindowSize(PciDeviceError),
786    // Unable to create a pipe.
787    #[error("failed to create pipe: {0}")]
788    CreatePipe(base::Error),
789    // Unable to create a root.
790    #[error("failed to create pci root: {0}")]
791    CreateRoot(anyhow::Error),
792    // Unable to create serial device from serial parameters
793    #[error("failed to create serial device: {0}")]
794    CreateSerialDevice(devices::SerialError),
795    // Unable to create tube
796    #[error("failed to create tube: {0}")]
797    CreateTube(base::TubeError),
798    /// Could not clone an event.
799    #[error("failed to clone event: {0}")]
800    EventClone(base::Error),
801    /// Could not create an event.
802    #[error("failed to create event: {0}")]
803    EventCreate(base::Error),
804    /// Failed to generate ACPI content.
805    #[error("failed to generate ACPI content")]
806    GenerateAcpi,
807    /// No more IRQs are available.
808    #[error("no more IRQs are available")]
809    IrqsExhausted,
810    /// VFIO device is missing a DT symbol.
811    #[error("cannot match VFIO device to DT node due to a missing symbol")]
812    MissingDeviceTreeSymbol,
813    /// Missing a required serial device.
814    #[error("missing required serial device {0}")]
815    MissingRequiredSerialDevice(u8),
816    /// Could not add a device to the mmio bus.
817    #[error("failed to add to mmio bus: {0}")]
818    MmioInsert(BusError),
819    /// Failed to insert device into PCI root.
820    #[error("failed to insert device into PCI root: {0}")]
821    PciRootAddDevice(PciDeviceError),
822    #[cfg(any(target_os = "android", target_os = "linux"))]
823    /// Failed to initialize proxy device for jailed device.
824    #[error("failed to create proxy device: {0}")]
825    ProxyDeviceCreation(devices::ProxyError),
826    #[cfg(any(target_os = "android", target_os = "linux"))]
827    /// Failed to register battery device.
828    #[error("failed to register battery device to VM: {0}")]
829    RegisterBattery(devices::BatteryError),
830    /// Could not register PCI device to pci root bus
831    #[error("failed to register PCI device to pci root bus")]
832    RegisterDevice(SendError<PciRootCommand>),
833    /// Could not register PCI device capabilities.
834    #[error("could not register PCI device capabilities: {0}")]
835    RegisterDeviceCapabilities(PciDeviceError),
836    /// Failed to register ioevent with VM.
837    #[error("failed to register ioevent to VM: {0}")]
838    RegisterIoevent(base::Error),
839    /// Failed to register irq event with VM.
840    #[error("failed to register irq event to VM: {0}")]
841    RegisterIrqfd(base::Error),
842    /// Could not setup VFIO platform IRQ for the device.
843    #[error("Setting up VFIO platform IRQ: {0}")]
844    SetupVfioPlatformIrq(anyhow::Error),
845}
846
847/// Config a PCI device for used by this vm.
848pub fn configure_pci_device(
849    linux: &mut RunnableLinuxVm,
850    mut device: Box<dyn PciDevice>,
851    #[cfg(any(target_os = "android", target_os = "linux"))] jail: Option<Minijail>,
852    resources: &mut SystemAllocator,
853    hp_control_tube: &mpsc::Sender<PciRootCommand>,
854    #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
855) -> Result<PciAddress, DeviceRegistrationError> {
856    // Allocate PCI device address before allocating BARs.
857    let pci_address = device
858        .allocate_address(resources)
859        .map_err(DeviceRegistrationError::AllocateDeviceAddrs)?;
860
861    // Allocate ranges that may need to be in the low MMIO region (MmioType::Low).
862    let mmio_ranges = device
863        .allocate_io_bars(resources)
864        .map_err(DeviceRegistrationError::AllocateIoAddrs)?;
865
866    // Allocate device ranges that may be in low or high MMIO after low-only ranges.
867    let device_ranges = device
868        .allocate_device_bars(resources)
869        .map_err(DeviceRegistrationError::AllocateDeviceAddrs)?;
870
871    // If device is a pcie bridge, add its pci bus to pci root
872    if let Some(pci_bus) = device.get_new_pci_bus() {
873        hp_control_tube
874            .send(PciRootCommand::AddBridge(pci_bus))
875            .map_err(DeviceRegistrationError::RegisterDevice)?;
876        let bar_ranges = Vec::new();
877        device
878            .configure_bridge_window(resources, &bar_ranges)
879            .map_err(DeviceRegistrationError::ConfigureWindowSize)?;
880    }
881
882    // Do not suggest INTx for hot-plug devices.
883    let intx_event = devices::IrqLevelEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
884
885    if let PreferredIrq::Fixed { pin, gsi } = device.preferred_irq() {
886        resources.reserve_irq(gsi);
887
888        device.assign_irq(
889            intx_event
890                .try_clone()
891                .map_err(DeviceRegistrationError::EventClone)?,
892            pin,
893            gsi,
894        );
895
896        linux
897            .irq_chip
898            .register_level_irq_event(gsi, &intx_event, IrqEventSource::from_device(&device))
899            .map_err(DeviceRegistrationError::RegisterIrqfd)?;
900    }
901
902    let mut keep_rds = device.keep_rds();
903    syslog::push_descriptors(&mut keep_rds);
904    cros_tracing::push_descriptors!(&mut keep_rds);
905    metrics::push_descriptors(&mut keep_rds);
906
907    device
908        .register_device_capabilities()
909        .map_err(DeviceRegistrationError::RegisterDeviceCapabilities)?;
910
911    #[cfg(any(target_os = "android", target_os = "linux"))]
912    let arced_dev: Arc<Mutex<dyn BusDevice>> = if let Some(jail) = jail {
913        let proxy = ProxyDevice::new(
914            device,
915            jail,
916            keep_rds,
917            #[cfg(feature = "swap")]
918            swap_controller,
919        )
920        .map_err(DeviceRegistrationError::ProxyDeviceCreation)?;
921        linux
922            .pid_debug_label_map
923            .insert(proxy.pid() as u32, proxy.debug_label());
924        Arc::new(Mutex::new(proxy))
925    } else {
926        device.on_sandboxed();
927        Arc::new(Mutex::new(device))
928    };
929
930    #[cfg(windows)]
931    let arced_dev = {
932        device.on_sandboxed();
933        Arc::new(Mutex::new(device))
934    };
935
936    #[cfg(any(target_os = "android", target_os = "linux"))]
937    hp_control_tube
938        .send(PciRootCommand::Add(pci_address, arced_dev.clone()))
939        .map_err(DeviceRegistrationError::RegisterDevice)?;
940
941    for range in &mmio_ranges {
942        linux
943            .mmio_bus
944            .insert(arced_dev.clone(), range.addr, range.size)
945            .map_err(DeviceRegistrationError::MmioInsert)?;
946    }
947
948    for range in &device_ranges {
949        linux
950            .mmio_bus
951            .insert(arced_dev.clone(), range.addr, range.size)
952            .map_err(DeviceRegistrationError::MmioInsert)?;
953    }
954
955    Ok(pci_address)
956}
957
958// Generate pci topology starting from parent bus
959fn generate_pci_topology(
960    parent_bus: Arc<Mutex<PciBus>>,
961    resources: &mut SystemAllocator,
962    io_ranges: &mut BTreeMap<usize, Vec<BarRange>>,
963    device_ranges: &mut BTreeMap<usize, Vec<BarRange>>,
964    device_addrs: &[PciAddress],
965    devices: &mut Vec<(Box<dyn PciDevice>, Option<Minijail>)>,
966) -> Result<(Vec<BarRange>, u8), DeviceRegistrationError> {
967    let mut bar_ranges = Vec::new();
968    let bus_num = parent_bus.lock().get_bus_num();
969    let mut subordinate_bus = bus_num;
970    for (dev_idx, addr) in device_addrs.iter().enumerate() {
971        // Only target for devices that located on this bus
972        if addr.bus == bus_num {
973            // If this device is a pci bridge (a.k.a., it has a pci bus structure),
974            // create its topology recursively
975            if let Some(child_bus) = devices[dev_idx].0.get_new_pci_bus() {
976                let (child_bar_ranges, child_sub_bus) = generate_pci_topology(
977                    child_bus.clone(),
978                    resources,
979                    io_ranges,
980                    device_ranges,
981                    device_addrs,
982                    devices,
983                )?;
984                let device = &mut devices[dev_idx].0;
985                parent_bus
986                    .lock()
987                    .add_child_bus(child_bus.clone())
988                    .map_err(|_| DeviceRegistrationError::BrokenPciTopology)?;
989                let bridge_window = device
990                    .configure_bridge_window(resources, &child_bar_ranges)
991                    .map_err(DeviceRegistrationError::ConfigureWindowSize)?;
992                bar_ranges.extend(bridge_window);
993
994                let ranges = device
995                    .allocate_io_bars(resources)
996                    .map_err(DeviceRegistrationError::AllocateIoAddrs)?;
997                io_ranges.insert(dev_idx, ranges.clone());
998                bar_ranges.extend(ranges);
999
1000                let ranges = device
1001                    .allocate_device_bars(resources)
1002                    .map_err(DeviceRegistrationError::AllocateDeviceAddrs)?;
1003                device_ranges.insert(dev_idx, ranges.clone());
1004                bar_ranges.extend(ranges);
1005
1006                device.set_subordinate_bus(child_sub_bus);
1007
1008                subordinate_bus = std::cmp::max(subordinate_bus, child_sub_bus);
1009            }
1010        }
1011    }
1012
1013    for (dev_idx, addr) in device_addrs.iter().enumerate() {
1014        if addr.bus == bus_num {
1015            let device = &mut devices[dev_idx].0;
1016            // Allocate MMIO for non-bridge devices
1017            if device.get_new_pci_bus().is_none() {
1018                let ranges = device
1019                    .allocate_io_bars(resources)
1020                    .map_err(DeviceRegistrationError::AllocateIoAddrs)?;
1021                io_ranges.insert(dev_idx, ranges.clone());
1022                bar_ranges.extend(ranges);
1023
1024                let ranges = device
1025                    .allocate_device_bars(resources)
1026                    .map_err(DeviceRegistrationError::AllocateDeviceAddrs)?;
1027                device_ranges.insert(dev_idx, ranges.clone());
1028                bar_ranges.extend(ranges);
1029            }
1030        }
1031    }
1032    Ok((bar_ranges, subordinate_bus))
1033}
1034
1035/// Ensure all PCI devices have an assigned PCI address.
1036pub fn assign_pci_addresses(
1037    devices: &mut [(Box<dyn BusDeviceObj>, Option<Minijail>)],
1038    resources: &mut SystemAllocator,
1039) -> Result<(), DeviceRegistrationError> {
1040    // First allocate devices with a preferred address.
1041    for pci_device in devices
1042        .iter_mut()
1043        .filter_map(|(device, _jail)| device.as_pci_device_mut())
1044        .filter(|pci_device| pci_device.preferred_address().is_some())
1045    {
1046        let _ = pci_device
1047            .allocate_address(resources)
1048            .map_err(DeviceRegistrationError::AllocateDeviceAddrs)?;
1049    }
1050
1051    // Then allocate addresses for the remaining devices.
1052    for pci_device in devices
1053        .iter_mut()
1054        .filter_map(|(device, _jail)| device.as_pci_device_mut())
1055        .filter(|pci_device| pci_device.preferred_address().is_none())
1056    {
1057        let _ = pci_device
1058            .allocate_address(resources)
1059            .map_err(DeviceRegistrationError::AllocateDeviceAddrs)?;
1060    }
1061
1062    Ok(())
1063}
1064
1065/// Creates a root PCI device for use by this Vm.
1066pub fn generate_pci_root(
1067    mut devices: Vec<(Box<dyn PciDevice>, Option<Minijail>)>,
1068    irq_chip: &dyn IrqChip,
1069    mmio_bus: Arc<Bus>,
1070    mmio_base: GuestAddress,
1071    mmio_register_bit_num: usize,
1072    io_bus: Arc<Bus>,
1073    resources: &mut SystemAllocator,
1074    mut vm: &dyn Vm,
1075    max_irqs: usize,
1076    vcfg_base: Option<u64>,
1077    #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
1078) -> Result<
1079    (
1080        PciRoot,
1081        Vec<(PciAddress, u32, PciInterruptPin)>,
1082        BTreeMap<u32, String>,
1083        BTreeMap<PciAddress, Vec<u8>>,
1084        BTreeMap<PciAddress, Vec<u8>>,
1085    ),
1086    DeviceRegistrationError,
1087> {
1088    let mut device_addrs = Vec::new();
1089
1090    for (device, _jail) in devices.iter_mut() {
1091        let address = device
1092            .allocate_address(resources)
1093            .map_err(DeviceRegistrationError::AllocateDeviceAddrs)?;
1094        device_addrs.push(address);
1095    }
1096
1097    let mut device_ranges = BTreeMap::new();
1098    let mut io_ranges = BTreeMap::new();
1099    let root_bus = Arc::new(Mutex::new(PciBus::new(0, 0, false)));
1100
1101    generate_pci_topology(
1102        root_bus.clone(),
1103        resources,
1104        &mut io_ranges,
1105        &mut device_ranges,
1106        &device_addrs,
1107        &mut devices,
1108    )?;
1109
1110    let mut root = PciRoot::new(
1111        vm,
1112        Arc::downgrade(&mmio_bus),
1113        mmio_base,
1114        mmio_register_bit_num,
1115        Arc::downgrade(&io_bus),
1116        root_bus,
1117    )
1118    .map_err(DeviceRegistrationError::CreateRoot)?;
1119    #[cfg_attr(windows, allow(unused_mut))]
1120    let mut pid_labels = BTreeMap::new();
1121
1122    // Allocate legacy INTx
1123    let mut pci_irqs = Vec::new();
1124    let mut irqs: Vec<u32> = Vec::new();
1125
1126    // Mapping of (bus, dev, pin) -> IRQ number.
1127    let mut dev_pin_irq = BTreeMap::new();
1128
1129    for (dev_idx, (device, _jail)) in devices.iter_mut().enumerate() {
1130        let pci_address = device_addrs[dev_idx];
1131
1132        let irq = match device.preferred_irq() {
1133            PreferredIrq::Fixed { pin, gsi } => {
1134                // The device reported a preferred IRQ, so use that rather than allocating one.
1135                resources.reserve_irq(gsi);
1136                Some((pin, gsi))
1137            }
1138            PreferredIrq::Any => {
1139                // The device did not provide a preferred IRQ but requested one, so allocate one.
1140
1141                // Choose a pin based on the slot's function number. Function 0 must always use
1142                // INTA# for single-function devices per the PCI spec, and we choose to use INTA#
1143                // for function 0 on multifunction devices and distribute the remaining functions
1144                // evenly across the other pins.
1145                let pin = match pci_address.func % 4 {
1146                    0 => PciInterruptPin::IntA,
1147                    1 => PciInterruptPin::IntB,
1148                    2 => PciInterruptPin::IntC,
1149                    _ => PciInterruptPin::IntD,
1150                };
1151
1152                // If an IRQ number has already been assigned for a different function with this
1153                // (bus, device, pin) combination, use it. Otherwise allocate a new one and insert
1154                // it into the map.
1155                let pin_key = (pci_address.bus, pci_address.dev, pin);
1156                let irq_num = if let Some(irq_num) = dev_pin_irq.get(&pin_key) {
1157                    *irq_num
1158                } else {
1159                    // If we have allocated fewer than `max_irqs` total, add a new irq to the `irqs`
1160                    // pool. Otherwise, share one of the existing `irqs`.
1161                    let irq_num = if irqs.len() < max_irqs {
1162                        let irq_num = resources
1163                            .allocate_irq()
1164                            .ok_or(DeviceRegistrationError::AllocateIrq)?;
1165                        irqs.push(irq_num);
1166                        irq_num
1167                    } else {
1168                        // Pick one of the existing IRQs to share, using `dev_idx` to distribute IRQ
1169                        // sharing evenly across devices.
1170                        irqs[dev_idx % max_irqs]
1171                    };
1172
1173                    dev_pin_irq.insert(pin_key, irq_num);
1174                    irq_num
1175                };
1176                Some((pin, irq_num))
1177            }
1178            PreferredIrq::None => {
1179                // The device does not want an INTx# IRQ.
1180                None
1181            }
1182        };
1183
1184        if let Some((pin, gsi)) = irq {
1185            let intx_event =
1186                devices::IrqLevelEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
1187
1188            device.assign_irq(
1189                intx_event
1190                    .try_clone()
1191                    .map_err(DeviceRegistrationError::EventClone)?,
1192                pin,
1193                gsi,
1194            );
1195
1196            irq_chip
1197                .register_level_irq_event(gsi, &intx_event, IrqEventSource::from_device(device))
1198                .map_err(DeviceRegistrationError::RegisterIrqfd)?;
1199
1200            pci_irqs.push((pci_address, gsi, pin));
1201        }
1202    }
1203
1204    // To prevent issues where device's on_sandbox may spawn thread before all
1205    // sandboxed devices are sandboxed we partition iterator to go over sandboxed
1206    // first. This is needed on linux platforms. On windows, this is a no-op since
1207    // jails are always None, even for sandboxed devices.
1208    let devices = {
1209        let (sandboxed, non_sandboxed): (Vec<_>, Vec<_>) = devices
1210            .into_iter()
1211            .enumerate()
1212            .partition(|(_, (_, jail))| jail.is_some());
1213        sandboxed.into_iter().chain(non_sandboxed)
1214    };
1215
1216    let mut amls = BTreeMap::new();
1217    let mut gpe_scope_amls = BTreeMap::new();
1218    for (dev_idx, dev_value) in devices {
1219        #[cfg(any(target_os = "android", target_os = "linux"))]
1220        let (mut device, jail) = dev_value;
1221        #[cfg(windows)]
1222        let (mut device, _) = dev_value;
1223        let address = device_addrs[dev_idx];
1224
1225        let mut keep_rds = device.keep_rds();
1226        syslog::push_descriptors(&mut keep_rds);
1227        cros_tracing::push_descriptors!(&mut keep_rds);
1228        metrics::push_descriptors(&mut keep_rds);
1229        keep_rds.append(&mut vm.get_memory().as_raw_descriptors());
1230
1231        let ranges = io_ranges.remove(&dev_idx).unwrap_or_default();
1232        let device_ranges = device_ranges.remove(&dev_idx).unwrap_or_default();
1233        device
1234            .register_device_capabilities()
1235            .map_err(DeviceRegistrationError::RegisterDeviceCapabilities)?;
1236
1237        if let Some(vcfg_base) = vcfg_base {
1238            let (methods, shm) = device.generate_acpi_methods();
1239            if !methods.is_empty() {
1240                amls.insert(address, methods);
1241            }
1242            if let Some((offset, mmap)) = shm {
1243                let _ = vm.add_memory_region(
1244                    GuestAddress(vcfg_base + offset as u64),
1245                    Box::new(mmap),
1246                    false,
1247                    false,
1248                    MemCacheType::CacheCoherent,
1249                );
1250            }
1251        }
1252        let gpe_nr = device.set_gpe(resources);
1253
1254        #[cfg(any(target_os = "android", target_os = "linux"))]
1255        let arced_dev: Arc<Mutex<dyn BusDevice>> = if let Some(jail) = jail {
1256            let proxy = ProxyDevice::new(
1257                device,
1258                jail,
1259                keep_rds,
1260                #[cfg(feature = "swap")]
1261                swap_controller,
1262            )
1263            .map_err(DeviceRegistrationError::ProxyDeviceCreation)?;
1264            pid_labels.insert(proxy.pid() as u32, proxy.debug_label());
1265            Arc::new(Mutex::new(proxy))
1266        } else {
1267            device.on_sandboxed();
1268            Arc::new(Mutex::new(device))
1269        };
1270        #[cfg(windows)]
1271        let arced_dev = {
1272            device.on_sandboxed();
1273            Arc::new(Mutex::new(device))
1274        };
1275        root.add_device(address, arced_dev.clone(), &mut vm)
1276            .map_err(DeviceRegistrationError::PciRootAddDevice)?;
1277        for range in &ranges {
1278            mmio_bus
1279                .insert(arced_dev.clone(), range.addr, range.size)
1280                .map_err(DeviceRegistrationError::MmioInsert)?;
1281        }
1282
1283        for range in &device_ranges {
1284            mmio_bus
1285                .insert(arced_dev.clone(), range.addr, range.size)
1286                .map_err(DeviceRegistrationError::MmioInsert)?;
1287        }
1288
1289        if let Some(gpe_nr) = gpe_nr {
1290            if let Some(acpi_path) = root.acpi_path(&address) {
1291                let mut gpe_aml = Vec::new();
1292
1293                GpeScope {}.cast_to_aml_bytes(
1294                    &mut gpe_aml,
1295                    gpe_nr,
1296                    format!("\\{acpi_path}").as_str(),
1297                );
1298                if !gpe_aml.is_empty() {
1299                    gpe_scope_amls.insert(address, gpe_aml);
1300                }
1301            }
1302        }
1303    }
1304
1305    Ok((root, pci_irqs, pid_labels, amls, gpe_scope_amls))
1306}
1307
1308/// Errors for image loading.
1309#[sorted]
1310#[derive(Error, Debug)]
1311pub enum LoadImageError {
1312    #[error("Alignment not a power of two: {0}")]
1313    BadAlignment(u64),
1314    #[error("Getting image size failed: {0}")]
1315    GetLen(io::Error),
1316    #[error("GuestMemory get slice failed: {0}")]
1317    GuestMemorySlice(GuestMemoryError),
1318    #[error("Image size too large: {0}")]
1319    ImageSizeTooLarge(u64),
1320    #[error("No suitable memory region found")]
1321    NoSuitableMemoryRegion,
1322    #[error("Reading image into memory failed: {0}")]
1323    ReadToMemory(io::Error),
1324    #[error("Cannot load zero-sized image")]
1325    ZeroSizedImage,
1326}
1327
1328/// Load an image from a file into guest memory.
1329///
1330/// # Arguments
1331///
1332/// * `guest_mem` - The memory to be used by the guest.
1333/// * `guest_addr` - The starting address to load the image in the guest memory.
1334/// * `max_size` - The amount of space in bytes available in the guest memory for the image.
1335/// * `image` - The file containing the image to be loaded.
1336///
1337/// The size in bytes of the loaded image is returned.
1338pub fn load_image<F>(
1339    guest_mem: &GuestMemory,
1340    image: &mut F,
1341    guest_addr: GuestAddress,
1342    max_size: u64,
1343) -> Result<u32, LoadImageError>
1344where
1345    F: FileReadWriteAtVolatile + FileGetLen,
1346{
1347    let size = image.get_len().map_err(LoadImageError::GetLen)?;
1348
1349    if size > u32::MAX as u64 || size > max_size {
1350        return Err(LoadImageError::ImageSizeTooLarge(size));
1351    }
1352
1353    // This is safe due to the bounds check above.
1354    let size = size as u32;
1355
1356    let guest_slice = guest_mem
1357        .get_slice_at_addr(guest_addr, size as usize)
1358        .map_err(LoadImageError::GuestMemorySlice)?;
1359    image
1360        .read_exact_at_volatile(guest_slice, 0)
1361        .map_err(LoadImageError::ReadToMemory)?;
1362
1363    Ok(size)
1364}
1365
1366/// Load an image from a file into guest memory at the highest possible address.
1367///
1368/// # Arguments
1369///
1370/// * `guest_mem` - The memory to be used by the guest.
1371/// * `image` - The file containing the image to be loaded.
1372/// * `min_guest_addr` - The minimum address of the start of the image.
1373/// * `max_guest_addr` - The address to load the last byte of the image.
1374/// * `region_filter` - The optional filter function for determining if the given guest memory
1375///   region is suitable for loading the image into it.
1376/// * `align` - The minimum alignment of the start address of the image in bytes (must be a power of
1377///   two).
1378///
1379/// The guest address and size in bytes of the loaded image are returned.
1380pub fn load_image_high<F>(
1381    guest_mem: &GuestMemory,
1382    image: &mut F,
1383    min_guest_addr: GuestAddress,
1384    max_guest_addr: GuestAddress,
1385    region_filter: Option<fn(&MemoryRegionInformation) -> bool>,
1386    align: u64,
1387) -> Result<(GuestAddress, u32), LoadImageError>
1388where
1389    F: FileReadWriteAtVolatile + FileGetLen,
1390{
1391    if !align.is_power_of_two() {
1392        return Err(LoadImageError::BadAlignment(align));
1393    }
1394
1395    let max_size = max_guest_addr.offset_from(min_guest_addr) & !(align - 1);
1396    let size = image.get_len().map_err(LoadImageError::GetLen)?;
1397
1398    if size == 0 {
1399        return Err(LoadImageError::ZeroSizedImage);
1400    }
1401
1402    if size > u32::MAX as u64 || size > max_size {
1403        return Err(LoadImageError::ImageSizeTooLarge(size));
1404    }
1405
1406    // Sort the list of guest memory regions by address so we can iterate over them in reverse order
1407    // (high to low).
1408    let mut regions: Vec<_> = guest_mem
1409        .regions()
1410        .filter(region_filter.unwrap_or(|_| true))
1411        .collect();
1412    regions.sort_unstable_by(|a, b| a.guest_addr.cmp(&b.guest_addr));
1413
1414    // Find the highest valid address inside a guest memory region that satisfies the requested
1415    // alignment and min/max address requirements while having enough space for the image.
1416    let guest_addr = regions
1417        .into_iter()
1418        .rev()
1419        .filter_map(|r| {
1420            // Highest address within this region.
1421            let rgn_max_addr = r
1422                .guest_addr
1423                .checked_add((r.size as u64).checked_sub(1)?)?
1424                .min(max_guest_addr);
1425            // Lowest aligned address within this region.
1426            let rgn_start_aligned = r.guest_addr.align(align)?;
1427            // Hypothetical address of the image if loaded at the end of the region.
1428            let image_addr = rgn_max_addr.checked_sub(size - 1)? & !(align - 1);
1429
1430            // Would the image fit within the region?
1431            if image_addr >= rgn_start_aligned {
1432                Some(image_addr)
1433            } else {
1434                None
1435            }
1436        })
1437        .find(|&addr| addr >= min_guest_addr)
1438        .ok_or(LoadImageError::NoSuitableMemoryRegion)?;
1439
1440    // This is safe due to the bounds check above.
1441    let size = size as u32;
1442
1443    let guest_slice = guest_mem
1444        .get_slice_at_addr(guest_addr, size as usize)
1445        .map_err(LoadImageError::GuestMemorySlice)?;
1446    image
1447        .read_exact_at_volatile(guest_slice, 0)
1448        .map_err(LoadImageError::ReadToMemory)?;
1449
1450    Ok((guest_addr, size))
1451}
1452
1453/// SMBIOS table configuration
1454#[derive(Clone, Debug, Default, Serialize, Deserialize, FromKeyValues, PartialEq, Eq)]
1455#[serde(deny_unknown_fields, rename_all = "kebab-case")]
1456pub struct SmbiosOptions {
1457    /// BIOS vendor name.
1458    pub bios_vendor: Option<String>,
1459
1460    /// BIOS version number (free-form string).
1461    pub bios_version: Option<String>,
1462
1463    /// System manufacturer name.
1464    pub manufacturer: Option<String>,
1465
1466    /// System product name.
1467    pub product_name: Option<String>,
1468
1469    /// System serial number (free-form string).
1470    pub serial_number: Option<String>,
1471
1472    /// System UUID.
1473    pub uuid: Option<Uuid>,
1474
1475    /// Additional OEM strings to add to SMBIOS table.
1476    #[serde(default)]
1477    pub oem_strings: Vec<String>,
1478}
1479
1480#[cfg(test)]
1481mod tests {
1482    use serde_keyvalue::from_key_values;
1483    use tempfile::tempfile;
1484
1485    use super::*;
1486
1487    #[test]
1488    fn parse_pstore() {
1489        let res: Pstore = from_key_values("path=/some/path,size=16384").unwrap();
1490        assert_eq!(
1491            res,
1492            Pstore {
1493                path: "/some/path".into(),
1494                size: 16384,
1495            }
1496        );
1497
1498        let res = from_key_values::<Pstore>("path=/some/path");
1499        assert!(res.is_err());
1500
1501        let res = from_key_values::<Pstore>("size=16384");
1502        assert!(res.is_err());
1503
1504        let res = from_key_values::<Pstore>("");
1505        assert!(res.is_err());
1506    }
1507
1508    #[test]
1509    fn deserialize_cpuset_serde_kv() {
1510        let res: CpuSet = from_key_values("[0,4,7]").unwrap();
1511        assert_eq!(res, CpuSet::new(vec![0, 4, 7]));
1512
1513        let res: CpuSet = from_key_values("[9-12]").unwrap();
1514        assert_eq!(res, CpuSet::new(vec![9, 10, 11, 12]));
1515
1516        let res: CpuSet = from_key_values("[0,4,7,9-12,15]").unwrap();
1517        assert_eq!(res, CpuSet::new(vec![0, 4, 7, 9, 10, 11, 12, 15]));
1518    }
1519
1520    #[test]
1521    fn deserialize_serialize_cpuset_json() {
1522        let json_str = "[0,4,7]";
1523        let cpuset = CpuSet::new(vec![0, 4, 7]);
1524        let res: CpuSet = serde_json::from_str(json_str).unwrap();
1525        assert_eq!(res, cpuset);
1526        assert_eq!(serde_json::to_string(&cpuset).unwrap(), json_str);
1527
1528        let json_str = r#"["9-12"]"#;
1529        let cpuset = CpuSet::new(vec![9, 10, 11, 12]);
1530        let res: CpuSet = serde_json::from_str(json_str).unwrap();
1531        assert_eq!(res, cpuset);
1532        assert_eq!(serde_json::to_string(&cpuset).unwrap(), json_str);
1533
1534        let json_str = r#"[0,4,7,"9-12",15]"#;
1535        let cpuset = CpuSet::new(vec![0, 4, 7, 9, 10, 11, 12, 15]);
1536        let res: CpuSet = serde_json::from_str(json_str).unwrap();
1537        assert_eq!(res, cpuset);
1538        assert_eq!(serde_json::to_string(&cpuset).unwrap(), json_str);
1539    }
1540
1541    #[test]
1542    fn load_image_high_max_4g() {
1543        let mem = GuestMemory::new(&[
1544            (GuestAddress(0x0000_0000), 0x4000_0000), // 0x00000000..0x40000000
1545            (GuestAddress(0x8000_0000), 0x4000_0000), // 0x80000000..0xC0000000
1546        ])
1547        .unwrap();
1548
1549        const TEST_IMAGE_SIZE: u64 = 1234;
1550        let mut test_image = tempfile().unwrap();
1551        test_image.set_len(TEST_IMAGE_SIZE).unwrap();
1552
1553        const TEST_ALIGN: u64 = 0x8000;
1554        let (addr, size) = load_image_high(
1555            &mem,
1556            &mut test_image,
1557            GuestAddress(0x8000),
1558            GuestAddress(0xFFFF_FFFF), // max_guest_addr beyond highest guest memory region
1559            None,
1560            TEST_ALIGN,
1561        )
1562        .unwrap();
1563
1564        assert_eq!(addr, GuestAddress(0xBFFF_8000));
1565        assert_eq!(addr.offset() % TEST_ALIGN, 0);
1566        assert_eq!(size, TEST_IMAGE_SIZE as u32);
1567    }
1568}