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