• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #![cfg(any(target_arch = "arm", target_arch = "aarch64"))]
6 
7 use std::collections::BTreeMap;
8 use std::io;
9 use std::sync::Arc;
10 
11 use arch::{get_serial_cmdline, GetSerialCmdlineError, RunnableLinuxVm, VmComponents, VmImage};
12 use base::{Event, MemoryMappingBuilder};
13 use devices::serial_device::{SerialHardware, SerialParameters};
14 use devices::{
15     Bus, BusDeviceObj, BusError, IrqChip, IrqChipAArch64, PciAddress, PciConfigMmio, PciDevice,
16 };
17 use hypervisor::{
18     arm64_core_reg, DeviceKind, Hypervisor, HypervisorCap, ProtectionType, VcpuAArch64,
19     VcpuFeature, Vm, VmAArch64,
20 };
21 use minijail::Minijail;
22 use remain::sorted;
23 use resources::{range_inclusive_len, MemRegion, SystemAllocator, SystemAllocatorConfig};
24 use sync::Mutex;
25 use thiserror::Error;
26 use vm_control::BatteryType;
27 use vm_memory::{GuestAddress, GuestMemory, GuestMemoryError};
28 
29 mod fdt;
30 
31 // We place the kernel at offset 8MB
32 const AARCH64_KERNEL_OFFSET: u64 = 0x800000;
33 const AARCH64_FDT_MAX_SIZE: u64 = 0x200000;
34 const AARCH64_INITRD_ALIGN: u64 = 0x1000000;
35 
36 // These constants indicate the address space used by the ARM vGIC.
37 const AARCH64_GIC_DIST_SIZE: u64 = 0x10000;
38 const AARCH64_GIC_CPUI_SIZE: u64 = 0x20000;
39 
40 // This indicates the start of DRAM inside the physical address space.
41 const AARCH64_PHYS_MEM_START: u64 = 0x80000000;
42 const AARCH64_AXI_BASE: u64 = 0x40000000;
43 const AARCH64_PLATFORM_MMIO_SIZE: u64 = 0x800000;
44 
45 // FDT is placed at the front of RAM when booting in BIOS mode.
46 const AARCH64_FDT_OFFSET_IN_BIOS_MODE: u64 = 0x0;
47 // Therefore, the BIOS is placed after the FDT in memory.
48 const AARCH64_BIOS_OFFSET: u64 = AARCH64_FDT_MAX_SIZE;
49 const AARCH64_BIOS_MAX_LEN: u64 = 1 << 20;
50 
51 const AARCH64_PROTECTED_VM_FW_MAX_SIZE: u64 = 0x200000;
52 const AARCH64_PROTECTED_VM_FW_START: u64 =
53     AARCH64_PHYS_MEM_START - AARCH64_PROTECTED_VM_FW_MAX_SIZE;
54 
55 const AARCH64_PVTIME_IPA_MAX_SIZE: u64 = 0x10000;
56 const AARCH64_PVTIME_IPA_START: u64 = AARCH64_PROTECTED_VM_FW_START - AARCH64_PVTIME_IPA_MAX_SIZE;
57 const AARCH64_PVTIME_SIZE: u64 = 64;
58 
59 // These constants indicate the placement of the GIC registers in the physical
60 // address space.
61 const AARCH64_GIC_DIST_BASE: u64 = AARCH64_AXI_BASE - AARCH64_GIC_DIST_SIZE;
62 const AARCH64_GIC_CPUI_BASE: u64 = AARCH64_GIC_DIST_BASE - AARCH64_GIC_CPUI_SIZE;
63 const AARCH64_GIC_REDIST_SIZE: u64 = 0x20000;
64 
65 // PSR (Processor State Register) bits
66 const PSR_MODE_EL1H: u64 = 0x00000005;
67 const PSR_F_BIT: u64 = 0x00000040;
68 const PSR_I_BIT: u64 = 0x00000080;
69 const PSR_A_BIT: u64 = 0x00000100;
70 const PSR_D_BIT: u64 = 0x00000200;
71 
get_kernel_addr() -> GuestAddress72 fn get_kernel_addr() -> GuestAddress {
73     GuestAddress(AARCH64_PHYS_MEM_START + AARCH64_KERNEL_OFFSET)
74 }
75 
get_bios_addr() -> GuestAddress76 fn get_bios_addr() -> GuestAddress {
77     GuestAddress(AARCH64_PHYS_MEM_START + AARCH64_BIOS_OFFSET)
78 }
79 
80 // Serial device requires 8 bytes of registers;
81 const AARCH64_SERIAL_SIZE: u64 = 0x8;
82 // This was the speed kvmtool used, not sure if it matters.
83 const AARCH64_SERIAL_SPEED: u32 = 1843200;
84 // The serial device gets the first interrupt line
85 // Which gets mapped to the first SPI interrupt (physical 32).
86 const AARCH64_SERIAL_1_3_IRQ: u32 = 0;
87 const AARCH64_SERIAL_2_4_IRQ: u32 = 2;
88 
89 // Place the RTC device at page 2
90 const AARCH64_RTC_ADDR: u64 = 0x2000;
91 // The RTC device gets one 4k page
92 const AARCH64_RTC_SIZE: u64 = 0x1000;
93 // The RTC device gets the second interrupt line
94 const AARCH64_RTC_IRQ: u32 = 1;
95 
96 // PCI MMIO configuration region base address.
97 const AARCH64_PCI_CFG_BASE: u64 = 0x10000;
98 // PCI MMIO configuration region size.
99 const AARCH64_PCI_CFG_SIZE: u64 = 0x1000000;
100 // This is the base address of MMIO devices.
101 const AARCH64_MMIO_BASE: u64 = 0x2000000;
102 // Size of the whole MMIO region.
103 const AARCH64_MMIO_SIZE: u64 = 0x2000000;
104 // Virtio devices start at SPI interrupt number 3
105 const AARCH64_IRQ_BASE: u32 = 3;
106 
107 // PMU PPI interrupt, same as qemu
108 const AARCH64_PMU_IRQ: u32 = 7;
109 
110 #[sorted]
111 #[derive(Error, Debug)]
112 pub enum Error {
113     #[error("bios could not be loaded: {0}")]
114     BiosLoadFailure(arch::LoadImageError),
115     #[error("failed to build arm pvtime memory: {0}")]
116     BuildPvtimeError(base::MmapError),
117     #[error("unable to clone an Event: {0}")]
118     CloneEvent(base::Error),
119     #[error("failed to clone IRQ chip: {0}")]
120     CloneIrqChip(base::Error),
121     #[error("the given kernel command line was invalid: {0}")]
122     Cmdline(kernel_cmdline::Error),
123     #[error("unable to make an Event: {0}")]
124     CreateEvent(base::Error),
125     #[error("FDT could not be created: {0}")]
126     CreateFdt(arch::fdt::Error),
127     #[error("failed to create GIC: {0}")]
128     CreateGICFailure(base::Error),
129     #[error("failed to create a PCI root hub: {0}")]
130     CreatePciRoot(arch::DeviceRegistrationError),
131     #[error("failed to create platform bus: {0}")]
132     CreatePlatformBus(arch::DeviceRegistrationError),
133     #[error("unable to create serial devices: {0}")]
134     CreateSerialDevices(arch::DeviceRegistrationError),
135     #[error("failed to create socket: {0}")]
136     CreateSocket(io::Error),
137     #[error("failed to create VCPU: {0}")]
138     CreateVcpu(base::Error),
139     #[error("vm created wrong kind of vcpu")]
140     DowncastVcpu,
141     #[error("failed to finalize IRQ chip: {0}")]
142     FinalizeIrqChip(base::Error),
143     #[error("failed to get PSCI version: {0}")]
144     GetPsciVersion(base::Error),
145     #[error("failed to get serial cmdline: {0}")]
146     GetSerialCmdline(GetSerialCmdlineError),
147     #[error("failed to initialize arm pvtime: {0}")]
148     InitPvtimeError(base::Error),
149     #[error("initrd could not be loaded: {0}")]
150     InitrdLoadFailure(arch::LoadImageError),
151     #[error("kernel could not be loaded: {0}")]
152     KernelLoadFailure(arch::LoadImageError),
153     #[error("failed to map arm pvtime memory: {0}")]
154     MapPvtimeError(base::Error),
155     #[error("failed to protect vm: {0}")]
156     ProtectVm(base::Error),
157     #[error("ramoops address is different from high_mmio_base: {0} vs {1}")]
158     RamoopsAddress(u64, u64),
159     #[error("failed to register irq fd: {0}")]
160     RegisterIrqfd(base::Error),
161     #[error("error registering PCI bus: {0}")]
162     RegisterPci(BusError),
163     #[error("error registering virtual socket device: {0}")]
164     RegisterVsock(arch::DeviceRegistrationError),
165     #[error("failed to set device attr: {0}")]
166     SetDeviceAttr(base::Error),
167     #[error("failed to set register: {0}")]
168     SetReg(base::Error),
169     #[error("failed to set up guest memory: {0}")]
170     SetupGuestMemory(GuestMemoryError),
171     #[error("this function isn't supported")]
172     Unsupported,
173     #[error("failed to initialize VCPU: {0}")]
174     VcpuInit(base::Error),
175 }
176 
177 pub type Result<T> = std::result::Result<T, Error>;
178 
179 /// Returns a Vec of the valid memory addresses.
180 /// These should be used to configure the GuestMemory structure for the platfrom.
arch_memory_regions(size: u64) -> Vec<(GuestAddress, u64)>181 pub fn arch_memory_regions(size: u64) -> Vec<(GuestAddress, u64)> {
182     vec![(GuestAddress(AARCH64_PHYS_MEM_START), size)]
183 }
184 
fdt_offset(mem_size: u64, has_bios: bool) -> u64185 fn fdt_offset(mem_size: u64, has_bios: bool) -> u64 {
186     // TODO(rammuthiah) make kernel and BIOS startup use FDT from the same location. ARCVM startup
187     // currently expects the kernel at 0x80080000 and the FDT at the end of RAM for unknown reasons.
188     // Root cause and figure out how to fold these code paths together.
189     if has_bios {
190         AARCH64_FDT_OFFSET_IN_BIOS_MODE
191     } else {
192         // Put fdt up near the top of memory
193         // TODO(sonnyrao): will have to handle this differently if there's
194         // > 4GB memory
195         mem_size - AARCH64_FDT_MAX_SIZE - 0x10000
196     }
197 }
198 
199 pub struct AArch64;
200 
201 impl arch::LinuxArch for AArch64 {
202     type Error = Error;
203 
guest_memory_layout( components: &VmComponents, ) -> std::result::Result<Vec<(GuestAddress, u64)>, Self::Error>204     fn guest_memory_layout(
205         components: &VmComponents,
206     ) -> std::result::Result<Vec<(GuestAddress, u64)>, Self::Error> {
207         Ok(arch_memory_regions(components.memory_size))
208     }
209 
get_system_allocator_config<V: Vm>(vm: &V) -> SystemAllocatorConfig210     fn get_system_allocator_config<V: Vm>(vm: &V) -> SystemAllocatorConfig {
211         Self::get_resource_allocator_config(
212             vm.get_memory().memory_size(),
213             vm.get_guest_phys_addr_bits(),
214         )
215     }
216 
build_vm<V, Vcpu>( mut components: VmComponents, _exit_evt: &Event, _reset_evt: &Event, system_allocator: &mut SystemAllocator, serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>, serial_jail: Option<Minijail>, _battery: (&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, kvm_vcpu_ids: &mut Vec<usize>, ) -> std::result::Result<RunnableLinuxVm<V, Vcpu>, Self::Error> where V: VmAArch64, Vcpu: VcpuAArch64,217     fn build_vm<V, Vcpu>(
218         mut components: VmComponents,
219         _exit_evt: &Event,
220         _reset_evt: &Event,
221         system_allocator: &mut SystemAllocator,
222         serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>,
223         serial_jail: Option<Minijail>,
224         _battery: (&Option<BatteryType>, Option<Minijail>),
225         mut vm: V,
226         ramoops_region: Option<arch::pstore::RamoopsRegion>,
227         devs: Vec<(Box<dyn BusDeviceObj>, Option<Minijail>)>,
228         irq_chip: &mut dyn IrqChipAArch64,
229         kvm_vcpu_ids: &mut Vec<usize>,
230     ) -> std::result::Result<RunnableLinuxVm<V, Vcpu>, Self::Error>
231     where
232         V: VmAArch64,
233         Vcpu: VcpuAArch64,
234     {
235         let has_bios = match components.vm_image {
236             VmImage::Bios(_) => true,
237             _ => false,
238         };
239 
240         let mem = vm.get_memory().clone();
241 
242         // separate out image loading from other setup to get a specific error for
243         // image loading
244         let mut initrd = None;
245         let image_size = match components.vm_image {
246             VmImage::Bios(ref mut bios) => {
247                 arch::load_image(&mem, bios, get_bios_addr(), AARCH64_BIOS_MAX_LEN)
248                     .map_err(Error::BiosLoadFailure)?
249             }
250             VmImage::Kernel(ref mut kernel_image) => {
251                 let kernel_size =
252                     arch::load_image(&mem, kernel_image, get_kernel_addr(), u64::max_value())
253                         .map_err(Error::KernelLoadFailure)?;
254                 let kernel_end = get_kernel_addr().offset() + kernel_size as u64;
255                 initrd = match components.initrd_image {
256                     Some(initrd_file) => {
257                         let mut initrd_file = initrd_file;
258                         let initrd_addr =
259                             (kernel_end + (AARCH64_INITRD_ALIGN - 1)) & !(AARCH64_INITRD_ALIGN - 1);
260                         let initrd_max_size =
261                             components.memory_size - (initrd_addr - AARCH64_PHYS_MEM_START);
262                         let initrd_addr = GuestAddress(initrd_addr);
263                         let initrd_size =
264                             arch::load_image(&mem, &mut initrd_file, initrd_addr, initrd_max_size)
265                                 .map_err(Error::InitrdLoadFailure)?;
266                         Some((initrd_addr, initrd_size))
267                     }
268                     None => None,
269                 };
270                 kernel_size
271             }
272         };
273 
274         let mut use_pmu = vm
275             .get_hypervisor()
276             .check_capability(HypervisorCap::ArmPmuV3);
277         let vcpu_count = components.vcpu_count;
278         let mut has_pvtime = true;
279         let mut vcpus = Vec::with_capacity(vcpu_count);
280         for vcpu_id in 0..vcpu_count {
281             let vcpu: Vcpu = *vm
282                 .create_vcpu(vcpu_id)
283                 .map_err(Error::CreateVcpu)?
284                 .downcast::<Vcpu>()
285                 .map_err(|_| Error::DowncastVcpu)?;
286             Self::configure_vcpu_early(
287                 vm.get_memory(),
288                 &vcpu,
289                 vcpu_id,
290                 use_pmu,
291                 has_bios,
292                 image_size,
293                 components.protected_vm,
294             )?;
295             has_pvtime &= vcpu.has_pvtime_support();
296             vcpus.push(vcpu);
297             kvm_vcpu_ids.push(vcpu_id);
298         }
299 
300         irq_chip.finalize().map_err(Error::FinalizeIrqChip)?;
301 
302         if has_pvtime {
303             let pvtime_mem = MemoryMappingBuilder::new(AARCH64_PVTIME_IPA_MAX_SIZE as usize)
304                 .build()
305                 .map_err(Error::BuildPvtimeError)?;
306             vm.add_memory_region(
307                 GuestAddress(AARCH64_PVTIME_IPA_START),
308                 Box::new(pvtime_mem),
309                 false,
310                 false,
311             )
312             .map_err(Error::MapPvtimeError)?;
313         }
314 
315         if components.protected_vm == ProtectionType::Protected {
316             vm.load_protected_vm_firmware(
317                 GuestAddress(AARCH64_PROTECTED_VM_FW_START),
318                 AARCH64_PROTECTED_VM_FW_MAX_SIZE,
319             )
320             .map_err(Error::ProtectVm)?;
321         }
322 
323         for (vcpu_id, vcpu) in vcpus.iter().enumerate() {
324             use_pmu &= vcpu.init_pmu(AARCH64_PMU_IRQ as u64 + 16).is_ok();
325             if has_pvtime {
326                 vcpu.init_pvtime(AARCH64_PVTIME_IPA_START + (vcpu_id as u64 * AARCH64_PVTIME_SIZE))
327                     .map_err(Error::InitPvtimeError)?;
328             }
329         }
330 
331         let mmio_bus = Arc::new(devices::Bus::new());
332 
333         // ARM doesn't really use the io bus like x86, so just create an empty bus.
334         let io_bus = Arc::new(devices::Bus::new());
335 
336         // Event used by PMDevice to notify crosvm that
337         // guest OS is trying to suspend.
338         let suspend_evt = Event::new().map_err(Error::CreateEvent)?;
339 
340         let (pci_devices, others): (Vec<_>, Vec<_>) = devs
341             .into_iter()
342             .partition(|(dev, _)| dev.as_pci_device().is_some());
343 
344         let pci_devices = pci_devices
345             .into_iter()
346             .map(|(dev, jail_orig)| (dev.into_pci_device().unwrap(), jail_orig))
347             .collect();
348         let (pci, pci_irqs, mut pid_debug_label_map) = arch::generate_pci_root(
349             pci_devices,
350             irq_chip.as_irq_chip_mut(),
351             mmio_bus.clone(),
352             io_bus.clone(),
353             system_allocator,
354             &mut vm,
355             (devices::AARCH64_GIC_NR_SPIS - AARCH64_IRQ_BASE) as usize,
356         )
357         .map_err(Error::CreatePciRoot)?;
358 
359         let pci_root = Arc::new(Mutex::new(pci));
360         let pci_bus = Arc::new(Mutex::new(PciConfigMmio::new(pci_root.clone(), 8)));
361         let (platform_devices, _others): (Vec<_>, Vec<_>) = others
362             .into_iter()
363             .partition(|(dev, _)| dev.as_platform_device().is_some());
364 
365         let platform_devices = platform_devices
366             .into_iter()
367             .map(|(dev, jail_orig)| (*(dev.into_platform_device().unwrap()), jail_orig))
368             .collect();
369         let mut platform_pid_debug_label_map = arch::generate_platform_bus(
370             platform_devices,
371             irq_chip.as_irq_chip_mut(),
372             &mmio_bus,
373             system_allocator,
374         )
375         .map_err(Error::CreatePlatformBus)?;
376         pid_debug_label_map.append(&mut platform_pid_debug_label_map);
377 
378         Self::add_arch_devs(irq_chip.as_irq_chip_mut(), &mmio_bus)?;
379 
380         let com_evt_1_3 = devices::IrqEdgeEvent::new().map_err(Error::CreateEvent)?;
381         let com_evt_2_4 = devices::IrqEdgeEvent::new().map_err(Error::CreateEvent)?;
382         arch::add_serial_devices(
383             components.protected_vm,
384             &mmio_bus,
385             &com_evt_1_3.get_trigger(),
386             &com_evt_2_4.get_trigger(),
387             serial_parameters,
388             serial_jail,
389         )
390         .map_err(Error::CreateSerialDevices)?;
391 
392         irq_chip
393             .register_edge_irq_event(AARCH64_SERIAL_1_3_IRQ, &com_evt_1_3)
394             .map_err(Error::RegisterIrqfd)?;
395         irq_chip
396             .register_edge_irq_event(AARCH64_SERIAL_2_4_IRQ, &com_evt_2_4)
397             .map_err(Error::RegisterIrqfd)?;
398 
399         mmio_bus
400             .insert(pci_bus.clone(), AARCH64_PCI_CFG_BASE, AARCH64_PCI_CFG_SIZE)
401             .map_err(Error::RegisterPci)?;
402 
403         let mut cmdline = Self::get_base_linux_cmdline();
404         get_serial_cmdline(&mut cmdline, serial_parameters, "mmio")
405             .map_err(Error::GetSerialCmdline)?;
406         for param in components.extra_kernel_params {
407             cmdline.insert_str(&param).map_err(Error::Cmdline)?;
408         }
409 
410         if let Some(ramoops_region) = ramoops_region {
411             arch::pstore::add_ramoops_kernel_cmdline(&mut cmdline, &ramoops_region)
412                 .map_err(Error::Cmdline)?;
413         }
414 
415         let psci_version = vcpus[0].get_psci_version().map_err(Error::GetPsciVersion)?;
416 
417         let pci_cfg = fdt::PciConfigRegion {
418             base: AARCH64_PCI_CFG_BASE,
419             size: AARCH64_PCI_CFG_SIZE,
420         };
421 
422         let pci_ranges: Vec<fdt::PciRange> = system_allocator
423             .mmio_pools()
424             .iter()
425             .map(|range| fdt::PciRange {
426                 space: fdt::PciAddressSpace::Memory64,
427                 bus_address: *range.start(),
428                 cpu_physical_address: *range.start(),
429                 size: range_inclusive_len(range).unwrap(),
430                 prefetchable: false,
431             })
432             .collect();
433 
434         fdt::create_fdt(
435             AARCH64_FDT_MAX_SIZE as usize,
436             &mem,
437             pci_irqs,
438             pci_cfg,
439             &pci_ranges,
440             vcpu_count as u32,
441             components.cpu_clusters,
442             components.cpu_capacity,
443             fdt_offset(components.memory_size, has_bios),
444             cmdline.as_str(),
445             initrd,
446             components.android_fstab,
447             irq_chip.get_vgic_version() == DeviceKind::ArmVgicV3,
448             use_pmu,
449             psci_version,
450             components.swiotlb,
451         )
452         .map_err(Error::CreateFdt)?;
453 
454         Ok(RunnableLinuxVm {
455             vm,
456             vcpu_count,
457             vcpus: Some(vcpus),
458             vcpu_affinity: components.vcpu_affinity,
459             no_smt: components.no_smt,
460             irq_chip: irq_chip.try_box_clone().map_err(Error::CloneIrqChip)?,
461             has_bios,
462             io_bus,
463             mmio_bus,
464             pid_debug_label_map,
465             suspend_evt,
466             rt_cpus: components.rt_cpus,
467             delay_rt: components.delay_rt,
468             bat_control: None,
469             pm: None,
470             resume_notify_devices: Vec::new(),
471             root_config: pci_root,
472             hotplug_bus: Vec::new(),
473         })
474     }
475 
configure_vcpu<V: Vm>( _vm: &V, _hypervisor: &dyn Hypervisor, _irq_chip: &mut dyn IrqChipAArch64, _vcpu: &mut dyn VcpuAArch64, _vcpu_id: usize, _num_cpus: usize, _has_bios: bool, _no_smt: bool, _host_cpu_topology: bool, ) -> std::result::Result<(), Self::Error>476     fn configure_vcpu<V: Vm>(
477         _vm: &V,
478         _hypervisor: &dyn Hypervisor,
479         _irq_chip: &mut dyn IrqChipAArch64,
480         _vcpu: &mut dyn VcpuAArch64,
481         _vcpu_id: usize,
482         _num_cpus: usize,
483         _has_bios: bool,
484         _no_smt: bool,
485         _host_cpu_topology: bool,
486     ) -> std::result::Result<(), Self::Error> {
487         // AArch64 doesn't configure vcpus on the vcpu thread, so nothing to do here.
488         Ok(())
489     }
490 
register_pci_device<V: VmAArch64, Vcpu: VcpuAArch64>( _linux: &mut RunnableLinuxVm<V, Vcpu>, _device: Box<dyn PciDevice>, _minijail: Option<Minijail>, _resources: &mut SystemAllocator, ) -> std::result::Result<PciAddress, Self::Error>491     fn register_pci_device<V: VmAArch64, Vcpu: VcpuAArch64>(
492         _linux: &mut RunnableLinuxVm<V, Vcpu>,
493         _device: Box<dyn PciDevice>,
494         _minijail: Option<Minijail>,
495         _resources: &mut SystemAllocator,
496     ) -> std::result::Result<PciAddress, Self::Error> {
497         // hotplug function isn't verified on AArch64, so set it unsupported here.
498         Err(Error::Unsupported)
499     }
500 }
501 
502 impl AArch64 {
503     /// This returns a base part of the kernel command for this architecture
get_base_linux_cmdline() -> kernel_cmdline::Cmdline504     fn get_base_linux_cmdline() -> kernel_cmdline::Cmdline {
505         let mut cmdline = kernel_cmdline::Cmdline::new(base::pagesize());
506         cmdline.insert_str("panic=-1").unwrap();
507         cmdline
508     }
509 
510     /// Returns a system resource allocator configuration.
511     ///
512     /// # Arguments
513     ///
514     /// * `mem_size` - Size of guest memory (RAM) in bytes.
515     /// * `guest_phys_addr_bits` - Size of guest physical addresses (IPA) in bits.
get_resource_allocator_config( mem_size: u64, guest_phys_addr_bits: u8, ) -> SystemAllocatorConfig516     fn get_resource_allocator_config(
517         mem_size: u64,
518         guest_phys_addr_bits: u8,
519     ) -> SystemAllocatorConfig {
520         let guest_phys_end = 1u64 << guest_phys_addr_bits;
521         // The platform MMIO region is immediately past the end of RAM.
522         let plat_mmio_base = AARCH64_PHYS_MEM_START + mem_size;
523         let plat_mmio_size = AARCH64_PLATFORM_MMIO_SIZE;
524         // The high MMIO region is the rest of the address space after the platform MMIO region.
525         let high_mmio_base = plat_mmio_base + plat_mmio_size;
526         let high_mmio_size = guest_phys_end
527             .checked_sub(high_mmio_base)
528             .unwrap_or_else(|| {
529                 panic!(
530                     "guest_phys_end {:#x} < high_mmio_base {:#x}",
531                     guest_phys_end, high_mmio_base,
532                 );
533             });
534         SystemAllocatorConfig {
535             io: None,
536             low_mmio: MemRegion {
537                 base: AARCH64_MMIO_BASE,
538                 size: AARCH64_MMIO_SIZE,
539             },
540             high_mmio: MemRegion {
541                 base: high_mmio_base,
542                 size: high_mmio_size,
543             },
544             platform_mmio: Some(MemRegion {
545                 base: plat_mmio_base,
546                 size: plat_mmio_size,
547             }),
548             first_irq: AARCH64_IRQ_BASE,
549         }
550     }
551 
552     /// This adds any early platform devices for this architecture.
553     ///
554     /// # Arguments
555     ///
556     /// * `irq_chip` - The IRQ chip to add irqs to.
557     /// * `bus` - The bus to add devices to.
add_arch_devs(irq_chip: &mut dyn IrqChip, bus: &Bus) -> Result<()>558     fn add_arch_devs(irq_chip: &mut dyn IrqChip, bus: &Bus) -> Result<()> {
559         let rtc_evt = devices::IrqEdgeEvent::new().map_err(Error::CreateEvent)?;
560         irq_chip
561             .register_edge_irq_event(AARCH64_RTC_IRQ, &rtc_evt)
562             .map_err(Error::RegisterIrqfd)?;
563 
564         let rtc = Arc::new(Mutex::new(devices::pl030::Pl030::new(rtc_evt)));
565         bus.insert(rtc, AARCH64_RTC_ADDR, AARCH64_RTC_SIZE)
566             .expect("failed to add rtc device");
567 
568         Ok(())
569     }
570 
571     /// Sets up `vcpu`.
572     ///
573     /// AArch64 needs vcpus set up before its kernel IRQ chip is created, so `configure_vcpu_early`
574     /// is called from `build_vm` on the main thread.  `LinuxArch::configure_vcpu`, which is used
575     /// by X86_64 to do setup later from the vcpu thread, is a no-op on AArch64 since vcpus were
576     /// already configured here.
577     ///
578     /// # Arguments
579     ///
580     /// * `guest_mem` - The guest memory object.
581     /// * `vcpu` - The vcpu to configure.
582     /// * `vcpu_id` - The VM's index for `vcpu`.
583     /// * `use_pmu` - Should `vcpu` be configured to use the Performance Monitor Unit.
configure_vcpu_early( guest_mem: &GuestMemory, vcpu: &dyn VcpuAArch64, vcpu_id: usize, use_pmu: bool, has_bios: bool, image_size: usize, protected_vm: ProtectionType, ) -> Result<()>584     fn configure_vcpu_early(
585         guest_mem: &GuestMemory,
586         vcpu: &dyn VcpuAArch64,
587         vcpu_id: usize,
588         use_pmu: bool,
589         has_bios: bool,
590         image_size: usize,
591         protected_vm: ProtectionType,
592     ) -> Result<()> {
593         let mut features = vec![VcpuFeature::PsciV0_2];
594         if use_pmu {
595             features.push(VcpuFeature::PmuV3);
596         }
597         // Non-boot cpus are powered off initially
598         if vcpu_id != 0 {
599             features.push(VcpuFeature::PowerOff)
600         }
601         vcpu.init(&features).map_err(Error::VcpuInit)?;
602 
603         // All interrupts masked
604         let pstate = PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT | PSR_MODE_EL1H;
605         vcpu.set_one_reg(arm64_core_reg!(pstate), pstate)
606             .map_err(Error::SetReg)?;
607 
608         // Other cpus are powered off initially
609         if vcpu_id == 0 {
610             let entry_addr = if has_bios {
611                 get_bios_addr()
612             } else {
613                 get_kernel_addr()
614             };
615             let entry_addr_reg_id = if protected_vm == ProtectionType::Protected {
616                 arm64_core_reg!(regs, 1)
617             } else {
618                 arm64_core_reg!(pc)
619             };
620             vcpu.set_one_reg(entry_addr_reg_id, entry_addr.offset())
621                 .map_err(Error::SetReg)?;
622 
623             /* X0 -- fdt address */
624             let mem_size = guest_mem.memory_size();
625             let fdt_addr = (AARCH64_PHYS_MEM_START + fdt_offset(mem_size, has_bios)) as u64;
626             vcpu.set_one_reg(arm64_core_reg!(regs, 0), fdt_addr)
627                 .map_err(Error::SetReg)?;
628 
629             /* X2 -- image size */
630             if protected_vm == ProtectionType::Protected {
631                 vcpu.set_one_reg(arm64_core_reg!(regs, 2), image_size as u64)
632                     .map_err(Error::SetReg)?;
633             }
634         }
635 
636         Ok(())
637     }
638 }
639