From a7a15d56dd6c10912b023d8871522b66272b063d Mon Sep 17 00:00:00 2001 From: Michael Zhao Date: Mon, 6 Jun 2022 15:17:59 +0800 Subject: [PATCH] aarch64: Move `setup_regs` to `hypervisor` `setup_regs` of AArch64 calls KVM sepecific code. Now move it to `hypervisor` crate. Signed-off-by: Michael Zhao --- arch/src/aarch64/mod.rs | 12 ++++--- arch/src/aarch64/regs.rs | 75 --------------------------------------- hypervisor/src/cpu.rs | 5 +++ hypervisor/src/kvm/mod.rs | 45 +++++++++++++++++++++++ vmm/src/cpu.rs | 6 ++-- 5 files changed, 60 insertions(+), 83 deletions(-) delete mode 100644 arch/src/aarch64/regs.rs diff --git a/arch/src/aarch64/mod.rs b/arch/src/aarch64/mod.rs index 002e004af..bf71ac080 100644 --- a/arch/src/aarch64/mod.rs +++ b/arch/src/aarch64/mod.rs @@ -6,8 +6,6 @@ pub mod fdt; /// Layout for this aarch64 system. pub mod layout; -/// Logic for configuring aarch64 registers. -pub mod regs; /// Module for loading UEFI binary. pub mod uefi; @@ -37,7 +35,7 @@ pub enum Error { InitramfsAddress, /// Error configuring the general purpose registers - RegsConfiguration(regs::Error), + RegsConfiguration(hypervisor::HypervisorCpuError), /// Error configuring the MPIDR register VcpuRegMpidr(hypervisor::HypervisorCpuError), @@ -67,8 +65,12 @@ pub fn configure_vcpu( kernel_entry_point: Option, ) -> super::Result { if let Some(kernel_entry_point) = kernel_entry_point { - regs::setup_regs(vcpu, id, kernel_entry_point.entry_addr.raw_value()) - .map_err(Error::RegsConfiguration)?; + vcpu.setup_regs( + id, + kernel_entry_point.entry_addr.raw_value(), + super::layout::FDT_START.raw_value(), + ) + .map_err(Error::RegsConfiguration)?; } let mpidr = vcpu.read_mpidr().map_err(Error::VcpuRegMpidr)?; diff --git a/arch/src/aarch64/regs.rs b/arch/src/aarch64/regs.rs deleted file mode 100644 index ad80ff7fe..000000000 --- a/arch/src/aarch64/regs.rs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 -// -// Portions Copyright 2017 The Chromium OS Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the THIRD-PARTY file. - -use hypervisor::kvm::kvm_bindings::{ - kvm_regs, user_pt_regs, KVM_REG_ARM64, KVM_REG_ARM_CORE, KVM_REG_SIZE_U64, -}; -use hypervisor::{arm64_core_reg_id, offset__of}; -use std::sync::Arc; -use std::{mem, result}; -use vm_memory::Address; - -/// Errors thrown while setting aarch64 registers. -#[derive(Debug)] -pub enum Error { - /// Failed to set core register (PC, PSTATE or general purpose ones). - SetCoreRegister(hypervisor::HypervisorCpuError), - /// Failed to get a system register. - GetSysRegister(hypervisor::HypervisorCpuError), -} -type Result = result::Result; - -#[allow(non_upper_case_globals)] -// PSR (Processor State Register) bits. -// Taken from arch/arm64/include/uapi/asm/ptrace.h. -const PSR_MODE_EL1h: u64 = 0x0000_0005; -const PSR_F_BIT: u64 = 0x0000_0040; -const PSR_I_BIT: u64 = 0x0000_0080; -const PSR_A_BIT: u64 = 0x0000_0100; -const PSR_D_BIT: u64 = 0x0000_0200; -// Taken from arch/arm64/kvm/inject_fault.c. -const PSTATE_FAULT_BITS_64: u64 = PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | PSR_I_BIT | PSR_D_BIT; - -/// Configure core registers for a given CPU. -/// -/// # Arguments -/// -/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd. -/// * `cpu_id` - Index of current vcpu. -/// * `boot_ip` - Starting instruction pointer. -/// * `mem` - Reserved DRAM for current VM. -pub fn setup_regs(vcpu: &Arc, cpu_id: u8, boot_ip: u64) -> Result<()> { - let kreg_off = offset__of!(kvm_regs, regs); - - // Get the register index of the PSTATE (Processor State) register. - let pstate = offset__of!(user_pt_regs, pstate) + kreg_off; - vcpu.set_reg( - arm64_core_reg_id!(KVM_REG_SIZE_U64, pstate), - PSTATE_FAULT_BITS_64, - ) - .map_err(Error::SetCoreRegister)?; - - // Other vCPUs are powered off initially awaiting PSCI wakeup. - if cpu_id == 0 { - // Setting the PC (Processor Counter) to the current program address (kernel address). - let pc = offset__of!(user_pt_regs, pc) + kreg_off; - vcpu.set_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, pc), boot_ip as u64) - .map_err(Error::SetCoreRegister)?; - - // Last mandatory thing to set -> the address pointing to the FDT (also called DTB). - // "The device tree blob (dtb) must be placed on an 8-byte boundary and must - // not exceed 2 megabytes in size." -> https://www.kernel.org/doc/Documentation/arm64/booting.txt. - // We are choosing to place it the end of DRAM. See `get_fdt_addr`. - let regs0 = offset__of!(user_pt_regs, regs) + kreg_off; - vcpu.set_reg( - arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0), - super::layout::FDT_START.raw_value(), - ) - .map_err(Error::SetCoreRegister)?; - } - Ok(()) -} diff --git a/hypervisor/src/cpu.rs b/hypervisor/src/cpu.rs index 90254a0a2..e5c275f3a 100644 --- a/hypervisor/src/cpu.rs +++ b/hypervisor/src/cpu.rs @@ -453,6 +453,11 @@ pub trait Vcpu: Send + Sync { #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] fn read_mpidr(&self) -> Result; /// + /// Configure core registers for a given CPU. + /// + #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] + fn setup_regs(&self, cpu_id: u8, boot_ip: u64, fdt_start: u64) -> Result<()>; + /// /// Retrieve the vCPU state. /// This function is necessary to snapshot the VM /// diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index eb609ee12..39da7ceae 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -1566,6 +1566,51 @@ impl cpu::Vcpu for KvmVcpu { .get_one_reg(MPIDR_EL1) .map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into())) } + /// + /// Configure core registers for a given CPU. + /// + #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] + fn setup_regs(&self, cpu_id: u8, boot_ip: u64, fdt_start: u64) -> cpu::Result<()> { + #[allow(non_upper_case_globals)] + // PSR (Processor State Register) bits. + // Taken from arch/arm64/include/uapi/asm/ptrace.h. + const PSR_MODE_EL1h: u64 = 0x0000_0005; + const PSR_F_BIT: u64 = 0x0000_0040; + const PSR_I_BIT: u64 = 0x0000_0080; + const PSR_A_BIT: u64 = 0x0000_0100; + const PSR_D_BIT: u64 = 0x0000_0200; + // Taken from arch/arm64/kvm/inject_fault.c. + const PSTATE_FAULT_BITS_64: u64 = + PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | PSR_I_BIT | PSR_D_BIT; + + let kreg_off = offset__of!(kvm_regs, regs); + + // Get the register index of the PSTATE (Processor State) register. + let pstate = offset__of!(user_pt_regs, pstate) + kreg_off; + self.set_reg( + arm64_core_reg_id!(KVM_REG_SIZE_U64, pstate), + PSTATE_FAULT_BITS_64, + ) + .map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?; + + // Other vCPUs are powered off initially awaiting PSCI wakeup. + if cpu_id == 0 { + // Setting the PC (Processor Counter) to the current program address (kernel address). + let pc = offset__of!(user_pt_regs, pc) + kreg_off; + self.set_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, pc), boot_ip as u64) + .map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?; + + // Last mandatory thing to set -> the address pointing to the FDT (also called DTB). + // "The device tree blob (dtb) must be placed on an 8-byte boundary and must + // not exceed 2 megabytes in size." -> https://www.kernel.org/doc/Documentation/arm64/booting.txt. + // We are choosing to place it the end of DRAM. See `get_fdt_addr`. + let regs0 = offset__of!(user_pt_regs, regs) + kreg_off; + self.set_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0), fdt_start) + .map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?; + } + Ok(()) + } + #[cfg(target_arch = "x86_64")] /// /// Get the current CPU state diff --git a/vmm/src/cpu.rs b/vmm/src/cpu.rs index c728e61fc..6e772115b 100644 --- a/vmm/src/cpu.rs +++ b/vmm/src/cpu.rs @@ -2436,7 +2436,7 @@ mod tests { #[cfg(target_arch = "aarch64")] #[cfg(test)] mod tests { - use arch::aarch64::regs::*; + use arch::layout; use hypervisor::kvm::aarch64::{is_system_register, MPIDR_EL1}; use hypervisor::kvm::kvm_bindings::{ kvm_one_reg, kvm_regs, kvm_vcpu_init, user_pt_regs, KVM_REG_ARM64, KVM_REG_ARM64_SYSREG, @@ -2451,7 +2451,7 @@ mod tests { let vm = hv.create_vm().unwrap(); let vcpu = vm.create_vcpu(0, None).unwrap(); - let res = setup_regs(&vcpu, 0, 0x0); + let res = vcpu.setup_regs(0, 0x0, layout::FDT_START.0); // Must fail when vcpu is not initialized yet. assert!(res.is_err()); @@ -2459,7 +2459,7 @@ mod tests { vm.get_preferred_target(&mut kvi).unwrap(); vcpu.vcpu_init(&kvi).unwrap(); - assert!(setup_regs(&vcpu, 0, 0x0).is_ok()); + assert!(vcpu.setup_regs(0, 0x0, layout::FDT_START.0).is_ok()); } #[test]