ArmPkg: TimerDxe: Add support for GICv5 PPIs

GICv5 uses a different ID scheme for interrupt numbers to previous GICs; the
top bits indicate the type of interrupt (PPI/SPI/LPI). Update TimerDxe to use
the new ID scheme for GICv5. As the timer PPIs are architected for GICv5 they
should be the same on all GICv5 platforms.

Signed-off-by: Sarah Walker <Sarah.Walker2@arm.com>
This commit is contained in:
Sarah Walker
2025-06-24 14:11:08 +01:00
committed by mergify[bot]
parent b7fdcbbeb8
commit b762965bda
2 changed files with 38 additions and 4 deletions

View File

@@ -22,6 +22,8 @@
#include <Protocol/Timer.h>
#include <Protocol/HardwareInterrupt.h>
#include "TimerDxe.h"
// The notification function to call on every timer interrupt.
EFI_TIMER_NOTIFY mTimerNotifyFunction = (EFI_TIMER_NOTIFY)NULL;
EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;
@@ -359,6 +361,9 @@ TimerInitialize (
EFI_STATUS Status;
UINTN TimerCtrlReg;
UINT32 TimerHypIntrNum;
UINT32 TimerVirtIntrNum;
UINT32 TimerSecIntrNum;
UINT32 TimerIntrNum;
if (ArmIsArchTimerImplemented () == 0) {
DEBUG ((DEBUG_ERROR, "ARM Architectural Timer is not available in the CPU, hence can't use this Driver \n"));
@@ -377,27 +382,38 @@ TimerInitialize (
Status = TimerDriverSetTimerPeriod (&gTimer, 0);
ASSERT_EFI_ERROR (Status);
if (ArmHasGicV5SystemRegisters ()) {
TimerSecIntrNum = GICV5_ARCH_TIMER_SEC_INTID;
TimerIntrNum = GICV5_ARCH_TIMER_INTID;
TimerHypIntrNum = GICV5_ARCH_TIMER_HYP_INTID;
TimerVirtIntrNum = GICV5_ARCH_TIMER_VIRT_INTID;
} else {
TimerVirtIntrNum = PcdGet32 (PcdArmArchTimerVirtIntrNum);
TimerHypIntrNum = PcdGet32 (PcdArmArchTimerHypIntrNum);
TimerSecIntrNum = PcdGet32 (PcdArmArchTimerSecIntrNum);
TimerIntrNum = PcdGet32 (PcdArmArchTimerIntrNum);
}
// Install secure and Non-secure interrupt handlers
// Note: Because it is not possible to determine the security state of the
// CPU dynamically, we just install interrupt handler for both sec and non-sec
// timer PPI
Status = gInterrupt->RegisterInterruptSource (gInterrupt, PcdGet32 (PcdArmArchTimerVirtIntrNum), TimerInterruptHandler);
Status = gInterrupt->RegisterInterruptSource (gInterrupt, TimerVirtIntrNum, TimerInterruptHandler);
ASSERT_EFI_ERROR (Status);
//
// The hypervisor timer interrupt may be omitted by implementations that
// execute under virtualization.
//
TimerHypIntrNum = PcdGet32 (PcdArmArchTimerHypIntrNum);
if (TimerHypIntrNum != 0) {
Status = gInterrupt->RegisterInterruptSource (gInterrupt, TimerHypIntrNum, TimerInterruptHandler);
ASSERT_EFI_ERROR (Status);
}
Status = gInterrupt->RegisterInterruptSource (gInterrupt, PcdGet32 (PcdArmArchTimerSecIntrNum), TimerInterruptHandler);
Status = gInterrupt->RegisterInterruptSource (gInterrupt, TimerSecIntrNum, TimerInterruptHandler);
ASSERT_EFI_ERROR (Status);
Status = gInterrupt->RegisterInterruptSource (gInterrupt, PcdGet32 (PcdArmArchTimerIntrNum), TimerInterruptHandler);
Status = gInterrupt->RegisterInterruptSource (gInterrupt, TimerIntrNum, TimerInterruptHandler);
ASSERT_EFI_ERROR (Status);
// Set up default timer

View File

@@ -0,0 +1,18 @@
/** @file
*
* Copyright (c) 2025, ARM Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef TIMER_DXE_H_
#define TIMER_DXE_H_
// Timer IntIDs are architecturally defined for GICv5
#define GICV5_ARCH_TIMER_HYP_INTID 0x2000001a
#define GICV5_ARCH_TIMER_VIRT_INTID 0x2000001b
#define GICV5_ARCH_TIMER_HYP_VIRT_INTID 0x2000001c
#define GICV5_ARCH_TIMER_SEC_INTID 0x2000001d
#define GICV5_ARCH_TIMER_INTID 0x2000001e
#endif // TIMER_DXE_H_