mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-02-21 19:02:30 +00:00
arch: AArch64: Porting GIC icc_regs implementation
This commit ports the implementation of GIC ICC registers from Firecracker. Signed-off-by: Henry Wang <Henry.Wang@arm.com>
This commit is contained in:
parent
bfde6977c8
commit
09d53aad11
196
arch/src/aarch64/gic/icc_regs.rs
Normal file
196
arch/src/aarch64/gic/icc_regs.rs
Normal file
@ -0,0 +1,196 @@
|
||||
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::{Error, Result};
|
||||
use hypervisor::kvm::kvm_bindings::{
|
||||
kvm_device_attr, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, KVM_REG_ARM64_SYSREG_CRM_MASK,
|
||||
KVM_REG_ARM64_SYSREG_CRM_SHIFT, KVM_REG_ARM64_SYSREG_CRN_MASK, KVM_REG_ARM64_SYSREG_CRN_SHIFT,
|
||||
KVM_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP0_SHIFT, KVM_REG_ARM64_SYSREG_OP1_MASK,
|
||||
KVM_REG_ARM64_SYSREG_OP1_SHIFT, KVM_REG_ARM64_SYSREG_OP2_MASK, KVM_REG_ARM64_SYSREG_OP2_SHIFT,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
const KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT: u32 = 32;
|
||||
const KVM_DEV_ARM_VGIC_V3_MPIDR_MASK: u64 = 0xffffffff << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT as u64;
|
||||
|
||||
const ICC_CTLR_EL1_PRIBITS_SHIFT: u32 = 8;
|
||||
const ICC_CTLR_EL1_PRIBITS_MASK: u32 = 7 << ICC_CTLR_EL1_PRIBITS_SHIFT;
|
||||
|
||||
macro_rules! arm64_vgic_sys_reg {
|
||||
($name: tt, $op0: tt, $op1: tt, $crn: tt, $crm: tt, $op2: expr) => {
|
||||
const $name: u64 = ((($op0 as u64) << KVM_REG_ARM64_SYSREG_OP0_SHIFT)
|
||||
& KVM_REG_ARM64_SYSREG_OP0_MASK as u64)
|
||||
| ((($op1 as u64) << KVM_REG_ARM64_SYSREG_OP1_SHIFT)
|
||||
& KVM_REG_ARM64_SYSREG_OP1_MASK as u64)
|
||||
| ((($crn as u64) << KVM_REG_ARM64_SYSREG_CRN_SHIFT)
|
||||
& KVM_REG_ARM64_SYSREG_CRN_MASK as u64)
|
||||
| ((($crm as u64) << KVM_REG_ARM64_SYSREG_CRM_SHIFT)
|
||||
& KVM_REG_ARM64_SYSREG_CRM_MASK as u64)
|
||||
| ((($op2 as u64) << KVM_REG_ARM64_SYSREG_OP2_SHIFT)
|
||||
& KVM_REG_ARM64_SYSREG_OP2_MASK as u64);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! SYS_ICC_AP0Rn_EL1 {
|
||||
($name: tt, $n: tt) => {
|
||||
arm64_vgic_sys_reg!($name, 3, 0, 12, 8, (4 | $n));
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! SYS_ICC_AP1Rn_EL1 {
|
||||
($name: tt, $n: tt) => {
|
||||
arm64_vgic_sys_reg!($name, 3, 0, 12, 9, $n);
|
||||
};
|
||||
}
|
||||
|
||||
arm64_vgic_sys_reg!(SYS_ICC_SRE_EL1, 3, 0, 12, 12, 5);
|
||||
arm64_vgic_sys_reg!(SYS_ICC_CTLR_EL1, 3, 0, 12, 12, 4);
|
||||
arm64_vgic_sys_reg!(SYS_ICC_IGRPEN0_EL1, 3, 0, 12, 12, 6);
|
||||
arm64_vgic_sys_reg!(SYS_ICC_IGRPEN1_EL1, 3, 0, 12, 12, 7);
|
||||
arm64_vgic_sys_reg!(SYS_ICC_PMR_EL1, 3, 0, 4, 6, 0);
|
||||
arm64_vgic_sys_reg!(SYS_ICC_BPR0_EL1, 3, 0, 12, 8, 3);
|
||||
arm64_vgic_sys_reg!(SYS_ICC_BPR1_EL1, 3, 0, 12, 12, 3);
|
||||
SYS_ICC_AP0Rn_EL1!(SYS_ICC_AP0R0_EL1, 0);
|
||||
SYS_ICC_AP0Rn_EL1!(SYS_ICC_AP0R1_EL1, 1);
|
||||
SYS_ICC_AP0Rn_EL1!(SYS_ICC_AP0R2_EL1, 2);
|
||||
SYS_ICC_AP0Rn_EL1!(SYS_ICC_AP0R3_EL1, 3);
|
||||
SYS_ICC_AP1Rn_EL1!(SYS_ICC_AP1R0_EL1, 0);
|
||||
SYS_ICC_AP1Rn_EL1!(SYS_ICC_AP1R1_EL1, 1);
|
||||
SYS_ICC_AP1Rn_EL1!(SYS_ICC_AP1R2_EL1, 2);
|
||||
SYS_ICC_AP1Rn_EL1!(SYS_ICC_AP1R3_EL1, 3);
|
||||
|
||||
static VGIC_ICC_REGS: &'static [u64] = &[
|
||||
SYS_ICC_SRE_EL1,
|
||||
SYS_ICC_CTLR_EL1,
|
||||
SYS_ICC_IGRPEN0_EL1,
|
||||
SYS_ICC_IGRPEN1_EL1,
|
||||
SYS_ICC_PMR_EL1,
|
||||
SYS_ICC_BPR0_EL1,
|
||||
SYS_ICC_BPR1_EL1,
|
||||
SYS_ICC_AP0R0_EL1,
|
||||
SYS_ICC_AP0R1_EL1,
|
||||
SYS_ICC_AP0R2_EL1,
|
||||
SYS_ICC_AP0R3_EL1,
|
||||
SYS_ICC_AP1R0_EL1,
|
||||
SYS_ICC_AP1R1_EL1,
|
||||
SYS_ICC_AP1R2_EL1,
|
||||
SYS_ICC_AP1R3_EL1,
|
||||
];
|
||||
|
||||
fn icc_attr_access(
|
||||
gic: &Arc<dyn hypervisor::Device>,
|
||||
offset: u64,
|
||||
typer: u64,
|
||||
val: &u32,
|
||||
set: bool,
|
||||
) -> Result<()> {
|
||||
let mut gic_icc_attr = kvm_device_attr {
|
||||
group: KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
|
||||
attr: ((typer & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) | offset), // this needs the mpidr
|
||||
addr: val as *const u32 as u64,
|
||||
flags: 0,
|
||||
};
|
||||
if set {
|
||||
#[allow(clippy::unnecessary_mut_passed)]
|
||||
gic.set_device_attr(&mut gic_icc_attr)
|
||||
.map_err(Error::SetDeviceAttribute)?;
|
||||
} else {
|
||||
gic.get_device_attr(&mut gic_icc_attr)
|
||||
.map_err(Error::GetDeviceAttribute)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get ICC registers.
|
||||
pub fn get_icc_regs(gic: &Arc<dyn hypervisor::Device>, gicr_typer: &[u64]) -> Result<Vec<u32>> {
|
||||
let mut state: Vec<u32> = Vec::new();
|
||||
// We need this for the ICC_AP<m>R<n>_EL1 registers.
|
||||
let mut num_priority_bits = 0;
|
||||
|
||||
for ix in gicr_typer {
|
||||
let i = *ix;
|
||||
for icc_offset in VGIC_ICC_REGS {
|
||||
let val = 0;
|
||||
if *icc_offset == SYS_ICC_CTLR_EL1 {
|
||||
// calculate priority bits by reading the ctrl_el1 register.
|
||||
icc_attr_access(gic, *icc_offset, i, &val, false)?;
|
||||
// The priority bits are found in the ICC_CTLR_EL1 register (bits from 10:8).
|
||||
// See page 194 from https://static.docs.arm.com/ihi0069/c/IHI0069C_gic_
|
||||
// architecture_specification.pdf.
|
||||
// Citation:
|
||||
// "Priority bits. Read-only and writes are ignored. The number of priority bits
|
||||
// implemented, minus one."
|
||||
num_priority_bits =
|
||||
((val & ICC_CTLR_EL1_PRIBITS_MASK) >> ICC_CTLR_EL1_PRIBITS_SHIFT) + 1;
|
||||
state.push(val);
|
||||
}
|
||||
// As per ARMv8 documentation: https://static.docs.arm.com/ihi0069/c/IHI0069C_
|
||||
// gic_architecture_specification.pdf
|
||||
// page 178,
|
||||
// ICC_AP0R1_EL1 is only implemented in implementations that support 6 or more bits of
|
||||
// priority.
|
||||
// ICC_AP0R2_EL1 and ICC_AP0R3_EL1 are only implemented in implementations that support
|
||||
// 7 bits of priority.
|
||||
else if *icc_offset == SYS_ICC_AP0R1_EL1 || *icc_offset == SYS_ICC_AP1R1_EL1 {
|
||||
if num_priority_bits >= 6 {
|
||||
icc_attr_access(gic, *icc_offset, i, &val, false)?;
|
||||
state.push(val);
|
||||
}
|
||||
} else if *icc_offset == SYS_ICC_AP0R2_EL1
|
||||
|| *icc_offset == SYS_ICC_AP0R3_EL1
|
||||
|| *icc_offset == SYS_ICC_AP1R2_EL1
|
||||
|| *icc_offset == SYS_ICC_AP1R3_EL1
|
||||
{
|
||||
if num_priority_bits == 7 {
|
||||
icc_attr_access(gic, *icc_offset, i, &val, false)?;
|
||||
state.push(val);
|
||||
}
|
||||
} else {
|
||||
icc_attr_access(gic, *icc_offset, i, &val, false)?;
|
||||
state.push(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
/// Set ICC registers.
|
||||
pub fn set_icc_regs(
|
||||
gic: &Arc<dyn hypervisor::Device>,
|
||||
gicr_typer: &[u64],
|
||||
state: &[u32],
|
||||
) -> Result<()> {
|
||||
let mut num_priority_bits = 0;
|
||||
let mut idx = 0;
|
||||
for ix in gicr_typer {
|
||||
let i = *ix;
|
||||
for icc_offset in VGIC_ICC_REGS {
|
||||
if *icc_offset == SYS_ICC_CTLR_EL1 {
|
||||
let ctrl_el1 = state[idx];
|
||||
num_priority_bits =
|
||||
((ctrl_el1 & ICC_CTLR_EL1_PRIBITS_MASK) >> ICC_CTLR_EL1_PRIBITS_SHIFT) + 1;
|
||||
}
|
||||
if *icc_offset == SYS_ICC_AP0R1_EL1 || *icc_offset == SYS_ICC_AP1R1_EL1 {
|
||||
if num_priority_bits >= 6 {
|
||||
icc_attr_access(gic, *icc_offset, i, &state[idx], true)?;
|
||||
idx += 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if *icc_offset == SYS_ICC_AP0R2_EL1
|
||||
|| *icc_offset == SYS_ICC_AP0R3_EL1
|
||||
|| *icc_offset == SYS_ICC_AP1R2_EL1
|
||||
|| *icc_offset == SYS_ICC_AP1R3_EL1
|
||||
{
|
||||
if num_priority_bits == 7 {
|
||||
icc_attr_access(gic, *icc_offset, i, &state[idx], true)?;
|
||||
idx += 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
icc_attr_access(gic, *icc_offset, i, &state[idx], true)?;
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
@ -5,9 +5,11 @@ pub mod dist_regs;
|
||||
mod gicv2;
|
||||
mod gicv3;
|
||||
mod gicv3_its;
|
||||
pub mod icc_regs;
|
||||
pub mod redist_regs;
|
||||
|
||||
pub use self::dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
|
||||
pub use self::icc_regs::{get_icc_regs, set_icc_regs};
|
||||
pub use self::redist_regs::{get_redist_regs, set_redist_regs};
|
||||
use std::result;
|
||||
use std::sync::Arc;
|
||||
|
Loading…
x
Reference in New Issue
Block a user