x86_64/
lib.rs

1// Copyright 2017 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//! x86 architecture support.
6
7#![cfg(target_arch = "x86_64")]
8
9mod fdt;
10
11#[cfg(feature = "gdb")]
12mod gdb;
13
14const SETUP_DTB: u32 = 2;
15const SETUP_RNG_SEED: u32 = 9;
16
17#[allow(dead_code)]
18#[allow(non_upper_case_globals)]
19#[allow(non_camel_case_types)]
20#[allow(non_snake_case)]
21pub mod bootparam;
22
23#[allow(dead_code)]
24#[allow(non_upper_case_globals)]
25mod msr_index;
26
27#[allow(dead_code)]
28#[allow(non_upper_case_globals)]
29#[allow(non_camel_case_types)]
30#[allow(clippy::all)]
31mod mpspec;
32
33pub mod multiboot_spec;
34
35pub mod acpi;
36mod bzimage;
37pub mod cpuid;
38mod gdt;
39pub mod interrupts;
40pub mod mptable;
41pub mod regs;
42pub mod smbios;
43
44use std::arch::x86_64::CpuidResult;
45use std::cmp::min;
46use std::collections::BTreeMap;
47use std::fmt;
48use std::fs::File;
49use std::io;
50use std::io::Write;
51use std::mem;
52use std::path::PathBuf;
53use std::sync::mpsc;
54use std::sync::Arc;
55
56use acpi_tables::aml;
57use acpi_tables::aml::Aml;
58use acpi_tables::sdt::SDT;
59use anyhow::Context;
60use arch::get_serial_cmdline;
61use arch::serial::SerialDeviceInfo;
62use arch::CpuSet;
63use arch::DtbOverlay;
64use arch::FdtPosition;
65use arch::GetSerialCmdlineError;
66use arch::MemoryRegionConfig;
67use arch::PciConfig;
68use arch::RunnableLinuxVm;
69use arch::VmComponents;
70use arch::VmImage;
71use base::debug;
72use base::info;
73use base::warn;
74#[cfg(any(target_os = "android", target_os = "linux"))]
75use base::AsRawDescriptors;
76use base::Event;
77use base::FileGetLen;
78use base::FileReadWriteAtVolatile;
79use base::SendTube;
80use base::Tube;
81use base::TubeError;
82use chrono::Utc;
83pub use cpuid::adjust_cpuid;
84pub use cpuid::CpuIdContext;
85use devices::acpi::PM_WAKEUP_GPIO;
86use devices::Bus;
87use devices::BusDevice;
88use devices::BusDeviceObj;
89use devices::BusResumeDevice;
90use devices::BusType;
91use devices::Debugcon;
92use devices::FwCfgParameters;
93use devices::IrqChip;
94use devices::IrqChipX86_64;
95use devices::IrqEventSource;
96use devices::PciAddress;
97use devices::PciConfigIo;
98use devices::PciConfigMmio;
99use devices::PciDevice;
100use devices::PciInterruptPin;
101use devices::PciRoot;
102use devices::PciRootCommand;
103use devices::PciVirtualConfigMmio;
104use devices::Pflash;
105#[cfg(any(target_os = "android", target_os = "linux"))]
106use devices::ProxyDevice;
107use devices::Serial;
108use devices::SerialHardware;
109use devices::SerialParameters;
110use devices::VirtualPmc;
111use devices::FW_CFG_BASE_PORT;
112use devices::FW_CFG_MAX_FILE_SLOTS;
113use devices::FW_CFG_WIDTH;
114use hypervisor::CpuConfigX86_64;
115use hypervisor::Hypervisor;
116use hypervisor::HypervisorX86_64;
117use hypervisor::ProtectionType;
118use hypervisor::VcpuInitX86_64;
119use hypervisor::VcpuX86_64;
120use hypervisor::Vm;
121use hypervisor::VmCap;
122use hypervisor::VmX86_64;
123#[cfg(feature = "seccomp_trace")]
124use jail::read_jail_addr;
125#[cfg(windows)]
126use jail::FakeMinijailStub as Minijail;
127#[cfg(any(target_os = "android", target_os = "linux"))]
128use minijail::Minijail;
129use mptable::MPTABLE_RANGE;
130use multiboot_spec::MultibootInfo;
131use multiboot_spec::MultibootMmapEntry;
132use multiboot_spec::MULTIBOOT_BOOTLOADER_MAGIC;
133use rand::rngs::OsRng;
134use rand::RngCore;
135use remain::sorted;
136use resources::AddressRange;
137use resources::SystemAllocator;
138use resources::SystemAllocatorConfig;
139use sync::Condvar;
140use sync::Mutex;
141use thiserror::Error;
142use vm_control::BatControl;
143use vm_control::BatteryType;
144use vm_memory::GuestAddress;
145use vm_memory::GuestMemory;
146use vm_memory::GuestMemoryError;
147use vm_memory::MemoryRegionOptions;
148use vm_memory::MemoryRegionPurpose;
149use zerocopy::FromBytes;
150use zerocopy::Immutable;
151use zerocopy::IntoBytes;
152use zerocopy::KnownLayout;
153
154use crate::bootparam::boot_params;
155use crate::bootparam::setup_header;
156use crate::bootparam::XLF_CAN_BE_LOADED_ABOVE_4G;
157use crate::cpuid::EDX_HYBRID_CPU_SHIFT;
158
159#[sorted]
160#[derive(Error, Debug)]
161pub enum Error {
162    #[error("error allocating a single gpe")]
163    AllocateGpe,
164    #[error("error allocating IO resource: {0}")]
165    AllocateIOResouce(resources::Error),
166    #[error("error allocating a single irq")]
167    AllocateIrq,
168    #[error("unable to clone an Event: {0}")]
169    CloneEvent(base::Error),
170    #[error("failed to clone IRQ chip: {0}")]
171    CloneIrqChip(base::Error),
172    #[cfg(any(target_os = "android", target_os = "linux"))]
173    #[error("failed to clone jail: {0}")]
174    CloneJail(minijail::Error),
175    #[error("unable to clone a Tube: {0}")]
176    CloneTube(TubeError),
177    #[error("the given kernel command line was invalid: {0}")]
178    Cmdline(kernel_cmdline::Error),
179    #[error("failed writing command line to guest memory")]
180    CommandLineCopy,
181    #[error("command line overflowed guest memory")]
182    CommandLineOverflow,
183    #[error("failed to configure hotplugged pci device: {0}")]
184    ConfigurePciDevice(arch::DeviceRegistrationError),
185    #[error("bad PCI ECAM configuration: {0}")]
186    ConfigurePciEcam(String),
187    #[error("bad PCI mem configuration: {0}")]
188    ConfigurePciMem(String),
189    #[error("failed to configure segment registers: {0}")]
190    ConfigureSegments(regs::Error),
191    #[error("error configuring the system")]
192    ConfigureSystem,
193    #[error("unable to create ACPI tables")]
194    CreateAcpi,
195    #[error("unable to create battery devices: {0}")]
196    CreateBatDevices(arch::DeviceRegistrationError),
197    #[error("could not create debugcon device: {0}")]
198    CreateDebugconDevice(devices::SerialError),
199    #[error("unable to make an Event: {0}")]
200    CreateEvent(base::Error),
201    #[error("failed to create fdt: {0}")]
202    CreateFdt(cros_fdt::Error),
203    #[error("failed to create fw_cfg device: {0}")]
204    CreateFwCfgDevice(devices::FwCfgError),
205    #[error("failed to create IOAPIC device: {0}")]
206    CreateIoapicDevice(base::Error),
207    #[error("failed to create a PCI root hub: {0}")]
208    CreatePciRoot(arch::DeviceRegistrationError),
209    #[error("unable to create PIT: {0}")]
210    CreatePit(base::Error),
211    #[error("unable to make PIT device: {0}")]
212    CreatePitDevice(devices::PitError),
213    #[cfg(any(target_os = "android", target_os = "linux"))]
214    #[error("unable to create proxy device: {0}")]
215    CreateProxyDevice(devices::ProxyError),
216    #[error("unable to create serial devices: {0}")]
217    CreateSerialDevices(arch::DeviceRegistrationError),
218    #[error("failed to create socket: {0}")]
219    CreateSocket(io::Error),
220    #[error("failed to create tube: {0}")]
221    CreateTube(base::TubeError),
222    #[error("failed to create VCPU: {0}")]
223    CreateVcpu(base::Error),
224    #[error("DTB size is larger than the allowed size")]
225    DTBSizeGreaterThanAllowed,
226    #[error("invalid e820 setup params")]
227    E820Configuration,
228    #[error("failed to enable singlestep execution: {0}")]
229    EnableSinglestep(base::Error),
230    #[error("failed to enable split irqchip: {0}")]
231    EnableSplitIrqchip(base::Error),
232    #[error("failed to get serial cmdline: {0}")]
233    GetSerialCmdline(GetSerialCmdlineError),
234    #[error("failed to insert device onto bus: {0}")]
235    InsertBus(devices::BusError),
236    #[error("the kernel extends past the end of RAM")]
237    InvalidCpuConfig,
238    #[error("invalid CPU config parameters")]
239    KernelOffsetPastEnd,
240    #[error("error loading bios: {0}")]
241    LoadBios(io::Error),
242    #[error("error loading kernel bzImage: {0}")]
243    LoadBzImage(bzimage::Error),
244    #[error("error loading custom pVM firmware: {0}")]
245    LoadCustomPvmFw(arch::LoadImageError),
246    #[error("error loading initrd: {0}")]
247    LoadInitrd(arch::LoadImageError),
248    #[error("error loading Kernel: {0}")]
249    LoadKernel(kernel_loader::Error),
250    #[error("error loading pflash: {0}")]
251    LoadPflash(io::Error),
252    #[error("error loading pVM firmware: {0}")]
253    LoadPvmFw(base::Error),
254    #[error("error in multiboot_info setup")]
255    MultibootInfoSetup,
256    #[error("error translating address: Page not present")]
257    PageNotPresent,
258    #[error("pci mmio overlaps with pVM firmware memory")]
259    PciMmioOverlapPvmFw,
260    #[error("pVM firmware not supported when bios is used on x86_64")]
261    PvmFwBiosUnsupported,
262    #[error("error reading guest memory {0}")]
263    ReadingGuestMemory(vm_memory::GuestMemoryError),
264    #[error("single register read not supported on x86_64")]
265    ReadRegIsUnsupported,
266    #[error("error reading CPU registers {0}")]
267    ReadRegs(base::Error),
268    #[error("error registering an IrqFd: {0}")]
269    RegisterIrqfd(base::Error),
270    #[error("error registering virtual socket device: {0}")]
271    RegisterVsock(arch::DeviceRegistrationError),
272    #[error("error reserved pcie config mmio")]
273    ReservePcieCfgMmio(resources::Error),
274    #[error("failed to set a hardware breakpoint: {0}")]
275    SetHwBreakpoint(base::Error),
276    #[error("failed to set identity map addr: {0}")]
277    SetIdentityMapAddr(base::Error),
278    #[error("failed to set interrupts: {0}")]
279    SetLint(interrupts::Error),
280    #[error("failed to set tss addr: {0}")]
281    SetTssAddr(base::Error),
282    #[error("failed to set up cmos: {0}")]
283    SetupCmos(anyhow::Error),
284    #[error("failed to set up cpuid: {0}")]
285    SetupCpuid(cpuid::Error),
286    #[error("setup data too large")]
287    SetupDataTooLarge,
288    #[error("failed to set up FPU: {0}")]
289    SetupFpu(base::Error),
290    #[error("failed to set up guest memory: {0}")]
291    SetupGuestMemory(GuestMemoryError),
292    #[error("failed to set up mptable: {0}")]
293    SetupMptable(mptable::Error),
294    #[error("failed to set up MSRs: {0}")]
295    SetupMsrs(base::Error),
296    #[error("failed to set up page tables: {0}")]
297    SetupPageTables(regs::Error),
298    #[error("failed to set up pflash: {0}")]
299    SetupPflash(anyhow::Error),
300    #[error("failed to set up registers: {0}")]
301    SetupRegs(regs::Error),
302    #[error("failed to set up SMBIOS: {0}")]
303    SetupSmbios(smbios::Error),
304    #[error("failed to set up sregs: {0}")]
305    SetupSregs(base::Error),
306    #[error("too many vCPUs")]
307    TooManyVcpus,
308    #[error("failed to translate virtual address")]
309    TranslatingVirtAddr,
310    #[error("protected VMs not supported on x86_64")]
311    UnsupportedProtectionType,
312    #[error("single register write not supported on x86_64")]
313    WriteRegIsUnsupported,
314    #[error("error writing CPU registers {0}")]
315    WriteRegs(base::Error),
316    #[error("error writing guest memory {0}")]
317    WritingGuestMemory(GuestMemoryError),
318    #[error("error writing setup_data: {0}")]
319    WritingSetupData(GuestMemoryError),
320    #[error("the zero page extends past the end of guest_mem")]
321    ZeroPagePastRamEnd,
322    #[error("error writing the zero page of guest memory")]
323    ZeroPageSetup,
324}
325
326pub type Result<T> = std::result::Result<T, Error>;
327
328pub struct X8664arch;
329
330// Like `bootparam::setup_data` without the incomplete array field at the end, which allows us to
331// safely implement Copy, Clone
332#[repr(C)]
333#[derive(Copy, Clone, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
334struct setup_data_hdr {
335    pub next: u64,
336    pub type_: u32,
337    pub len: u32,
338}
339
340#[repr(u32)]
341#[derive(Copy, Clone, Debug, PartialEq, Eq)]
342pub enum SetupDataType {
343    Dtb = SETUP_DTB,
344    RngSeed = SETUP_RNG_SEED,
345}
346
347/// A single entry to be inserted in the bootparam `setup_data` linked list.
348pub struct SetupData {
349    pub data: Vec<u8>,
350    pub type_: SetupDataType,
351}
352
353impl SetupData {
354    /// Returns the length of the data
355    pub fn size(&self) -> usize {
356        self.data.len()
357    }
358}
359
360/// Collection of SetupData entries to be inserted in the
361/// bootparam `setup_data` linked list.
362pub struct SetupDataEntries {
363    entries: Vec<SetupData>,
364    setup_data_start: usize,
365    setup_data_end: usize,
366    available_size: usize,
367}
368
369impl SetupDataEntries {
370    /// Returns a new instance of SetupDataEntries
371    pub fn new(setup_data_start: usize, setup_data_end: usize) -> SetupDataEntries {
372        SetupDataEntries {
373            entries: Vec::new(),
374            setup_data_start,
375            setup_data_end,
376            available_size: setup_data_end - setup_data_start,
377        }
378    }
379
380    /// Adds a new SetupDataEntry and returns the remaining size available
381    pub fn insert(&mut self, setup_data: SetupData) -> usize {
382        self.available_size -= setup_data.size();
383        self.entries.push(setup_data);
384
385        self.available_size
386    }
387
388    /// Copy setup_data entries to guest memory and link them together with the `next` field.
389    /// Returns the guest address of the first entry in the setup_data list, if any.
390    pub fn write_setup_data(&self, guest_mem: &GuestMemory) -> Result<Option<GuestAddress>> {
391        write_setup_data(
392            guest_mem,
393            GuestAddress(self.setup_data_start as u64),
394            GuestAddress(self.setup_data_end as u64),
395            &self.entries,
396        )
397    }
398}
399
400#[derive(Copy, Clone, Debug)]
401enum E820Type {
402    Ram = 0x01,
403    Reserved = 0x2,
404}
405
406#[derive(Copy, Clone, Debug)]
407struct E820Entry {
408    pub address: GuestAddress,
409    pub len: u64,
410    pub mem_type: E820Type,
411}
412
413const KB: u64 = 1 << 10;
414const MB: u64 = 1 << 20;
415const GB: u64 = 1 << 30;
416
417pub const BOOT_STACK_POINTER: u64 = 0x8000;
418const FIRST_ADDR_PAST_32BITS: u64 = 1 << 32;
419// Make sure it align to 256MB for MTRR convenient
420const MEM_32BIT_GAP_SIZE: u64 = 768 * MB;
421// Reserved memory for nand_bios/LAPIC/IOAPIC/HPET/.....
422const RESERVED_MEM_SIZE: u64 = 0x800_0000;
423const DEFAULT_PCI_MEM_END: u64 = FIRST_ADDR_PAST_32BITS - RESERVED_MEM_SIZE - 1;
424// Reserve 64MB for pcie enhanced configuration
425const DEFAULT_PCIE_CFG_MMIO_SIZE: u64 = 0x400_0000;
426const DEFAULT_PCIE_CFG_MMIO_END: u64 = FIRST_ADDR_PAST_32BITS - RESERVED_MEM_SIZE - 1;
427const DEFAULT_PCIE_CFG_MMIO_START: u64 = DEFAULT_PCIE_CFG_MMIO_END - DEFAULT_PCIE_CFG_MMIO_SIZE + 1;
428// Linux (with 4-level paging) has a physical memory limit of 46 bits (64 TiB).
429const HIGH_MMIO_MAX_END: u64 = (1u64 << 46) - 1;
430pub const KERNEL_32BIT_ENTRY_OFFSET: u64 = 0x0;
431pub const KERNEL_64BIT_ENTRY_OFFSET: u64 = 0x200;
432pub const MULTIBOOT_INFO_OFFSET: u64 = 0x6000;
433pub const MULTIBOOT_INFO_SIZE: u64 = 0x1000;
434pub const ZERO_PAGE_OFFSET: u64 = 0x7000;
435// Set BIOS max size to 16M: this is used only when `unrestricted guest` is disabled
436const BIOS_MAX_SIZE: u64 = 0x1000000;
437
438pub const KERNEL_START_OFFSET: u64 = 0x20_0000;
439const CMDLINE_OFFSET: u64 = 0x2_0000;
440const CMDLINE_MAX_SIZE: u64 = 0x800; // including terminating zero
441const SETUP_DATA_START: u64 = CMDLINE_OFFSET + CMDLINE_MAX_SIZE;
442const SETUP_DATA_END: u64 = MPTABLE_RANGE.start;
443const X86_64_FDT_MAX_SIZE: u64 = 0x4000;
444const X86_64_SERIAL_1_3_IRQ: u32 = 4;
445const X86_64_SERIAL_2_4_IRQ: u32 = 3;
446// X86_64_SCI_IRQ is used to fill the ACPI FACP table.
447// The sci_irq number is better to be a legacy
448// IRQ number which is less than 16(actually most of the
449// platforms have fixed IRQ number 9). So we can
450// reserve the IRQ number 5 for SCI and let the
451// the other devices starts from next.
452pub const X86_64_SCI_IRQ: u32 = 5;
453// The CMOS RTC uses IRQ 8; start allocating IRQs at 9.
454pub const X86_64_IRQ_BASE: u32 = 9;
455const ACPI_HI_RSDP_WINDOW_BASE: u64 = 0x000E_0000;
456
457// pVM firmware memory. Should be within the low 4GB, so that it is identity-mapped
458// by setup_page_tables() when a protected VM boots in long mode, since the pVM firmware is
459// the VM entry point.
460const PROTECTED_VM_FW_MAX_SIZE: u64 = 0x40_0000;
461// Load the pVM firmware just below 2 GB to allow use of `-mcmodel=small`.
462const PROTECTED_VM_FW_START: u64 = 0x8000_0000 - PROTECTED_VM_FW_MAX_SIZE;
463
464#[derive(Debug, PartialEq, Eq)]
465pub enum CpuManufacturer {
466    Intel,
467    Amd,
468    Unknown,
469}
470
471pub fn get_cpu_manufacturer() -> CpuManufacturer {
472    cpuid::cpu_manufacturer()
473}
474
475pub struct ArchMemoryLayout {
476    // the pci mmio range below 4G
477    pci_mmio_before_32bit: AddressRange,
478    // the pcie cfg mmio range
479    pcie_cfg_mmio: AddressRange,
480    // the pVM firmware memory (if running a protected VM)
481    pvmfw_mem: Option<AddressRange>,
482}
483
484pub fn create_arch_memory_layout(
485    pci_config: &PciConfig,
486    has_protected_vm_firmware: bool,
487) -> Result<ArchMemoryLayout> {
488    // the max bus number is 256 and each bus occupy 1MB, so the max pcie cfg mmio size = 256M
489    const MAX_PCIE_ECAM_SIZE: u64 = 256 * MB;
490    let pcie_cfg_mmio = match pci_config.ecam {
491        Some(MemoryRegionConfig {
492            start,
493            size: Some(size),
494        }) => AddressRange::from_start_and_size(start, size.min(MAX_PCIE_ECAM_SIZE)).unwrap(),
495        Some(MemoryRegionConfig { start, size: None }) => {
496            AddressRange::from_start_and_end(start, DEFAULT_PCIE_CFG_MMIO_END)
497        }
498        None => {
499            AddressRange::from_start_and_end(DEFAULT_PCIE_CFG_MMIO_START, DEFAULT_PCIE_CFG_MMIO_END)
500        }
501    };
502    if pcie_cfg_mmio.start % pcie_cfg_mmio.len().unwrap() != 0
503        || pcie_cfg_mmio.start % MB != 0
504        || pcie_cfg_mmio.len().unwrap() % MB != 0
505    {
506        return Err(Error::ConfigurePciEcam(
507            "base and len must be aligned to 1MB and base must be a multiple of len".to_string(),
508        ));
509    }
510    if pcie_cfg_mmio.end >= 0x1_0000_0000 {
511        return Err(Error::ConfigurePciEcam(
512            "end address can't go beyond 4G".to_string(),
513        ));
514    }
515
516    let pci_mmio_before_32bit = match pci_config.mem {
517        Some(MemoryRegionConfig {
518            start,
519            size: Some(size),
520        }) => AddressRange::from_start_and_size(start, size)
521            .ok_or(Error::ConfigurePciMem("region overflowed".to_string()))?,
522        Some(MemoryRegionConfig { start, size: None }) => {
523            AddressRange::from_start_and_end(start, DEFAULT_PCI_MEM_END)
524        }
525        None => AddressRange::from_start_and_end(
526            pcie_cfg_mmio
527                .start
528                .min(FIRST_ADDR_PAST_32BITS - MEM_32BIT_GAP_SIZE),
529            DEFAULT_PCI_MEM_END,
530        ),
531    };
532
533    let pvmfw_mem = if has_protected_vm_firmware {
534        let range = AddressRange {
535            start: PROTECTED_VM_FW_START,
536            end: PROTECTED_VM_FW_START + PROTECTED_VM_FW_MAX_SIZE - 1,
537        };
538        if !pci_mmio_before_32bit.intersect(range).is_empty() {
539            return Err(Error::PciMmioOverlapPvmFw);
540        }
541
542        Some(range)
543    } else {
544        None
545    };
546
547    Ok(ArchMemoryLayout {
548        pci_mmio_before_32bit,
549        pcie_cfg_mmio,
550        pvmfw_mem,
551    })
552}
553
554/// The x86 reset vector for i386+ and x86_64 puts the processor into an "unreal mode" where it
555/// can access the last 1 MB of the 32-bit address space in 16-bit mode, and starts the instruction
556/// pointer at the effective physical address 0xFFFF_FFF0.
557fn bios_start(bios_size: u64) -> GuestAddress {
558    GuestAddress(FIRST_ADDR_PAST_32BITS - bios_size)
559}
560
561fn identity_map_addr_start() -> GuestAddress {
562    // Set Identity map address 4 pages before the max BIOS size
563    GuestAddress(FIRST_ADDR_PAST_32BITS - BIOS_MAX_SIZE - 4 * 0x1000)
564}
565
566fn tss_addr_start() -> GuestAddress {
567    // Set TSS address one page after identity map address
568    GuestAddress(identity_map_addr_start().offset() + 0x1000)
569}
570
571fn tss_addr_end() -> GuestAddress {
572    // Set TSS address section to have 3 pages
573    GuestAddress(tss_addr_start().offset() + 0x3000)
574}
575
576fn configure_boot_params(
577    guest_mem: &GuestMemory,
578    cmdline_addr: GuestAddress,
579    setup_data: Option<GuestAddress>,
580    initrd: Option<(GuestAddress, usize)>,
581    mut params: boot_params,
582    e820_entries: &[E820Entry],
583) -> Result<()> {
584    const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55;
585    const KERNEL_HDR_MAGIC: u32 = 0x5372_6448;
586    const KERNEL_LOADER_OTHER: u8 = 0xff;
587    const KERNEL_MIN_ALIGNMENT_BYTES: u32 = 0x100_0000; // Must be non-zero.
588
589    params.hdr.type_of_loader = KERNEL_LOADER_OTHER;
590    params.hdr.boot_flag = KERNEL_BOOT_FLAG_MAGIC;
591    params.hdr.header = KERNEL_HDR_MAGIC;
592    params.hdr.cmd_line_ptr = cmdline_addr.offset() as u32;
593    params.ext_cmd_line_ptr = (cmdline_addr.offset() >> 32) as u32;
594    params.hdr.kernel_alignment = KERNEL_MIN_ALIGNMENT_BYTES;
595    if let Some(setup_data) = setup_data {
596        params.hdr.setup_data = setup_data.offset();
597    }
598    if let Some((initrd_addr, initrd_size)) = initrd {
599        params.hdr.ramdisk_image = initrd_addr.offset() as u32;
600        params.ext_ramdisk_image = (initrd_addr.offset() >> 32) as u32;
601        params.hdr.ramdisk_size = initrd_size as u32;
602        params.ext_ramdisk_size = (initrd_size as u64 >> 32) as u32;
603    }
604
605    if e820_entries.len() >= params.e820_table.len() {
606        return Err(Error::E820Configuration);
607    }
608
609    for (src, dst) in e820_entries.iter().zip(params.e820_table.iter_mut()) {
610        dst.addr = src.address.offset();
611        dst.size = src.len;
612        dst.type_ = src.mem_type as u32;
613    }
614    params.e820_entries = e820_entries.len() as u8;
615
616    let zero_page_addr = GuestAddress(ZERO_PAGE_OFFSET);
617    if !guest_mem.is_valid_range(zero_page_addr, mem::size_of::<boot_params>() as u64) {
618        return Err(Error::ZeroPagePastRamEnd);
619    }
620
621    guest_mem
622        .write_obj_at_addr(params, zero_page_addr)
623        .map_err(|_| Error::ZeroPageSetup)?;
624
625    Ok(())
626}
627
628fn configure_multiboot_info(
629    guest_mem: &GuestMemory,
630    cmdline_addr: GuestAddress,
631    e820_entries: &[E820Entry],
632) -> Result<()> {
633    let mut multiboot_info = MultibootInfo {
634        ..Default::default()
635    };
636
637    // Extra Multiboot-related data is added directly after the info structure.
638    let mut multiboot_data_addr =
639        GuestAddress(MULTIBOOT_INFO_OFFSET + mem::size_of_val(&multiboot_info) as u64);
640    multiboot_data_addr = multiboot_data_addr
641        .align(16)
642        .ok_or(Error::MultibootInfoSetup)?;
643
644    // mem_lower is the amount of RAM below 1 MB, in units of KiB.
645    let mem_lower = guest_mem
646        .regions()
647        .filter(|r| {
648            r.options.purpose == MemoryRegionPurpose::GuestMemoryRegion
649                && r.guest_addr.offset() < 1 * MB
650        })
651        .map(|r| r.size as u64)
652        .sum::<u64>()
653        / KB;
654
655    // mem_upper is the amount of RAM above 1 MB up to the first memory hole, in units of KiB.
656    // We don't have the ISA 15-16 MB hole, so this includes all RAM from 1 MB up to the
657    // beginning of the PCI hole just below 4 GB.
658    let mem_upper = guest_mem
659        .regions()
660        .filter(|r| {
661            r.options.purpose == MemoryRegionPurpose::GuestMemoryRegion
662                && r.guest_addr.offset() >= 1 * MB
663                && r.guest_addr.offset() < 4 * GB
664        })
665        .map(|r| r.size as u64)
666        .sum::<u64>()
667        / KB;
668
669    multiboot_info.mem_lower = mem_lower as u32;
670    multiboot_info.mem_upper = mem_upper as u32;
671    multiboot_info.flags |= MultibootInfo::F_MEM;
672
673    // Memory map - convert from params.e820_table to Multiboot format.
674    let multiboot_mmap: Vec<MultibootMmapEntry> = e820_entries
675        .iter()
676        .map(|e820_entry| MultibootMmapEntry {
677            size: 20, // size of the entry, not including the size field itself
678            base_addr: e820_entry.address.offset(),
679            length: e820_entry.len,
680            type_: e820_entry.mem_type as u32,
681        })
682        .collect();
683    let multiboot_mmap_bytes = multiboot_mmap.as_bytes();
684    let multiboot_mmap_addr =
685        append_multiboot_info(guest_mem, &mut multiboot_data_addr, multiboot_mmap_bytes)?;
686    multiboot_info.mmap_addr = multiboot_mmap_addr.offset() as u32;
687    multiboot_info.mmap_length = multiboot_mmap_bytes.len() as u32;
688    multiboot_info.flags |= MultibootInfo::F_MMAP;
689
690    // Command line
691    multiboot_info.cmdline = cmdline_addr.offset() as u32;
692    multiboot_info.flags |= MultibootInfo::F_CMDLINE;
693
694    // Boot loader name
695    let boot_loader_name_addr =
696        append_multiboot_info(guest_mem, &mut multiboot_data_addr, b"crosvm\0")?;
697    multiboot_info.boot_loader_name = boot_loader_name_addr.offset() as u32;
698    multiboot_info.flags |= MultibootInfo::F_BOOT_LOADER_NAME;
699
700    guest_mem
701        .write_obj_at_addr(multiboot_info, GuestAddress(MULTIBOOT_INFO_OFFSET))
702        .map_err(|_| Error::MultibootInfoSetup)?;
703
704    Ok(())
705}
706
707fn append_multiboot_info(
708    guest_mem: &GuestMemory,
709    addr: &mut GuestAddress,
710    data: &[u8],
711) -> Result<GuestAddress> {
712    let data_addr = *addr;
713    let new_addr = addr
714        .checked_add(data.len() as u64)
715        .and_then(|a| a.align(16))
716        .ok_or(Error::MultibootInfoSetup)?;
717
718    // Make sure we don't write beyond the region reserved for Multiboot info.
719    if new_addr.offset() - MULTIBOOT_INFO_OFFSET > MULTIBOOT_INFO_SIZE {
720        return Err(Error::MultibootInfoSetup);
721    }
722
723    guest_mem
724        .write_all_at_addr(data, data_addr)
725        .map_err(|_| Error::MultibootInfoSetup)?;
726
727    *addr = new_addr;
728    Ok(data_addr)
729}
730
731/// Write setup_data entries in guest memory and link them together with the `next` field.
732///
733/// Returns the guest address of the first entry in the setup_data list, if any.
734fn write_setup_data(
735    guest_mem: &GuestMemory,
736    setup_data_start: GuestAddress,
737    setup_data_end: GuestAddress,
738    setup_data: &[SetupData],
739) -> Result<Option<GuestAddress>> {
740    let mut setup_data_list_head = None;
741
742    // Place the first setup_data at the first 64-bit aligned offset following setup_data_start.
743    let mut setup_data_addr = setup_data_start.align(8).ok_or(Error::SetupDataTooLarge)?;
744
745    let mut entry_iter = setup_data.iter().peekable();
746    while let Some(entry) = entry_iter.next() {
747        if setup_data_list_head.is_none() {
748            setup_data_list_head = Some(setup_data_addr);
749        }
750
751        // Ensure the entry (header plus data) fits into guest memory.
752        let entry_size = (mem::size_of::<setup_data_hdr>() + entry.data.len()) as u64;
753        let entry_end = setup_data_addr
754            .checked_add(entry_size)
755            .ok_or(Error::SetupDataTooLarge)?;
756
757        if entry_end >= setup_data_end {
758            return Err(Error::SetupDataTooLarge);
759        }
760
761        let next_setup_data_addr = if entry_iter.peek().is_some() {
762            // Place the next setup_data at a 64-bit aligned address.
763            setup_data_addr
764                .checked_add(entry_size)
765                .and_then(|addr| addr.align(8))
766                .ok_or(Error::SetupDataTooLarge)?
767        } else {
768            // This is the final entry. Terminate the list with next == 0.
769            GuestAddress(0)
770        };
771
772        let hdr = setup_data_hdr {
773            next: next_setup_data_addr.offset(),
774            type_: entry.type_ as u32,
775            len: entry
776                .data
777                .len()
778                .try_into()
779                .map_err(|_| Error::SetupDataTooLarge)?,
780        };
781
782        guest_mem
783            .write_obj_at_addr(hdr, setup_data_addr)
784            .map_err(Error::WritingSetupData)?;
785        guest_mem
786            .write_all_at_addr(
787                &entry.data,
788                setup_data_addr.unchecked_add(mem::size_of::<setup_data_hdr>() as u64),
789            )
790            .map_err(Error::WritingSetupData)?;
791
792        setup_data_addr = next_setup_data_addr;
793    }
794
795    Ok(setup_data_list_head)
796}
797
798/// Find the first `setup_data_hdr` with the given type in guest memory and return its address.
799fn find_setup_data(
800    mem: &GuestMemory,
801    setup_data_start: GuestAddress,
802    setup_data_end: GuestAddress,
803    type_: SetupDataType,
804) -> Option<GuestAddress> {
805    let mut setup_data_addr = setup_data_start.align(8)?;
806    while setup_data_addr < setup_data_end {
807        let hdr: setup_data_hdr = mem.read_obj_from_addr(setup_data_addr).ok()?;
808        if hdr.type_ == type_ as u32 {
809            return Some(setup_data_addr);
810        }
811
812        if hdr.next == 0 {
813            return None;
814        }
815
816        setup_data_addr = GuestAddress(hdr.next);
817    }
818    None
819}
820
821/// Generate a SETUP_RNG_SEED SetupData with random seed data.
822fn setup_data_rng_seed() -> SetupData {
823    let mut data = vec![0u8; 256];
824    OsRng.fill_bytes(&mut data);
825    SetupData {
826        data,
827        type_: SetupDataType::RngSeed,
828    }
829}
830
831/// Add an e820 region to the e820 map.
832fn add_e820_entry(
833    e820_entries: &mut Vec<E820Entry>,
834    range: AddressRange,
835    mem_type: E820Type,
836) -> Result<()> {
837    e820_entries.push(E820Entry {
838        address: GuestAddress(range.start),
839        len: range.len().ok_or(Error::E820Configuration)?,
840        mem_type,
841    });
842
843    Ok(())
844}
845
846/// Generate a memory map in INT 0x15 AX=0xE820 format.
847fn generate_e820_memory_map(
848    arch_memory_layout: &ArchMemoryLayout,
849    guest_mem: &GuestMemory,
850) -> Result<Vec<E820Entry>> {
851    let mut e820_entries = Vec::new();
852
853    for r in guest_mem.regions() {
854        let range = AddressRange::from_start_and_size(r.guest_addr.offset(), r.size as u64)
855            .expect("invalid guest mem region");
856        let mem_type = match r.options.purpose {
857            MemoryRegionPurpose::Bios => E820Type::Reserved,
858            MemoryRegionPurpose::GuestMemoryRegion => E820Type::Ram,
859            // After the pVM firmware jumped to the guest, the pVM firmware itself is no longer
860            // running, so its memory is reusable by the guest OS. So add this memory as RAM rather
861            // than Reserved.
862            MemoryRegionPurpose::ProtectedFirmwareRegion => E820Type::Ram,
863            MemoryRegionPurpose::ReservedMemory => E820Type::Reserved,
864        };
865        add_e820_entry(&mut e820_entries, range, mem_type)?;
866    }
867
868    let pcie_cfg_mmio_range = arch_memory_layout.pcie_cfg_mmio;
869    add_e820_entry(&mut e820_entries, pcie_cfg_mmio_range, E820Type::Reserved)?;
870
871    add_e820_entry(
872        &mut e820_entries,
873        X8664arch::get_pcie_vcfg_mmio_range(guest_mem, &pcie_cfg_mmio_range),
874        E820Type::Reserved,
875    )?;
876
877    // Reserve memory section for Identity map and TSS
878    add_e820_entry(
879        &mut e820_entries,
880        AddressRange {
881            start: identity_map_addr_start().offset(),
882            end: tss_addr_end().offset() - 1,
883        },
884        E820Type::Reserved,
885    )?;
886
887    Ok(e820_entries)
888}
889
890/// Returns a Vec of the valid memory addresses.
891/// These should be used to configure the GuestMemory structure for the platform.
892/// For x86_64 all addresses are valid from the start of the kernel except a
893/// carve out at the end of 32bit address space.
894pub fn arch_memory_regions(
895    arch_memory_layout: &ArchMemoryLayout,
896    mem_size: u64,
897    bios_size: Option<u64>,
898) -> Vec<(GuestAddress, u64, MemoryRegionOptions)> {
899    let mut regions = Vec::new();
900
901    // Some guest kernels expect a typical PC memory layout where the region between 640 KB and
902    // 1 MB is reserved for device memory/ROMs and get confused if there is a RAM region
903    // spanning this area, so we provide the traditional 640 KB low memory and 1 MB+
904    // high memory regions.
905    let mem_below_1m = 640 * KB;
906    regions.push((
907        GuestAddress(0),
908        mem_below_1m,
909        MemoryRegionOptions::new().purpose(MemoryRegionPurpose::GuestMemoryRegion),
910    ));
911
912    // Reserved/BIOS data area between 640 KB and 1 MB.
913    // This needs to be backed by an actual GuestMemory region so we can write BIOS tables here, but
914    // it should be reported as "reserved" in the e820 memory map to match PC architecture
915    // expectations.
916    regions.push((
917        GuestAddress(640 * KB),
918        (1 * MB) - (640 * KB),
919        MemoryRegionOptions::new().purpose(MemoryRegionPurpose::ReservedMemory),
920    ));
921
922    // RAM between 1 MB and 4 GB
923    let mem_1m_to_4g = arch_memory_layout.pci_mmio_before_32bit.start.min(mem_size) - 1 * MB;
924    regions.push((
925        GuestAddress(1 * MB),
926        mem_1m_to_4g,
927        MemoryRegionOptions::new().purpose(MemoryRegionPurpose::GuestMemoryRegion),
928    ));
929
930    // RAM above 4 GB
931    let mem_above_4g = mem_size.saturating_sub(1 * MB + mem_1m_to_4g);
932    if mem_above_4g > 0 {
933        regions.push((
934            GuestAddress(FIRST_ADDR_PAST_32BITS),
935            mem_above_4g,
936            MemoryRegionOptions::new().purpose(MemoryRegionPurpose::GuestMemoryRegion),
937        ));
938    }
939
940    if let Some(bios_size) = bios_size {
941        regions.push((
942            bios_start(bios_size),
943            bios_size,
944            MemoryRegionOptions::new().purpose(MemoryRegionPurpose::Bios),
945        ));
946    }
947
948    if let Some(pvmfw_mem) = arch_memory_layout.pvmfw_mem {
949        // Remove any areas of guest memory regions that overlap the pVM firmware range.
950        while let Some(overlapping_region_index) = regions.iter().position(|(addr, size, _opts)| {
951            let region_addr_range = AddressRange::from_start_and_size(addr.offset(), *size)
952                .expect("invalid GuestMemory range");
953            region_addr_range.overlaps(pvmfw_mem)
954        }) {
955            let overlapping_region = regions.swap_remove(overlapping_region_index);
956            let overlapping_region_range = AddressRange::from_start_and_size(
957                overlapping_region.0.offset(),
958                overlapping_region.1,
959            )
960            .unwrap();
961            let (first, second) = overlapping_region_range.non_overlapping_ranges(pvmfw_mem);
962            if !first.is_empty() {
963                regions.push((
964                    GuestAddress(first.start),
965                    first.len().unwrap(),
966                    overlapping_region.2.clone(),
967                ));
968            }
969            if !second.is_empty() {
970                regions.push((
971                    GuestAddress(second.start),
972                    second.len().unwrap(),
973                    overlapping_region.2,
974                ));
975            }
976        }
977
978        // Insert a region for the pVM firmware area.
979        regions.push((
980            GuestAddress(pvmfw_mem.start),
981            pvmfw_mem.len().expect("invalid pvmfw region"),
982            MemoryRegionOptions::new().purpose(MemoryRegionPurpose::ProtectedFirmwareRegion),
983        ));
984    }
985
986    regions.sort_unstable_by_key(|(addr, _, _)| *addr);
987
988    for (addr, size, options) in &regions {
989        debug!(
990            "{:#018x}-{:#018x} {:?}",
991            addr.offset(),
992            addr.offset() + size - 1,
993            options.purpose,
994        );
995    }
996
997    regions
998}
999
1000impl arch::LinuxArch for X8664arch {
1001    type Error = Error;
1002    type ArchMemoryLayout = ArchMemoryLayout;
1003
1004    fn arch_memory_layout(
1005        components: &VmComponents,
1006    ) -> std::result::Result<Self::ArchMemoryLayout, Self::Error> {
1007        create_arch_memory_layout(
1008            &components.pci_config,
1009            components.hv_cfg.protection_type.runs_firmware(),
1010        )
1011    }
1012
1013    fn guest_memory_layout(
1014        components: &VmComponents,
1015        arch_memory_layout: &Self::ArchMemoryLayout,
1016        _hypervisor: &impl Hypervisor,
1017    ) -> std::result::Result<Vec<(GuestAddress, u64, MemoryRegionOptions)>, Self::Error> {
1018        let bios_size = match &components.vm_image {
1019            VmImage::Bios(bios_file) => Some(bios_file.metadata().map_err(Error::LoadBios)?.len()),
1020            VmImage::Kernel(_) => None,
1021        };
1022
1023        Ok(arch_memory_regions(
1024            arch_memory_layout,
1025            components.memory_size,
1026            bios_size,
1027        ))
1028    }
1029
1030    fn get_system_allocator_config<V: Vm>(
1031        vm: &V,
1032        arch_memory_layout: &Self::ArchMemoryLayout,
1033    ) -> SystemAllocatorConfig {
1034        SystemAllocatorConfig {
1035            io: Some(AddressRange {
1036                start: 0xc000,
1037                end: 0xffff,
1038            }),
1039            low_mmio: arch_memory_layout.pci_mmio_before_32bit,
1040            high_mmio: Self::get_high_mmio_range(vm, arch_memory_layout),
1041            platform_mmio: None,
1042            first_irq: X86_64_IRQ_BASE,
1043        }
1044    }
1045
1046    fn build_vm<V, Vcpu>(
1047        mut components: VmComponents,
1048        arch_memory_layout: &Self::ArchMemoryLayout,
1049        vm_evt_wrtube: &SendTube,
1050        system_allocator: &mut SystemAllocator,
1051        serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>,
1052        serial_jail: Option<Minijail>,
1053        battery: (Option<BatteryType>, Option<Minijail>),
1054        mut vm: V,
1055        ramoops_region: Option<arch::pstore::RamoopsRegion>,
1056        devs: Vec<(Box<dyn BusDeviceObj>, Option<Minijail>)>,
1057        irq_chip: &mut dyn IrqChipX86_64,
1058        vcpu_ids: &mut Vec<usize>,
1059        dump_device_tree_blob: Option<PathBuf>,
1060        debugcon_jail: Option<Minijail>,
1061        pflash_jail: Option<Minijail>,
1062        fw_cfg_jail: Option<Minijail>,
1063        #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
1064        guest_suspended_cvar: Option<Arc<(Mutex<bool>, Condvar)>>,
1065        device_tree_overlays: Vec<DtbOverlay>,
1066        _fdt_position: Option<FdtPosition>,
1067        _no_pmu: bool,
1068    ) -> std::result::Result<RunnableLinuxVm<V, Vcpu>, Self::Error>
1069    where
1070        V: VmX86_64,
1071        Vcpu: VcpuX86_64,
1072    {
1073        let mem = vm.get_memory().clone();
1074
1075        let vcpu_count = components.vcpu_count;
1076
1077        vm.set_identity_map_addr(identity_map_addr_start())
1078            .map_err(Error::SetIdentityMapAddr)?;
1079
1080        vm.set_tss_addr(tss_addr_start())
1081            .map_err(Error::SetTssAddr)?;
1082
1083        // Use IRQ info in ACPI if provided by the user.
1084        let mut mptable = true;
1085        let mut sci_irq = X86_64_SCI_IRQ;
1086
1087        // punch pcie config mmio from pci low mmio, so that it couldn't be
1088        // allocated to any device.
1089        let pcie_cfg_mmio_range = arch_memory_layout.pcie_cfg_mmio;
1090        system_allocator
1091            .reserve_mmio(pcie_cfg_mmio_range)
1092            .map_err(Error::ReservePcieCfgMmio)?;
1093
1094        for sdt in components.acpi_sdts.iter() {
1095            if sdt.is_signature(b"FACP") {
1096                mptable = false;
1097                let sci_irq_fadt: u16 = sdt.read(acpi::FADT_FIELD_SCI_INTERRUPT);
1098                sci_irq = sci_irq_fadt.into();
1099                if !system_allocator.reserve_irq(sci_irq) {
1100                    warn!("sci irq {} already reserved.", sci_irq);
1101                }
1102            }
1103        }
1104
1105        let pcie_vcfg_range = Self::get_pcie_vcfg_mmio_range(&mem, &pcie_cfg_mmio_range);
1106        let mmio_bus = Arc::new(Bus::new(BusType::Mmio));
1107        let io_bus = Arc::new(Bus::new(BusType::Io));
1108
1109        let (pci_devices, _devs): (Vec<_>, Vec<_>) = devs
1110            .into_iter()
1111            .partition(|(dev, _)| dev.as_pci_device().is_some());
1112
1113        let pci_devices = pci_devices
1114            .into_iter()
1115            .map(|(dev, jail_orig)| (dev.into_pci_device().unwrap(), jail_orig))
1116            .collect();
1117
1118        let (pci, pci_irqs, pid_debug_label_map, amls, gpe_scope_amls) = arch::generate_pci_root(
1119            pci_devices,
1120            irq_chip.as_irq_chip_mut(),
1121            mmio_bus.clone(),
1122            GuestAddress(pcie_cfg_mmio_range.start),
1123            12,
1124            io_bus.clone(),
1125            system_allocator,
1126            &mut vm,
1127            4, // Share the four pin interrupts (INTx#)
1128            Some(pcie_vcfg_range.start),
1129            #[cfg(feature = "swap")]
1130            swap_controller,
1131        )
1132        .map_err(Error::CreatePciRoot)?;
1133
1134        let pci = Arc::new(Mutex::new(pci));
1135        pci.lock().enable_pcie_cfg_mmio(pcie_cfg_mmio_range.start);
1136        let pci_cfg = PciConfigIo::new(
1137            pci.clone(),
1138            components.break_linux_pci_config_io,
1139            vm_evt_wrtube.try_clone().map_err(Error::CloneTube)?,
1140        );
1141        let pci_bus = Arc::new(Mutex::new(pci_cfg));
1142        io_bus.insert(pci_bus, 0xcf8, 0x8).unwrap();
1143
1144        let pcie_cfg_mmio = Arc::new(Mutex::new(PciConfigMmio::new(pci.clone(), 12)));
1145        let pcie_cfg_mmio_len = pcie_cfg_mmio_range.len().unwrap();
1146        mmio_bus
1147            .insert(pcie_cfg_mmio, pcie_cfg_mmio_range.start, pcie_cfg_mmio_len)
1148            .unwrap();
1149
1150        let pcie_vcfg_mmio = Arc::new(Mutex::new(PciVirtualConfigMmio::new(pci.clone(), 13)));
1151        mmio_bus
1152            .insert(
1153                pcie_vcfg_mmio,
1154                pcie_vcfg_range.start,
1155                pcie_vcfg_range.len().unwrap(),
1156            )
1157            .unwrap();
1158
1159        // Event used to notify crosvm that guest OS is trying to suspend.
1160        let (suspend_tube_send, suspend_tube_recv) =
1161            Tube::directional_pair().map_err(Error::CreateTube)?;
1162        let suspend_tube_send = Arc::new(Mutex::new(suspend_tube_send));
1163
1164        if components.fw_cfg_enable {
1165            Self::setup_fw_cfg_device(
1166                &io_bus,
1167                components.fw_cfg_parameters.clone(),
1168                components.bootorder_fw_cfg_blob.clone(),
1169                fw_cfg_jail,
1170                #[cfg(feature = "swap")]
1171                swap_controller,
1172            )?;
1173        }
1174
1175        if !components.no_i8042 {
1176            Self::setup_legacy_i8042_device(
1177                &io_bus,
1178                irq_chip.pit_uses_speaker_port(),
1179                vm_evt_wrtube.try_clone().map_err(Error::CloneTube)?,
1180            )?;
1181        }
1182        let mut vm_request_tube = if !components.no_rtc {
1183            let (host_tube, device_tube) = Tube::pair()
1184                .context("create tube")
1185                .map_err(Error::SetupCmos)?;
1186            Self::setup_legacy_cmos_device(
1187                arch_memory_layout,
1188                &io_bus,
1189                irq_chip,
1190                device_tube,
1191                components.memory_size,
1192            )
1193            .map_err(Error::SetupCmos)?;
1194            Some(host_tube)
1195        } else {
1196            None
1197        };
1198        let serial_devices = Self::setup_serial_devices(
1199            components.hv_cfg.protection_type,
1200            irq_chip.as_irq_chip_mut(),
1201            &io_bus,
1202            serial_parameters,
1203            serial_jail,
1204            #[cfg(feature = "swap")]
1205            swap_controller,
1206        )?;
1207        Self::setup_debugcon_devices(
1208            components.hv_cfg.protection_type,
1209            &io_bus,
1210            serial_parameters,
1211            debugcon_jail,
1212            #[cfg(feature = "swap")]
1213            swap_controller,
1214        )?;
1215
1216        let bios_size = if let VmImage::Bios(ref bios) = components.vm_image {
1217            bios.metadata().map_err(Error::LoadBios)?.len()
1218        } else {
1219            0
1220        };
1221        if let Some(pflash_image) = components.pflash_image {
1222            Self::setup_pflash(
1223                pflash_image,
1224                components.pflash_block_size,
1225                bios_size,
1226                &mmio_bus,
1227                pflash_jail,
1228                #[cfg(feature = "swap")]
1229                swap_controller,
1230            )?;
1231        }
1232
1233        // Functions that use/create jails MUST be used before the call to
1234        // setup_acpi_devices below, as this move us into a multiprocessing state
1235        // from which we can no longer fork.
1236
1237        let mut resume_notify_devices = Vec::new();
1238
1239        // each bus occupy 1MB mmio for pcie enhanced configuration
1240        let max_bus = (pcie_cfg_mmio_len / 0x100000 - 1) as u8;
1241        let (mut acpi_dev_resource, bat_control) = Self::setup_acpi_devices(
1242            arch_memory_layout,
1243            pci.clone(),
1244            &mem,
1245            &io_bus,
1246            system_allocator,
1247            suspend_tube_send.clone(),
1248            vm_evt_wrtube.try_clone().map_err(Error::CloneTube)?,
1249            components.acpi_sdts,
1250            irq_chip.as_irq_chip_mut(),
1251            sci_irq,
1252            battery,
1253            &mmio_bus,
1254            max_bus,
1255            &mut resume_notify_devices,
1256            #[cfg(feature = "swap")]
1257            swap_controller,
1258            #[cfg(any(target_os = "android", target_os = "linux"))]
1259            components.ac_adapter,
1260            guest_suspended_cvar,
1261            &pci_irqs,
1262        )?;
1263
1264        // Create customized SSDT table
1265        let sdt = acpi::create_customize_ssdt(pci.clone(), amls, gpe_scope_amls);
1266        if let Some(sdt) = sdt {
1267            acpi_dev_resource.sdts.push(sdt);
1268        }
1269
1270        irq_chip
1271            .finalize_devices(system_allocator, &io_bus, &mmio_bus)
1272            .map_err(Error::RegisterIrqfd)?;
1273
1274        // All of these bios generated tables are set manually for the benefit of the kernel boot
1275        // flow (since there's no BIOS to set it) and for the BIOS boot flow since crosvm doesn't
1276        // have a way to pass the BIOS these configs.
1277        // This works right now because the only guest BIOS used with crosvm (u-boot) ignores these
1278        // tables and the guest OS picks them up.
1279        // If another guest does need a way to pass these tables down to it's BIOS, this approach
1280        // should be rethought.
1281
1282        // Make sure the `vcpu_count` casts below and the arithmetic in `setup_mptable` are well
1283        // defined.
1284        if vcpu_count >= u8::MAX.into() {
1285            return Err(Error::TooManyVcpus);
1286        }
1287
1288        if mptable {
1289            mptable::setup_mptable(&mem, vcpu_count as u8, &pci_irqs)
1290                .map_err(Error::SetupMptable)?;
1291        }
1292        smbios::setup_smbios(&mem, &components.smbios, bios_size).map_err(Error::SetupSmbios)?;
1293
1294        let host_cpus = if components.host_cpu_topology {
1295            components.vcpu_affinity.clone()
1296        } else {
1297            None
1298        };
1299
1300        // TODO (tjeznach) Write RSDP to bootconfig before writing to memory
1301        acpi::create_acpi_tables(
1302            &mem,
1303            vcpu_count as u8,
1304            sci_irq,
1305            0xcf9,
1306            6, // RST_CPU|SYS_RST
1307            &acpi_dev_resource,
1308            host_cpus,
1309            vcpu_ids,
1310            &pci_irqs,
1311            pcie_cfg_mmio_range.start,
1312            max_bus,
1313            components.force_s2idle,
1314        )
1315        .ok_or(Error::CreateAcpi)?;
1316
1317        let mut cmdline = Self::get_base_linux_cmdline();
1318
1319        get_serial_cmdline(&mut cmdline, serial_parameters, "io", &serial_devices)
1320            .map_err(Error::GetSerialCmdline)?;
1321
1322        for param in components.extra_kernel_params {
1323            cmdline.insert_str(&param).map_err(Error::Cmdline)?;
1324        }
1325
1326        if let Some(ramoops_region) = ramoops_region {
1327            arch::pstore::add_ramoops_kernel_cmdline(&mut cmdline, &ramoops_region)
1328                .map_err(Error::Cmdline)?;
1329        }
1330
1331        let pci_start = arch_memory_layout.pci_mmio_before_32bit.start;
1332
1333        let mut vcpu_init = vec![VcpuInitX86_64::default(); vcpu_count];
1334        let mut msrs = BTreeMap::new();
1335
1336        let protection_type = components.hv_cfg.protection_type;
1337
1338        match components.vm_image {
1339            VmImage::Bios(ref mut bios) => {
1340                if protection_type.runs_firmware() {
1341                    return Err(Error::PvmFwBiosUnsupported);
1342                }
1343
1344                // Allow a bios to hardcode CMDLINE_OFFSET and read the kernel command line from it.
1345                Self::load_cmdline(
1346                    &mem,
1347                    GuestAddress(CMDLINE_OFFSET),
1348                    cmdline,
1349                    CMDLINE_MAX_SIZE as usize - 1,
1350                )?;
1351                Self::load_bios(&mem, bios)?;
1352                regs::set_default_msrs(&mut msrs);
1353                // The default values for `Regs` and `Sregs` already set up the reset vector.
1354            }
1355            VmImage::Kernel(ref mut kernel_image) => {
1356                let (params, kernel_region, kernel_entry, mut cpu_mode, kernel_type) =
1357                    Self::load_kernel(&mem, kernel_image)?;
1358
1359                info!("Loaded {} kernel", kernel_type);
1360
1361                Self::setup_system_memory(
1362                    arch_memory_layout,
1363                    &mem,
1364                    cmdline,
1365                    components.initrd_image,
1366                    components.android_fstab,
1367                    kernel_region,
1368                    params,
1369                    dump_device_tree_blob,
1370                    device_tree_overlays,
1371                    protection_type,
1372                )?;
1373
1374                if protection_type.needs_firmware_loaded() {
1375                    arch::load_image(
1376                        &mem,
1377                        &mut components
1378                            .pvm_fw
1379                            .expect("pvmfw must be available if ProtectionType loads it"),
1380                        GuestAddress(PROTECTED_VM_FW_START),
1381                        PROTECTED_VM_FW_MAX_SIZE,
1382                    )
1383                    .map_err(Error::LoadCustomPvmFw)?;
1384                } else if protection_type.runs_firmware() {
1385                    // Tell the hypervisor to load the pVM firmware.
1386                    vm.load_protected_vm_firmware(
1387                        GuestAddress(PROTECTED_VM_FW_START),
1388                        PROTECTED_VM_FW_MAX_SIZE,
1389                    )
1390                    .map_err(Error::LoadPvmFw)?;
1391                }
1392
1393                let entry_addr = if protection_type.needs_firmware_loaded() {
1394                    Some(PROTECTED_VM_FW_START)
1395                } else if protection_type.runs_firmware() {
1396                    None // Initial RIP value is set by the hypervisor
1397                } else {
1398                    Some(kernel_entry.offset())
1399                };
1400
1401                if let Some(entry) = entry_addr {
1402                    vcpu_init[0].regs.rip = entry;
1403                }
1404
1405                match kernel_type {
1406                    KernelType::BzImage | KernelType::Elf => {
1407                        // Configure the bootstrap VCPU for the Linux/x86 boot protocol.
1408                        // <https://www.kernel.org/doc/html/latest/x86/boot.html>
1409                        vcpu_init[0].regs.rsp = BOOT_STACK_POINTER;
1410                        vcpu_init[0].regs.rsi = ZERO_PAGE_OFFSET;
1411                    }
1412                    KernelType::Multiboot => {
1413                        // Provide Multiboot-compatible bootloader information.
1414                        vcpu_init[0].regs.rax = MULTIBOOT_BOOTLOADER_MAGIC.into();
1415                        vcpu_init[0].regs.rbx = MULTIBOOT_INFO_OFFSET;
1416                    }
1417                }
1418
1419                if protection_type.runs_firmware() {
1420                    // Pass DTB address to pVM firmware. This is redundant with the DTB entry in the
1421                    // `setup_data` list, but it allows the pVM firmware to know the location of the
1422                    // DTB without having the `setup_data` region mapped yet.
1423                    if let Some(fdt_setup_data_addr) = find_setup_data(
1424                        &mem,
1425                        GuestAddress(SETUP_DATA_START),
1426                        GuestAddress(SETUP_DATA_END),
1427                        SetupDataType::Dtb,
1428                    ) {
1429                        vcpu_init[0].regs.rdx =
1430                            fdt_setup_data_addr.offset() + size_of::<setup_data_hdr>() as u64;
1431                    }
1432
1433                    // Pass pVM payload entry address to pVM firmware.
1434                    // NOTE: this is only for development purposes. An actual pvmfw
1435                    // implementation should not use this value and should instead receive
1436                    // the pVM payload start and size info from crosvm as the DTB properties
1437                    // /config/kernel-address and /config/kernel-size and determine the offset
1438                    // of the entry point on its own, not trust crosvm to provide it.
1439                    vcpu_init[0].regs.rdi = kernel_entry.offset();
1440
1441                    // The pVM firmware itself always starts in 32-bit protected mode
1442                    // with paging disabled, regardless of the type of payload.
1443                    cpu_mode = CpuMode::FlatProtectedMode;
1444                }
1445
1446                match cpu_mode {
1447                    CpuMode::LongMode => {
1448                        regs::set_long_mode_msrs(&mut msrs);
1449
1450                        // Set up long mode and enable paging.
1451                        regs::configure_segments_and_sregs(&mem, &mut vcpu_init[0].sregs)
1452                            .map_err(Error::ConfigureSegments)?;
1453                        regs::setup_page_tables(&mem, &mut vcpu_init[0].sregs)
1454                            .map_err(Error::SetupPageTables)?;
1455                    }
1456                    CpuMode::FlatProtectedMode => {
1457                        regs::set_default_msrs(&mut msrs);
1458
1459                        // Set up 32-bit protected mode with paging disabled.
1460                        regs::configure_segments_and_sregs_flat32(&mem, &mut vcpu_init[0].sregs)
1461                            .map_err(Error::ConfigureSegments)?;
1462                    }
1463                }
1464
1465                regs::set_mtrr_msrs(&mut msrs, &vm, pci_start);
1466            }
1467        }
1468
1469        // Initialize MSRs for all VCPUs.
1470        for vcpu in vcpu_init.iter_mut() {
1471            vcpu.msrs = msrs.clone();
1472        }
1473
1474        let mut vm_request_tubes = Vec::new();
1475        if let Some(req_tube) = vm_request_tube.take() {
1476            vm_request_tubes.push(req_tube);
1477        }
1478
1479        Ok(RunnableLinuxVm {
1480            vm,
1481            vcpu_count,
1482            vcpus: None,
1483            vcpu_affinity: components.vcpu_affinity,
1484            vcpu_init,
1485            no_smt: components.no_smt,
1486            irq_chip: irq_chip.try_box_clone().map_err(Error::CloneIrqChip)?,
1487            io_bus,
1488            mmio_bus,
1489            pid_debug_label_map,
1490            suspend_tube: (suspend_tube_send, suspend_tube_recv),
1491            resume_notify_devices,
1492            rt_cpus: components.rt_cpus,
1493            delay_rt: components.delay_rt,
1494            bat_control,
1495            pm: Some(acpi_dev_resource.pm),
1496            root_config: pci,
1497            #[cfg(any(target_os = "android", target_os = "linux"))]
1498            platform_devices: Vec::new(),
1499            hotplug_bus: BTreeMap::new(),
1500            devices_thread: None,
1501            vm_request_tubes,
1502        })
1503    }
1504
1505    fn configure_vcpu<V: Vm>(
1506        vm: &V,
1507        hypervisor: &dyn HypervisorX86_64,
1508        irq_chip: &mut dyn IrqChipX86_64,
1509        vcpu: &mut dyn VcpuX86_64,
1510        vcpu_init: VcpuInitX86_64,
1511        vcpu_id: usize,
1512        num_cpus: usize,
1513        cpu_config: Option<CpuConfigX86_64>,
1514    ) -> Result<()> {
1515        let cpu_config = match cpu_config {
1516            Some(config) => config,
1517            None => return Err(Error::InvalidCpuConfig),
1518        };
1519        if !vm.check_capability(VmCap::EarlyInitCpuid) {
1520            cpuid::setup_cpuid(hypervisor, irq_chip, vcpu, vcpu_id, num_cpus, cpu_config)
1521                .map_err(Error::SetupCpuid)?;
1522        }
1523
1524        vcpu.set_regs(&vcpu_init.regs).map_err(Error::WriteRegs)?;
1525
1526        vcpu.set_sregs(&vcpu_init.sregs)
1527            .map_err(Error::SetupSregs)?;
1528
1529        vcpu.set_fpu(&vcpu_init.fpu).map_err(Error::SetupFpu)?;
1530
1531        let vcpu_supported_var_mtrrs = regs::vcpu_supported_variable_mtrrs(vcpu);
1532        let num_var_mtrrs = regs::count_variable_mtrrs(&vcpu_init.msrs);
1533        let skip_mtrr_msrs = if num_var_mtrrs > vcpu_supported_var_mtrrs {
1534            warn!(
1535                "Too many variable MTRR entries ({} required, {} supported),
1536                please check pci_start addr, guest with pass through device may be very slow",
1537                num_var_mtrrs, vcpu_supported_var_mtrrs,
1538            );
1539            // Filter out the MTRR entries from the MSR list.
1540            true
1541        } else {
1542            false
1543        };
1544
1545        for (msr_index, value) in vcpu_init.msrs.into_iter() {
1546            if skip_mtrr_msrs && regs::is_mtrr_msr(msr_index) {
1547                continue;
1548            }
1549
1550            vcpu.set_msr(msr_index, value).map_err(Error::SetupMsrs)?;
1551        }
1552
1553        interrupts::set_lint(vcpu_id, irq_chip).map_err(Error::SetLint)?;
1554
1555        Ok(())
1556    }
1557
1558    fn register_pci_device<V: VmX86_64, Vcpu: VcpuX86_64>(
1559        linux: &mut RunnableLinuxVm<V, Vcpu>,
1560        device: Box<dyn PciDevice>,
1561        #[cfg(any(target_os = "android", target_os = "linux"))] minijail: Option<Minijail>,
1562        resources: &mut SystemAllocator,
1563        hp_control_tube: &mpsc::Sender<PciRootCommand>,
1564        #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
1565    ) -> Result<PciAddress> {
1566        arch::configure_pci_device(
1567            linux,
1568            device,
1569            #[cfg(any(target_os = "android", target_os = "linux"))]
1570            minijail,
1571            resources,
1572            hp_control_tube,
1573            #[cfg(feature = "swap")]
1574            swap_controller,
1575        )
1576        .map_err(Error::ConfigurePciDevice)
1577    }
1578
1579    fn get_host_cpu_frequencies_khz() -> Result<BTreeMap<usize, Vec<u32>>> {
1580        Ok(BTreeMap::new())
1581    }
1582
1583    fn get_host_cpu_max_freq_khz() -> Result<BTreeMap<usize, u32>> {
1584        Ok(BTreeMap::new())
1585    }
1586
1587    fn get_host_cpu_capacity() -> Result<BTreeMap<usize, u32>> {
1588        Ok(BTreeMap::new())
1589    }
1590
1591    fn get_host_cpu_clusters() -> Result<Vec<CpuSet>> {
1592        Ok(Vec::new())
1593    }
1594}
1595
1596// OSC returned status register in CDW1
1597const OSC_STATUS_UNSUPPORT_UUID: u32 = 0x4;
1598// pci host bridge OSC returned control register in CDW3
1599#[allow(dead_code)]
1600const PCI_HB_OSC_CONTROL_PCIE_HP: u32 = 0x1;
1601const PCI_HB_OSC_CONTROL_SHPC_HP: u32 = 0x2;
1602#[allow(dead_code)]
1603const PCI_HB_OSC_CONTROL_PCIE_PME: u32 = 0x4;
1604const PCI_HB_OSC_CONTROL_PCIE_AER: u32 = 0x8;
1605#[allow(dead_code)]
1606const PCI_HB_OSC_CONTROL_PCIE_CAP: u32 = 0x10;
1607
1608struct PciRootOSC {}
1609
1610// Method (_OSC, 4, NotSerialized)  // _OSC: Operating System Capabilities
1611// {
1612//     CreateDWordField (Arg3, Zero, CDW1)  // flag and return value
1613//     If (Arg0 == ToUUID ("33db4d5b-1ff7-401c-9657-7441c03dd766"))
1614//     {
1615//         CreateDWordField (Arg3, 8, CDW3) // control field
1616//         if ( 0 == (CDW1 & 0x01))  // Query flag ?
1617//         {
1618//              CDW3 &= !(SHPC_HP | AER)
1619//         }
1620//     } Else {
1621//         CDW1 |= UNSUPPORT_UUID
1622//     }
1623//     Return (Arg3)
1624// }
1625impl Aml for PciRootOSC {
1626    fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
1627        let osc_uuid = "33DB4D5B-1FF7-401C-9657-7441C03DD766";
1628        // virtual pcie root port supports hotplug, pme, and pcie cap register, clear all
1629        // the other bits.
1630        let mask = !(PCI_HB_OSC_CONTROL_SHPC_HP | PCI_HB_OSC_CONTROL_PCIE_AER);
1631        aml::Method::new(
1632            "_OSC".into(),
1633            4,
1634            false,
1635            vec![
1636                &aml::CreateDWordField::new(
1637                    &aml::Name::new_field_name("CDW1"),
1638                    &aml::Arg(3),
1639                    &aml::ZERO,
1640                ),
1641                &aml::If::new(
1642                    &aml::Equal::new(&aml::Arg(0), &aml::Uuid::new(osc_uuid)),
1643                    vec![
1644                        &aml::CreateDWordField::new(
1645                            &aml::Name::new_field_name("CDW3"),
1646                            &aml::Arg(3),
1647                            &(8_u8),
1648                        ),
1649                        &aml::If::new(
1650                            &aml::Equal::new(
1651                                &aml::ZERO,
1652                                &aml::And::new(
1653                                    &aml::ZERO,
1654                                    &aml::Name::new_field_name("CDW1"),
1655                                    &aml::ONE,
1656                                ),
1657                            ),
1658                            vec![&aml::And::new(
1659                                &aml::Name::new_field_name("CDW3"),
1660                                &mask,
1661                                &aml::Name::new_field_name("CDW3"),
1662                            )],
1663                        ),
1664                    ],
1665                ),
1666                &aml::Else::new(vec![&aml::Or::new(
1667                    &aml::Name::new_field_name("CDW1"),
1668                    &OSC_STATUS_UNSUPPORT_UUID,
1669                    &aml::Name::new_field_name("CDW1"),
1670                )]),
1671                &aml::Return::new(&aml::Arg(3)),
1672            ],
1673        )
1674        .to_aml_bytes(aml)
1675    }
1676}
1677
1678pub enum CpuMode {
1679    /// 32-bit protected mode with paging disabled.
1680    FlatProtectedMode,
1681
1682    /// 64-bit long mode.
1683    LongMode,
1684}
1685
1686#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1687pub enum KernelType {
1688    BzImage,
1689    Elf,
1690    Multiboot,
1691}
1692
1693impl fmt::Display for KernelType {
1694    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1695        match self {
1696            KernelType::BzImage => write!(f, "bzImage"),
1697            KernelType::Elf => write!(f, "ELF"),
1698            KernelType::Multiboot => write!(f, "Multiboot"),
1699        }
1700    }
1701}
1702
1703impl X8664arch {
1704    /// Loads the bios from an open file.
1705    ///
1706    /// # Arguments
1707    ///
1708    /// * `mem` - The memory to be used by the guest.
1709    /// * `bios_image` - the File object for the specified bios
1710    fn load_bios(mem: &GuestMemory, bios_image: &mut File) -> Result<()> {
1711        let bios_image_length = bios_image.get_len().map_err(Error::LoadBios)?;
1712        if bios_image_length >= FIRST_ADDR_PAST_32BITS {
1713            return Err(Error::LoadBios(io::Error::new(
1714                io::ErrorKind::InvalidData,
1715                format!(
1716                    "bios was {bios_image_length} bytes, expected less than {FIRST_ADDR_PAST_32BITS}",
1717                ),
1718            )));
1719        }
1720
1721        let guest_slice = mem
1722            .get_slice_at_addr(bios_start(bios_image_length), bios_image_length as usize)
1723            .map_err(Error::SetupGuestMemory)?;
1724        bios_image
1725            .read_exact_at_volatile(guest_slice, 0)
1726            .map_err(Error::LoadBios)?;
1727        Ok(())
1728    }
1729
1730    fn setup_pflash(
1731        pflash_image: File,
1732        block_size: u32,
1733        bios_size: u64,
1734        mmio_bus: &Bus,
1735        jail: Option<Minijail>,
1736        #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
1737    ) -> Result<()> {
1738        let size = pflash_image.metadata().map_err(Error::LoadPflash)?.len();
1739        let start = FIRST_ADDR_PAST_32BITS - bios_size - size;
1740        let pflash_image = Box::new(pflash_image);
1741
1742        #[cfg(any(target_os = "android", target_os = "linux"))]
1743        let fds = pflash_image.as_raw_descriptors();
1744
1745        let pflash = Pflash::new(pflash_image, block_size).map_err(Error::SetupPflash)?;
1746        let pflash: Arc<Mutex<dyn BusDevice>> = match jail {
1747            #[cfg(any(target_os = "android", target_os = "linux"))]
1748            Some(jail) => Arc::new(Mutex::new(
1749                ProxyDevice::new(
1750                    pflash,
1751                    jail,
1752                    fds,
1753                    #[cfg(feature = "swap")]
1754                    swap_controller,
1755                )
1756                .map_err(Error::CreateProxyDevice)?,
1757            )),
1758            #[cfg(windows)]
1759            Some(_) => unreachable!(),
1760            None => Arc::new(Mutex::new(pflash)),
1761        };
1762        mmio_bus
1763            .insert(pflash, start, size)
1764            .map_err(Error::InsertBus)?;
1765
1766        Ok(())
1767    }
1768
1769    /// Writes the command line string to the given memory slice.
1770    ///
1771    /// # Arguments
1772    ///
1773    /// * `guest_mem` - A u8 slice that will be partially overwritten by the command line.
1774    /// * `guest_addr` - The address in `guest_mem` at which to load the command line.
1775    /// * `cmdline` - The kernel command line.
1776    /// * `kernel_max_cmdline_len` - The maximum command line length (without NUL terminator)
1777    ///   supported by the kernel.
1778    fn load_cmdline(
1779        guest_mem: &GuestMemory,
1780        guest_addr: GuestAddress,
1781        cmdline: kernel_cmdline::Cmdline,
1782        kernel_max_cmdline_len: usize,
1783    ) -> Result<()> {
1784        let mut cmdline_guest_mem_slice = guest_mem
1785            .get_slice_at_addr(guest_addr, CMDLINE_MAX_SIZE as usize)
1786            .map_err(|_| Error::CommandLineOverflow)?;
1787
1788        let mut cmdline_bytes: Vec<u8> = cmdline
1789            .into_bytes_with_max_len(kernel_max_cmdline_len)
1790            .map_err(Error::Cmdline)?;
1791        cmdline_bytes.push(0u8); // Add NUL terminator.
1792
1793        cmdline_guest_mem_slice
1794            .write_all(&cmdline_bytes)
1795            .map_err(|_| Error::CommandLineOverflow)?;
1796
1797        Ok(())
1798    }
1799
1800    /// Loads the kernel from an open file.
1801    ///
1802    /// # Arguments
1803    ///
1804    /// * `mem` - The memory to be used by the guest.
1805    /// * `kernel_image` - the File object for the specified kernel.
1806    ///
1807    /// # Returns
1808    ///
1809    /// On success, returns the Linux x86_64 boot protocol parameters, the address range containing
1810    /// the kernel, the entry point (initial `RIP` value), the initial CPU mode, and the type of
1811    /// kernel.
1812    fn load_kernel(
1813        mem: &GuestMemory,
1814        kernel_image: &mut File,
1815    ) -> Result<(boot_params, AddressRange, GuestAddress, CpuMode, KernelType)> {
1816        let kernel_start = GuestAddress(KERNEL_START_OFFSET);
1817
1818        let multiboot =
1819            kernel_loader::multiboot_header_from_file(kernel_image).map_err(Error::LoadKernel)?;
1820
1821        if let Some(multiboot_load) = multiboot.as_ref().and_then(|m| m.load.as_ref()) {
1822            let loaded_kernel = kernel_loader::load_multiboot(mem, kernel_image, multiboot_load)
1823                .map_err(Error::LoadKernel)?;
1824
1825            let boot_params = boot_params {
1826                hdr: setup_header {
1827                    cmdline_size: CMDLINE_MAX_SIZE as u32 - 1,
1828                    ..Default::default()
1829                },
1830                ..Default::default()
1831            };
1832            return Ok((
1833                boot_params,
1834                loaded_kernel.address_range,
1835                loaded_kernel.entry,
1836                CpuMode::FlatProtectedMode,
1837                KernelType::Multiboot,
1838            ));
1839        }
1840
1841        match kernel_loader::load_elf(mem, kernel_start, kernel_image, 0) {
1842            Ok(loaded_kernel) => {
1843                // ELF kernels don't contain a `boot_params` structure, so synthesize a default one.
1844                let boot_params = boot_params {
1845                    hdr: setup_header {
1846                        cmdline_size: CMDLINE_MAX_SIZE as u32 - 1,
1847                        ..Default::default()
1848                    },
1849                    ..Default::default()
1850                };
1851                Ok((
1852                    boot_params,
1853                    loaded_kernel.address_range,
1854                    loaded_kernel.entry,
1855                    match loaded_kernel.class {
1856                        kernel_loader::ElfClass::ElfClass32 => CpuMode::FlatProtectedMode,
1857                        kernel_loader::ElfClass::ElfClass64 => CpuMode::LongMode,
1858                    },
1859                    KernelType::Elf,
1860                ))
1861            }
1862            Err(kernel_loader::Error::InvalidMagicNumber) => {
1863                // The image failed to parse as ELF, so try to load it as a bzImage.
1864                let (boot_params, bzimage_region, bzimage_entry, cpu_mode) =
1865                    bzimage::load_bzimage(mem, kernel_start, kernel_image)
1866                        .map_err(Error::LoadBzImage)?;
1867                Ok((
1868                    boot_params,
1869                    bzimage_region,
1870                    bzimage_entry,
1871                    cpu_mode,
1872                    KernelType::BzImage,
1873                ))
1874            }
1875            Err(e) => Err(Error::LoadKernel(e)),
1876        }
1877    }
1878
1879    /// Configures the system memory space should be called once per vm before
1880    /// starting vcpu threads.
1881    ///
1882    /// # Arguments
1883    ///
1884    /// * `mem` - The memory to be used by the guest.
1885    /// * `cmdline` - the kernel commandline
1886    /// * `initrd_file` - an initial ramdisk image
1887    pub fn setup_system_memory(
1888        arch_memory_layout: &ArchMemoryLayout,
1889        mem: &GuestMemory,
1890        cmdline: kernel_cmdline::Cmdline,
1891        initrd_file: Option<File>,
1892        android_fstab: Option<File>,
1893        kernel_region: AddressRange,
1894        params: boot_params,
1895        dump_device_tree_blob: Option<PathBuf>,
1896        device_tree_overlays: Vec<DtbOverlay>,
1897        protection_type: ProtectionType,
1898    ) -> Result<()> {
1899        let e820_entries = generate_e820_memory_map(arch_memory_layout, mem)?;
1900
1901        let kernel_max_cmdline_len = if params.hdr.cmdline_size == 0 {
1902            // Old kernels have a maximum length of 255 bytes, not including the NUL.
1903            255
1904        } else {
1905            params.hdr.cmdline_size as usize
1906        };
1907        debug!("kernel_max_cmdline_len={kernel_max_cmdline_len}");
1908        Self::load_cmdline(
1909            mem,
1910            GuestAddress(CMDLINE_OFFSET),
1911            cmdline,
1912            kernel_max_cmdline_len,
1913        )?;
1914
1915        let initrd = match initrd_file {
1916            Some(mut initrd_file) => {
1917                let initrd_addr_max = if params.hdr.xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G != 0 {
1918                    u64::MAX
1919                } else if params.hdr.initrd_addr_max == 0 {
1920                    // Default initrd_addr_max for old kernels (see Documentation/x86/boot.txt).
1921                    0x37FFFFFF
1922                } else {
1923                    u64::from(params.hdr.initrd_addr_max)
1924                };
1925
1926                let (initrd_start, initrd_size) = arch::load_image_high(
1927                    mem,
1928                    &mut initrd_file,
1929                    GuestAddress(kernel_region.end + 1),
1930                    GuestAddress(initrd_addr_max),
1931                    Some(|region| {
1932                        region.options.purpose != MemoryRegionPurpose::ProtectedFirmwareRegion
1933                    }),
1934                    base::pagesize() as u64,
1935                )
1936                .map_err(Error::LoadInitrd)?;
1937                Some((initrd_start, initrd_size))
1938            }
1939            None => None,
1940        };
1941
1942        let mut setup_data_entries =
1943            SetupDataEntries::new(SETUP_DATA_START as usize, SETUP_DATA_END as usize);
1944
1945        let setup_data_size = setup_data_entries.insert(setup_data_rng_seed());
1946
1947        // SETUP_DTB should be the last one in SETUP_DATA.
1948        // This is to reserve enough space for SETUP_DTB
1949        // without exceeding the size of SETUP_DATA area.
1950        if android_fstab.is_some()
1951            || !device_tree_overlays.is_empty()
1952            || protection_type.runs_firmware()
1953        {
1954            let fdt_max_size = min(X86_64_FDT_MAX_SIZE as usize, setup_data_size);
1955            let mut device_tree_blob = fdt::create_fdt(
1956                mem,
1957                android_fstab,
1958                dump_device_tree_blob,
1959                device_tree_overlays,
1960                kernel_region,
1961                initrd,
1962            )
1963            .map_err(Error::CreateFdt)?;
1964            if device_tree_blob.len() > fdt_max_size {
1965                return Err(Error::DTBSizeGreaterThanAllowed);
1966            }
1967
1968            // Reserve and zero fill dtb memory to maximum allowable size
1969            // so that pvmfw could patch and extend the dtb in-place.
1970            device_tree_blob.resize(fdt_max_size, 0);
1971
1972            setup_data_entries.insert(SetupData {
1973                data: device_tree_blob,
1974                type_: SetupDataType::Dtb,
1975            });
1976        }
1977
1978        let setup_data = setup_data_entries.write_setup_data(mem)?;
1979
1980        configure_boot_params(
1981            mem,
1982            GuestAddress(CMDLINE_OFFSET),
1983            setup_data,
1984            initrd,
1985            params,
1986            &e820_entries,
1987        )?;
1988
1989        configure_multiboot_info(mem, GuestAddress(CMDLINE_OFFSET), &e820_entries)?;
1990
1991        Ok(())
1992    }
1993
1994    fn get_pcie_vcfg_mmio_range(mem: &GuestMemory, pcie_cfg_mmio: &AddressRange) -> AddressRange {
1995        // Put PCIe VCFG region at a 2MB boundary after physical memory or 4gb, whichever is
1996        // greater.
1997        let ram_end_round_2mb = mem.end_addr().offset().next_multiple_of(2 * MB);
1998        let start = std::cmp::max(ram_end_round_2mb, 4 * GB);
1999        // Each pci device's ECAM size is 4kb and its vcfg size is 8kb
2000        let end = start + pcie_cfg_mmio.len().unwrap() * 2 - 1;
2001        AddressRange { start, end }
2002    }
2003
2004    /// Returns the high mmio range
2005    fn get_high_mmio_range<V: Vm>(vm: &V, arch_memory_layout: &ArchMemoryLayout) -> AddressRange {
2006        let mem = vm.get_memory();
2007        let start = Self::get_pcie_vcfg_mmio_range(mem, &arch_memory_layout.pcie_cfg_mmio).end + 1;
2008
2009        let phys_mem_end = (1u64 << vm.get_guest_phys_addr_bits()) - 1;
2010        let high_mmio_end = std::cmp::min(phys_mem_end, HIGH_MMIO_MAX_END);
2011
2012        AddressRange {
2013            start,
2014            end: high_mmio_end,
2015        }
2016    }
2017
2018    /// This returns a minimal kernel command for this architecture
2019    pub fn get_base_linux_cmdline() -> kernel_cmdline::Cmdline {
2020        let mut cmdline = kernel_cmdline::Cmdline::new();
2021        cmdline.insert_str("panic=-1").unwrap();
2022
2023        cmdline
2024    }
2025
2026    /// Sets up fw_cfg device.
2027    ///  # Arguments
2028    ///
2029    /// * `io_bus` - the IO bus object
2030    /// * `fw_cfg_parameters` - command-line specified data to add to device. May contain all None
2031    ///   fields if user did not specify data to add to the device
2032    fn setup_fw_cfg_device(
2033        io_bus: &Bus,
2034        fw_cfg_parameters: Vec<FwCfgParameters>,
2035        bootorder_fw_cfg_blob: Vec<u8>,
2036        fw_cfg_jail: Option<Minijail>,
2037        #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
2038    ) -> Result<()> {
2039        let fw_cfg = match devices::FwCfgDevice::new(FW_CFG_MAX_FILE_SLOTS, fw_cfg_parameters) {
2040            Ok(mut device) => {
2041                // this condition will only be true if the user specified at least one bootindex
2042                // option on the command line. If none were specified, bootorder_fw_cfg_blob will
2043                // only have a null byte (null terminator)
2044                if bootorder_fw_cfg_blob.len() > 1 {
2045                    // Add boot order file to the device. If the file is not present, firmware may
2046                    // not be able to boot.
2047                    if let Err(err) = device.add_file(
2048                        "bootorder",
2049                        bootorder_fw_cfg_blob,
2050                        devices::FwCfgItemType::GenericItem,
2051                    ) {
2052                        return Err(Error::CreateFwCfgDevice(err));
2053                    }
2054                }
2055                device
2056            }
2057            Err(err) => {
2058                return Err(Error::CreateFwCfgDevice(err));
2059            }
2060        };
2061
2062        let fw_cfg: Arc<Mutex<dyn BusDevice>> = match fw_cfg_jail.as_ref() {
2063            #[cfg(any(target_os = "android", target_os = "linux"))]
2064            Some(jail) => {
2065                let jail_clone = jail.try_clone().map_err(Error::CloneJail)?;
2066                #[cfg(feature = "seccomp_trace")]
2067                debug!(
2068                    "seccomp_trace {{\"event\": \"minijail_clone\", \"src_jail_addr\": \"0x{:x}\", \"dst_jail_addr\": \"0x{:x}\"}}",
2069                    read_jail_addr(jail),
2070                    read_jail_addr(&jail_clone)
2071                );
2072                Arc::new(Mutex::new(
2073                    ProxyDevice::new(
2074                        fw_cfg,
2075                        jail_clone,
2076                        Vec::new(),
2077                        #[cfg(feature = "swap")]
2078                        swap_controller,
2079                    )
2080                    .map_err(Error::CreateProxyDevice)?,
2081                ))
2082            }
2083            #[cfg(windows)]
2084            Some(_) => unreachable!(),
2085            None => Arc::new(Mutex::new(fw_cfg)),
2086        };
2087
2088        io_bus
2089            .insert(fw_cfg, FW_CFG_BASE_PORT, FW_CFG_WIDTH)
2090            .map_err(Error::InsertBus)?;
2091
2092        Ok(())
2093    }
2094
2095    /// Sets up the legacy x86 i8042/KBD platform device
2096    ///
2097    /// # Arguments
2098    ///
2099    /// * - `io_bus` - the IO bus object
2100    /// * - `pit_uses_speaker_port` - does the PIT use port 0x61 for the PC speaker
2101    /// * - `vm_evt_wrtube` - the event object which should receive exit events
2102    pub fn setup_legacy_i8042_device(
2103        io_bus: &Bus,
2104        pit_uses_speaker_port: bool,
2105        vm_evt_wrtube: SendTube,
2106    ) -> Result<()> {
2107        let i8042 = Arc::new(Mutex::new(devices::I8042Device::new(
2108            vm_evt_wrtube.try_clone().map_err(Error::CloneTube)?,
2109        )));
2110
2111        if pit_uses_speaker_port {
2112            io_bus.insert(i8042, 0x062, 0x3).unwrap();
2113        } else {
2114            io_bus.insert(i8042, 0x061, 0x4).unwrap();
2115        }
2116
2117        Ok(())
2118    }
2119
2120    /// Sets up the legacy x86 CMOS/RTC platform device
2121    /// # Arguments
2122    ///
2123    /// * - `io_bus` - the IO bus object
2124    /// * - `mem_size` - the size in bytes of physical ram for the guest
2125    pub fn setup_legacy_cmos_device(
2126        arch_memory_layout: &ArchMemoryLayout,
2127        io_bus: &Bus,
2128        irq_chip: &mut dyn IrqChipX86_64,
2129        vm_control: Tube,
2130        mem_size: u64,
2131    ) -> anyhow::Result<()> {
2132        let mem_regions = arch_memory_regions(arch_memory_layout, mem_size, None);
2133
2134        let mem_below_4g = mem_regions
2135            .iter()
2136            .filter(|r| r.0.offset() < FIRST_ADDR_PAST_32BITS)
2137            .map(|r| r.1)
2138            .sum();
2139
2140        let mem_above_4g = mem_regions
2141            .iter()
2142            .filter(|r| r.0.offset() >= FIRST_ADDR_PAST_32BITS)
2143            .map(|r| r.1)
2144            .sum();
2145
2146        let irq_evt = devices::IrqEdgeEvent::new().context("cmos irq")?;
2147        let cmos = devices::cmos::Cmos::new(
2148            mem_below_4g,
2149            mem_above_4g,
2150            Utc::now,
2151            vm_control,
2152            irq_evt.try_clone().context("cmos irq clone")?,
2153        )
2154        .context("create cmos")?;
2155
2156        irq_chip
2157            .register_edge_irq_event(
2158                devices::cmos::RTC_IRQ as u32,
2159                &irq_evt,
2160                IrqEventSource::from_device(&cmos),
2161            )
2162            .context("cmos register irq")?;
2163        io_bus
2164            .insert(Arc::new(Mutex::new(cmos)), 0x70, 0x2)
2165            .context("cmos insert irq")?;
2166
2167        Ok(())
2168    }
2169
2170    /// Sets up the acpi devices for this platform and
2171    /// return the resources which is used to set the ACPI tables.
2172    ///
2173    /// # Arguments
2174    ///
2175    /// * `io_bus` the I/O bus to add the devices to
2176    /// * `resources` the SystemAllocator to allocate IO and MMIO for acpi devices.
2177    /// * `suspend_tube` the tube object which used to suspend/resume the VM.
2178    /// * `sdts` ACPI system description tables
2179    /// * `irq_chip` the IrqChip object for registering irq events
2180    /// * `battery` indicate whether to create the battery
2181    /// * `mmio_bus` the MMIO bus to add the devices to
2182    /// * `pci_irqs` IRQ assignment of PCI devices. Tuples of (PCI address, gsi, PCI interrupt pin).
2183    ///   Note that this matches one of the return values of generate_pci_root.
2184    pub fn setup_acpi_devices(
2185        arch_memory_layout: &ArchMemoryLayout,
2186        pci_root: Arc<Mutex<PciRoot>>,
2187        mem: &GuestMemory,
2188        io_bus: &Bus,
2189        resources: &mut SystemAllocator,
2190        suspend_tube: Arc<Mutex<SendTube>>,
2191        vm_evt_wrtube: SendTube,
2192        sdts: Vec<SDT>,
2193        irq_chip: &mut dyn IrqChip,
2194        sci_irq: u32,
2195        battery: (Option<BatteryType>, Option<Minijail>),
2196        #[cfg_attr(windows, allow(unused_variables))] mmio_bus: &Bus,
2197        max_bus: u8,
2198        resume_notify_devices: &mut Vec<Arc<Mutex<dyn BusResumeDevice>>>,
2199        #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
2200        #[cfg(any(target_os = "android", target_os = "linux"))] ac_adapter: bool,
2201        guest_suspended_cvar: Option<Arc<(Mutex<bool>, Condvar)>>,
2202        pci_irqs: &[(PciAddress, u32, PciInterruptPin)],
2203    ) -> Result<(acpi::AcpiDevResource, Option<BatControl>)> {
2204        // The AML data for the acpi devices
2205        let mut amls = Vec::new();
2206
2207        let bat_control = if let Some(battery_type) = battery.0 {
2208            match battery_type {
2209                #[cfg(any(target_os = "android", target_os = "linux"))]
2210                BatteryType::Goldfish => {
2211                    let irq_num = resources.allocate_irq().ok_or(Error::CreateBatDevices(
2212                        arch::DeviceRegistrationError::AllocateIrq,
2213                    ))?;
2214                    let (control_tube, _mmio_base) = arch::sys::linux::add_goldfish_battery(
2215                        &mut amls,
2216                        battery.1,
2217                        mmio_bus,
2218                        irq_chip,
2219                        irq_num,
2220                        resources,
2221                        #[cfg(feature = "swap")]
2222                        swap_controller,
2223                    )
2224                    .map_err(Error::CreateBatDevices)?;
2225                    Some(BatControl {
2226                        type_: BatteryType::Goldfish,
2227                        control_tube,
2228                    })
2229                }
2230                #[cfg(windows)]
2231                _ => None,
2232            }
2233        } else {
2234            None
2235        };
2236
2237        let pm_alloc = resources.get_anon_alloc();
2238        let pm_iobase = match resources.io_allocator() {
2239            Some(io) => io
2240                .allocate_with_align(
2241                    devices::acpi::ACPIPM_RESOURCE_LEN as u64,
2242                    pm_alloc,
2243                    "ACPIPM".to_string(),
2244                    4, // must be 32-bit aligned
2245                )
2246                .map_err(Error::AllocateIOResouce)?,
2247            None => 0x600,
2248        };
2249
2250        let pcie_vcfg = aml::Name::new(
2251            "VCFG".into(),
2252            &Self::get_pcie_vcfg_mmio_range(mem, &arch_memory_layout.pcie_cfg_mmio).start,
2253        );
2254        pcie_vcfg.to_aml_bytes(&mut amls);
2255
2256        let pm_sci_evt = devices::IrqLevelEvent::new().map_err(Error::CreateEvent)?;
2257
2258        #[cfg(any(target_os = "android", target_os = "linux"))]
2259        let acdc = if ac_adapter {
2260            // Allocate GPE for AC adapter notfication
2261            let gpe = resources.allocate_gpe().ok_or(Error::AllocateGpe)?;
2262
2263            let alloc = resources.get_anon_alloc();
2264            let mmio_base = resources
2265                .allocate_mmio(
2266                    devices::ac_adapter::ACDC_VIRT_MMIO_SIZE,
2267                    alloc,
2268                    "AcAdapter".to_string(),
2269                    resources::AllocOptions::new().align(devices::ac_adapter::ACDC_VIRT_MMIO_SIZE),
2270                )
2271                .unwrap();
2272            let ac_adapter_dev = devices::ac_adapter::AcAdapter::new(mmio_base, gpe);
2273            let ac_dev = Arc::new(Mutex::new(ac_adapter_dev));
2274            mmio_bus
2275                .insert(
2276                    ac_dev.clone(),
2277                    mmio_base,
2278                    devices::ac_adapter::ACDC_VIRT_MMIO_SIZE,
2279                )
2280                .unwrap();
2281
2282            ac_dev.lock().to_aml_bytes(&mut amls);
2283            Some(ac_dev)
2284        } else {
2285            None
2286        };
2287        #[cfg(windows)]
2288        let acdc = None;
2289
2290        //Virtual PMC
2291        if let Some(guest_suspended_cvar) = guest_suspended_cvar {
2292            let alloc = resources.get_anon_alloc();
2293            let mmio_base = resources
2294                .allocate_mmio(
2295                    devices::pmc_virt::VPMC_VIRT_MMIO_SIZE,
2296                    alloc,
2297                    "VirtualPmc".to_string(),
2298                    resources::AllocOptions::new().align(devices::pmc_virt::VPMC_VIRT_MMIO_SIZE),
2299                )
2300                .unwrap();
2301
2302            let pmc_virtio_mmio =
2303                Arc::new(Mutex::new(VirtualPmc::new(mmio_base, guest_suspended_cvar)));
2304            mmio_bus
2305                .insert(
2306                    pmc_virtio_mmio.clone(),
2307                    mmio_base,
2308                    devices::pmc_virt::VPMC_VIRT_MMIO_SIZE,
2309                )
2310                .unwrap();
2311            pmc_virtio_mmio.lock().to_aml_bytes(&mut amls);
2312        }
2313
2314        let mut pmresource = devices::ACPIPMResource::new(
2315            pm_sci_evt.try_clone().map_err(Error::CloneEvent)?,
2316            suspend_tube,
2317            vm_evt_wrtube,
2318            acdc,
2319        );
2320        pmresource.to_aml_bytes(&mut amls);
2321        irq_chip
2322            .register_level_irq_event(
2323                sci_irq,
2324                &pm_sci_evt,
2325                IrqEventSource::from_device(&pmresource),
2326            )
2327            .map_err(Error::RegisterIrqfd)?;
2328        pmresource.start();
2329
2330        let mut crs_entries: Vec<Box<dyn Aml>> = vec![
2331            Box::new(aml::AddressSpace::new_bus_number(0x0u16, max_bus as u16)),
2332            Box::new(aml::IO::new(0xcf8, 0xcf8, 1, 0x8)),
2333        ];
2334        for r in resources.mmio_pools() {
2335            let entry: Box<dyn Aml> = match (u32::try_from(r.start), u32::try_from(r.end)) {
2336                (Ok(start), Ok(end)) => Box::new(aml::AddressSpace::new_memory(
2337                    aml::AddressSpaceCachable::NotCacheable,
2338                    true,
2339                    start,
2340                    end,
2341                )),
2342                _ => Box::new(aml::AddressSpace::new_memory(
2343                    aml::AddressSpaceCachable::NotCacheable,
2344                    true,
2345                    r.start,
2346                    r.end,
2347                )),
2348            };
2349            crs_entries.push(entry);
2350        }
2351
2352        let prt_entries: Vec<aml::Package> = pci_irqs
2353            .iter()
2354            .map(|(pci_address, gsi, pci_intr_pin)| {
2355                aml::Package::new(vec![
2356                    &pci_address.acpi_adr(),
2357                    &pci_intr_pin.to_mask(),
2358                    &aml::ZERO,
2359                    gsi,
2360                ])
2361            })
2362            .collect();
2363
2364        aml::Device::new(
2365            "_SB_.PC00".into(),
2366            vec![
2367                &aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0A08")),
2368                &aml::Name::new("_CID".into(), &aml::EISAName::new("PNP0A03")),
2369                &aml::Name::new("_ADR".into(), &aml::ZERO),
2370                &aml::Name::new("_SEG".into(), &aml::ZERO),
2371                &aml::Name::new("_UID".into(), &aml::ZERO),
2372                &aml::Name::new("SUPP".into(), &aml::ZERO),
2373                &aml::Name::new(
2374                    "_CRS".into(),
2375                    &aml::ResourceTemplate::new(crs_entries.iter().map(|b| b.as_ref()).collect()),
2376                ),
2377                &PciRootOSC {},
2378                &aml::Name::new(
2379                    "_PRT".into(),
2380                    &aml::Package::new(prt_entries.iter().map(|p| p as &dyn Aml).collect()),
2381                ),
2382            ],
2383        )
2384        .to_aml_bytes(&mut amls);
2385
2386        if let (Some(start), Some(len)) = (
2387            u32::try_from(arch_memory_layout.pcie_cfg_mmio.start).ok(),
2388            arch_memory_layout
2389                .pcie_cfg_mmio
2390                .len()
2391                .and_then(|l| u32::try_from(l).ok()),
2392        ) {
2393            aml::Device::new(
2394                "_SB_.MB00".into(),
2395                vec![
2396                    &aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0C02")),
2397                    &aml::Name::new(
2398                        "_CRS".into(),
2399                        &aml::ResourceTemplate::new(vec![&aml::Memory32Fixed::new(
2400                            true, start, len,
2401                        )]),
2402                    ),
2403                ],
2404            )
2405            .to_aml_bytes(&mut amls);
2406        } else {
2407            warn!("Failed to create ACPI MMCFG region reservation");
2408        }
2409
2410        let root_bus = pci_root.lock().get_root_bus();
2411        let addresses = root_bus.lock().get_downstream_devices();
2412        for address in addresses {
2413            if let Some(acpi_path) = pci_root.lock().acpi_path(&address) {
2414                const DEEPEST_SLEEP_STATE: u32 = 3;
2415                aml::Device::new(
2416                    (*acpi_path).into(),
2417                    vec![
2418                        &aml::Name::new("_ADR".into(), &address.acpi_adr()),
2419                        &aml::Name::new(
2420                            "_PRW".into(),
2421                            &aml::Package::new(vec![&PM_WAKEUP_GPIO, &DEEPEST_SLEEP_STATE]),
2422                        ),
2423                    ],
2424                )
2425                .to_aml_bytes(&mut amls);
2426            }
2427        }
2428
2429        let pm = Arc::new(Mutex::new(pmresource));
2430        io_bus
2431            .insert(
2432                pm.clone(),
2433                pm_iobase,
2434                devices::acpi::ACPIPM_RESOURCE_LEN as u64,
2435            )
2436            .unwrap();
2437        resume_notify_devices.push(pm.clone());
2438
2439        Ok((
2440            acpi::AcpiDevResource {
2441                amls,
2442                pm_iobase,
2443                pm,
2444                sdts,
2445            },
2446            bat_control,
2447        ))
2448    }
2449
2450    /// Sets up the serial devices for this platform. Returns a list of configured serial devices.
2451    ///
2452    /// # Arguments
2453    ///
2454    /// * - `irq_chip` the IrqChip object for registering irq events
2455    /// * - `io_bus` the I/O bus to add the devices to
2456    /// * - `serial_parameters` - definitions for how the serial devices should be configured
2457    pub fn setup_serial_devices(
2458        protection_type: ProtectionType,
2459        irq_chip: &mut dyn IrqChip,
2460        io_bus: &Bus,
2461        serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>,
2462        serial_jail: Option<Minijail>,
2463        #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
2464    ) -> Result<Vec<SerialDeviceInfo>> {
2465        let com_evt_1_3 = devices::IrqEdgeEvent::new().map_err(Error::CreateEvent)?;
2466        let com_evt_2_4 = devices::IrqEdgeEvent::new().map_err(Error::CreateEvent)?;
2467
2468        let serial_devices = arch::add_serial_devices(
2469            protection_type,
2470            io_bus,
2471            (X86_64_SERIAL_1_3_IRQ, com_evt_1_3.get_trigger()),
2472            (X86_64_SERIAL_2_4_IRQ, com_evt_2_4.get_trigger()),
2473            serial_parameters,
2474            serial_jail,
2475            #[cfg(feature = "swap")]
2476            swap_controller,
2477        )
2478        .map_err(Error::CreateSerialDevices)?;
2479
2480        let source = IrqEventSource {
2481            device_id: Serial::device_id(),
2482            queue_id: 0,
2483            device_name: Serial::debug_label(),
2484        };
2485        irq_chip
2486            .register_edge_irq_event(X86_64_SERIAL_1_3_IRQ, &com_evt_1_3, source.clone())
2487            .map_err(Error::RegisterIrqfd)?;
2488        irq_chip
2489            .register_edge_irq_event(X86_64_SERIAL_2_4_IRQ, &com_evt_2_4, source)
2490            .map_err(Error::RegisterIrqfd)?;
2491
2492        Ok(serial_devices)
2493    }
2494
2495    fn setup_debugcon_devices(
2496        protection_type: ProtectionType,
2497        io_bus: &Bus,
2498        serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>,
2499        debugcon_jail: Option<Minijail>,
2500        #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
2501    ) -> Result<()> {
2502        for param in serial_parameters.values() {
2503            if param.hardware != SerialHardware::Debugcon {
2504                continue;
2505            }
2506
2507            let mut preserved_fds = Vec::new();
2508            let con = param
2509                .create_serial_device::<Debugcon>(
2510                    protection_type,
2511                    // Debugcon doesn't use the interrupt event
2512                    &Event::new().map_err(Error::CreateEvent)?,
2513                    &mut preserved_fds,
2514                )
2515                .map_err(Error::CreateDebugconDevice)?;
2516
2517            let con: Arc<Mutex<dyn BusDevice>> = match debugcon_jail.as_ref() {
2518                #[cfg(any(target_os = "android", target_os = "linux"))]
2519                Some(jail) => {
2520                    let jail_clone = jail.try_clone().map_err(Error::CloneJail)?;
2521                    #[cfg(feature = "seccomp_trace")]
2522                    debug!(
2523                        "seccomp_trace {{\"event\": \"minijail_clone\", \"src_jail_addr\": \"0x{:x}\", \"dst_jail_addr\": \"0x{:x}\"}}",
2524                        read_jail_addr(jail),
2525                        read_jail_addr(&jail_clone)
2526                    );
2527                    Arc::new(Mutex::new(
2528                        ProxyDevice::new(
2529                            con,
2530                            jail_clone,
2531                            preserved_fds,
2532                            #[cfg(feature = "swap")]
2533                            swap_controller,
2534                        )
2535                        .map_err(Error::CreateProxyDevice)?,
2536                    ))
2537                }
2538                #[cfg(windows)]
2539                Some(_) => unreachable!(),
2540                None => Arc::new(Mutex::new(con)),
2541            };
2542            io_bus
2543                .insert(con.clone(), param.debugcon_port.into(), 1)
2544                .map_err(Error::InsertBus)?;
2545        }
2546
2547        Ok(())
2548    }
2549}
2550
2551#[sorted]
2552#[derive(Error, Debug)]
2553pub enum MsrError {
2554    #[error("CPU not support. Only intel CPUs support ITMT.")]
2555    CpuUnSupport,
2556    #[error("msr must be unique: {0}")]
2557    MsrDuplicate(u32),
2558}
2559
2560#[derive(Error, Debug)]
2561pub enum HybridSupportError {
2562    #[error("Host CPU doesn't support hybrid architecture.")]
2563    UnsupportedHostCpu,
2564}
2565
2566/// The wrapper for CPUID call functions.
2567pub struct CpuIdCall {
2568    /// __cpuid_count or a fake function for test.
2569    cpuid_count: unsafe fn(u32, u32) -> CpuidResult,
2570    /// __cpuid or a fake function for test.
2571    cpuid: unsafe fn(u32) -> CpuidResult,
2572}
2573
2574impl CpuIdCall {
2575    pub fn new(
2576        cpuid_count: unsafe fn(u32, u32) -> CpuidResult,
2577        cpuid: unsafe fn(u32) -> CpuidResult,
2578    ) -> CpuIdCall {
2579        CpuIdCall { cpuid_count, cpuid }
2580    }
2581}
2582
2583/// Check if host supports hybrid CPU feature. The check include:
2584///     1. Check if CPUID.1AH exists. CPUID.1AH is hybrid information enumeration leaf.
2585///     2. Check if CPUID.07H.00H:EDX[bit 15] sets. This bit means the processor is identified as a
2586///        hybrid part.
2587///     3. Check if CPUID.1AH:EAX sets. The hybrid core type is set in EAX.
2588///
2589/// # Arguments
2590///
2591/// * - `cpuid` the wrapped cpuid functions used to get CPUID info.
2592pub fn check_host_hybrid_support(cpuid: &CpuIdCall) -> std::result::Result<(), HybridSupportError> {
2593    // CPUID.0H.EAX returns maximum input value for basic CPUID information.
2594    //
2595    // SAFETY:
2596    // Safe because we pass 0 for this call and the host supports the
2597    // `cpuid` instruction.
2598    let mut cpuid_entry = unsafe { (cpuid.cpuid)(0x0) };
2599    if cpuid_entry.eax < 0x1A {
2600        return Err(HybridSupportError::UnsupportedHostCpu);
2601    }
2602    // SAFETY:
2603    // Safe because we pass 0x7 and 0 for this call and the host supports the
2604    // `cpuid` instruction.
2605    cpuid_entry = unsafe { (cpuid.cpuid_count)(0x7, 0) };
2606    if cpuid_entry.edx & 1 << EDX_HYBRID_CPU_SHIFT == 0 {
2607        return Err(HybridSupportError::UnsupportedHostCpu);
2608    }
2609    // From SDM, if a value entered for CPUID.EAX is less than or equal to the
2610    // maximum input value and the leaf is not supported on that processor then
2611    // 0 is returned in all the registers.
2612    // For the CPU with hybrid support, its CPUID.1AH.EAX shouldn't be zero.
2613    //
2614    // SAFETY:
2615    // Safe because we pass 0 for this call and the host supports the
2616    // `cpuid` instruction.
2617    cpuid_entry = unsafe { (cpuid.cpuid)(0x1A) };
2618    if cpuid_entry.eax == 0 {
2619        return Err(HybridSupportError::UnsupportedHostCpu);
2620    }
2621    Ok(())
2622}
2623
2624#[cfg(test)]
2625mod tests {
2626    use std::mem::size_of;
2627
2628    use super::*;
2629
2630    fn setup() -> ArchMemoryLayout {
2631        let pci_config = PciConfig {
2632            ecam: Some(MemoryRegionConfig {
2633                start: 3 * GB,
2634                size: Some(256 * MB),
2635            }),
2636            mem: Some(MemoryRegionConfig {
2637                start: 2 * GB,
2638                size: None,
2639            }),
2640        };
2641        create_arch_memory_layout(&pci_config, false).unwrap()
2642    }
2643
2644    #[test]
2645    fn regions_lt_4gb_nobios() {
2646        let arch_memory_layout = setup();
2647        let regions = arch_memory_regions(&arch_memory_layout, 512 * MB, /* bios_size */ None);
2648        assert_eq!(
2649            regions,
2650            [
2651                (
2652                    GuestAddress(0),
2653                    640 * KB,
2654                    MemoryRegionOptions {
2655                        align: 0,
2656                        purpose: MemoryRegionPurpose::GuestMemoryRegion,
2657                        file_backed: None,
2658                    },
2659                ),
2660                (
2661                    GuestAddress(640 * KB),
2662                    384 * KB,
2663                    MemoryRegionOptions {
2664                        align: 0,
2665                        purpose: MemoryRegionPurpose::ReservedMemory,
2666                        file_backed: None,
2667                    },
2668                ),
2669                (
2670                    GuestAddress(1 * MB),
2671                    512 * MB - 1 * MB,
2672                    MemoryRegionOptions {
2673                        align: 0,
2674                        purpose: MemoryRegionPurpose::GuestMemoryRegion,
2675                        file_backed: None,
2676                    },
2677                )
2678            ]
2679        );
2680    }
2681
2682    #[test]
2683    fn regions_gt_4gb_nobios() {
2684        let arch_memory_layout = setup();
2685        let size = 4 * GB + 0x8000;
2686        let regions = arch_memory_regions(&arch_memory_layout, size, /* bios_size */ None);
2687        assert_eq!(
2688            regions,
2689            [
2690                (
2691                    GuestAddress(0),
2692                    640 * KB,
2693                    MemoryRegionOptions {
2694                        align: 0,
2695                        purpose: MemoryRegionPurpose::GuestMemoryRegion,
2696                        file_backed: None,
2697                    },
2698                ),
2699                (
2700                    GuestAddress(640 * KB),
2701                    384 * KB,
2702                    MemoryRegionOptions {
2703                        align: 0,
2704                        purpose: MemoryRegionPurpose::ReservedMemory,
2705                        file_backed: None,
2706                    },
2707                ),
2708                (
2709                    GuestAddress(1 * MB),
2710                    2 * GB - 1 * MB,
2711                    MemoryRegionOptions {
2712                        align: 0,
2713                        purpose: MemoryRegionPurpose::GuestMemoryRegion,
2714                        file_backed: None,
2715                    },
2716                ),
2717                (
2718                    GuestAddress(4 * GB),
2719                    2 * GB + 0x8000,
2720                    MemoryRegionOptions {
2721                        align: 0,
2722                        purpose: MemoryRegionPurpose::GuestMemoryRegion,
2723                        file_backed: None,
2724                    },
2725                ),
2726            ]
2727        );
2728    }
2729
2730    #[test]
2731    fn regions_lt_4gb_bios() {
2732        let arch_memory_layout = setup();
2733        let bios_len = 1 * MB;
2734        let regions = arch_memory_regions(&arch_memory_layout, 512 * MB, Some(bios_len));
2735        assert_eq!(
2736            regions,
2737            [
2738                (
2739                    GuestAddress(0),
2740                    640 * KB,
2741                    MemoryRegionOptions {
2742                        align: 0,
2743                        purpose: MemoryRegionPurpose::GuestMemoryRegion,
2744                        file_backed: None,
2745                    },
2746                ),
2747                (
2748                    GuestAddress(640 * KB),
2749                    384 * KB,
2750                    MemoryRegionOptions {
2751                        align: 0,
2752                        purpose: MemoryRegionPurpose::ReservedMemory,
2753                        file_backed: None,
2754                    },
2755                ),
2756                (
2757                    GuestAddress(1 * MB),
2758                    512 * MB - 1 * MB,
2759                    MemoryRegionOptions {
2760                        align: 0,
2761                        purpose: MemoryRegionPurpose::GuestMemoryRegion,
2762                        file_backed: None,
2763                    },
2764                ),
2765                (
2766                    GuestAddress(4 * GB - bios_len),
2767                    bios_len,
2768                    MemoryRegionOptions {
2769                        align: 0,
2770                        purpose: MemoryRegionPurpose::Bios,
2771                        file_backed: None,
2772                    },
2773                ),
2774            ]
2775        );
2776    }
2777
2778    #[test]
2779    fn regions_gt_4gb_bios() {
2780        let arch_memory_layout = setup();
2781        let bios_len = 1 * MB;
2782        let regions = arch_memory_regions(&arch_memory_layout, 4 * GB + 0x8000, Some(bios_len));
2783        assert_eq!(
2784            regions,
2785            [
2786                (
2787                    GuestAddress(0),
2788                    640 * KB,
2789                    MemoryRegionOptions {
2790                        align: 0,
2791                        purpose: MemoryRegionPurpose::GuestMemoryRegion,
2792                        file_backed: None,
2793                    },
2794                ),
2795                (
2796                    GuestAddress(640 * KB),
2797                    384 * KB,
2798                    MemoryRegionOptions {
2799                        align: 0,
2800                        purpose: MemoryRegionPurpose::ReservedMemory,
2801                        file_backed: None,
2802                    },
2803                ),
2804                (
2805                    GuestAddress(1 * MB),
2806                    2 * GB - 1 * MB,
2807                    MemoryRegionOptions {
2808                        align: 0,
2809                        purpose: MemoryRegionPurpose::GuestMemoryRegion,
2810                        file_backed: None,
2811                    },
2812                ),
2813                (
2814                    GuestAddress(4 * GB - bios_len),
2815                    bios_len,
2816                    MemoryRegionOptions {
2817                        align: 0,
2818                        purpose: MemoryRegionPurpose::Bios,
2819                        file_backed: None,
2820                    },
2821                ),
2822                (
2823                    GuestAddress(4 * GB),
2824                    2 * GB + 0x8000,
2825                    MemoryRegionOptions {
2826                        align: 0,
2827                        purpose: MemoryRegionPurpose::GuestMemoryRegion,
2828                        file_backed: None,
2829                    },
2830                ),
2831            ]
2832        );
2833    }
2834
2835    #[test]
2836    fn regions_eq_4gb_nobios() {
2837        let arch_memory_layout = setup();
2838        // Test with exact size of 4GB - the overhead.
2839        let regions = arch_memory_regions(&arch_memory_layout, 2 * GB, /* bios_size */ None);
2840        assert_eq!(
2841            regions,
2842            [
2843                (
2844                    GuestAddress(0),
2845                    640 * KB,
2846                    MemoryRegionOptions {
2847                        align: 0,
2848                        purpose: MemoryRegionPurpose::GuestMemoryRegion,
2849                        file_backed: None,
2850                    },
2851                ),
2852                (
2853                    GuestAddress(640 * KB),
2854                    384 * KB,
2855                    MemoryRegionOptions {
2856                        align: 0,
2857                        purpose: MemoryRegionPurpose::ReservedMemory,
2858                        file_backed: None,
2859                    },
2860                ),
2861                (
2862                    GuestAddress(1 * MB),
2863                    2 * GB - 1 * MB,
2864                    MemoryRegionOptions {
2865                        align: 0,
2866                        purpose: MemoryRegionPurpose::GuestMemoryRegion,
2867                        file_backed: None,
2868                    },
2869                )
2870            ]
2871        );
2872    }
2873
2874    #[test]
2875    fn regions_eq_4gb_bios() {
2876        let arch_memory_layout = setup();
2877        // Test with exact size of 4GB - the overhead.
2878        let bios_len = 1 * MB;
2879        let regions = arch_memory_regions(&arch_memory_layout, 2 * GB, Some(bios_len));
2880        assert_eq!(
2881            regions,
2882            [
2883                (
2884                    GuestAddress(0),
2885                    640 * KB,
2886                    MemoryRegionOptions {
2887                        align: 0,
2888                        purpose: MemoryRegionPurpose::GuestMemoryRegion,
2889                        file_backed: None,
2890                    },
2891                ),
2892                (
2893                    GuestAddress(640 * KB),
2894                    384 * KB,
2895                    MemoryRegionOptions {
2896                        align: 0,
2897                        purpose: MemoryRegionPurpose::ReservedMemory,
2898                        file_backed: None,
2899                    },
2900                ),
2901                (
2902                    GuestAddress(1 * MB),
2903                    2 * GB - 1 * MB,
2904                    MemoryRegionOptions {
2905                        align: 0,
2906                        purpose: MemoryRegionPurpose::GuestMemoryRegion,
2907                        file_backed: None,
2908                    },
2909                ),
2910                (
2911                    GuestAddress(4 * GB - bios_len),
2912                    bios_len,
2913                    MemoryRegionOptions {
2914                        align: 0,
2915                        purpose: MemoryRegionPurpose::Bios,
2916                        file_backed: None,
2917                    },
2918                ),
2919            ]
2920        );
2921    }
2922
2923    #[test]
2924    fn check_pci_mmio_layout() {
2925        let arch_memory_layout = setup();
2926
2927        assert_eq!(arch_memory_layout.pci_mmio_before_32bit.start, 2 * GB);
2928        assert_eq!(arch_memory_layout.pcie_cfg_mmio.start, 3 * GB);
2929        assert_eq!(arch_memory_layout.pcie_cfg_mmio.len().unwrap(), 256 * MB);
2930    }
2931
2932    #[test]
2933    fn check_32bit_gap_size_alignment() {
2934        let arch_memory_layout = setup();
2935        // pci_mmio_before_32bit is 256 MB aligned to be friendly for MTRR mappings.
2936        assert_eq!(
2937            arch_memory_layout.pci_mmio_before_32bit.start % (256 * MB),
2938            0
2939        );
2940    }
2941
2942    #[test]
2943    fn write_setup_data_empty() {
2944        let mem = GuestMemory::new(&[(GuestAddress(0), 0x2_0000)]).unwrap();
2945        let setup_data = [];
2946        let setup_data_addr = write_setup_data(
2947            &mem,
2948            GuestAddress(0x1000),
2949            GuestAddress(0x2000),
2950            &setup_data,
2951        )
2952        .expect("write_setup_data");
2953        assert_eq!(setup_data_addr, None);
2954    }
2955
2956    #[test]
2957    fn write_setup_data_two_of_them() {
2958        let mem = GuestMemory::new(&[(GuestAddress(0), 0x2_0000)]).unwrap();
2959
2960        let entry1_addr = GuestAddress(0x1000);
2961        let entry1_next_addr = entry1_addr;
2962        let entry1_len_addr = entry1_addr.checked_add(12).unwrap();
2963        let entry1_data_addr = entry1_addr.checked_add(16).unwrap();
2964        let entry1_data = [0x55u8; 13];
2965        let entry1_size = (size_of::<setup_data_hdr>() + entry1_data.len()) as u64;
2966        let entry1_align = 3;
2967
2968        let entry2_addr = GuestAddress(entry1_addr.offset() + entry1_size + entry1_align);
2969        let entry2_next_addr = entry2_addr;
2970        let entry2_len_addr = entry2_addr.checked_add(12).unwrap();
2971        let entry2_data_addr = entry2_addr.checked_add(16).unwrap();
2972        let entry2_data = [0xAAu8; 9];
2973
2974        let setup_data = [
2975            SetupData {
2976                data: entry1_data.to_vec(),
2977                type_: SetupDataType::Dtb,
2978            },
2979            SetupData {
2980                data: entry2_data.to_vec(),
2981                type_: SetupDataType::Dtb,
2982            },
2983        ];
2984
2985        let setup_data_head_addr = write_setup_data(
2986            &mem,
2987            GuestAddress(0x1000),
2988            GuestAddress(0x2000),
2989            &setup_data,
2990        )
2991        .expect("write_setup_data");
2992        assert_eq!(setup_data_head_addr, Some(entry1_addr));
2993
2994        assert_eq!(
2995            mem.read_obj_from_addr::<u64>(entry1_next_addr).unwrap(),
2996            entry2_addr.offset()
2997        );
2998        assert_eq!(
2999            mem.read_obj_from_addr::<u32>(entry1_len_addr).unwrap(),
3000            entry1_data.len() as u32
3001        );
3002        assert_eq!(
3003            mem.read_obj_from_addr::<[u8; 13]>(entry1_data_addr)
3004                .unwrap(),
3005            entry1_data
3006        );
3007
3008        assert_eq!(mem.read_obj_from_addr::<u64>(entry2_next_addr).unwrap(), 0);
3009        assert_eq!(
3010            mem.read_obj_from_addr::<u32>(entry2_len_addr).unwrap(),
3011            entry2_data.len() as u32
3012        );
3013        assert_eq!(
3014            mem.read_obj_from_addr::<[u8; 9]>(entry2_data_addr).unwrap(),
3015            entry2_data
3016        );
3017    }
3018
3019    #[test]
3020    fn cmdline_overflow() {
3021        const MEM_SIZE: u64 = 0x1000;
3022        let gm = GuestMemory::new(&[(GuestAddress(0x0), MEM_SIZE)]).unwrap();
3023        let mut cmdline = kernel_cmdline::Cmdline::new();
3024        cmdline.insert_str("12345").unwrap();
3025        let cmdline_address = GuestAddress(MEM_SIZE - 5);
3026        let err =
3027            X8664arch::load_cmdline(&gm, cmdline_address, cmdline, CMDLINE_MAX_SIZE as usize - 1)
3028                .unwrap_err();
3029        assert!(matches!(err, Error::CommandLineOverflow));
3030    }
3031
3032    #[test]
3033    fn cmdline_write_end() {
3034        const MEM_SIZE: u64 = 0x1000;
3035        let gm = GuestMemory::new(&[(GuestAddress(0x0), MEM_SIZE)]).unwrap();
3036        let mut cmdline = kernel_cmdline::Cmdline::new();
3037        cmdline.insert_str("1234").unwrap();
3038        let mut cmdline_address = GuestAddress(45);
3039        X8664arch::load_cmdline(&gm, cmdline_address, cmdline, CMDLINE_MAX_SIZE as usize - 1)
3040            .unwrap();
3041        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
3042        assert_eq!(val, b'1');
3043        cmdline_address = cmdline_address.unchecked_add(1);
3044        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
3045        assert_eq!(val, b'2');
3046        cmdline_address = cmdline_address.unchecked_add(1);
3047        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
3048        assert_eq!(val, b'3');
3049        cmdline_address = cmdline_address.unchecked_add(1);
3050        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
3051        assert_eq!(val, b'4');
3052        cmdline_address = cmdline_address.unchecked_add(1);
3053        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
3054        assert_eq!(val, b'\0');
3055    }
3056}