From 6b6ca05b8539d5e58212d0a903ec6d7da467e6c8 Mon Sep 17 00:00:00 2001 From: Rajat Goyal Date: Mon, 23 Jun 2025 12:13:44 +0000 Subject: [PATCH] Add support for Systems with effective HCR_EL2.E2H = 1 - Implemented logic to detect the effective value of HCR_EL2.E2H. - Updated code to conditionally access appropriate system registers based on whether Virtualization Host Extensions (VHE) are enabled. - Ensures correct behavior in systems running with E2H set. Signed-off-by: Rajat Goyal Co-authored-by: Nick Graves --- val/include/acs_timer_support.h | 21 ++++++++ val/src/AArch64/ArchTimerSupport.S | 87 ++++++++++++++++++++++++++++-- val/src/acs_timer_support.c | 73 ++++++++++++++++++++----- 3 files changed, 166 insertions(+), 15 deletions(-) diff --git a/val/include/acs_timer_support.h b/val/include/acs_timer_support.h index 0d6ad5e9..000ac090 100644 --- a/val/include/acs_timer_support.h +++ b/val/include/acs_timer_support.h @@ -139,4 +139,25 @@ void ArmWriteCnthvTval (uint64_t Val); void ArmGenericTimerEnableTimer (ARM_ARCH_TIMER_REGS reg); void ArmGenericTimerDisableTimer (ARM_ARCH_TIMER_REGS reg); +uint64_t ArmReadHcrEl2(void); +uint64_t ArmReadAA64MMFR1EL1(void); +uint64_t ArmReadAA64MMFR4EL1(void); + +uint64_t ArmReadCntpCtl02(void); +uint64_t ArmReadCntpTval02(void); +uint64_t ArmReadCntpCval02(void); +void ArmWriteCntpCtl02(uint64_t val); +void ArmWriteCntpTval02(uint64_t val); +void ArmWriteCntpCval02(uint64_t val); + +uint64_t ArmReadCntvTval02(void); +uint64_t ArmReadCntvCtl02(void); +uint64_t ArmReadCntvCval02(void); +void ArmWriteCntvTval02(uint64_t val); +void ArmWriteCntvCtl02(uint64_t val); +void ArmWriteCntvCval02(uint64_t val); + +uint64_t ArmReadCntkCtl12(void); +void ArmWriteCntkCtl12(uint64_t val); + #endif // __ARM_ARCH_TIMER_H__ diff --git a/val/src/AArch64/ArchTimerSupport.S b/val/src/AArch64/ArchTimerSupport.S index b5cde605..6f83f5f4 100644 --- a/val/src/AArch64/ArchTimerSupport.S +++ b/val/src/AArch64/ArchTimerSupport.S @@ -39,22 +39,38 @@ .text .align 2 +GCC_ASM_EXPORT(ArmReadHcrEl2) +GCC_ASM_EXPORT(ArmReadAA64MMFR1EL1) +GCC_ASM_EXPORT(ArmReadAA64MMFR4EL1) GCC_ASM_EXPORT(ArmReadCntFrq) GCC_ASM_EXPORT(ArmReadCntPct) GCC_ASM_EXPORT(ArmReadCntkCtl) GCC_ASM_EXPORT(ArmWriteCntkCtl) +GCC_ASM_EXPORT(ArmReadCntkCtl12) +GCC_ASM_EXPORT(ArmWriteCntkCtl12) GCC_ASM_EXPORT(ArmReadCntpTval) GCC_ASM_EXPORT(ArmWriteCntpTval) +GCC_ASM_EXPORT(ArmReadCntpTval02) +GCC_ASM_EXPORT(ArmWriteCntpTval02) GCC_ASM_EXPORT(ArmReadCntpCtl) +GCC_ASM_EXPORT(ArmReadCntpCtl02) GCC_ASM_EXPORT(ArmReadCntvTval) GCC_ASM_EXPORT(ArmWriteCntvTval) +GCC_ASM_EXPORT(ArmReadCntvTval02) +GCC_ASM_EXPORT(ArmWriteCntvTval02) GCC_ASM_EXPORT(ArmReadCntvCtl) GCC_ASM_EXPORT(ArmWriteCntvCtl) +GCC_ASM_EXPORT(ArmReadCntvCtl02) +GCC_ASM_EXPORT(ArmWriteCntvCtl02) GCC_ASM_EXPORT(ArmReadCntvCt) GCC_ASM_EXPORT(ArmReadCntpCval) GCC_ASM_EXPORT(ArmWriteCntpCval) +GCC_ASM_EXPORT(ArmReadCntpCval02) +GCC_ASM_EXPORT(ArmWriteCntpCval02) GCC_ASM_EXPORT(ArmReadCntvCval) GCC_ASM_EXPORT(ArmWriteCntvCval) +GCC_ASM_EXPORT(ArmReadCntvCval02) +GCC_ASM_EXPORT(ArmWriteCntvCval02) GCC_ASM_EXPORT(ArmReadCntvOff) GCC_ASM_EXPORT(ArmWriteCntvOff) GCC_ASM_EXPORT(ArmReadCnthpCtl) @@ -66,6 +82,20 @@ GCC_ASM_EXPORT(ArmWriteCnthvCtl) GCC_ASM_EXPORT(ArmReadCnthvTval) GCC_ASM_EXPORT(ArmWriteCnthvTval) GCC_ASM_EXPORT(ArmWriteCntpCtl) +GCC_ASM_EXPORT(ArmWriteCntpCtl02) + +ASM_PFX(ArmReadHcrEl2): + mrs x0, hcr_el2 // Read HCR_EL2 + ret + +ASM_PFX(ArmReadAA64MMFR1EL1): + mrs x0, id_aa64mmfr1_el1 // Read ID_AA64MMFR1_EL1 + ret + +ASM_PFX(ArmReadAA64MMFR4EL1): + //mrs x0, id_aa64mmfr4_el1 // Read ID_AA64MMFR4_EL1 + mrs x0, s3_0_c0_c7_4 + ret ASM_PFX(ArmReadCntFrq): mrs x0, cntfrq_el0 // Read CNTFRQ @@ -81,15 +111,26 @@ ASM_PFX(ArmReadCntkCtl): mrs x0, cntkctl_el1 // Read CNTK_CTL (Timer PL1 Control Register) ret +ASM_PFX(ArmReadCntkCtl12): + mrs x0, cntkctl_el12 // Read CNTK_CTL (Timer PL1 Control Register) when EL2 Host + ret ASM_PFX(ArmWriteCntkCtl): msr cntkctl_el1, x0 // Write to CNTK_CTL (Timer PL1 Control Register) isb ret +ASM_PFX(ArmWriteCntkCtl12): + msr cntkctl_el12, x0 // Write to CNTK_CTL (Timer PL1 Control Register) when EL2 Host + isb + ret ASM_PFX(ArmReadCntpTval): - mrs x0, cntp_tval_el0 // Read CNTP_TVAL (PL1 physical timer value register) + mrs x0, cntp_tval_el0 // Read CNTP_TVAL (PL1 physical timer value register) + ret + +ASM_PFX(ArmReadCntpTval02): + mrs x0, cntp_tval_el02 // Read CNTP_TVAL (PL1 physical timer value register) when EL2 Host ret ASM_PFX(ArmWriteCntpTval): @@ -97,39 +138,65 @@ ASM_PFX(ArmWriteCntpTval): isb ret +ASM_PFX(ArmWriteCntpTval02): + msr cntp_tval_el02, x0 // Write to CNTP_TVAL (PL1 physical timer value register) EL2 Host + isb + ret ASM_PFX(ArmReadCntpCtl): - mrs x0, cntp_ctl_el0 // Read CNTP_CTL (PL1 Physical Timer Control Register) + mrs x0, cntp_ctl_el0 // Read CNTP_CTL (PL1 Physical Timer Control Register) + ret + +ASM_PFX(ArmReadCntpCtl02): + mrs x0, cntp_ctl_el02 // Read CNTP_CTL (PL1 Physical Timer Control Register) when EL2 Host ret ASM_PFX(ArmWriteCntpCtl): - msr cntp_ctl_el0, x0 // Write to CNTP_CTL (PL1 Physical Timer Control Register) + msr cntp_ctl_el0, x0 // Write CNTP_CTL (PL1 Physical Timer Control Register) isb ret +ASM_PFX(ArmWriteCntpCtl02): + msr cntp_ctl_el02, x0 // Write CNTP_CTL (PL1 Physical Timer Control Register) when EL2 Host + isb + ret ASM_PFX(ArmReadCntvTval): mrs x0, cntv_tval_el0 // Read CNTV_TVAL (Virtual Timer Value register) ret +ASM_PFX(ArmReadCntvTval02): + mrs x0, cntv_tval_el02 // Read CNTV_TVAL_EL02 (Virtual Timer Value register) + ret ASM_PFX(ArmWriteCntvTval): msr cntv_tval_el0, x0 // Write to CNTV_TVAL (Virtual Timer Value register) isb ret +ASM_PFX(ArmWriteCntvTval02): + msr cntv_tval_el02, x0 // Write to CNTV_TVAL_EL02 (Virtual Timer Value register) + isb + ret ASM_PFX(ArmReadCntvCtl): mrs x0, cntv_ctl_el0 // Read CNTV_CTL (Virtual Timer Control Register) ret +ASM_PFX(ArmReadCntvCtl02): + mrs x0, cntv_ctl_el02 // Read CNTV_CTL_EL02 (Virtual Timer Control Register) + ret ASM_PFX(ArmWriteCntvCtl): msr cntv_ctl_el0, x0 // Write to CNTV_CTL (Virtual Timer Control Register) isb ret +ASM_PFX(ArmWriteCntvCtl02): + msr cntv_ctl_el02, x0 // Write to CNTV_CTL_EL02 (Virtual Timer Control Register) + isb + ret ASM_PFX(ArmReadCntvCt): mrs x0, cntvct_el0 // Read CNTVCT (Virtual Count Register) @@ -140,23 +207,37 @@ ASM_PFX(ArmReadCntpCval): mrs x0, cntp_cval_el0 // Read CNTP_CTVAL (Physical Timer Compare Value Register) ret +ASM_PFX(ArmReadCntpCval02): + mrs x0, cntp_cval_el02 // Read CNTP_CTVAL_EL02 (Physical Timer Compare Value Register) + ret ASM_PFX(ArmWriteCntpCval): msr cntp_cval_el0, x0 // Write to CNTP_CTVAL (Physical Timer Compare Value Register) isb ret +ASM_PFX(ArmWriteCntpCval02): + msr cntp_cval_el02, x0 // Write to CNTP_CTVAL_EL02 (Physical Timer Compare Value Register) + isb + ret ASM_PFX(ArmReadCntvCval): mrs x0, cntv_cval_el0 // Read CNTV_CTVAL (Virtual Timer Compare Value Register) ret +ASM_PFX(ArmReadCntvCval02): + mrs x0, cntv_cval_el02 // Read CNTV_CTVAL_EL02 (Virtual Timer Compare Value Register) + ret ASM_PFX(ArmWriteCntvCval): msr cntv_cval_el0, x0 // write to CNTV_CTVAL (Virtual Timer Compare Value Register) isb ret +ASM_PFX(ArmWriteCntvCval02): + msr cntv_cval_el02, x0 // write to CNTV_CTVAL_EL02 (Virtual Timer Compare Value Register) + isb + ret ASM_PFX(ArmReadCntvOff): mrs x0, cntvoff_el2 // Read CNTVOFF (virtual Offset register) diff --git a/val/src/acs_timer_support.c b/val/src/acs_timer_support.c index 98d86e0b..c134539e 100644 --- a/val/src/acs_timer_support.c +++ b/val/src/acs_timer_support.c @@ -19,6 +19,31 @@ #include "include/acs_timer_support.h" #include "include/acs_common.h" +/** + @brief This API is used to get the effective HCR_EL2.E2H +**/ +uint8_t get_effective_e2h(void) +{ + uint32_t effective_e2h; + uint32_t hcr_e2h = VAL_EXTRACT_BITS(ArmReadHcrEl2(), 34, 34); + uint32_t feat_vhe = VAL_EXTRACT_BITS(ArmReadAA64MMFR1EL1(), 8, 11); + uint32_t e2h0 = VAL_EXTRACT_BITS(ArmReadAA64MMFR4EL1(), 24, 27); + + val_print(ACS_PRINT_DEBUG, "\n hcr_e2h : 0x%x", hcr_e2h); + val_print(ACS_PRINT_DEBUG, "\n feat_vhe : 0x%x", feat_vhe); + val_print(ACS_PRINT_DEBUG, "\n e2h0 : 0x%x", e2h0); + + if (feat_vhe == 0x0) //ID_AA64MMFR1_EL1.VH + effective_e2h = 0; + else if (e2h0 != 0x0) //E2H0 = 0 means implemented + effective_e2h = 1; + else + effective_e2h = hcr_e2h; + + val_print(ACS_PRINT_DEBUG, "\n effective e2h : 0x%x", effective_e2h); + return effective_e2h; +} + /** @brief This API is used to read Timer related registers @@ -31,6 +56,9 @@ ArmArchTimerReadReg ( ARM_ARCH_TIMER_REGS Reg ) { + static uint8_t effective_e2h = 0xFF; + if (effective_e2h == 0xFF) + effective_e2h = get_effective_e2h(); switch (Reg) { @@ -41,28 +69,30 @@ ArmArchTimerReadReg ( return ArmReadCntPct(); case CntkCtl: - return ArmReadCntkCtl(); + return effective_e2h ? ArmReadCntkCtl12() : ArmReadCntkCtl(); case CntpTval: - return ArmReadCntpTval(); + /* Check For E2H, If EL2 Host then access to cntp_tval_el02 */ + return effective_e2h ? ArmReadCntpTval02() : ArmReadCntpTval(); case CntpCtl: - return ArmReadCntpCtl(); + /* Check For E2H, If EL2 Host then access to cntp_ctl_el02 */ + return effective_e2h ? ArmReadCntpCtl02() : ArmReadCntpCtl(); case CntvTval: - return ArmReadCntvTval(); + return effective_e2h ? ArmReadCntvTval02() : ArmReadCntvTval(); case CntvCtl: - return ArmReadCntvCtl(); + return effective_e2h ? ArmReadCntvCtl02() : ArmReadCntvCtl(); case CntvCt: return ArmReadCntvCt(); case CntpCval: - return ArmReadCntpCval(); + return effective_e2h ? ArmReadCntpCval02() : ArmReadCntpCval(); case CntvCval: - return ArmReadCntvCval(); + return effective_e2h ? ArmReadCntvCval02() : ArmReadCntvCval(); case CntvOff: return ArmReadCntvOff(); @@ -103,6 +133,10 @@ ArmArchTimerWriteReg ( ) { + static uint8_t effective_e2h = 0xFF; + if (effective_e2h == 0xFF) + effective_e2h = get_effective_e2h(); + switch(Reg) { case CntPct: @@ -110,23 +144,38 @@ ArmArchTimerWriteReg ( break; case CntkCtl: - ArmWriteCntkCtl(*data_buf); + if (effective_e2h) + ArmWriteCntkCtl12(*data_buf); + else + ArmWriteCntkCtl(*data_buf); break; case CntpTval: - ArmWriteCntpTval(*data_buf); + if (effective_e2h) + ArmWriteCntpTval02(*data_buf); + else + ArmWriteCntpTval(*data_buf); break; case CntpCtl: - ArmWriteCntpCtl(*data_buf); + if (effective_e2h) + ArmWriteCntpCtl02(*data_buf); + else + ArmWriteCntpCtl(*data_buf); break; case CntvTval: - ArmWriteCntvTval(*data_buf); + if (effective_e2h) + ArmWriteCntvTval02(*data_buf); + else + ArmWriteCntvTval(*data_buf); break; case CntvCtl: - ArmWriteCntvCtl(*data_buf); + if (effective_e2h) + ArmWriteCntvCtl02(*data_buf); + else + ArmWriteCntvCtl(*data_buf); break; case CntvCt: