mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-05 18:20:34 +00:00
aarch64: Check the current PSCI version when creating device tree on ARM
Call KVM_REG_ARM_PSCI_VERSION to see the PSCI version and use the value when creating a device-tree node. Also stop setting PSCI constants which are ignored by kernel. BUG=chromium:1141902 TEST=run crosvm on krane and check /proc/device-tree/psci/compatible Change-Id: I4b8ed7620d7f0e2205b84b5f08cfaa5ae8d94339 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2529289 Tested-by: Keiichi Watanabe <keiichiw@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Keiichi Watanabe <keiichiw@chromium.org> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
parent
bb318f8bf8
commit
f12c5ea7b4
4 changed files with 76 additions and 12 deletions
|
@ -12,6 +12,7 @@ use arch::fdt::{
|
|||
};
|
||||
use arch::SERIAL_ADDR;
|
||||
use devices::{PciAddress, PciInterruptPin};
|
||||
use hypervisor::PsciVersion;
|
||||
use vm_memory::{GuestAddress, GuestMemory};
|
||||
|
||||
// This is the start of DRAM in the physical address space.
|
||||
|
@ -182,18 +183,20 @@ fn create_serial_nodes(fdt: &mut Vec<u8>) -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// TODO(sonnyrao) -- check to see if host kernel supports PSCI 0_2
|
||||
fn create_psci_node(fdt: &mut Vec<u8>) -> Result<()> {
|
||||
let compatible = "arm,psci-0.2";
|
||||
fn create_psci_node(fdt: &mut Vec<u8>, version: &PsciVersion) -> Result<()> {
|
||||
let compatible = if version.major == 1 {
|
||||
// Put `psci-0.2` as well because PSCI 1.0 is compatible with PSCI 0.2.
|
||||
format!(
|
||||
"\"arm,psci-{}.{}\", \"arm,psci-0.2\"",
|
||||
version.major, version.minor
|
||||
)
|
||||
} else {
|
||||
format!("arm,psci-{}.{}", version.major, version.minor)
|
||||
};
|
||||
begin_node(fdt, "psci")?;
|
||||
property_string(fdt, "compatible", compatible)?;
|
||||
property_string(fdt, "compatible", &compatible)?;
|
||||
// Only support aarch64 guest
|
||||
property_string(fdt, "method", "hvc")?;
|
||||
// These constants are from PSCI
|
||||
property_u32(fdt, "cpu_suspend", 0xc4000001)?;
|
||||
property_u32(fdt, "cpu_off", 0x84000002)?;
|
||||
property_u32(fdt, "cpu_on", 0xc4000003)?;
|
||||
property_u32(fdt, "migrate", 0xc4000005)?;
|
||||
end_node(fdt)?;
|
||||
|
||||
Ok(())
|
||||
|
@ -358,6 +361,7 @@ fn create_rtc_node(fdt: &mut Vec<u8>) -> Result<()> {
|
|||
/// * `initrd` - An optional tuple of initrd guest physical address and size
|
||||
/// * `android_fstab` - An optional file holding Android fstab entries
|
||||
/// * `is_gicv3` - True if gicv3, false if v2
|
||||
/// * `psci_version` - the current PSCI version
|
||||
pub fn create_fdt(
|
||||
fdt_max_size: usize,
|
||||
guest_mem: &GuestMemory,
|
||||
|
@ -371,6 +375,7 @@ pub fn create_fdt(
|
|||
android_fstab: Option<File>,
|
||||
is_gicv3: bool,
|
||||
use_pmu: bool,
|
||||
psci_version: PsciVersion,
|
||||
) -> Result<()> {
|
||||
let mut fdt = vec![0; fdt_max_size];
|
||||
start_fdt(&mut fdt, fdt_max_size)?;
|
||||
|
@ -393,7 +398,7 @@ pub fn create_fdt(
|
|||
create_pmu_node(&mut fdt, num_cpus)?;
|
||||
}
|
||||
create_serial_nodes(&mut fdt)?;
|
||||
create_psci_node(&mut fdt)?;
|
||||
create_psci_node(&mut fdt, &psci_version)?;
|
||||
create_pci_nodes(&mut fdt, pci_irqs, pci_device_base, pci_device_size)?;
|
||||
create_rtc_node(&mut fdt)?;
|
||||
// End giant node
|
||||
|
|
|
@ -18,7 +18,9 @@ use base::Event;
|
|||
use devices::{
|
||||
Bus, BusError, IrqChip, IrqChipAArch64, PciAddress, PciConfigMmio, PciDevice, PciInterruptPin,
|
||||
};
|
||||
use hypervisor::{DeviceKind, Hypervisor, HypervisorCap, VcpuAArch64, VcpuFeature, VmAArch64};
|
||||
use hypervisor::{
|
||||
DeviceKind, Hypervisor, HypervisorCap, PsciVersion, VcpuAArch64, VcpuFeature, VmAArch64,
|
||||
};
|
||||
use minijail::Minijail;
|
||||
use remain::sorted;
|
||||
use resources::SystemAllocator;
|
||||
|
@ -124,6 +126,7 @@ pub enum Error {
|
|||
CreateVcpu(base::Error),
|
||||
CreateVm(Box<dyn StdError>),
|
||||
DowncastVcpu,
|
||||
GetPsciVersion(base::Error),
|
||||
GetSerialCmdline(GetSerialCmdlineError),
|
||||
InitrdLoadFailure(arch::LoadImageError),
|
||||
KernelLoadFailure(arch::LoadImageError),
|
||||
|
@ -157,6 +160,7 @@ impl Display for Error {
|
|||
CreateVcpu(e) => write!(f, "failed to create VCPU: {}", e),
|
||||
CreateVm(e) => write!(f, "failed to create vm: {}", e),
|
||||
DowncastVcpu => write!(f, "vm created wrong kind of vcpu"),
|
||||
GetPsciVersion(e) => write!(f, "failed to get PSCI version: {}", e),
|
||||
GetSerialCmdline(e) => write!(f, "failed to get serial cmdline: {}", e),
|
||||
InitrdLoadFailure(e) => write!(f, "initrd cound not be loaded: {}", e),
|
||||
KernelLoadFailure(e) => write!(f, "kernel cound not be loaded: {}", e),
|
||||
|
@ -318,6 +322,8 @@ impl arch::LinuxArch for AArch64 {
|
|||
let kernel_size = arch::load_image(&mem, kernel_image, get_kernel_addr(), u64::max_value())
|
||||
.map_err(Error::KernelLoadFailure)?;
|
||||
let kernel_end = get_kernel_addr().offset() + kernel_size as u64;
|
||||
let psci_version = vcpus[0].get_psci_version().map_err(Error::GetPsciVersion)?;
|
||||
|
||||
Self::setup_system_memory(
|
||||
&mem,
|
||||
components.memory_size,
|
||||
|
@ -329,6 +335,7 @@ impl arch::LinuxArch for AArch64 {
|
|||
kernel_end,
|
||||
irq_chip.get_vgic_version() == DeviceKind::ArmVgicV3,
|
||||
use_pmu,
|
||||
psci_version,
|
||||
)?;
|
||||
|
||||
Ok(RunnableLinuxVm {
|
||||
|
@ -377,6 +384,7 @@ impl AArch64 {
|
|||
kernel_end: u64,
|
||||
is_gicv3: bool,
|
||||
use_pmu: bool,
|
||||
psci_version: PsciVersion,
|
||||
) -> Result<()> {
|
||||
let initrd = match initrd_file {
|
||||
Some(initrd_file) => {
|
||||
|
@ -406,6 +414,7 @@ impl AArch64 {
|
|||
android_fstab,
|
||||
is_gicv3,
|
||||
use_pmu,
|
||||
psci_version,
|
||||
)
|
||||
.map_err(Error::CreateFdt)?;
|
||||
Ok(())
|
||||
|
|
|
@ -7,6 +7,12 @@ use downcast_rs::impl_downcast;
|
|||
|
||||
use crate::{Hypervisor, IrqRoute, IrqSource, IrqSourceChip, Vcpu, Vm};
|
||||
|
||||
/// Represents a version of Power State Coordination Interface (PSCI).
|
||||
pub struct PsciVersion {
|
||||
pub major: u32,
|
||||
pub minor: u32,
|
||||
}
|
||||
|
||||
/// A wrapper for using a VM on aarch64 and getting/setting its state.
|
||||
pub trait VmAArch64: Vm {
|
||||
/// Gets the `Hypervisor` that created this VM.
|
||||
|
@ -30,6 +36,13 @@ pub trait VcpuAArch64: Vcpu {
|
|||
/// Sets the value of a register on this VCPU. `reg_id` is the register ID, as specified in the
|
||||
/// KVM API documentation for KVM_SET_ONE_REG.
|
||||
fn set_one_reg(&self, reg_id: u64, data: u64) -> Result<()>;
|
||||
|
||||
/// Gets the value of a register on this VCPU. `reg_id` is the register ID, as specified in the
|
||||
/// KVM API documentation for KVM_GET_ONE_REG.
|
||||
fn get_one_reg(&self, reg_id: u64) -> Result<u64>;
|
||||
|
||||
/// Gets the current PSCI version.
|
||||
fn get_psci_version(&self) -> Result<PsciVersion>;
|
||||
}
|
||||
|
||||
impl_downcast!(VcpuAArch64);
|
||||
|
|
|
@ -9,7 +9,8 @@ use kvm_sys::*;
|
|||
|
||||
use super::{KvmVcpu, KvmVm};
|
||||
use crate::{
|
||||
ClockState, DeviceKind, Hypervisor, IrqSourceChip, VcpuAArch64, VcpuFeature, VmAArch64, VmCap,
|
||||
ClockState, DeviceKind, Hypervisor, IrqSourceChip, PsciVersion, VcpuAArch64, VcpuFeature,
|
||||
VmAArch64, VmCap,
|
||||
};
|
||||
|
||||
impl KvmVm {
|
||||
|
@ -156,6 +157,42 @@ impl VcpuAArch64 for KvmVcpu {
|
|||
errno_result()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_one_reg(&self, reg_id: u64) -> Result<u64> {
|
||||
let val: u64 = 0;
|
||||
let mut onereg = kvm_one_reg {
|
||||
id: reg_id,
|
||||
addr: (&val as *const u64) as u64,
|
||||
};
|
||||
|
||||
// Safe because we allocated the struct and we know the kernel will read exactly the size of
|
||||
// the struct.
|
||||
let ret = unsafe { ioctl_with_ref(self, KVM_GET_ONE_REG(), &mut onereg) };
|
||||
if ret == 0 {
|
||||
Ok(val)
|
||||
} else {
|
||||
return errno_result();
|
||||
}
|
||||
}
|
||||
|
||||
fn get_psci_version(&self) -> Result<PsciVersion> {
|
||||
// The definition of KVM_REG_ARM_PSCI_VERSION is in arch/arm64/include/uapi/asm/kvm.h.
|
||||
const KVM_REG_ARM_PSCI_VERSION: u64 =
|
||||
KVM_REG_ARM64 | (KVM_REG_SIZE_U64 as u64) | (KVM_REG_ARM_FW as u64);
|
||||
|
||||
match self.get_one_reg(KVM_REG_ARM_PSCI_VERSION) {
|
||||
Ok(v) => {
|
||||
let major = (v >> PSCI_VERSION_MAJOR_SHIFT) as u32;
|
||||
let minor = (v as u32) & PSCI_VERSION_MINOR_MASK;
|
||||
Ok(PsciVersion { major, minor })
|
||||
}
|
||||
Err(_) => {
|
||||
// When `KVM_REG_ARM_PSCI_VERSION` is not supported, we can return PSCI 0.2, as vCPU
|
||||
// has been initialized with `KVM_ARM_VCPU_PSCI_0_2` successfully.
|
||||
Ok(PsciVersion { major: 0, minor: 2 })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This function translates an IrqSrouceChip to the kvm u32 equivalent. It has a different
|
||||
|
|
Loading…
Reference in a new issue