diff --git a/arch/src/aarch64/mod.rs b/arch/src/aarch64/mod.rs index 3c76757b7..248240bd8 100644 --- a/arch/src/aarch64/mod.rs +++ b/arch/src/aarch64/mod.rs @@ -13,6 +13,8 @@ pub mod layout; /// Logic for configuring aarch64 registers. pub mod regs; +pub use self::fdt::DeviceInfoForFDT; +use crate::DeviceType; use crate::RegionType; use aarch64::gic::GICDevice; use kvm_ioctls::*; @@ -20,9 +22,35 @@ use std::collections::HashMap; use std::ffi::CStr; use std::fmt::Debug; use vm_memory::{ - Address, GuestAddress, GuestMemory, GuestMemoryAtomic, GuestMemoryMmap, GuestUsize, + Address, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic, GuestMemoryMmap, + GuestUsize, }; +/// Errors thrown while configuring aarch64 system. +#[derive(Debug)] +pub enum Error { + /// Failed to create a Flattened Device Tree for this aarch64 VM. + SetupFDT(fdt::Error), + + /// Failed to compute the initrd address. + InitrdAddress, + + /// Error configuring the general purpose registers + REGSConfiguration(regs::Error), + + /// Error fetching prefered target + VcpuArmPreferredTarget(kvm_ioctls::Error), + + /// Error doing Vcpu Init on Arm. + VcpuArmInit(kvm_ioctls::Error), +} + +impl From for super::Error { + fn from(e: Error) -> super::Error { + super::Error::AArch64Setup(e) + } +} + #[derive(Debug, Copy, Clone)] /// Specifies the entry point address where the guest must start /// executing code. @@ -31,32 +59,41 @@ pub struct EntryPoint { pub entry_addr: GuestAddress, } +/// Configure the specified VCPU, and return its MPIDR. pub fn configure_vcpu( - _fd: &VcpuFd, - _id: u8, - _kernel_entry_point: Option, - _vm_memory: &GuestMemoryAtomic, -) -> super::Result<()> { - unimplemented!(); -} + fd: &VcpuFd, + id: u8, + vm_fd: &VmFd, + kernel_entry_point: Option, + vm_memory: &GuestMemoryAtomic, +) -> super::Result { + let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default(); -/// Errors thrown while configuring aarch64 system. -#[derive(Debug)] -pub enum Error { - /// Failed to create a Flattened Device Tree for this aarch64 VM. - SetupFDT(fdt::Error), - /// Failed to compute the initrd address. - InitrdAddress, -} - -impl From for super::Error { - fn from(e: Error) -> super::Error { - super::Error::AArch64Setup(e) + // This reads back the kernel's preferred target type. + vm_fd + .get_preferred_target(&mut kvi) + .map_err(Error::VcpuArmPreferredTarget)?; + // We already checked that the capability is supported. + kvi.features[0] |= 1 << kvm_bindings::KVM_ARM_VCPU_PSCI_0_2; + // Non-boot cpus are powered off initially. + if id > 0 { + kvi.features[0] |= 1 << kvm_bindings::KVM_ARM_VCPU_POWER_OFF; } -} -pub use self::fdt::DeviceInfoForFDT; -use crate::DeviceType; + fd.vcpu_init(&kvi).map_err(Error::VcpuArmInit)?; + if let Some(kernel_entry_point) = kernel_entry_point { + regs::setup_regs( + fd, + id, + kernel_entry_point.entry_addr.raw_value(), + &vm_memory.memory(), + ) + .map_err(Error::REGSConfiguration)?; + } + + let mpidr = regs::read_mpidr(fd).map_err(Error::REGSConfiguration)?; + Ok(mpidr) +} pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> { let mut regions = Vec::new(); diff --git a/vmm/src/cpu.rs b/vmm/src/cpu.rs index 808a78136..8e806a3c3 100644 --- a/vmm/src/cpu.rs +++ b/vmm/src/cpu.rs @@ -239,6 +239,8 @@ pub struct Vcpu { interrupt_controller: Option>>, #[cfg_attr(target_arch = "aarch64", allow(dead_code))] vm_ts: std::time::Instant, + #[cfg(target_arch = "aarch64")] + mpidr: u64, } #[cfg(target_arch = "x86_64")] @@ -284,6 +286,8 @@ impl Vcpu { mmio_bus, interrupt_controller, vm_ts: creation_ts, + #[cfg(target_arch = "aarch64")] + mpidr: 0, }))) } @@ -296,14 +300,18 @@ impl Vcpu { /// * `vm_memory` - Guest memory. /// * `cpuid` - (x86_64) CpuId, wrapper over the `kvm_cpuid2` structure. pub fn configure( - &self, + &mut self, + #[cfg(target_arch = "aarch64")] vm_fd: &VmFd, kernel_entry_point: Option, vm_memory: &GuestMemoryAtomic, #[cfg(target_arch = "x86_64")] cpuid: CpuId, ) -> Result<()> { #[cfg(target_arch = "aarch64")] - arch::configure_vcpu(&self.fd, self.id, kernel_entry_point, vm_memory) - .map_err(Error::VcpuConfiguration)?; + { + self.mpidr = + arch::configure_vcpu(&self.fd, self.id, vm_fd, kernel_entry_point, vm_memory) + .map_err(Error::VcpuConfiguration)?; + } #[cfg(target_arch = "x86_64")] arch::configure_vcpu(&self.fd, self.id, kernel_entry_point, vm_memory, cpuid) @@ -312,6 +320,12 @@ impl Vcpu { Ok(()) } + /// Gets the MPIDR register value. + #[cfg(target_arch = "aarch64")] + pub fn get_mpidr(&self) -> u64 { + self.mpidr + } + /// Runs the VCPU until it exits, returning the reason. /// /// Note that the state of the VCPU and associated VM must be setup first for this to do @@ -784,7 +798,7 @@ impl CpuManager { #[cfg(target_arch = "aarch64")] vcpu.lock() .unwrap() - .configure(entry_point, &vm_memory) + .configure(&self.fd, entry_point, &vm_memory) .expect("Failed to configure vCPU"); } @@ -985,6 +999,16 @@ impl CpuManager { .fold(0, |acc, state| acc + state.active() as u8) } + #[cfg(target_arch = "aarch64")] + pub fn get_mpidr(&self) -> Vec { + let vcpu_mpidr = self + .vcpus + .iter() + .map(|cpu| cpu.lock().unwrap().get_mpidr()) + .collect(); + vcpu_mpidr + } + #[cfg(feature = "acpi")] pub fn create_madt(&self) -> SDT { // This is also checked in the commandline parsing.