Files
system76-edk2/ArmVirtPkg/Library/ArmVirtTimerFdtClientLib/ArmVirtTimerFdtClientLib.c
Leif Lindholm eb485b6438 ArmVirtPkg: handle virtual EL2 timer in DT
FEAT_VHE, introduced in ARMv8.1, adds a virtual EL2 timer.
However, this library verifies that exactly 3 or 4 12-byte timer
interrupts are provided in input DT, ASSERTing when the new timer
is added.

Change the assert to >= 36.

Extend the current logic, also initializing PcdArmArchTimerHypVirtIntrNum
if 5 interrupts are provided.

Signed-off-by: Leif Lindholm <quic_llindhol@quicinc.com>
Reported-by: Peter Maydell <peter.maydell@linaro.org>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Tested-by: Peter Maydell <peter.maydell@linaro.org>
2023-09-19 20:27:55 +00:00

108 lines
3.2 KiB
C

/** @file
FDT client library for ARM's TimerDxe
Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/FdtClient.h>
#pragma pack (1)
typedef struct {
UINT32 Type;
UINT32 Number;
UINT32 Flags;
} INTERRUPT_PROPERTY;
#pragma pack ()
RETURN_STATUS
EFIAPI
ArmVirtTimerFdtClientLibConstructor (
VOID
)
{
EFI_STATUS Status;
FDT_CLIENT_PROTOCOL *FdtClient;
CONST INTERRUPT_PROPERTY *InterruptProp;
UINT32 PropSize;
INT32 SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum;
INT32 HypVirtIntrNum;
RETURN_STATUS PcdStatus;
Status = gBS->LocateProtocol (
&gFdtClientProtocolGuid,
NULL,
(VOID **)&FdtClient
);
ASSERT_EFI_ERROR (Status);
Status = FdtClient->FindCompatibleNodeProperty (
FdtClient,
"arm,armv7-timer",
"interrupts",
(CONST VOID **)&InterruptProp,
&PropSize
);
if (Status == EFI_NOT_FOUND) {
Status = FdtClient->FindCompatibleNodeProperty (
FdtClient,
"arm,armv8-timer",
"interrupts",
(CONST VOID **)&InterruptProp,
&PropSize
);
}
if (EFI_ERROR (Status)) {
return Status;
}
//
// - interrupts : Interrupt list for secure, non-secure, virtual,
// hypervisor and hypervisor virtual timers, in that order.
//
ASSERT (PropSize >= 36);
SecIntrNum = SwapBytes32 (InterruptProp[0].Number)
+ (InterruptProp[0].Type ? 16 : 0);
IntrNum = SwapBytes32 (InterruptProp[1].Number)
+ (InterruptProp[1].Type ? 16 : 0);
VirtIntrNum = SwapBytes32 (InterruptProp[2].Number)
+ (InterruptProp[2].Type ? 16 : 0);
HypIntrNum = PropSize < 48 ? 0 : SwapBytes32 (InterruptProp[3].Number)
+ (InterruptProp[3].Type ? 16 : 0);
HypVirtIntrNum = PropSize < 60 ? 0 : SwapBytes32 (InterruptProp[4].Number)
+ (InterruptProp[4].Type ? 16 : 0);
DEBUG ((
DEBUG_INFO,
"Found Timer interrupts %d, %d, %d, %d\n",
SecIntrNum,
IntrNum,
VirtIntrNum,
HypIntrNum
));
PcdStatus = PcdSet32S (PcdArmArchTimerSecIntrNum, SecIntrNum);
ASSERT_RETURN_ERROR (PcdStatus);
PcdStatus = PcdSet32S (PcdArmArchTimerIntrNum, IntrNum);
ASSERT_RETURN_ERROR (PcdStatus);
PcdStatus = PcdSet32S (PcdArmArchTimerVirtIntrNum, VirtIntrNum);
ASSERT_RETURN_ERROR (PcdStatus);
PcdStatus = PcdSet32S (PcdArmArchTimerHypIntrNum, HypIntrNum);
ASSERT_RETURN_ERROR (PcdStatus);
PcdStatus = PcdSet32S (PcdArmArchTimerHypVirtIntrNum, HypVirtIntrNum);
ASSERT_RETURN_ERROR (PcdStatus);
return EFI_SUCCESS;
}