mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
For ARM64 guests we need to set three important partition property: 1) PPI interrupt ID for timer interrupt 2) PPI interrupt ID for PMU interrupts. 3) Hiding LPI support from the guest because MSHV does emulate ITS for the guest. Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
229 lines
6.7 KiB
Rust
229 lines
6.7 KiB
Rust
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
|
|
//
|
|
// Copyright © 2025, Microsoft Corporation
|
|
//
|
|
|
|
use bitfield_struct::bitfield;
|
|
use open_enum::open_enum;
|
|
use zerocopy::{FromBytes, IntoBytes};
|
|
|
|
/// ESR_EL2, exception syndrome register.
|
|
#[bitfield(u64)]
|
|
#[derive(IntoBytes, FromBytes)]
|
|
pub struct EsrEl2 {
|
|
#[bits(25)]
|
|
pub iss: u32,
|
|
pub il: bool,
|
|
#[bits(6)]
|
|
pub ec: u8,
|
|
#[bits(5)]
|
|
pub iss2: u8,
|
|
#[bits(27)]
|
|
_rsvd: u32,
|
|
}
|
|
|
|
#[open_enum]
|
|
#[derive(Debug)]
|
|
#[repr(u8)]
|
|
pub enum FaultStatusCode {
|
|
ADDRESS_SIZE_FAULT_LEVEL0 = 0b000000,
|
|
ADDRESS_SIZE_FAULT_LEVEL1 = 0b000001,
|
|
ADDRESS_SIZE_FAULT_LEVEL2 = 0b000010,
|
|
ADDRESS_SIZE_FAULT_LEVEL3 = 0b000011,
|
|
TRANSLATION_FAULT_LEVEL0 = 0b000100,
|
|
TRANSLATION_FAULT_LEVEL1 = 0b000101,
|
|
TRANSLATION_FAULT_LEVEL2 = 0b000110,
|
|
TRANSLATION_FAULT_LEVEL3 = 0b000111,
|
|
ACCESS_FLAG_FAULT_LEVEL0 = 0b001000,
|
|
ACCESS_FLAG_FAULT_LEVEL1 = 0b001001,
|
|
ACCESS_FLAG_FAULT_LEVEL2 = 0b001010,
|
|
ACCESS_FLAG_FAULT_LEVEL3 = 0b001011,
|
|
PERMISSION_FAULT_LEVEL0 = 0b001100,
|
|
PERMISSION_FAULT_LEVEL1 = 0b001101,
|
|
PERMISSION_FAULT_LEVEL2 = 0b001110,
|
|
PERMISSION_FAULT_LEVEL3 = 0b001111,
|
|
SYNCHRONOUS_EXTERNAL_ABORT = 0b010000,
|
|
SYNC_TAG_CHECK_FAULT = 0b010001,
|
|
SEA_TTW_LEVEL_NEG1 = 0b010011,
|
|
SEA_TTW_LEVEL0 = 0b010100,
|
|
SEA_TTW_LEVEL1 = 0b010101,
|
|
SEA_TTW_LEVEL2 = 0b010110,
|
|
SEA_TTW_LEVEL3 = 0b010111,
|
|
ECC_PARITY = 0b011000,
|
|
ECC_PARITY_TTW_LEVEL_NEG1 = 0b011011,
|
|
ECC_PARITY_TTW_LEVEL0 = 0b011100,
|
|
ECC_PARITY_TTW_LEVEL1 = 0b011101,
|
|
ECC_PARITY_TTW_LEVEL2 = 0b011110,
|
|
ECC_PARITY_TTW_LEVEL3 = 0b011111,
|
|
/// Valid only for data fault.
|
|
ALIGNMENT_FAULT = 0b100001,
|
|
/// Valid only for instruction fault.
|
|
GRANULE_PROTECTION_FAULT_LEVEL_NEG = 0b100011,
|
|
/// Valid only for instruction fault.
|
|
GRANULE_PROTECTION_FAULT_LEVEL0 = 0b100100,
|
|
/// Valid only for instruction fault.
|
|
GRANULE_PROTECTION_FAULT_LEVEL1 = 0b100101,
|
|
/// Valid only for instruction fault.
|
|
GRANULE_PROTECTION_FAULT_LEVEL2 = 0b100110,
|
|
/// Valid only for instruction fault.
|
|
GRANULE_PROTECTION_FAULT_LEVEL3 = 0b100111,
|
|
ADDRESS_SIZE_FAULT_LEVEL_NEG1 = 0b101001,
|
|
TRANSLATION_FAULT_LEVEL_NEG1 = 0b101011,
|
|
TLB_CONFLICT_ABORT = 0b110000,
|
|
UNSUPPORTED_HW_UPDATE_FAULT = 0b110001,
|
|
}
|
|
|
|
/// Support for embedding within IssDataAbort/IssInstructionAbort
|
|
impl FaultStatusCode {
|
|
const fn from_bits(bits: u32) -> Self {
|
|
FaultStatusCode((bits & 0x3f) as u8)
|
|
}
|
|
|
|
const fn into_bits(self) -> u32 {
|
|
self.0 as u32
|
|
}
|
|
}
|
|
|
|
#[bitfield(u32)]
|
|
pub struct IssDataAbort {
|
|
#[bits(6)]
|
|
pub dfsc: FaultStatusCode,
|
|
// Write operation (write not read)
|
|
pub wnr: bool,
|
|
pub s1ptw: bool,
|
|
pub cm: bool,
|
|
pub ea: bool,
|
|
/// FAR not valid
|
|
pub fnv: bool,
|
|
#[bits(2)]
|
|
pub set: u8,
|
|
pub vncr: bool,
|
|
/// Acquire/release
|
|
pub ar: bool,
|
|
/// (ISV==1) 64-bit, (ISV==0) FAR is approximate
|
|
pub sf: bool,
|
|
#[bits(5)]
|
|
/// Register index.
|
|
pub srt: u8,
|
|
/// Sign extended.
|
|
pub sse: bool,
|
|
#[bits(2)]
|
|
/// access width log2
|
|
pub sas: u8,
|
|
/// Valid ESREL2 iss field.
|
|
pub isv: bool,
|
|
#[bits(7)]
|
|
_unused: u8,
|
|
}
|
|
|
|
#[open_enum]
|
|
#[repr(u8)]
|
|
pub enum ExceptionClass {
|
|
UNKNOWN = 0b000000,
|
|
WFI = 0b000001,
|
|
MCR_MRC_COPROC_15 = 0b000011,
|
|
MCRR_MRRC_COPROC_15 = 0b000100,
|
|
MCR_MRC_COPROC_14 = 0b000101,
|
|
LDC_STC = 0b000110,
|
|
FP_OR_SIMD = 0b000111,
|
|
VMRS = 0b001000,
|
|
POINTER_AUTH_HCR_OR_SCR = 0b001001,
|
|
LS64 = 0b001010,
|
|
MRRC_COPROC_14 = 0b001100,
|
|
BRANCH_TARGET = 0b001101,
|
|
ILLEGAL_STATE = 0b001110,
|
|
SVC32 = 0b010001,
|
|
HVC32 = 0b010010,
|
|
SMC32 = 0b010011,
|
|
SVC = 0b010101,
|
|
HVC = 0b010110,
|
|
SMC = 0b010111,
|
|
SYSTEM = 0b011000,
|
|
SVE = 0b011001,
|
|
ERET = 0b011010,
|
|
TSTART = 0b011011,
|
|
POINTER_AUTH = 0b011100,
|
|
SME = 0b011101,
|
|
INSTRUCTION_ABORT_LOWER = 0b100000,
|
|
INSTRUCTION_ABORT = 0b100001,
|
|
PC_ALIGNMENT = 0b100010,
|
|
DATA_ABORT_LOWER = 0b100100,
|
|
DATA_ABORT = 0b100101,
|
|
SP_ALIGNMENT_FAULT = 0b100110,
|
|
MEMORY_OP = 0b100111,
|
|
FP_EXCEPTION_32 = 0b101000,
|
|
FP_EXCEPTION_64 = 0b101100,
|
|
SERROR = 0b101111,
|
|
BREAKPOINT_LOWER = 0b110000,
|
|
BREAKPOINT = 0b110001,
|
|
STEP_LOWER = 0b110010,
|
|
STEP = 0b110011,
|
|
WATCHPOINT_LOWER = 0b110100,
|
|
WATCHPOINT = 0b110101,
|
|
BRK32 = 0b111000,
|
|
VECTOR_CATCH_32 = 0b111010,
|
|
BRK = 0b111100,
|
|
}
|
|
|
|
#[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.
|
|
pub const PSTATE_FAULT_BITS_64: u64 = PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | PSR_I_BIT | PSR_D_BIT;
|
|
|
|
// AArch64 system register encoding:
|
|
// See https://developer.arm.com/documentation/ddi0487 (chapter D12)
|
|
//
|
|
// 31 22 21 20 19 18 16 15 12 11 8 7 5 4 0
|
|
// +----------+---+-----+-----+-----+-----+-----+----+
|
|
// |1101010100| L | op0 | op1 | CRn | CRm | op2 | Rt |
|
|
// +----------+---+-----+-----+-----+-----+-----+----+
|
|
//
|
|
// Notes:
|
|
// - L and Rt are reserved as implementation defined fields, ignored.
|
|
|
|
const SYSREG_HEAD: u32 = 0b1101010100u32 << 22;
|
|
const SYSREG_OP0_SHIFT: u32 = 19;
|
|
const SYSREG_OP0_MASK: u32 = 0b11u32 << 19;
|
|
const SYSREG_OP1_SHIFT: u32 = 16;
|
|
const SYSREG_OP1_MASK: u32 = 0b111u32 << 16;
|
|
const SYSREG_CRN_SHIFT: u32 = 12;
|
|
const SYSREG_CRN_MASK: u32 = 0b1111u32 << 12;
|
|
const SYSREG_CRM_SHIFT: u32 = 8;
|
|
const SYSREG_CRM_MASK: u32 = 0b1111u32 << 8;
|
|
const SYSREG_OP2_SHIFT: u32 = 5;
|
|
const SYSREG_OP2_MASK: u32 = 0b111u32 << 5;
|
|
|
|
/// Define the ID of system registers
|
|
#[macro_export]
|
|
macro_rules! arm64_sys_reg {
|
|
($name: tt, $op0: tt, $op1: tt, $crn: tt, $crm: tt, $op2: tt) => {
|
|
pub const $name: u32 = SYSREG_HEAD
|
|
| ((($op0 as u32) << SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK as u32)
|
|
| ((($op1 as u32) << SYSREG_OP1_SHIFT) & SYSREG_OP1_MASK as u32)
|
|
| ((($crn as u32) << SYSREG_CRN_SHIFT) & SYSREG_CRN_MASK as u32)
|
|
| ((($crm as u32) << SYSREG_CRM_SHIFT) & SYSREG_CRM_MASK as u32)
|
|
| ((($op2 as u32) << SYSREG_OP2_SHIFT) & SYSREG_OP2_MASK as u32);
|
|
};
|
|
}
|
|
|
|
arm64_sys_reg!(MPIDR_EL1, 3, 0, 0, 0, 5);
|
|
arm64_sys_reg!(ID_AA64MMFR0_EL1, 3, 0, 0, 7, 0);
|
|
arm64_sys_reg!(TTBR1_EL1, 3, 0, 2, 0, 1);
|
|
arm64_sys_reg!(TCR_EL1, 3, 0, 2, 0, 2);
|
|
|
|
pub const AARCH64_ARCH_TIMER_PHYS_SECURE_IRQ: u32 = 13;
|
|
pub const AARCH64_ARCH_TIMER_PHYS_NONSECURE_IRQ: u32 = 14;
|
|
pub const AARCH64_ARCH_TIMER_VIRT_IRQ: u32 = 11;
|
|
pub const AARCH64_ARCH_TIMER_HYP_IRQ: u32 = 10;
|
|
|
|
// PMU PPI interrupt number
|
|
pub const AARCH64_PMU_IRQ: u32 = 7;
|
|
|
|
pub const AARCH64_MIN_PPI_IRQ: u32 = 16;
|