• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! ARM 64-bit architecture support.
6 
7 #![cfg(any(target_arch = "arm", target_arch = "aarch64"))]
8 
9 use std::collections::BTreeMap;
10 use std::fs::File;
11 use std::io;
12 use std::path::PathBuf;
13 use std::sync::mpsc;
14 use std::sync::Arc;
15 
16 use arch::get_serial_cmdline;
17 use arch::CpuSet;
18 use arch::DtbOverlay;
19 use arch::GetSerialCmdlineError;
20 use arch::RunnableLinuxVm;
21 use arch::VcpuAffinity;
22 use arch::VmComponents;
23 use arch::VmImage;
24 use base::Event;
25 use base::MemoryMappingBuilder;
26 use base::SendTube;
27 use devices::serial_device::SerialHardware;
28 use devices::serial_device::SerialParameters;
29 use devices::vmwdt::VMWDT_DEFAULT_CLOCK_HZ;
30 use devices::vmwdt::VMWDT_DEFAULT_TIMEOUT_SEC;
31 use devices::Bus;
32 use devices::BusDeviceObj;
33 use devices::BusError;
34 use devices::BusType;
35 use devices::IrqChip;
36 use devices::IrqChipAArch64;
37 use devices::IrqEventSource;
38 use devices::PciAddress;
39 use devices::PciConfigMmio;
40 use devices::PciDevice;
41 use devices::PciRootCommand;
42 use devices::Serial;
43 #[cfg(any(target_os = "android", target_os = "linux"))]
44 use devices::VirtCpufreq;
45 #[cfg(feature = "gdb")]
46 use gdbstub::arch::Arch;
47 #[cfg(feature = "gdb")]
48 use gdbstub_arch::aarch64::AArch64 as GdbArch;
49 use hypervisor::CpuConfigAArch64;
50 use hypervisor::DeviceKind;
51 use hypervisor::Hypervisor;
52 use hypervisor::HypervisorCap;
53 use hypervisor::MemCacheType;
54 use hypervisor::ProtectionType;
55 use hypervisor::VcpuAArch64;
56 use hypervisor::VcpuFeature;
57 use hypervisor::VcpuInitAArch64;
58 use hypervisor::VcpuRegAArch64;
59 use hypervisor::Vm;
60 use hypervisor::VmAArch64;
61 #[cfg(windows)]
62 use jail::FakeMinijailStub as Minijail;
63 use kernel_loader::LoadedKernel;
64 #[cfg(any(target_os = "android", target_os = "linux"))]
65 use minijail::Minijail;
66 use remain::sorted;
67 use resources::AddressRange;
68 use resources::SystemAllocator;
69 use resources::SystemAllocatorConfig;
70 #[cfg(any(target_os = "android", target_os = "linux"))]
71 use sync::Condvar;
72 use sync::Mutex;
73 use thiserror::Error;
74 use vm_control::BatControl;
75 use vm_control::BatteryType;
76 use vm_memory::GuestAddress;
77 use vm_memory::GuestMemory;
78 use vm_memory::GuestMemoryError;
79 use vm_memory::MemoryRegionOptions;
80 use vm_memory::MemoryRegionPurpose;
81 
82 mod fdt;
83 
84 // We place the kernel at the very beginning of physical memory.
85 const AARCH64_KERNEL_OFFSET: u64 = 0;
86 const AARCH64_FDT_MAX_SIZE: u64 = 0x200000;
87 const AARCH64_INITRD_ALIGN: u64 = 0x1000000;
88 
89 // These constants indicate the address space used by the ARM vGIC.
90 const AARCH64_GIC_DIST_SIZE: u64 = 0x10000;
91 const AARCH64_GIC_CPUI_SIZE: u64 = 0x20000;
92 
93 // This indicates the start of DRAM inside the physical address space.
94 const AARCH64_PHYS_MEM_START: u64 = 0x80000000;
95 const AARCH64_AXI_BASE: u64 = 0x40000000;
96 const AARCH64_PLATFORM_MMIO_SIZE: u64 = 0x800000;
97 
98 // FDT is placed at the front of RAM when booting in BIOS mode.
99 const AARCH64_FDT_OFFSET_IN_BIOS_MODE: u64 = 0x0;
100 // Therefore, the BIOS is placed after the FDT in memory.
101 const AARCH64_BIOS_OFFSET: u64 = AARCH64_FDT_MAX_SIZE;
102 const AARCH64_BIOS_MAX_LEN: u64 = 1 << 20;
103 
104 const AARCH64_PROTECTED_VM_FW_MAX_SIZE: u64 = 0x400000;
105 const AARCH64_PROTECTED_VM_FW_START: u64 =
106     AARCH64_PHYS_MEM_START - AARCH64_PROTECTED_VM_FW_MAX_SIZE;
107 
108 const AARCH64_PVTIME_IPA_MAX_SIZE: u64 = 0x10000;
109 const AARCH64_PVTIME_IPA_START: u64 = AARCH64_MMIO_BASE - AARCH64_PVTIME_IPA_MAX_SIZE;
110 const AARCH64_PVTIME_SIZE: u64 = 64;
111 
112 // These constants indicate the placement of the GIC registers in the physical
113 // address space.
114 const AARCH64_GIC_DIST_BASE: u64 = AARCH64_AXI_BASE - AARCH64_GIC_DIST_SIZE;
115 const AARCH64_GIC_CPUI_BASE: u64 = AARCH64_GIC_DIST_BASE - AARCH64_GIC_CPUI_SIZE;
116 const AARCH64_GIC_REDIST_SIZE: u64 = 0x20000;
117 
118 // PSR (Processor State Register) bits
119 const PSR_MODE_EL1H: u64 = 0x00000005;
120 const PSR_F_BIT: u64 = 0x00000040;
121 const PSR_I_BIT: u64 = 0x00000080;
122 const PSR_A_BIT: u64 = 0x00000100;
123 const PSR_D_BIT: u64 = 0x00000200;
124 
125 enum PayloadType {
126     Bios {
127         entry: GuestAddress,
128         image_size: u64,
129     },
130     Kernel(LoadedKernel),
131 }
132 
133 impl PayloadType {
entry(&self) -> GuestAddress134     fn entry(&self) -> GuestAddress {
135         match self {
136             Self::Bios {
137                 entry,
138                 image_size: _,
139             } => *entry,
140             Self::Kernel(k) => k.entry,
141         }
142     }
143 
size(&self) -> u64144     fn size(&self) -> u64 {
145         match self {
146             Self::Bios {
147                 entry: _,
148                 image_size,
149             } => *image_size,
150             Self::Kernel(k) => k.size,
151         }
152     }
153 }
154 
get_kernel_addr() -> GuestAddress155 fn get_kernel_addr() -> GuestAddress {
156     GuestAddress(AARCH64_PHYS_MEM_START + AARCH64_KERNEL_OFFSET)
157 }
158 
get_bios_addr() -> GuestAddress159 fn get_bios_addr() -> GuestAddress {
160     GuestAddress(AARCH64_PHYS_MEM_START + AARCH64_BIOS_OFFSET)
161 }
162 
163 // When static swiotlb allocation is required, returns the address it should be allocated at.
164 // Otherwise, returns None.
get_swiotlb_addr( memory_size: u64, hypervisor: &(impl Hypervisor + ?Sized), ) -> Option<GuestAddress>165 fn get_swiotlb_addr(
166     memory_size: u64,
167     hypervisor: &(impl Hypervisor + ?Sized),
168 ) -> Option<GuestAddress> {
169     if hypervisor.check_capability(HypervisorCap::StaticSwiotlbAllocationRequired) {
170         Some(GuestAddress(AARCH64_PHYS_MEM_START + memory_size))
171     } else {
172         None
173     }
174 }
175 
176 // This was the speed kvmtool used, not sure if it matters.
177 const AARCH64_SERIAL_SPEED: u32 = 1843200;
178 // The serial device gets the first interrupt line
179 // Which gets mapped to the first SPI interrupt (physical 32).
180 const AARCH64_SERIAL_1_3_IRQ: u32 = 0;
181 const AARCH64_SERIAL_2_4_IRQ: u32 = 2;
182 
183 // Place the RTC device at page 2
184 const AARCH64_RTC_ADDR: u64 = 0x2000;
185 // The RTC device gets one 4k page
186 const AARCH64_RTC_SIZE: u64 = 0x1000;
187 // The RTC device gets the second interrupt line
188 const AARCH64_RTC_IRQ: u32 = 1;
189 
190 // The Goldfish battery device gets the 3rd interrupt line
191 const AARCH64_BAT_IRQ: u32 = 3;
192 
193 // Place the virtual watchdog device at page 3
194 const AARCH64_VMWDT_ADDR: u64 = 0x3000;
195 // The virtual watchdog device gets one 4k page
196 const AARCH64_VMWDT_SIZE: u64 = 0x1000;
197 
198 // PCI MMIO configuration region base address.
199 const AARCH64_PCI_CFG_BASE: u64 = 0x10000;
200 // PCI MMIO configuration region size.
201 const AARCH64_PCI_CFG_SIZE: u64 = 0x1000000;
202 // This is the base address of MMIO devices.
203 const AARCH64_MMIO_BASE: u64 = 0x2000000;
204 // Size of the whole MMIO region.
205 const AARCH64_MMIO_SIZE: u64 = 0x2000000;
206 // Virtio devices start at SPI interrupt number 4
207 const AARCH64_IRQ_BASE: u32 = 4;
208 
209 // Virtual CPU Frequency Device.
210 const AARCH64_VIRTFREQ_BASE: u64 = 0x1040000;
211 const AARCH64_VIRTFREQ_SIZE: u64 = 0x8;
212 const AARCH64_VIRTFREQ_MAXSIZE: u64 = 0x10000;
213 
214 // PMU PPI interrupt, same as qemu
215 const AARCH64_PMU_IRQ: u32 = 7;
216 
217 #[sorted]
218 #[derive(Error, Debug)]
219 pub enum Error {
220     #[error("failed to allocate IRQ number")]
221     AllocateIrq,
222     #[error("bios could not be loaded: {0}")]
223     BiosLoadFailure(arch::LoadImageError),
224     #[error("failed to build arm pvtime memory: {0}")]
225     BuildPvtimeError(base::MmapError),
226     #[error("unable to clone an Event: {0}")]
227     CloneEvent(base::Error),
228     #[error("failed to clone IRQ chip: {0}")]
229     CloneIrqChip(base::Error),
230     #[error("the given kernel command line was invalid: {0}")]
231     Cmdline(kernel_cmdline::Error),
232     #[error("failed to configure CPU Frequencies: {0}")]
233     CpuFrequencies(base::Error),
234     #[error("failed to configure CPU topology: {0}")]
235     CpuTopology(base::Error),
236     #[error("unable to create battery devices: {0}")]
237     CreateBatDevices(arch::DeviceRegistrationError),
238     #[error("unable to make an Event: {0}")]
239     CreateEvent(base::Error),
240     #[error("FDT could not be created: {0}")]
241     CreateFdt(cros_fdt::Error),
242     #[error("failed to create GIC: {0}")]
243     CreateGICFailure(base::Error),
244     #[error("failed to create a PCI root hub: {0}")]
245     CreatePciRoot(arch::DeviceRegistrationError),
246     #[error("failed to create platform bus: {0}")]
247     CreatePlatformBus(arch::DeviceRegistrationError),
248     #[error("unable to create serial devices: {0}")]
249     CreateSerialDevices(arch::DeviceRegistrationError),
250     #[error("failed to create socket: {0}")]
251     CreateSocket(io::Error),
252     #[error("failed to create VCPU: {0}")]
253     CreateVcpu(base::Error),
254     #[error("custom pVM firmware could not be loaded: {0}")]
255     CustomPvmFwLoadFailure(arch::LoadImageError),
256     #[error("vm created wrong kind of vcpu")]
257     DowncastVcpu,
258     #[error("failed to enable singlestep execution: {0}")]
259     EnableSinglestep(base::Error),
260     #[error("failed to finalize IRQ chip: {0}")]
261     FinalizeIrqChip(base::Error),
262     #[error("failed to get HW breakpoint count: {0}")]
263     GetMaxHwBreakPoint(base::Error),
264     #[error("failed to get PSCI version: {0}")]
265     GetPsciVersion(base::Error),
266     #[error("failed to get serial cmdline: {0}")]
267     GetSerialCmdline(GetSerialCmdlineError),
268     #[error("failed to initialize arm pvtime: {0}")]
269     InitPvtimeError(base::Error),
270     #[error("initrd could not be loaded: {0}")]
271     InitrdLoadFailure(arch::LoadImageError),
272     #[error("failed to initialize virtual machine {0}")]
273     InitVmError(base::Error),
274     #[error("kernel could not be loaded: {0}")]
275     KernelLoadFailure(kernel_loader::Error),
276     #[error("error loading Kernel from Elf image: {0}")]
277     LoadElfKernel(kernel_loader::Error),
278     #[error("failed to map arm pvtime memory: {0}")]
279     MapPvtimeError(base::Error),
280     #[error("pVM firmware could not be loaded: {0}")]
281     PvmFwLoadFailure(base::Error),
282     #[error("ramoops address is different from high_mmio_base: {0} vs {1}")]
283     RamoopsAddress(u64, u64),
284     #[error("error reading guest memory: {0}")]
285     ReadGuestMemory(vm_memory::GuestMemoryError),
286     #[error("error reading CPU register: {0}")]
287     ReadReg(base::Error),
288     #[error("error reading CPU registers: {0}")]
289     ReadRegs(base::Error),
290     #[error("failed to register irq fd: {0}")]
291     RegisterIrqfd(base::Error),
292     #[error("error registering PCI bus: {0}")]
293     RegisterPci(BusError),
294     #[error("error registering virtual cpufreq device: {0}")]
295     RegisterVirtCpufreq(BusError),
296     #[error("error registering virtual socket device: {0}")]
297     RegisterVsock(arch::DeviceRegistrationError),
298     #[error("failed to set device attr: {0}")]
299     SetDeviceAttr(base::Error),
300     #[error("failed to set a hardware breakpoint: {0}")]
301     SetHwBreakpoint(base::Error),
302     #[error("failed to set register: {0}")]
303     SetReg(base::Error),
304     #[error("failed to set up guest memory: {0}")]
305     SetupGuestMemory(GuestMemoryError),
306     #[error("this function isn't supported")]
307     Unsupported,
308     #[error("failed to initialize VCPU: {0}")]
309     VcpuInit(base::Error),
310     #[error("error writing guest memory: {0}")]
311     WriteGuestMemory(GuestMemoryError),
312     #[error("error writing CPU register: {0}")]
313     WriteReg(base::Error),
314     #[error("error writing CPU registers: {0}")]
315     WriteRegs(base::Error),
316 }
317 
318 pub type Result<T> = std::result::Result<T, Error>;
319 
320 /// Returns the address in guest memory at which the FDT should be located.
fdt_address(memory_end: GuestAddress, has_bios: bool) -> GuestAddress321 fn fdt_address(memory_end: GuestAddress, has_bios: bool) -> GuestAddress {
322     // TODO(rammuthiah) make kernel and BIOS startup use FDT from the same location. ARCVM startup
323     // currently expects the kernel at 0x80080000 and the FDT at the end of RAM for unknown reasons.
324     // Root cause and figure out how to fold these code paths together.
325     if has_bios {
326         GuestAddress(AARCH64_PHYS_MEM_START + AARCH64_FDT_OFFSET_IN_BIOS_MODE)
327     } else {
328         // Put fdt up near the top of memory
329         // TODO(sonnyrao): will have to handle this differently if there's
330         // > 4GB memory
331         memory_end
332             .checked_sub(AARCH64_FDT_MAX_SIZE)
333             .expect("Not enough memory for FDT")
334             .checked_sub(0x10000)
335             .expect("Not enough memory for FDT")
336     }
337 }
338 
load_kernel( guest_mem: &GuestMemory, kernel_start: GuestAddress, mut kernel_image: &mut File, ) -> Result<LoadedKernel>339 fn load_kernel(
340     guest_mem: &GuestMemory,
341     kernel_start: GuestAddress,
342     mut kernel_image: &mut File,
343 ) -> Result<LoadedKernel> {
344     if let Ok(elf_kernel) = kernel_loader::load_elf(
345         guest_mem,
346         kernel_start,
347         &mut kernel_image,
348         AARCH64_PHYS_MEM_START,
349     ) {
350         return Ok(elf_kernel);
351     }
352 
353     if let Ok(lz4_kernel) =
354         kernel_loader::load_arm64_kernel_lz4(guest_mem, kernel_start, &mut kernel_image)
355     {
356         return Ok(lz4_kernel);
357     }
358 
359     kernel_loader::load_arm64_kernel(guest_mem, kernel_start, kernel_image)
360         .map_err(Error::KernelLoadFailure)
361 }
362 
363 pub struct AArch64;
364 
get_block_size() -> u64365 fn get_block_size() -> u64 {
366     let page_size = base::pagesize();
367     // Each PTE entry being 8 bytes long, we can fit in one page (page_size / 8)
368     // entries.
369     let ptes_per_page = page_size / 8;
370     let block_size = page_size * ptes_per_page;
371 
372     block_size as u64
373 }
374 
get_vcpu_mpidr_aff<Vcpu: VcpuAArch64>(vcpus: &[Vcpu], index: usize) -> Option<u64>375 fn get_vcpu_mpidr_aff<Vcpu: VcpuAArch64>(vcpus: &[Vcpu], index: usize) -> Option<u64> {
376     const MPIDR_AFF_MASK: u64 = 0xff_00ff_ffff;
377 
378     Some(vcpus.get(index)?.get_mpidr().ok()? & MPIDR_AFF_MASK)
379 }
380 
381 impl arch::LinuxArch for AArch64 {
382     type Error = Error;
383 
384     /// Returns a Vec of the valid memory addresses.
385     /// These should be used to configure the GuestMemory structure for the platform.
guest_memory_layout( components: &VmComponents, hypervisor: &impl Hypervisor, ) -> std::result::Result<Vec<(GuestAddress, u64, MemoryRegionOptions)>, Self::Error>386     fn guest_memory_layout(
387         components: &VmComponents,
388         hypervisor: &impl Hypervisor,
389     ) -> std::result::Result<Vec<(GuestAddress, u64, MemoryRegionOptions)>, Self::Error> {
390         let mut memory_regions = vec![(
391             GuestAddress(AARCH64_PHYS_MEM_START),
392             components.memory_size,
393             MemoryRegionOptions::new().align(get_block_size()),
394         )];
395 
396         // Allocate memory for the pVM firmware.
397         if components.hv_cfg.protection_type.runs_firmware() {
398             memory_regions.push((
399                 GuestAddress(AARCH64_PROTECTED_VM_FW_START),
400                 AARCH64_PROTECTED_VM_FW_MAX_SIZE,
401                 MemoryRegionOptions::new().purpose(MemoryRegionPurpose::ProtectedFirmwareRegion),
402             ));
403         }
404 
405         if let Some(size) = components.swiotlb {
406             if let Some(addr) = get_swiotlb_addr(components.memory_size, hypervisor) {
407                 memory_regions.push((
408                     addr,
409                     size,
410                     MemoryRegionOptions::new().purpose(MemoryRegionPurpose::StaticSwiotlbRegion),
411                 ));
412             }
413         }
414 
415         Ok(memory_regions)
416     }
417 
get_system_allocator_config<V: Vm>(vm: &V) -> SystemAllocatorConfig418     fn get_system_allocator_config<V: Vm>(vm: &V) -> SystemAllocatorConfig {
419         Self::get_resource_allocator_config(
420             vm.get_memory().end_addr(),
421             vm.get_guest_phys_addr_bits(),
422         )
423     }
424 
build_vm<V, Vcpu>( mut components: VmComponents, _vm_evt_wrtube: &SendTube, system_allocator: &mut SystemAllocator, serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>, serial_jail: Option<Minijail>, (bat_type, bat_jail): (Option<BatteryType>, Option<Minijail>), mut vm: V, ramoops_region: Option<arch::pstore::RamoopsRegion>, devs: Vec<(Box<dyn BusDeviceObj>, Option<Minijail>)>, irq_chip: &mut dyn IrqChipAArch64, vcpu_ids: &mut Vec<usize>, dump_device_tree_blob: Option<PathBuf>, _debugcon_jail: Option<Minijail>, #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>, #[cfg(any(target_os = "android", target_os = "linux"))] _guest_suspended_cvar: Option< Arc<(Mutex<bool>, Condvar)>, >, device_tree_overlays: Vec<DtbOverlay>, ) -> std::result::Result<RunnableLinuxVm<V, Vcpu>, Self::Error> where V: VmAArch64, Vcpu: VcpuAArch64,425     fn build_vm<V, Vcpu>(
426         mut components: VmComponents,
427         _vm_evt_wrtube: &SendTube,
428         system_allocator: &mut SystemAllocator,
429         serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>,
430         serial_jail: Option<Minijail>,
431         (bat_type, bat_jail): (Option<BatteryType>, Option<Minijail>),
432         mut vm: V,
433         ramoops_region: Option<arch::pstore::RamoopsRegion>,
434         devs: Vec<(Box<dyn BusDeviceObj>, Option<Minijail>)>,
435         irq_chip: &mut dyn IrqChipAArch64,
436         vcpu_ids: &mut Vec<usize>,
437         dump_device_tree_blob: Option<PathBuf>,
438         _debugcon_jail: Option<Minijail>,
439         #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
440         #[cfg(any(target_os = "android", target_os = "linux"))] _guest_suspended_cvar: Option<
441             Arc<(Mutex<bool>, Condvar)>,
442         >,
443         device_tree_overlays: Vec<DtbOverlay>,
444     ) -> std::result::Result<RunnableLinuxVm<V, Vcpu>, Self::Error>
445     where
446         V: VmAArch64,
447         Vcpu: VcpuAArch64,
448     {
449         let has_bios = matches!(components.vm_image, VmImage::Bios(_));
450         let mem = vm.get_memory().clone();
451 
452         // separate out image loading from other setup to get a specific error for
453         // image loading
454         let mut initrd = None;
455         let payload = match components.vm_image {
456             VmImage::Bios(ref mut bios) => {
457                 let image_size =
458                     arch::load_image(&mem, bios, get_bios_addr(), AARCH64_BIOS_MAX_LEN)
459                         .map_err(Error::BiosLoadFailure)?;
460                 PayloadType::Bios {
461                     entry: get_bios_addr(),
462                     image_size: image_size as u64,
463                 }
464             }
465             VmImage::Kernel(ref mut kernel_image) => {
466                 let loaded_kernel = load_kernel(&mem, get_kernel_addr(), kernel_image)?;
467                 let kernel_end = loaded_kernel.address_range.end;
468                 initrd = match components.initrd_image {
469                     Some(initrd_file) => {
470                         let mut initrd_file = initrd_file;
471                         let initrd_addr =
472                             (kernel_end + (AARCH64_INITRD_ALIGN - 1)) & !(AARCH64_INITRD_ALIGN - 1);
473                         let initrd_max_size =
474                             components.memory_size - (initrd_addr - AARCH64_PHYS_MEM_START);
475                         let initrd_addr = GuestAddress(initrd_addr);
476                         let initrd_size =
477                             arch::load_image(&mem, &mut initrd_file, initrd_addr, initrd_max_size)
478                                 .map_err(Error::InitrdLoadFailure)?;
479                         Some((initrd_addr, initrd_size))
480                     }
481                     None => None,
482                 };
483                 PayloadType::Kernel(loaded_kernel)
484             }
485         };
486 
487         let memory_end = GuestAddress(AARCH64_PHYS_MEM_START + components.memory_size);
488         let fdt_offset = fdt_address(memory_end, has_bios);
489 
490         let mut use_pmu = vm
491             .get_hypervisor()
492             .check_capability(HypervisorCap::ArmPmuV3);
493         let vcpu_count = components.vcpu_count;
494         let mut has_pvtime = true;
495         let mut vcpus = Vec::with_capacity(vcpu_count);
496         let mut vcpu_init = Vec::with_capacity(vcpu_count);
497         for vcpu_id in 0..vcpu_count {
498             let vcpu: Vcpu = *vm
499                 .create_vcpu(vcpu_id)
500                 .map_err(Error::CreateVcpu)?
501                 .downcast::<Vcpu>()
502                 .map_err(|_| Error::DowncastVcpu)?;
503             let per_vcpu_init = if vm
504                 .get_hypervisor()
505                 .check_capability(HypervisorCap::HypervisorInitializedBootContext)
506             {
507                 // No registers are initialized: VcpuInitAArch64.regs is an empty BTreeMap
508                 Default::default()
509             } else {
510                 Self::vcpu_init(
511                     vcpu_id,
512                     &payload,
513                     fdt_offset,
514                     components.hv_cfg.protection_type,
515                     components.boot_cpu,
516                 )
517             };
518             has_pvtime &= vcpu.has_pvtime_support();
519             vcpus.push(vcpu);
520             vcpu_ids.push(vcpu_id);
521             vcpu_init.push(per_vcpu_init);
522         }
523 
524         // Initialize Vcpus after all Vcpu objects have been created.
525         for (vcpu_id, vcpu) in vcpus.iter().enumerate() {
526             vcpu.init(&Self::vcpu_features(vcpu_id, use_pmu, components.boot_cpu))
527                 .map_err(Error::VcpuInit)?;
528         }
529 
530         irq_chip.finalize().map_err(Error::FinalizeIrqChip)?;
531 
532         if has_pvtime {
533             let pvtime_mem = MemoryMappingBuilder::new(AARCH64_PVTIME_IPA_MAX_SIZE as usize)
534                 .build()
535                 .map_err(Error::BuildPvtimeError)?;
536             vm.add_memory_region(
537                 GuestAddress(AARCH64_PVTIME_IPA_START),
538                 Box::new(pvtime_mem),
539                 false,
540                 false,
541                 MemCacheType::CacheCoherent,
542             )
543             .map_err(Error::MapPvtimeError)?;
544         }
545 
546         if components.hv_cfg.protection_type.loads_firmware() {
547             arch::load_image(
548                 &mem,
549                 &mut components
550                     .pvm_fw
551                     .expect("pvmfw must be available if ProtectionType loads it"),
552                 GuestAddress(AARCH64_PROTECTED_VM_FW_START),
553                 AARCH64_PROTECTED_VM_FW_MAX_SIZE,
554             )
555             .map_err(Error::CustomPvmFwLoadFailure)?;
556         } else if components.hv_cfg.protection_type.runs_firmware() {
557             // Tell the hypervisor to load the pVM firmware.
558             vm.load_protected_vm_firmware(
559                 GuestAddress(AARCH64_PROTECTED_VM_FW_START),
560                 AARCH64_PROTECTED_VM_FW_MAX_SIZE,
561             )
562             .map_err(Error::PvmFwLoadFailure)?;
563         }
564 
565         for (vcpu_id, vcpu) in vcpus.iter().enumerate() {
566             use_pmu &= vcpu.init_pmu(AARCH64_PMU_IRQ as u64 + 16).is_ok();
567             if has_pvtime {
568                 vcpu.init_pvtime(AARCH64_PVTIME_IPA_START + (vcpu_id as u64 * AARCH64_PVTIME_SIZE))
569                     .map_err(Error::InitPvtimeError)?;
570             }
571         }
572 
573         let mmio_bus = Arc::new(devices::Bus::new(BusType::Mmio));
574 
575         // ARM doesn't really use the io bus like x86, so just create an empty bus.
576         let io_bus = Arc::new(devices::Bus::new(BusType::Io));
577 
578         // Event used by PMDevice to notify crosvm that
579         // guest OS is trying to suspend.
580         let suspend_evt = Event::new().map_err(Error::CreateEvent)?;
581 
582         let (pci_devices, others): (Vec<_>, Vec<_>) = devs
583             .into_iter()
584             .partition(|(dev, _)| dev.as_pci_device().is_some());
585 
586         let pci_devices = pci_devices
587             .into_iter()
588             .map(|(dev, jail_orig)| (dev.into_pci_device().unwrap(), jail_orig))
589             .collect();
590         let (pci, pci_irqs, mut pid_debug_label_map, _amls, _gpe_scope_amls) =
591             arch::generate_pci_root(
592                 pci_devices,
593                 irq_chip.as_irq_chip_mut(),
594                 mmio_bus.clone(),
595                 GuestAddress(AARCH64_PCI_CFG_BASE),
596                 8,
597                 io_bus.clone(),
598                 system_allocator,
599                 &mut vm,
600                 (devices::AARCH64_GIC_NR_SPIS - AARCH64_IRQ_BASE) as usize,
601                 None,
602                 #[cfg(feature = "swap")]
603                 swap_controller,
604             )
605             .map_err(Error::CreatePciRoot)?;
606 
607         let pci_root = Arc::new(Mutex::new(pci));
608         let pci_bus = Arc::new(Mutex::new(PciConfigMmio::new(pci_root.clone(), 8)));
609         let (platform_devices, _others): (Vec<_>, Vec<_>) = others
610             .into_iter()
611             .partition(|(dev, _)| dev.as_platform_device().is_some());
612 
613         let platform_devices = platform_devices
614             .into_iter()
615             .map(|(dev, jail_orig)| (*(dev.into_platform_device().unwrap()), jail_orig))
616             .collect();
617         let (platform_devices, mut platform_pid_debug_label_map, dev_resources) =
618             arch::sys::linux::generate_platform_bus(
619                 platform_devices,
620                 irq_chip.as_irq_chip_mut(),
621                 &mmio_bus,
622                 system_allocator,
623                 &mut vm,
624                 #[cfg(feature = "swap")]
625                 swap_controller,
626                 components.hv_cfg.protection_type,
627             )
628             .map_err(Error::CreatePlatformBus)?;
629         pid_debug_label_map.append(&mut platform_pid_debug_label_map);
630 
631         Self::add_arch_devs(
632             irq_chip.as_irq_chip_mut(),
633             &mmio_bus,
634             vcpu_count,
635             _vm_evt_wrtube,
636         )?;
637 
638         let com_evt_1_3 = devices::IrqEdgeEvent::new().map_err(Error::CreateEvent)?;
639         let com_evt_2_4 = devices::IrqEdgeEvent::new().map_err(Error::CreateEvent)?;
640         let serial_devices = arch::add_serial_devices(
641             components.hv_cfg.protection_type,
642             &mmio_bus,
643             (AARCH64_SERIAL_1_3_IRQ, com_evt_1_3.get_trigger()),
644             (AARCH64_SERIAL_2_4_IRQ, com_evt_2_4.get_trigger()),
645             serial_parameters,
646             serial_jail,
647             #[cfg(feature = "swap")]
648             swap_controller,
649         )
650         .map_err(Error::CreateSerialDevices)?;
651 
652         let source = IrqEventSource {
653             device_id: Serial::device_id(),
654             queue_id: 0,
655             device_name: Serial::debug_label(),
656         };
657         irq_chip
658             .register_edge_irq_event(AARCH64_SERIAL_1_3_IRQ, &com_evt_1_3, source.clone())
659             .map_err(Error::RegisterIrqfd)?;
660         irq_chip
661             .register_edge_irq_event(AARCH64_SERIAL_2_4_IRQ, &com_evt_2_4, source)
662             .map_err(Error::RegisterIrqfd)?;
663 
664         mmio_bus
665             .insert(pci_bus, AARCH64_PCI_CFG_BASE, AARCH64_PCI_CFG_SIZE)
666             .map_err(Error::RegisterPci)?;
667 
668         #[cfg(any(target_os = "android", target_os = "linux"))]
669         if !components.cpu_frequencies.is_empty() {
670             // TODO: Revisit and optimization after benchmarking
671             let socket = components
672                 .virt_cpufreq_socket
673                 .map(|s| Arc::new(Mutex::new(s)));
674             for vcpu in 0..vcpu_count {
675                 let vcpu_affinity = match components.vcpu_affinity.clone() {
676                     Some(VcpuAffinity::Global(v)) => v,
677                     Some(VcpuAffinity::PerVcpu(mut m)) => m.remove(&vcpu).unwrap_or_default(),
678                     None => panic!("vcpu_affinity needs to be set for VirtCpufreq"),
679                 };
680 
681                 let virt_cpufreq = Arc::new(Mutex::new(VirtCpufreq::new(
682                     vcpu_affinity[0].try_into().unwrap(),
683                     socket.clone(),
684                 )));
685 
686                 if vcpu as u64 * AARCH64_VIRTFREQ_SIZE + AARCH64_VIRTFREQ_SIZE
687                     > AARCH64_VIRTFREQ_MAXSIZE
688                 {
689                     panic!("Exceeded maximum number of virt cpufreq devices");
690                 }
691 
692                 mmio_bus
693                     .insert(
694                         virt_cpufreq,
695                         AARCH64_VIRTFREQ_BASE + (vcpu as u64 * AARCH64_VIRTFREQ_SIZE),
696                         AARCH64_VIRTFREQ_SIZE,
697                     )
698                     .map_err(Error::RegisterVirtCpufreq)?;
699             }
700         }
701 
702         let mut cmdline = Self::get_base_linux_cmdline();
703         get_serial_cmdline(&mut cmdline, serial_parameters, "mmio", &serial_devices)
704             .map_err(Error::GetSerialCmdline)?;
705         for param in components.extra_kernel_params {
706             cmdline.insert_str(&param).map_err(Error::Cmdline)?;
707         }
708 
709         if let Some(ramoops_region) = ramoops_region {
710             arch::pstore::add_ramoops_kernel_cmdline(&mut cmdline, &ramoops_region)
711                 .map_err(Error::Cmdline)?;
712         }
713 
714         let psci_version = vcpus[0].get_psci_version().map_err(Error::GetPsciVersion)?;
715 
716         let pci_cfg = fdt::PciConfigRegion {
717             base: AARCH64_PCI_CFG_BASE,
718             size: AARCH64_PCI_CFG_SIZE,
719         };
720 
721         let pci_ranges: Vec<fdt::PciRange> = system_allocator
722             .mmio_pools()
723             .iter()
724             .map(|range| fdt::PciRange {
725                 space: fdt::PciAddressSpace::Memory64,
726                 bus_address: range.start,
727                 cpu_physical_address: range.start,
728                 size: range.len().unwrap(),
729                 prefetchable: false,
730             })
731             .collect();
732 
733         let (bat_control, bat_mmio_base_and_irq) = match bat_type {
734             Some(BatteryType::Goldfish) => {
735                 let bat_irq = AARCH64_BAT_IRQ;
736 
737                 // a dummy AML buffer. Aarch64 crosvm doesn't use ACPI.
738                 let mut amls = Vec::new();
739                 let (control_tube, mmio_base) = arch::sys::linux::add_goldfish_battery(
740                     &mut amls,
741                     bat_jail,
742                     &mmio_bus,
743                     irq_chip.as_irq_chip_mut(),
744                     bat_irq,
745                     system_allocator,
746                     #[cfg(feature = "swap")]
747                     swap_controller,
748                 )
749                 .map_err(Error::CreateBatDevices)?;
750                 (
751                     Some(BatControl {
752                         type_: BatteryType::Goldfish,
753                         control_tube,
754                     }),
755                     Some((mmio_base, bat_irq)),
756                 )
757             }
758             None => (None, None),
759         };
760 
761         let vmwdt_cfg = fdt::VmWdtConfig {
762             base: AARCH64_VMWDT_ADDR,
763             size: AARCH64_VMWDT_SIZE,
764             clock_hz: VMWDT_DEFAULT_CLOCK_HZ,
765             timeout_sec: VMWDT_DEFAULT_TIMEOUT_SEC,
766         };
767 
768         fdt::create_fdt(
769             AARCH64_FDT_MAX_SIZE as usize,
770             &mem,
771             pci_irqs,
772             pci_cfg,
773             &pci_ranges,
774             dev_resources,
775             vcpu_count as u32,
776             &|n| get_vcpu_mpidr_aff(&vcpus, n),
777             components.cpu_clusters,
778             components.cpu_capacity,
779             components.cpu_frequencies,
780             fdt_offset,
781             cmdline.as_str(),
782             (payload.entry(), payload.size() as usize),
783             initrd,
784             components.android_fstab,
785             irq_chip.get_vgic_version() == DeviceKind::ArmVgicV3,
786             use_pmu,
787             psci_version,
788             components.swiotlb.map(|size| {
789                 (
790                     get_swiotlb_addr(components.memory_size, vm.get_hypervisor()),
791                     size,
792                 )
793             }),
794             bat_mmio_base_and_irq,
795             vmwdt_cfg,
796             dump_device_tree_blob,
797             &|writer, phandles| vm.create_fdt(writer, phandles),
798             components.dynamic_power_coefficient,
799             device_tree_overlays,
800             &serial_devices,
801         )
802         .map_err(Error::CreateFdt)?;
803 
804         vm.init_arch(
805             payload.entry(),
806             fdt_offset,
807             AARCH64_FDT_MAX_SIZE.try_into().unwrap(),
808         )
809         .map_err(Error::InitVmError)?;
810 
811         Ok(RunnableLinuxVm {
812             vm,
813             vcpu_count,
814             vcpus: Some(vcpus),
815             vcpu_init,
816             vcpu_affinity: components.vcpu_affinity,
817             no_smt: components.no_smt,
818             irq_chip: irq_chip.try_box_clone().map_err(Error::CloneIrqChip)?,
819             io_bus,
820             mmio_bus,
821             pid_debug_label_map,
822             suspend_evt,
823             rt_cpus: components.rt_cpus,
824             delay_rt: components.delay_rt,
825             bat_control,
826             #[cfg(feature = "gdb")]
827             gdb: components.gdb,
828             pm: None,
829             resume_notify_devices: Vec::new(),
830             root_config: pci_root,
831             platform_devices,
832             hotplug_bus: BTreeMap::new(),
833             devices_thread: None,
834             vm_request_tube: None,
835         })
836     }
837 
configure_vcpu<V: Vm>( _vm: &V, _hypervisor: &dyn Hypervisor, _irq_chip: &mut dyn IrqChipAArch64, vcpu: &mut dyn VcpuAArch64, vcpu_init: VcpuInitAArch64, _vcpu_id: usize, _num_cpus: usize, _cpu_config: Option<CpuConfigAArch64>, ) -> std::result::Result<(), Self::Error>838     fn configure_vcpu<V: Vm>(
839         _vm: &V,
840         _hypervisor: &dyn Hypervisor,
841         _irq_chip: &mut dyn IrqChipAArch64,
842         vcpu: &mut dyn VcpuAArch64,
843         vcpu_init: VcpuInitAArch64,
844         _vcpu_id: usize,
845         _num_cpus: usize,
846         _cpu_config: Option<CpuConfigAArch64>,
847     ) -> std::result::Result<(), Self::Error> {
848         for (reg, value) in vcpu_init.regs.iter() {
849             vcpu.set_one_reg(*reg, *value).map_err(Error::SetReg)?;
850         }
851         Ok(())
852     }
853 
register_pci_device<V: VmAArch64, Vcpu: VcpuAArch64>( _linux: &mut RunnableLinuxVm<V, Vcpu>, _device: Box<dyn PciDevice>, _minijail: Option<Minijail>, _resources: &mut SystemAllocator, _tube: &mpsc::Sender<PciRootCommand>, #[cfg(feature = "swap")] _swap_controller: &mut Option<swap::SwapController>, ) -> std::result::Result<PciAddress, Self::Error>854     fn register_pci_device<V: VmAArch64, Vcpu: VcpuAArch64>(
855         _linux: &mut RunnableLinuxVm<V, Vcpu>,
856         _device: Box<dyn PciDevice>,
857         _minijail: Option<Minijail>,
858         _resources: &mut SystemAllocator,
859         _tube: &mpsc::Sender<PciRootCommand>,
860         #[cfg(feature = "swap")] _swap_controller: &mut Option<swap::SwapController>,
861     ) -> std::result::Result<PciAddress, Self::Error> {
862         // hotplug function isn't verified on AArch64, so set it unsupported here.
863         Err(Error::Unsupported)
864     }
865 
get_host_cpu_frequencies_khz() -> std::result::Result<BTreeMap<usize, Vec<u32>>, Self::Error>866     fn get_host_cpu_frequencies_khz() -> std::result::Result<BTreeMap<usize, Vec<u32>>, Self::Error>
867     {
868         Ok(
869             Self::collect_for_each_cpu(base::logical_core_frequencies_khz)
870                 .map_err(Error::CpuFrequencies)?
871                 .into_iter()
872                 .enumerate()
873                 .collect(),
874         )
875     }
876 
877     // Returns a (cpu_id -> value) map of the DMIPS/MHz capacities of logical cores
878     // in the host system.
get_host_cpu_capacity() -> std::result::Result<BTreeMap<usize, u32>, Self::Error>879     fn get_host_cpu_capacity() -> std::result::Result<BTreeMap<usize, u32>, Self::Error> {
880         Ok(Self::collect_for_each_cpu(base::logical_core_capacity)
881             .map_err(Error::CpuTopology)?
882             .into_iter()
883             .enumerate()
884             .collect())
885     }
886 
887     // Creates CPU cluster mask for each CPU in the host system.
get_host_cpu_clusters() -> std::result::Result<Vec<CpuSet>, Self::Error>888     fn get_host_cpu_clusters() -> std::result::Result<Vec<CpuSet>, Self::Error> {
889         let cluster_ids = Self::collect_for_each_cpu(base::logical_core_cluster_id)
890             .map_err(Error::CpuTopology)?;
891         let mut unique_clusters: Vec<CpuSet> = cluster_ids
892             .iter()
893             .map(|&vcpu_cluster_id| {
894                 cluster_ids
895                     .iter()
896                     .enumerate()
897                     .filter(|(_, &cpu_cluster_id)| vcpu_cluster_id == cpu_cluster_id)
898                     .map(|(cpu_id, _)| cpu_id)
899                     .collect()
900             })
901             .collect();
902         unique_clusters.sort_unstable();
903         unique_clusters.dedup();
904         Ok(unique_clusters)
905     }
906 }
907 
908 #[cfg(feature = "gdb")]
909 impl<T: VcpuAArch64> arch::GdbOps<T> for AArch64 {
910     type Error = Error;
911 
read_memory( _vcpu: &T, guest_mem: &GuestMemory, vaddr: GuestAddress, len: usize, ) -> Result<Vec<u8>>912     fn read_memory(
913         _vcpu: &T,
914         guest_mem: &GuestMemory,
915         vaddr: GuestAddress,
916         len: usize,
917     ) -> Result<Vec<u8>> {
918         let mut buf = vec![0; len];
919 
920         guest_mem
921             .read_exact_at_addr(&mut buf, vaddr)
922             .map_err(Error::ReadGuestMemory)?;
923 
924         Ok(buf)
925     }
926 
write_memory( _vcpu: &T, guest_mem: &GuestMemory, vaddr: GuestAddress, buf: &[u8], ) -> Result<()>927     fn write_memory(
928         _vcpu: &T,
929         guest_mem: &GuestMemory,
930         vaddr: GuestAddress,
931         buf: &[u8],
932     ) -> Result<()> {
933         guest_mem
934             .write_all_at_addr(buf, vaddr)
935             .map_err(Error::WriteGuestMemory)
936     }
937 
read_registers(vcpu: &T) -> Result<<GdbArch as Arch>::Registers>938     fn read_registers(vcpu: &T) -> Result<<GdbArch as Arch>::Registers> {
939         let mut regs: <GdbArch as Arch>::Registers = Default::default();
940 
941         vcpu.get_gdb_registers(&mut regs).map_err(Error::ReadRegs)?;
942 
943         Ok(regs)
944     }
945 
write_registers(vcpu: &T, regs: &<GdbArch as Arch>::Registers) -> Result<()>946     fn write_registers(vcpu: &T, regs: &<GdbArch as Arch>::Registers) -> Result<()> {
947         vcpu.set_gdb_registers(regs).map_err(Error::WriteRegs)
948     }
949 
read_register(vcpu: &T, reg_id: <GdbArch as Arch>::RegId) -> Result<Vec<u8>>950     fn read_register(vcpu: &T, reg_id: <GdbArch as Arch>::RegId) -> Result<Vec<u8>> {
951         let mut reg = vec![0; std::mem::size_of::<u128>()];
952         let size = vcpu
953             .get_gdb_register(reg_id, reg.as_mut_slice())
954             .map_err(Error::ReadReg)?;
955         reg.truncate(size);
956         Ok(reg)
957     }
958 
write_register(vcpu: &T, reg_id: <GdbArch as Arch>::RegId, data: &[u8]) -> Result<()>959     fn write_register(vcpu: &T, reg_id: <GdbArch as Arch>::RegId, data: &[u8]) -> Result<()> {
960         vcpu.set_gdb_register(reg_id, data).map_err(Error::WriteReg)
961     }
962 
enable_singlestep(vcpu: &T) -> Result<()>963     fn enable_singlestep(vcpu: &T) -> Result<()> {
964         const SINGLE_STEP: bool = true;
965         vcpu.set_guest_debug(&[], SINGLE_STEP)
966             .map_err(Error::EnableSinglestep)
967     }
968 
get_max_hw_breakpoints(vcpu: &T) -> Result<usize>969     fn get_max_hw_breakpoints(vcpu: &T) -> Result<usize> {
970         vcpu.get_max_hw_bps().map_err(Error::GetMaxHwBreakPoint)
971     }
972 
set_hw_breakpoints(vcpu: &T, breakpoints: &[GuestAddress]) -> Result<()>973     fn set_hw_breakpoints(vcpu: &T, breakpoints: &[GuestAddress]) -> Result<()> {
974         const SINGLE_STEP: bool = false;
975         vcpu.set_guest_debug(breakpoints, SINGLE_STEP)
976             .map_err(Error::SetHwBreakpoint)
977     }
978 }
979 
980 impl AArch64 {
981     /// This returns a base part of the kernel command for this architecture
get_base_linux_cmdline() -> kernel_cmdline::Cmdline982     fn get_base_linux_cmdline() -> kernel_cmdline::Cmdline {
983         let mut cmdline = kernel_cmdline::Cmdline::new(base::pagesize());
984         cmdline.insert_str("panic=-1").unwrap();
985         cmdline
986     }
987 
988     /// Returns a system resource allocator configuration.
989     ///
990     /// # Arguments
991     ///
992     /// * `memory_end` - The first address beyond the end of guest memory.
993     /// * `guest_phys_addr_bits` - Size of guest physical addresses (IPA) in bits.
get_resource_allocator_config( memory_end: GuestAddress, guest_phys_addr_bits: u8, ) -> SystemAllocatorConfig994     fn get_resource_allocator_config(
995         memory_end: GuestAddress,
996         guest_phys_addr_bits: u8,
997     ) -> SystemAllocatorConfig {
998         let guest_phys_end = 1u64 << guest_phys_addr_bits;
999         // The platform MMIO region is immediately past the end of RAM.
1000         let plat_mmio_base = memory_end.offset();
1001         let plat_mmio_size = AARCH64_PLATFORM_MMIO_SIZE;
1002         // The high MMIO region is the rest of the address space after the platform MMIO region.
1003         let high_mmio_base = plat_mmio_base + plat_mmio_size;
1004         let high_mmio_size = guest_phys_end
1005             .checked_sub(high_mmio_base)
1006             .unwrap_or_else(|| {
1007                 panic!(
1008                     "guest_phys_end {:#x} < high_mmio_base {:#x}",
1009                     guest_phys_end, high_mmio_base,
1010                 );
1011             });
1012         SystemAllocatorConfig {
1013             io: None,
1014             low_mmio: AddressRange::from_start_and_size(AARCH64_MMIO_BASE, AARCH64_MMIO_SIZE)
1015                 .expect("invalid mmio region"),
1016             high_mmio: AddressRange::from_start_and_size(high_mmio_base, high_mmio_size)
1017                 .expect("invalid high mmio region"),
1018             platform_mmio: Some(
1019                 AddressRange::from_start_and_size(plat_mmio_base, plat_mmio_size)
1020                     .expect("invalid platform mmio region"),
1021             ),
1022             first_irq: AARCH64_IRQ_BASE,
1023         }
1024     }
1025 
1026     /// This adds any early platform devices for this architecture.
1027     ///
1028     /// # Arguments
1029     ///
1030     /// * `irq_chip` - The IRQ chip to add irqs to.
1031     /// * `bus` - The bus to add devices to.
1032     /// * `vcpu_count` - The number of virtual CPUs for this guest VM
1033     /// * `vm_evt_wrtube` - The notification channel
add_arch_devs( irq_chip: &mut dyn IrqChip, bus: &Bus, vcpu_count: usize, vm_evt_wrtube: &SendTube, ) -> Result<()>1034     fn add_arch_devs(
1035         irq_chip: &mut dyn IrqChip,
1036         bus: &Bus,
1037         vcpu_count: usize,
1038         vm_evt_wrtube: &SendTube,
1039     ) -> Result<()> {
1040         let rtc_evt = devices::IrqEdgeEvent::new().map_err(Error::CreateEvent)?;
1041         let rtc = devices::pl030::Pl030::new(rtc_evt.try_clone().map_err(Error::CloneEvent)?);
1042         irq_chip
1043             .register_edge_irq_event(AARCH64_RTC_IRQ, &rtc_evt, IrqEventSource::from_device(&rtc))
1044             .map_err(Error::RegisterIrqfd)?;
1045 
1046         bus.insert(
1047             Arc::new(Mutex::new(rtc)),
1048             AARCH64_RTC_ADDR,
1049             AARCH64_RTC_SIZE,
1050         )
1051         .expect("failed to add rtc device");
1052 
1053         let vm_wdt = Arc::new(Mutex::new(
1054             devices::vmwdt::Vmwdt::new(vcpu_count, vm_evt_wrtube.try_clone().unwrap()).unwrap(),
1055         ));
1056         bus.insert(vm_wdt, AARCH64_VMWDT_ADDR, AARCH64_VMWDT_SIZE)
1057             .expect("failed to add vmwdt device");
1058 
1059         Ok(())
1060     }
1061 
1062     /// Get ARM-specific features for vcpu with index `vcpu_id`.
1063     ///
1064     /// # Arguments
1065     ///
1066     /// * `vcpu_id` - The VM's index for `vcpu`.
1067     /// * `use_pmu` - Should `vcpu` be configured to use the Performance Monitor Unit.
vcpu_features(vcpu_id: usize, use_pmu: bool, boot_cpu: usize) -> Vec<VcpuFeature>1068     fn vcpu_features(vcpu_id: usize, use_pmu: bool, boot_cpu: usize) -> Vec<VcpuFeature> {
1069         let mut features = vec![VcpuFeature::PsciV0_2];
1070         if use_pmu {
1071             features.push(VcpuFeature::PmuV3);
1072         }
1073         // Non-boot cpus are powered off initially
1074         if vcpu_id != boot_cpu {
1075             features.push(VcpuFeature::PowerOff);
1076         }
1077 
1078         features
1079     }
1080 
1081     /// Get initial register state for vcpu with index `vcpu_id`.
1082     ///
1083     /// # Arguments
1084     ///
1085     /// * `vcpu_id` - The VM's index for `vcpu`.
vcpu_init( vcpu_id: usize, payload: &PayloadType, fdt_address: GuestAddress, protection_type: ProtectionType, boot_cpu: usize, ) -> VcpuInitAArch641086     fn vcpu_init(
1087         vcpu_id: usize,
1088         payload: &PayloadType,
1089         fdt_address: GuestAddress,
1090         protection_type: ProtectionType,
1091         boot_cpu: usize,
1092     ) -> VcpuInitAArch64 {
1093         let mut regs: BTreeMap<VcpuRegAArch64, u64> = Default::default();
1094 
1095         // All interrupts masked
1096         let pstate = PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT | PSR_MODE_EL1H;
1097         regs.insert(VcpuRegAArch64::Pstate, pstate);
1098 
1099         // Other cpus are powered off initially
1100         if vcpu_id == boot_cpu {
1101             let entry_addr = if protection_type.loads_firmware() {
1102                 Some(AARCH64_PROTECTED_VM_FW_START)
1103             } else if protection_type.runs_firmware() {
1104                 None // Initial PC value is set by the hypervisor
1105             } else {
1106                 Some(payload.entry().offset())
1107             };
1108 
1109             /* PC -- entry point */
1110             if let Some(entry) = entry_addr {
1111                 regs.insert(VcpuRegAArch64::Pc, entry);
1112             }
1113 
1114             /* X0 -- fdt address */
1115             regs.insert(VcpuRegAArch64::X(0), fdt_address.offset());
1116 
1117             if protection_type.runs_firmware() {
1118                 /* X1 -- payload entry point */
1119                 regs.insert(VcpuRegAArch64::X(1), payload.entry().offset());
1120 
1121                 /* X2 -- image size */
1122                 regs.insert(VcpuRegAArch64::X(2), payload.size());
1123             }
1124         }
1125 
1126         VcpuInitAArch64 { regs }
1127     }
1128 
collect_for_each_cpu<F, T>(func: F) -> std::result::Result<Vec<T>, base::Error> where F: Fn(usize) -> std::result::Result<T, base::Error>,1129     fn collect_for_each_cpu<F, T>(func: F) -> std::result::Result<Vec<T>, base::Error>
1130     where
1131         F: Fn(usize) -> std::result::Result<T, base::Error>,
1132     {
1133         (0..base::number_of_logical_cores()?).map(func).collect()
1134     }
1135 }
1136 
1137 #[cfg(test)]
1138 mod tests {
1139     use super::*;
1140 
1141     #[test]
vcpu_init_unprotected_kernel()1142     fn vcpu_init_unprotected_kernel() {
1143         let payload = PayloadType::Kernel(LoadedKernel {
1144             address_range: AddressRange::from_start_and_size(0x8080_0000, 0x1000).unwrap(),
1145             size: 0x1000,
1146             entry: GuestAddress(0x8080_0000),
1147         });
1148         let fdt_address = GuestAddress(0x1234);
1149         let prot = ProtectionType::Unprotected;
1150 
1151         let vcpu_init = AArch64::vcpu_init(0, &payload, fdt_address, prot, 0);
1152 
1153         // PC: kernel image entry point
1154         assert_eq!(vcpu_init.regs.get(&VcpuRegAArch64::Pc), Some(&0x8080_0000));
1155 
1156         // X0: fdt_offset
1157         assert_eq!(vcpu_init.regs.get(&VcpuRegAArch64::X(0)), Some(&0x1234));
1158     }
1159 
1160     #[test]
vcpu_init_unprotected_bios()1161     fn vcpu_init_unprotected_bios() {
1162         let payload = PayloadType::Bios {
1163             entry: GuestAddress(0x8020_0000),
1164             image_size: 0x1000,
1165         };
1166         let fdt_address = GuestAddress(0x1234);
1167         let prot = ProtectionType::Unprotected;
1168 
1169         let vcpu_init = AArch64::vcpu_init(0, &payload, fdt_address, prot, 0);
1170 
1171         // PC: bios image entry point
1172         assert_eq!(vcpu_init.regs.get(&VcpuRegAArch64::Pc), Some(&0x8020_0000));
1173 
1174         // X0: fdt_offset
1175         assert_eq!(vcpu_init.regs.get(&VcpuRegAArch64::X(0)), Some(&0x1234));
1176     }
1177 
1178     #[test]
vcpu_init_protected_kernel()1179     fn vcpu_init_protected_kernel() {
1180         let payload = PayloadType::Kernel(LoadedKernel {
1181             address_range: AddressRange::from_start_and_size(0x8080_0000, 0x1000).unwrap(),
1182             size: 0x1000,
1183             entry: GuestAddress(0x8080_0000),
1184         });
1185         let fdt_address = GuestAddress(0x1234);
1186         let prot = ProtectionType::Protected;
1187 
1188         let vcpu_init = AArch64::vcpu_init(0, &payload, fdt_address, prot, 0);
1189 
1190         // The hypervisor provides the initial value of PC, so PC should not be present in the
1191         // vcpu_init register map.
1192         assert_eq!(vcpu_init.regs.get(&VcpuRegAArch64::Pc), None);
1193 
1194         // X0: fdt_offset
1195         assert_eq!(vcpu_init.regs.get(&VcpuRegAArch64::X(0)), Some(&0x1234));
1196 
1197         // X1: kernel image entry point
1198         assert_eq!(
1199             vcpu_init.regs.get(&VcpuRegAArch64::X(1)),
1200             Some(&0x8080_0000)
1201         );
1202 
1203         // X2: image size
1204         assert_eq!(vcpu_init.regs.get(&VcpuRegAArch64::X(2)), Some(&0x1000));
1205     }
1206 }
1207