vmm: Configure VM on AArch64

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
This commit is contained in:
Michael Zhao 2020-06-09 18:28:02 +08:00 committed by Rob Bradford
parent 917219fa92
commit 5cd1730bc4
6 changed files with 77 additions and 23 deletions

View File

@ -16,7 +16,6 @@ pub mod regs;
pub use self::fdt::DeviceInfoForFDT; pub use self::fdt::DeviceInfoForFDT;
use crate::DeviceType; use crate::DeviceType;
use crate::RegionType; use crate::RegionType;
use aarch64::gic::GICDevice;
use kvm_ioctls::*; use kvm_ioctls::*;
use std::collections::HashMap; use std::collections::HashMap;
use std::ffi::CStr; use std::ffi::CStr;
@ -29,9 +28,12 @@ use vm_memory::{
/// Errors thrown while configuring aarch64 system. /// Errors thrown while configuring aarch64 system.
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
/// Failed to create a Flattened Device Tree for this aarch64 VM. /// Failed to create a FDT.
SetupFDT(fdt::Error), SetupFDT(fdt::Error),
/// Failed to create a GIC.
SetupGIC(gic::Error),
/// Failed to compute the initrd address. /// Failed to compute the initrd address.
InitrdAddress, InitrdAddress,
@ -136,19 +138,22 @@ pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, Region
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
#[allow(unused_variables)] #[allow(unused_variables)]
pub fn configure_system<T: DeviceInfoForFDT + Clone + Debug>( pub fn configure_system<T: DeviceInfoForFDT + Clone + Debug>(
vm_fd: &VmFd,
guest_mem: &GuestMemoryMmap, guest_mem: &GuestMemoryMmap,
cmdline_cstring: &CStr, cmdline_cstring: &CStr,
vcpu_count: u64,
vcpu_mpidr: Vec<u64>, vcpu_mpidr: Vec<u64>,
device_info: &HashMap<(DeviceType, String), T>, device_info: &HashMap<(DeviceType, String), T>,
gic_device: &Box<dyn GICDevice>,
initrd: &Option<super::InitramfsConfig>, initrd: &Option<super::InitramfsConfig>,
) -> super::Result<()> { ) -> super::Result<()> {
let gic_device = gic::create_gic(vm_fd, vcpu_count).map_err(Error::SetupGIC)?;
let dtb = fdt::create_fdt( let dtb = fdt::create_fdt(
guest_mem, guest_mem,
cmdline_cstring, cmdline_cstring,
vcpu_mpidr, vcpu_mpidr,
device_info, device_info,
gic_device, &gic_device,
initrd, initrd,
) )
.map_err(Error::SetupFDT)?; .map_err(Error::SetupFDT)?;

View File

@ -46,7 +46,7 @@ tempfile = "3.1.0"
[dependencies.linux-loader] [dependencies.linux-loader]
git = "https://github.com/rust-vmm/linux-loader" git = "https://github.com/rust-vmm/linux-loader"
features = ["elf", "bzimage"] features = ["elf", "bzimage", "pe"]
[dev-dependencies] [dev-dependencies]
credibility = "0.1.3" credibility = "0.1.3"

View File

@ -1000,13 +1000,13 @@ impl CpuManager {
} }
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
pub fn get_mpidr(&self) -> Vec<u64> { pub fn get_mpidrs(&self) -> Vec<u64> {
let vcpu_mpidr = self let vcpu_mpidrs = self
.vcpus .vcpus
.iter() .iter()
.map(|cpu| cpu.lock().unwrap().get_mpidr()) .map(|cpu| cpu.lock().unwrap().get_mpidr())
.collect(); .collect();
vcpu_mpidr vcpu_mpidrs
} }
#[cfg(feature = "acpi")] #[cfg(feature = "acpi")]

View File

@ -1092,6 +1092,14 @@ impl DeviceManager {
Ok(interrupt_controller) Ok(interrupt_controller)
} }
#[cfg(target_arch = "aarch64")]
pub fn enable_interrupt_controller(&self) -> DeviceManagerResult<()> {
if let Some(interrupt_controller) = &self.interrupt_controller {
interrupt_controller.lock().unwrap().enable().unwrap();
}
Ok(())
}
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
fn add_interrupt_controller( fn add_interrupt_controller(
&mut self, &mut self,

View File

@ -56,7 +56,7 @@ pub struct MemoryManager {
next_kvm_memory_slot: u32, next_kvm_memory_slot: u32,
start_of_device_area: GuestAddress, start_of_device_area: GuestAddress,
end_of_device_area: GuestAddress, end_of_device_area: GuestAddress,
fd: Arc<VmFd>, pub fd: Arc<VmFd>,
hotplug_slots: Vec<HotPlugState>, hotplug_slots: Vec<HotPlugState>,
selected_slot: usize, selected_slot: usize,
backing_file: Option<PathBuf>, backing_file: Option<PathBuf>,

View File

@ -29,7 +29,7 @@ use crate::config::{
VmConfig, VsockConfig, VmConfig, VsockConfig,
}; };
use crate::cpu; use crate::cpu;
use crate::device_manager::{get_win_size, Console, DeviceManager, DeviceManagerError}; use crate::device_manager::{self, get_win_size, Console, DeviceManager, DeviceManagerError};
use crate::memory_manager::{Error as MemoryManagerError, MemoryManager}; use crate::memory_manager::{Error as MemoryManagerError, MemoryManager};
use crate::migration::{url_to_path, vm_config_from_snapshot, VM_SNAPSHOT_FILE}; use crate::migration::{url_to_path, vm_config_from_snapshot, VM_SNAPSHOT_FILE};
use crate::{CPU_MANAGER_SNAPSHOT_ID, DEVICE_MANAGER_SNAPSHOT_ID, MEMORY_MANAGER_SNAPSHOT_ID}; use crate::{CPU_MANAGER_SNAPSHOT_ID, DEVICE_MANAGER_SNAPSHOT_ID, MEMORY_MANAGER_SNAPSHOT_ID};
@ -46,7 +46,6 @@ use kvm_ioctls::*;
use linux_loader::cmdline::Cmdline; use linux_loader::cmdline::Cmdline;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use linux_loader::loader::elf::Error::InvalidElfMagicNumber; use linux_loader::loader::elf::Error::InvalidElfMagicNumber;
#[cfg(target_arch = "x86_64")]
use linux_loader::loader::KernelLoader; use linux_loader::loader::KernelLoader;
use signal_hook::{iterator::Signals, SIGINT, SIGTERM, SIGWINCH}; use signal_hook::{iterator::Signals, SIGINT, SIGTERM, SIGWINCH};
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
@ -56,17 +55,14 @@ use std::fs::{File, OpenOptions};
use std::io::{self, Write}; use std::io::{self, Write};
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use std::io::{Seek, SeekFrom}; use std::io::{Seek, SeekFrom};
#[cfg(target_arch = "x86_64")]
use std::ops::Deref; use std::ops::Deref;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex, RwLock};
use std::{result, str, thread}; use std::{result, str, thread};
use url::Url; use url::Url;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use vm_memory::{ use vm_memory::{Address, Bytes, GuestMemory, GuestMemoryMmap, GuestMemoryRegion};
Address, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryMmap, use vm_memory::{GuestAddress, GuestAddressSpace};
GuestMemoryRegion,
};
use vm_migration::{ use vm_migration::{
Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable, Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable,
Transportable, Transportable,
@ -114,6 +110,9 @@ pub enum Error {
/// Cannot configure system /// Cannot configure system
ConfigureSystem(arch::Error), ConfigureSystem(arch::Error),
/// Cannot enable interrupt controller
EnableInterruptController(device_manager::DeviceManagerError),
PoisonedState, PoisonedState,
/// Cannot create a device manager. /// Cannot create a device manager.
@ -254,7 +253,6 @@ impl VmState {
} }
pub struct Vm { pub struct Vm {
#[cfg_attr(target_arch = "aarch64", allow(dead_code))]
kernel: File, kernel: File,
#[cfg_attr(target_arch = "aarch64", allow(dead_code))] #[cfg_attr(target_arch = "aarch64", allow(dead_code))]
initramfs: Option<File>, initramfs: Option<File>,
@ -485,7 +483,25 @@ impl Vm {
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
fn load_kernel(&mut self) -> Result<EntryPoint> { fn load_kernel(&mut self) -> Result<EntryPoint> {
unimplemented!(); let guest_memory = self.memory_manager.lock().as_ref().unwrap().guest_memory();
let mem = guest_memory.memory();
let entry_addr = match linux_loader::loader::pe::PE::load(
mem.deref(),
Some(GuestAddress(arch::get_kernel_start())),
&mut self.kernel,
None,
) {
Ok(entry_addr) => entry_addr,
Err(e) => {
return Err(Error::KernelLoad(e));
}
};
let entry_point_addr: GuestAddress = entry_addr.kernel_load;
Ok(EntryPoint {
entry_addr: entry_point_addr,
})
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
@ -614,11 +630,36 @@ impl Vm {
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
fn configure_system(&mut self, _entry_addr: EntryPoint) -> Result<()> { fn configure_system(&mut self, _entry_addr: EntryPoint) -> Result<()> {
let _cmdline_cstring = self.get_cmdline()?; let cmdline_cstring = self.get_cmdline()?;
// What to do on AArch64 is: let vcpu_mpidrs = self.cpu_manager.lock().unwrap().get_mpidrs();
// - Setup GIC let guest_memory = self.memory_manager.lock().as_ref().unwrap().guest_memory();
// - Generate FDT let mem = guest_memory.memory();
unimplemented!();
let device_info = &self
.device_manager
.lock()
.unwrap()
.get_device_info()
.clone();
arch::configure_system(
&self.memory_manager.lock().as_ref().unwrap().fd,
&mem,
&cmdline_cstring,
self.cpu_manager.lock().unwrap().boot_vcpus() as u64,
vcpu_mpidrs,
device_info,
&None,
)
.map_err(Error::ConfigureSystem)?;
self.device_manager
.lock()
.unwrap()
.enable_interrupt_controller()
.map_err(Error::EnableInterruptController)?;
Ok(())
} }
pub fn shutdown(&mut self) -> Result<()> { pub fn shutdown(&mut self) -> Result<()> {