vmm: Enable VCPU for AArch64

Added MPIDR which is needed in system configuration.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
This commit is contained in:
Michael Zhao 2020-06-09 15:24:23 +08:00 committed by Rob Bradford
parent b5f1c912d6
commit 917219fa92
2 changed files with 88 additions and 27 deletions

View File

@ -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<Error> 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<EntryPoint>,
_vm_memory: &GuestMemoryAtomic<GuestMemoryMmap>,
) -> super::Result<()> {
unimplemented!();
fd: &VcpuFd,
id: u8,
vm_fd: &VmFd,
kernel_entry_point: Option<EntryPoint>,
vm_memory: &GuestMemoryAtomic<GuestMemoryMmap>,
) -> super::Result<u64> {
let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default();
// 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;
}
/// 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,
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)?;
}
impl From<Error> for super::Error {
fn from(e: Error) -> super::Error {
super::Error::AArch64Setup(e)
let mpidr = regs::read_mpidr(fd).map_err(Error::REGSConfiguration)?;
Ok(mpidr)
}
}
pub use self::fdt::DeviceInfoForFDT;
use crate::DeviceType;
pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> {
let mut regions = Vec::new();

View File

@ -239,6 +239,8 @@ pub struct Vcpu {
interrupt_controller: Option<Arc<Mutex<dyn InterruptController>>>,
#[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<EntryPoint>,
vm_memory: &GuestMemoryAtomic<GuestMemoryMmap>,
#[cfg(target_arch = "x86_64")] cpuid: CpuId,
) -> Result<()> {
#[cfg(target_arch = "aarch64")]
arch::configure_vcpu(&self.fd, self.id, kernel_entry_point, vm_memory)
{
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<u64> {
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.