summaryrefslogtreecommitdiffstats
path: root/ArmPkg/Drivers/ArmGicDxe
diff options
context:
space:
mode:
Diffstat (limited to 'ArmPkg/Drivers/ArmGicDxe')
-rw-r--r--ArmPkg/Drivers/ArmGicDxe/ArmGicCommonDxe.c244
-rw-r--r--ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.c84
-rw-r--r--ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.h142
-rw-r--r--ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.inf62
-rw-r--r--ArmPkg/Drivers/ArmGicDxe/ArmGicV2Dxe.inf51
-rw-r--r--ArmPkg/Drivers/ArmGicDxe/ArmGicV3Dxe.inf57
-rw-r--r--ArmPkg/Drivers/ArmGicDxe/GicV2/ArmGicV2Dxe.c593
-rw-r--r--ArmPkg/Drivers/ArmGicDxe/GicV3/AArch64/ArmGicV3.S101
-rw-r--r--ArmPkg/Drivers/ArmGicDxe/GicV3/Arm/ArmGicV3.S80
-rw-r--r--ArmPkg/Drivers/ArmGicDxe/GicV3/ArmGicV3Dxe.c721
10 files changed, 2135 insertions, 0 deletions
diff --git a/ArmPkg/Drivers/ArmGicDxe/ArmGicCommonDxe.c b/ArmPkg/Drivers/ArmGicDxe/ArmGicCommonDxe.c
new file mode 100644
index 0000000000..8e845511d6
--- /dev/null
+++ b/ArmPkg/Drivers/ArmGicDxe/ArmGicCommonDxe.c
@@ -0,0 +1,244 @@
+/*++
+
+Copyright (c) 2013-2023, Arm Ltd. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+--*/
+
+#include "ArmGicDxe.h"
+
+// Making this global saves a few bytes in image size
+EFI_HANDLE gHardwareInterruptHandle = NULL;
+
+// Notifications
+EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;
+
+// Maximum Number of Interrupts
+UINTN mGicNumInterrupts = 0;
+
+HARDWARE_INTERRUPT_HANDLER *gRegisteredInterruptHandlers = NULL;
+
+/**
+ Calculate GICD_ICFGRn base address and corresponding bit
+ field Int_config[1] of the GIC distributor register.
+
+ @param Source Hardware source of the interrupt.
+ @param RegAddress Corresponding GICD_ICFGRn base address.
+ @param Config1Bit Bit number of F Int_config[1] bit in the register.
+
+ @retval EFI_SUCCESS Source interrupt supported.
+ @retval EFI_UNSUPPORTED Source interrupt is not supported.
+**/
+EFI_STATUS
+GicGetDistributorIcfgBaseAndBit (
+ IN HARDWARE_INTERRUPT_SOURCE Source,
+ OUT UINTN *RegAddress,
+ OUT UINTN *Config1Bit
+ )
+{
+ UINTN RegIndex;
+ UINTN Field;
+
+ if (Source >= mGicNumInterrupts) {
+ ASSERT (Source < mGicNumInterrupts);
+ return EFI_UNSUPPORTED;
+ }
+
+ RegIndex = Source / ARM_GIC_ICDICFR_F_STRIDE; // NOTE: truncation is significant
+ Field = Source % ARM_GIC_ICDICFR_F_STRIDE;
+ *RegAddress = (UINTN)PcdGet64 (PcdGicDistributorBase)
+ + ARM_GIC_ICDICFR
+ + (ARM_GIC_ICDICFR_BYTES * RegIndex);
+ *Config1Bit = ((Field * ARM_GIC_ICDICFR_F_WIDTH)
+ + ARM_GIC_ICDICFR_F_CONFIG1_BIT);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Register Handler for the specified interrupt source.
+
+ @param This Instance pointer for this protocol
+ @param Source Hardware source of the interrupt
+ @param Handler Callback for interrupt. NULL to unregister
+
+ @retval EFI_SUCCESS Source was updated to support Handler.
+ @retval EFI_DEVICE_ERROR Hardware could not be programmed.
+
+**/
+EFI_STATUS
+EFIAPI
+RegisterInterruptSource (
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
+ IN HARDWARE_INTERRUPT_SOURCE Source,
+ IN HARDWARE_INTERRUPT_HANDLER Handler
+ )
+{
+ if (Source >= mGicNumInterrupts) {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((Handler == NULL) && (gRegisteredInterruptHandlers[Source] == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Handler != NULL) && (gRegisteredInterruptHandlers[Source] != NULL)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ gRegisteredInterruptHandlers[Source] = Handler;
+
+ // If the interrupt handler is unregistered then disable the interrupt
+ if (NULL == Handler) {
+ return This->DisableInterruptSource (This, Source);
+ } else {
+ return This->EnableInterruptSource (This, Source);
+ }
+}
+
+STATIC VOID *mCpuArchProtocolNotifyEventRegistration;
+
+STATIC
+VOID
+EFIAPI
+CpuArchEventProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_CPU_ARCH_PROTOCOL *Cpu;
+ EFI_STATUS Status;
+
+ // Get the CPU protocol that this driver requires.
+ Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ // Unregister the default exception handler.
+ Status = Cpu->RegisterInterruptHandler (Cpu, ARM_ARCH_EXCEPTION_IRQ, NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Cpu->RegisterInterruptHandler() - %r\n",
+ __func__,
+ Status
+ ));
+ return;
+ }
+
+ // Register to receive interrupts
+ Status = Cpu->RegisterInterruptHandler (
+ Cpu,
+ ARM_ARCH_EXCEPTION_IRQ,
+ Context
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Cpu->RegisterInterruptHandler() - %r\n",
+ __func__,
+ Status
+ ));
+ }
+
+ gBS->CloseEvent (Event);
+}
+
+EFI_STATUS
+InstallAndRegisterInterruptService (
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *InterruptProtocol,
+ IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *Interrupt2Protocol,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler,
+ IN EFI_EVENT_NOTIFY ExitBootServicesEvent
+ )
+{
+ EFI_STATUS Status;
+ CONST UINTN RihArraySize =
+ (sizeof (HARDWARE_INTERRUPT_HANDLER) * mGicNumInterrupts);
+
+ // Initialize the array for the Interrupt Handlers
+ gRegisteredInterruptHandlers = AllocateZeroPool (RihArraySize);
+ if (gRegisteredInterruptHandlers == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &gHardwareInterruptHandle,
+ &gHardwareInterruptProtocolGuid,
+ InterruptProtocol,
+ &gHardwareInterrupt2ProtocolGuid,
+ Interrupt2Protocol,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Install the interrupt handler as soon as the CPU arch protocol appears.
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gEfiCpuArchProtocolGuid,
+ TPL_CALLBACK,
+ CpuArchEventProtocolNotify,
+ InterruptHandler,
+ &mCpuArchProtocolNotifyEventRegistration
+ );
+
+ // Register for an ExitBootServicesEvent
+ Status = gBS->CreateEvent (
+ EVT_SIGNAL_EXIT_BOOT_SERVICES,
+ TPL_NOTIFY,
+ ExitBootServicesEvent,
+ NULL,
+ &EfiExitBootServicesEvent
+ );
+
+ return Status;
+}
+
+/**
+ Return the GIC CPU Interrupt Interface ID.
+
+ @param GicInterruptInterfaceBase Base address of the GIC Interrupt Interface.
+
+ @retval CPU Interface Identification information.
+**/
+UINT32
+EFIAPI
+ArmGicGetInterfaceIdentification (
+ IN UINTN GicInterruptInterfaceBase
+ )
+{
+ // Read the GIC Identification Register
+ return MmioRead32 (GicInterruptInterfaceBase + ARM_GIC_ICCIIDR);
+}
+
+UINTN
+EFIAPI
+ArmGicGetMaxNumInterrupts (
+ IN UINTN GicDistributorBase
+ )
+{
+ UINTN ItLines;
+
+ ItLines = MmioRead32 (GicDistributorBase + ARM_GIC_ICDICTR) & 0x1F;
+
+ //
+ // Interrupt ID 1020-1023 are reserved.
+ //
+ return (ItLines == 0x1f) ? 1020 : 32 * (ItLines + 1);
+}
+
+VOID
+EFIAPI
+ArmGicDisableDistributor (
+ IN UINTN GicDistributorBase
+ )
+{
+ // Disable Gic Distributor
+ MmioWrite32 (GicDistributorBase + ARM_GIC_ICDDCR, 0x0);
+}
diff --git a/ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.c b/ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.c
new file mode 100644
index 0000000000..b0da48e3a3
--- /dev/null
+++ b/ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.c
@@ -0,0 +1,84 @@
+/*++
+
+Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+Module Name:
+
+ ArmGicDxe.c
+
+Abstract:
+
+ Driver implementing the GIC interrupt controller protocol
+
+--*/
+
+#include <PiDxe.h>
+
+#include "ArmGicDxe.h"
+
+STATIC
+BOOLEAN
+GicV3Supported (
+ VOID
+ )
+{
+ UINT32 IccSre;
+
+ // Ideally we would like to use the GICC IIDR Architecture version here, but
+ // this does not seem to be very reliable as the implementation could easily
+ // get it wrong. It is more reliable to check if the GICv3 System Register
+ // feature is implemented on the CPU. This is also convenient as our GICv3
+ // driver requires SRE. If only Memory mapped access is available we try to
+ // drive the GIC as a v2.
+ if (ArmHasGicSystemRegisters ()) {
+ // Make sure System Register access is enabled (SRE). This depends on the
+ // higher privilege level giving us permission, otherwise we will either
+ // cause an exception here, or the write doesn't stick in which case we need
+ // to fall back to the GICv2 MMIO interface.
+ // Note: We do not need to set ICC_SRE_EL2.Enable because the OS is started
+ // at the same exception level.
+ // It is the OS responsibility to set this bit.
+ IccSre = ArmGicV3GetControlSystemRegisterEnable ();
+ if (!(IccSre & ICC_SRE_EL2_SRE)) {
+ ArmGicV3SetControlSystemRegisterEnable (IccSre | ICC_SRE_EL2_SRE);
+ IccSre = ArmGicV3GetControlSystemRegisterEnable ();
+ }
+
+ if (IccSre & ICC_SRE_EL2_SRE) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Initialize the state information for the CPU Architectural Protocol
+
+ @param ImageHandle of the loaded driver
+ @param SystemTable Pointer to the System Table
+
+ @retval EFI_SUCCESS Protocol registered
+ @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
+ @retval EFI_DEVICE_ERROR Hardware problems
+ @retval EFI_UNSUPPORTED GIC version not supported
+
+**/
+EFI_STATUS
+InterruptDxeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ if (!GicV3Supported ()) {
+ Status = GicV2DxeInitialize (ImageHandle, SystemTable);
+ } else {
+ Status = GicV3DxeInitialize (ImageHandle, SystemTable);
+ }
+
+ return Status;
+}
diff --git a/ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.h b/ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.h
new file mode 100644
index 0000000000..733984265b
--- /dev/null
+++ b/ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.h
@@ -0,0 +1,142 @@
+/*++
+
+Copyright (c) 2013-2017, ARM Ltd. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+--*/
+
+#ifndef ARM_GIC_DXE_H_
+#define ARM_GIC_DXE_H_
+
+#include <Library/ArmGicLib.h>
+#include <Library/ArmLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/Cpu.h>
+#include <Protocol/HardwareInterrupt.h>
+#include <Protocol/HardwareInterrupt2.h>
+
+extern UINTN mGicNumInterrupts;
+extern HARDWARE_INTERRUPT_HANDLER *gRegisteredInterruptHandlers;
+
+// Common API
+EFI_STATUS
+InstallAndRegisterInterruptService (
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *InterruptProtocol,
+ IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *Interrupt2Protocol,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler,
+ IN EFI_EVENT_NOTIFY ExitBootServicesEvent
+ );
+
+EFI_STATUS
+EFIAPI
+RegisterInterruptSource (
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
+ IN HARDWARE_INTERRUPT_SOURCE Source,
+ IN HARDWARE_INTERRUPT_HANDLER Handler
+ );
+
+// GicV2 API
+EFI_STATUS
+GicV2DxeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+// GicV3 API
+EFI_STATUS
+GicV3DxeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+// Shared code
+
+/**
+ Calculate GICD_ICFGRn base address and corresponding bit
+ field Int_config[1] of the GIC distributor register.
+
+ @param Source Hardware source of the interrupt.
+ @param RegAddress Corresponding GICD_ICFGRn base address.
+ @param Config1Bit Bit number of F Int_config[1] bit in the register.
+
+ @retval EFI_SUCCESS Source interrupt supported.
+ @retval EFI_UNSUPPORTED Source interrupt is not supported.
+**/
+EFI_STATUS
+GicGetDistributorIcfgBaseAndBit (
+ IN HARDWARE_INTERRUPT_SOURCE Source,
+ OUT UINTN *RegAddress,
+ OUT UINTN *Config1Bit
+ );
+
+UINT32
+EFIAPI
+ArmGicGetInterfaceIdentification (
+ IN UINTN GicInterruptInterfaceBase
+ );
+
+VOID
+EFIAPI
+ArmGicDisableDistributor (
+ IN UINTN GicDistributorBase
+ );
+
+UINTN
+EFIAPI
+ArmGicGetMaxNumInterrupts (
+ IN UINTN GicDistributorBase
+ );
+
+UINT32
+EFIAPI
+ArmGicV3GetControlSystemRegisterEnable (
+ VOID
+ );
+
+VOID
+EFIAPI
+ArmGicV3SetControlSystemRegisterEnable (
+ IN UINT32 ControlSystemRegisterEnable
+ );
+
+VOID
+EFIAPI
+ArmGicV3EnableInterruptInterface (
+ VOID
+ );
+
+VOID
+EFIAPI
+ArmGicV3DisableInterruptInterface (
+ VOID
+ );
+
+UINTN
+EFIAPI
+ArmGicV3AcknowledgeInterrupt (
+ VOID
+ );
+
+VOID
+EFIAPI
+ArmGicV3EndOfInterrupt (
+ IN UINTN Source
+ );
+
+VOID
+ArmGicV3SetBinaryPointer (
+ IN UINTN BinaryPoint
+ );
+
+VOID
+ArmGicV3SetPriorityMask (
+ IN UINTN Priority
+ );
+
+#endif // ARM_GIC_DXE_H_
diff --git a/ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.inf b/ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.inf
new file mode 100644
index 0000000000..26cc1b740b
--- /dev/null
+++ b/ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.inf
@@ -0,0 +1,62 @@
+#/** @file
+#
+# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
+# Copyright (c) 2012 - 2017, ARM Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = ArmGicDxe
+ FILE_GUID = DE371F7C-DEC4-4D21-ADF1-593ABCC15882
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InterruptDxeInitialize
+
+[Sources.common]
+ ArmGicDxe.h
+ ArmGicDxe.c
+ ArmGicCommonDxe.c
+
+ GicV2/ArmGicV2Dxe.c
+ GicV3/ArmGicV3Dxe.c
+
+[Sources.ARM]
+ GicV3/Arm/ArmGicV3.S | GCC
+
+[Sources.AARCH64]
+ GicV3/AArch64/ArmGicV3.S
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ ArmPkg/ArmPkg.dec
+
+[LibraryClasses]
+ ArmLib
+ BaseLib
+ UefiLib
+ UefiBootServicesTableLib
+ DebugLib
+ PrintLib
+ MemoryAllocationLib
+ UefiDriverEntryPoint
+ IoLib
+ PcdLib
+ UefiLib
+
+[Protocols]
+ gHardwareInterruptProtocolGuid ## PRODUCES
+ gHardwareInterrupt2ProtocolGuid ## PRODUCES
+ gEfiCpuArchProtocolGuid ## CONSUMES ## NOTIFY
+
+[Pcd.common]
+ gArmTokenSpaceGuid.PcdGicDistributorBase
+ gArmTokenSpaceGuid.PcdGicRedistributorsBase
+ gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase
+
+[Depex]
+ TRUE
diff --git a/ArmPkg/Drivers/ArmGicDxe/ArmGicV2Dxe.inf b/ArmPkg/Drivers/ArmGicDxe/ArmGicV2Dxe.inf
new file mode 100644
index 0000000000..21db74c07a
--- /dev/null
+++ b/ArmPkg/Drivers/ArmGicDxe/ArmGicV2Dxe.inf
@@ -0,0 +1,51 @@
+#/** @file
+#
+# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
+# Copyright (c) 2012 - 2017, ARM Ltd. All rights reserved.<BR>
+# Copyright (c) 2025, Google LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+ INF_VERSION = 1.30
+ BASE_NAME = ArmGicV2Dxe
+ FILE_GUID = 8562bf1e-f816-44fa-82d6-763f3b131e6d
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = GicV2DxeInitialize
+
+[Sources.common]
+ ArmGicCommonDxe.c
+ ArmGicDxe.c
+ ArmGicDxe.h
+ GicV2/ArmGicV2Dxe.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ ArmLib
+ BaseLib
+ DebugLib
+ IoLib
+ PcdLib
+ PrintLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Protocols]
+ gHardwareInterruptProtocolGuid ## PRODUCES
+ gHardwareInterrupt2ProtocolGuid ## PRODUCES
+ gEfiCpuArchProtocolGuid ## CONSUMES ## NOTIFY
+
+[Pcd.common]
+ gArmTokenSpaceGuid.PcdGicDistributorBase
+ gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase
+
+[Depex]
+ TRUE
diff --git a/ArmPkg/Drivers/ArmGicDxe/ArmGicV3Dxe.inf b/ArmPkg/Drivers/ArmGicDxe/ArmGicV3Dxe.inf
new file mode 100644
index 0000000000..9136677084
--- /dev/null
+++ b/ArmPkg/Drivers/ArmGicDxe/ArmGicV3Dxe.inf
@@ -0,0 +1,57 @@
+#/** @file
+#
+# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
+# Copyright (c) 2012 - 2017, ARM Ltd. All rights reserved.<BR>
+# Copyright (c) 2025, Google LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+ INF_VERSION = 1.30
+ BASE_NAME = ArmGicV3Dxe
+ FILE_GUID = 953ff472-9b9e-4058-84cf-227daf89dc82
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = GicV3DxeInitialize
+
+[Sources.common]
+ ArmGicCommonDxe.c
+ ArmGicDxe.c
+ ArmGicDxe.h
+ GicV3/ArmGicV3Dxe.c
+
+[Sources.ARM]
+ GicV3/Arm/ArmGicV3.S | GCC
+
+[Sources.AARCH64]
+ GicV3/AArch64/ArmGicV3.S
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ ArmPkg/ArmPkg.dec
+
+[LibraryClasses]
+ ArmLib
+ BaseLib
+ DebugLib
+ IoLib
+ PcdLib
+ PrintLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Protocols]
+ gHardwareInterruptProtocolGuid ## PRODUCES
+ gHardwareInterrupt2ProtocolGuid ## PRODUCES
+ gEfiCpuArchProtocolGuid ## CONSUMES ## NOTIFY
+
+[Pcd.common]
+ gArmTokenSpaceGuid.PcdGicDistributorBase
+ gArmTokenSpaceGuid.PcdGicRedistributorsBase
+
+[Depex]
+ TRUE
diff --git a/ArmPkg/Drivers/ArmGicDxe/GicV2/ArmGicV2Dxe.c b/ArmPkg/Drivers/ArmGicDxe/GicV2/ArmGicV2Dxe.c
new file mode 100644
index 0000000000..258869b2c7
--- /dev/null
+++ b/ArmPkg/Drivers/ArmGicDxe/GicV2/ArmGicV2Dxe.c
@@ -0,0 +1,593 @@
+/*++
+
+Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>
+Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>
+Portions copyright (c) 2011-2023, Arm Ltd. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+Module Name:
+
+ GicV2/ArmGicV2Dxe.c
+
+Abstract:
+
+ Driver implementing the GicV2 interrupt controller protocol
+
+--*/
+
+#include <Library/ArmGicLib.h>
+
+#include "ArmGicDxe.h"
+
+#define ARM_GIC_DEFAULT_PRIORITY 0x80
+
+// Interrupts from 1020 to 1023 are considered as special interrupts
+// (eg: spurious interrupts)
+#define ARM_GIC_IS_SPECIAL_INTERRUPTS(Interrupt) \
+ (((Interrupt) >= 1020) && ((Interrupt) <= 1023))
+
+extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol;
+extern EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V2Protocol;
+
+STATIC UINTN mGicInterruptInterfaceBase;
+STATIC UINTN mGicDistributorBase;
+
+STATIC
+VOID
+ArmGicEnableInterrupt (
+ IN UINTN GicDistributorBase,
+ IN UINTN GicRedistributorBase,
+ IN UINTN Source
+ )
+{
+ UINT32 RegOffset;
+ UINT8 RegShift;
+
+ // Calculate enable register offset and bit position
+ RegOffset = (UINT32)(Source / 32);
+ RegShift = (UINT8)(Source % 32);
+
+ // Write set-enable register
+ MmioWrite32 (
+ GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset),
+ 1 << RegShift
+ );
+}
+
+STATIC
+VOID
+ArmGicDisableInterrupt (
+ IN UINTN GicDistributorBase,
+ IN UINTN GicRedistributorBase,
+ IN UINTN Source
+ )
+{
+ UINT32 RegOffset;
+ UINT8 RegShift;
+
+ // Calculate enable register offset and bit position
+ RegOffset = (UINT32)(Source / 32);
+ RegShift = (UINT8)(Source % 32);
+
+ // Write clear-enable register
+ MmioWrite32 (
+ GicDistributorBase + ARM_GIC_ICDICER + (4 * RegOffset),
+ 1 << RegShift
+ );
+}
+
+STATIC
+BOOLEAN
+ArmGicIsInterruptEnabled (
+ IN UINTN GicDistributorBase,
+ IN UINTN GicRedistributorBase,
+ IN UINTN Source
+ )
+{
+ UINT32 RegOffset;
+ UINT8 RegShift;
+ UINT32 Interrupts;
+
+ // Calculate enable register offset and bit position
+ RegOffset = (UINT32)(Source / 32);
+ RegShift = (UINT8)(Source % 32);
+
+ Interrupts = MmioRead32 (
+ GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset)
+ );
+
+ return ((Interrupts & (1 << RegShift)) != 0);
+}
+
+/**
+ Enable interrupt source Source.
+
+ @param This Instance pointer for this protocol
+ @param Source Hardware source of the interrupt
+
+ @retval EFI_SUCCESS Source interrupt enabled.
+ @retval EFI_UNSUPPORTED Source interrupt is not supported
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicV2EnableInterruptSource (
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
+ IN HARDWARE_INTERRUPT_SOURCE Source
+ )
+{
+ if (Source >= mGicNumInterrupts) {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ ArmGicEnableInterrupt (mGicDistributorBase, 0, Source);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Disable interrupt source Source.
+
+ @param This Instance pointer for this protocol
+ @param Source Hardware source of the interrupt
+
+ @retval EFI_SUCCESS Source interrupt disabled.
+ @retval EFI_UNSUPPORTED Source interrupt is not supported
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicV2DisableInterruptSource (
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
+ IN HARDWARE_INTERRUPT_SOURCE Source
+ )
+{
+ if (Source >= mGicNumInterrupts) {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ ArmGicDisableInterrupt (mGicDistributorBase, 0, Source);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return current state of interrupt source Source.
+
+ @param This Instance pointer for this protocol
+ @param Source Hardware source of the interrupt
+ @param InterruptState TRUE: source enabled, FALSE: source disabled.
+
+ @retval EFI_SUCCESS InterruptState is valid
+ @retval EFI_UNSUPPORTED Source interrupt is not supported
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicV2GetInterruptSourceState (
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
+ IN HARDWARE_INTERRUPT_SOURCE Source,
+ IN BOOLEAN *InterruptState
+ )
+{
+ if (Source >= mGicNumInterrupts) {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ *InterruptState = ArmGicIsInterruptEnabled (mGicDistributorBase, 0, Source);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+UINTN
+ArmGicV2AcknowledgeInterrupt (
+ IN UINTN GicInterruptInterfaceBase
+ )
+{
+ // Read the Interrupt Acknowledge Register
+ return MmioRead32 (GicInterruptInterfaceBase + ARM_GIC_ICCIAR);
+}
+
+STATIC
+VOID
+ArmGicV2EndOfInterrupt (
+ IN UINTN GicInterruptInterfaceBase,
+ IN UINTN Source
+ )
+{
+ ASSERT (Source <= MAX_UINT32);
+ MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCEIOR, (UINT32)Source);
+}
+
+/**
+ Signal to the hardware that the End Of Interrupt state
+ has been reached.
+
+ @param This Instance pointer for this protocol
+ @param Source Hardware source of the interrupt
+
+ @retval EFI_SUCCESS Source interrupt ended successfully.
+ @retval EFI_UNSUPPORTED Source interrupt is not supported
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicV2EndOfInterrupt (
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
+ IN HARDWARE_INTERRUPT_SOURCE Source
+ )
+{
+ if (Source >= mGicNumInterrupts) {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ ArmGicV2EndOfInterrupt (mGicInterruptInterfaceBase, Source);
+ return EFI_SUCCESS;
+}
+
+/**
+ EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
+
+ @param InterruptType Defines the type of interrupt or exception that
+ occurred on the processor.This parameter is
+ processor architecture specific.
+ @param SystemContext A pointer to the processor context when
+ the interrupt occurred on the processor.
+
+ @return None
+
+**/
+STATIC
+VOID
+EFIAPI
+GicV2IrqInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN GicInterrupt;
+ HARDWARE_INTERRUPT_HANDLER InterruptHandler;
+
+ GicInterrupt = ArmGicV2AcknowledgeInterrupt (mGicInterruptInterfaceBase);
+
+ // Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the
+ // number of interrupt (ie: Spurious interrupt).
+ if ((GicInterrupt & ARM_GIC_ICCIAR_ACKINTID) >= mGicNumInterrupts) {
+ // The special interrupts do not need to be acknowledged
+ return;
+ }
+
+ InterruptHandler = gRegisteredInterruptHandlers[GicInterrupt];
+ if (InterruptHandler != NULL) {
+ // Call the registered interrupt handler.
+ InterruptHandler (GicInterrupt, SystemContext);
+ } else {
+ DEBUG ((DEBUG_ERROR, "Spurious GIC interrupt: 0x%x\n", (UINT32)GicInterrupt));
+ GicV2EndOfInterrupt (&gHardwareInterruptV2Protocol, GicInterrupt);
+ }
+}
+
+// The protocol instance produced by this driver
+EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol = {
+ RegisterInterruptSource,
+ GicV2EnableInterruptSource,
+ GicV2DisableInterruptSource,
+ GicV2GetInterruptSourceState,
+ GicV2EndOfInterrupt
+};
+
+/**
+ Get interrupt trigger type of an interrupt
+
+ @param This Instance pointer for this protocol
+ @param Source Hardware source of the interrupt.
+ @param TriggerType Returns interrupt trigger type.
+
+ @retval EFI_SUCCESS Source interrupt supported.
+ @retval EFI_UNSUPPORTED Source interrupt is not supported.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicV2GetTriggerType (
+ IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This,
+ IN HARDWARE_INTERRUPT_SOURCE Source,
+ OUT EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE *TriggerType
+ )
+{
+ UINTN RegAddress;
+ UINTN Config1Bit;
+ EFI_STATUS Status;
+
+ Status = GicGetDistributorIcfgBaseAndBit (
+ Source,
+ &RegAddress,
+ &Config1Bit
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((MmioRead32 (RegAddress) & (1 << Config1Bit)) == 0) {
+ *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH;
+ } else {
+ *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set interrupt trigger type of an interrupt
+
+ @param This Instance pointer for this protocol
+ @param Source Hardware source of the interrupt.
+ @param TriggerType Interrupt trigger type.
+
+ @retval EFI_SUCCESS Source interrupt supported.
+ @retval EFI_UNSUPPORTED Source interrupt is not supported.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicV2SetTriggerType (
+ IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This,
+ IN HARDWARE_INTERRUPT_SOURCE Source,
+ IN EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE TriggerType
+ )
+{
+ UINTN RegAddress;
+ UINTN Config1Bit;
+ UINT32 Value;
+ EFI_STATUS Status;
+ BOOLEAN SourceEnabled;
+
+ if ( (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)
+ && (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH))
+ {
+ DEBUG ((
+ DEBUG_ERROR,
+ "Invalid interrupt trigger type: %d\n", \
+ TriggerType
+ ));
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = GicGetDistributorIcfgBaseAndBit (
+ Source,
+ &RegAddress,
+ &Config1Bit
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = GicV2GetInterruptSourceState (
+ (EFI_HARDWARE_INTERRUPT_PROTOCOL *)This,
+ Source,
+ &SourceEnabled
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Value = (TriggerType == EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)
+ ? ARM_GIC_ICDICFR_EDGE_TRIGGERED
+ : ARM_GIC_ICDICFR_LEVEL_TRIGGERED;
+
+ // Before changing the value, we must disable the interrupt,
+ // otherwise GIC behavior is UNPREDICTABLE.
+ if (SourceEnabled) {
+ GicV2DisableInterruptSource (
+ (EFI_HARDWARE_INTERRUPT_PROTOCOL *)This,
+ Source
+ );
+ }
+
+ MmioAndThenOr32 (
+ RegAddress,
+ ~(0x1 << Config1Bit),
+ Value << Config1Bit
+ );
+
+ // Restore interrupt state
+ if (SourceEnabled) {
+ GicV2EnableInterruptSource (
+ (EFI_HARDWARE_INTERRUPT_PROTOCOL *)This,
+ Source
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+ArmGicEnableDistributor (
+ IN UINTN GicDistributorBase
+ )
+{
+ MmioWrite32 (GicDistributorBase + ARM_GIC_ICDDCR, 0x1);
+}
+
+EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V2Protocol = {
+ (HARDWARE_INTERRUPT2_REGISTER)RegisterInterruptSource,
+ (HARDWARE_INTERRUPT2_ENABLE)GicV2EnableInterruptSource,
+ (HARDWARE_INTERRUPT2_DISABLE)GicV2DisableInterruptSource,
+ (HARDWARE_INTERRUPT2_INTERRUPT_STATE)GicV2GetInterruptSourceState,
+ (HARDWARE_INTERRUPT2_END_OF_INTERRUPT)GicV2EndOfInterrupt,
+ GicV2GetTriggerType,
+ GicV2SetTriggerType
+};
+
+STATIC
+VOID
+ArmGicV2EnableInterruptInterface (
+ IN UINTN GicInterruptInterfaceBase
+ )
+{
+ /*
+ * Enable the CPU interface in Non-Secure world
+ * Note: The ICCICR register is banked when Security extensions are implemented
+ */
+ MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCICR, 0x1);
+}
+
+STATIC
+VOID
+ArmGicV2DisableInterruptInterface (
+ IN UINTN GicInterruptInterfaceBase
+ )
+{
+ // Disable Gic Interface
+ MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCICR, 0x0);
+ MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCPMR, 0x0);
+}
+
+/**
+ Shutdown our hardware
+
+ DXE Core will disable interrupts and turn off the timer and disable
+ interrupts after all the event handlers have run.
+
+ @param[in] Event The Event that is being processed
+ @param[in] Context Event Context
+**/
+STATIC
+VOID
+EFIAPI
+GicV2ExitBootServicesEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINTN Index;
+ UINTN GicInterrupt;
+
+ // Disable all the interrupts
+ for (Index = 0; Index < mGicNumInterrupts; Index++) {
+ GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol, Index);
+ }
+
+ // Acknowledge all pending interrupts
+ do {
+ GicInterrupt = ArmGicV2AcknowledgeInterrupt (mGicInterruptInterfaceBase);
+
+ if ((GicInterrupt & ARM_GIC_ICCIAR_ACKINTID) < mGicNumInterrupts) {
+ GicV2EndOfInterrupt (&gHardwareInterruptV2Protocol, GicInterrupt);
+ }
+ } while (!ARM_GIC_IS_SPECIAL_INTERRUPTS (GicInterrupt));
+
+ // Disable Gic Interface
+ ArmGicV2DisableInterruptInterface (mGicInterruptInterfaceBase);
+
+ // Disable Gic Distributor
+ ArmGicDisableDistributor (mGicDistributorBase);
+}
+
+/**
+ Initialize the state information for the CPU Architectural Protocol
+
+ @param ImageHandle of the loaded driver
+ @param SystemTable Pointer to the System Table
+
+ @retval EFI_SUCCESS Protocol registered
+ @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
+ @retval EFI_DEVICE_ERROR Hardware problems
+
+**/
+EFI_STATUS
+GicV2DxeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT32 RegOffset;
+ UINT8 RegShift;
+ UINT32 CpuTarget;
+
+ // Make sure the Interrupt Controller Protocol is not already installed in
+ // the system.
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);
+
+ ASSERT (PcdGet64 (PcdGicInterruptInterfaceBase) <= MAX_UINTN);
+ ASSERT (PcdGet64 (PcdGicDistributorBase) <= MAX_UINTN);
+
+ mGicInterruptInterfaceBase = (UINTN)PcdGet64 (PcdGicInterruptInterfaceBase);
+ mGicDistributorBase = (UINTN)PcdGet64 (PcdGicDistributorBase);
+ mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase);
+
+ for (Index = 0; Index < mGicNumInterrupts; Index++) {
+ GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol, Index);
+
+ // Set Priority
+ RegOffset = (UINT32)(Index / 4);
+ RegShift = (UINT8)((Index % 4) * 8);
+ MmioAndThenOr32 (
+ mGicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset),
+ ~(0xff << RegShift),
+ ARM_GIC_DEFAULT_PRIORITY << RegShift
+ );
+ }
+
+ // Targets the interrupts to the Primary Cpu
+
+ // Only Primary CPU will run this code. We can identify our GIC CPU ID by
+ // reading the GIC Distributor Target register. The 8 first GICD_ITARGETSRn
+ // are banked to each connected CPU. These 8 registers hold the CPU targets
+ // fields for interrupts 0-31. More Info in the GIC Specification about
+ // "Interrupt Processor Targets Registers"
+
+ // Read the first Interrupt Processor Targets Register (that corresponds to
+ // the 4 first SGIs)
+ CpuTarget = MmioRead32 (mGicDistributorBase + ARM_GIC_ICDIPTR);
+
+ // The CPU target is a bit field mapping each CPU to a GIC CPU Interface.
+ // This value is 0 when we run on a uniprocessor platform.
+ if (CpuTarget != 0) {
+ // The 8 first Interrupt Processor Targets Registers are read-only
+ for (Index = 8; Index < (mGicNumInterrupts / 4); Index++) {
+ MmioWrite32 (
+ mGicDistributorBase + ARM_GIC_ICDIPTR + (Index * 4),
+ CpuTarget
+ );
+ }
+ }
+
+ // Set binary point reg to 0x7 (no preemption)
+ MmioWrite32 (mGicInterruptInterfaceBase + ARM_GIC_ICCBPR, 0x7);
+
+ // Set priority mask reg to 0xff to allow all priorities through
+ MmioWrite32 (mGicInterruptInterfaceBase + ARM_GIC_ICCPMR, 0xff);
+
+ // Enable gic cpu interface
+ ArmGicV2EnableInterruptInterface (mGicInterruptInterfaceBase);
+
+ // Enable gic distributor
+ ArmGicEnableDistributor (mGicDistributorBase);
+
+ Status = InstallAndRegisterInterruptService (
+ &gHardwareInterruptV2Protocol,
+ &gHardwareInterrupt2V2Protocol,
+ GicV2IrqInterruptHandler,
+ GicV2ExitBootServicesEvent
+ );
+
+ return Status;
+}
diff --git a/ArmPkg/Drivers/ArmGicDxe/GicV3/AArch64/ArmGicV3.S b/ArmPkg/Drivers/ArmGicDxe/GicV3/AArch64/ArmGicV3.S
new file mode 100644
index 0000000000..504f026a1d
--- /dev/null
+++ b/ArmPkg/Drivers/ArmGicDxe/GicV3/AArch64/ArmGicV3.S
@@ -0,0 +1,101 @@
+#
+# Copyright (c) 2014, ARM Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+
+#include <AsmMacroLib.h>
+
+#if !defined(__clang__)
+
+//
+// Clang versions before v3.6 do not support the GNU extension that allows
+// system registers outside of the IMPLEMENTATION DEFINED range to be specified
+// using the generic notation below. However, clang knows these registers by
+// their architectural names, so it has no need for these aliases anyway.
+//
+#define ICC_SRE_EL1 S3_0_C12_C12_5
+#define ICC_SRE_EL2 S3_4_C12_C9_5
+#define ICC_IGRPEN1_EL1 S3_0_C12_C12_7
+#define ICC_EOIR1_EL1 S3_0_C12_C12_1
+#define ICC_IAR1_EL1 S3_0_C12_C12_0
+#define ICC_PMR_EL1 S3_0_C4_C6_0
+#define ICC_BPR1_EL1 S3_0_C12_C12_3
+
+#endif
+
+//UINT32
+//EFIAPI
+//ArmGicV3GetControlSystemRegisterEnable (
+// VOID
+// );
+ASM_FUNC(ArmGicV3GetControlSystemRegisterEnable)
+ EL1_OR_EL2(x1)
+1: mrs x0, ICC_SRE_EL1
+ b 4f
+2: mrs x0, ICC_SRE_EL2
+4: ret
+
+//VOID
+//EFIAPI
+//ArmGicV3SetControlSystemRegisterEnable (
+// IN UINT32 ControlSystemRegisterEnable
+// );
+ASM_FUNC(ArmGicV3SetControlSystemRegisterEnable)
+ EL1_OR_EL2(x1)
+1: msr ICC_SRE_EL1, x0
+ b 4f
+2: msr ICC_SRE_EL2, x0
+4: isb
+ ret
+
+//VOID
+//ArmGicV3EnableInterruptInterface (
+// VOID
+// );
+ASM_FUNC(ArmGicV3EnableInterruptInterface)
+ mov x0, #1
+ msr ICC_IGRPEN1_EL1, x0
+ ret
+
+//VOID
+//ArmGicV3DisableInterruptInterface (
+// VOID
+// );
+ASM_FUNC(ArmGicV3DisableInterruptInterface)
+ mov x0, #0
+ msr ICC_IGRPEN1_EL1, x0
+ ret
+
+//VOID
+//ArmGicV3EndOfInterrupt (
+// IN UINTN InterruptId
+// );
+ASM_FUNC(ArmGicV3EndOfInterrupt)
+ msr ICC_EOIR1_EL1, x0
+ ret
+
+//UINTN
+//ArmGicV3AcknowledgeInterrupt (
+// VOID
+// );
+ASM_FUNC(ArmGicV3AcknowledgeInterrupt)
+ mrs x0, ICC_IAR1_EL1
+ ret
+
+//VOID
+//ArmGicV3SetPriorityMask (
+// IN UINTN Priority
+// );
+ASM_FUNC(ArmGicV3SetPriorityMask)
+ msr ICC_PMR_EL1, x0
+ ret
+
+//VOID
+//ArmGicV3SetBinaryPointer (
+// IN UINTN BinaryPoint
+// );
+ASM_FUNC(ArmGicV3SetBinaryPointer)
+ msr ICC_BPR1_EL1, x0
+ ret
diff --git a/ArmPkg/Drivers/ArmGicDxe/GicV3/Arm/ArmGicV3.S b/ArmPkg/Drivers/ArmGicDxe/GicV3/Arm/ArmGicV3.S
new file mode 100644
index 0000000000..33c0a58464
--- /dev/null
+++ b/ArmPkg/Drivers/ArmGicDxe/GicV3/Arm/ArmGicV3.S
@@ -0,0 +1,80 @@
+#
+# Copyright (c) 2014, ARM Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+
+#include <AsmMacroLib.h>
+#include <Library/ArmLib.h>
+
+// For the moment we assume this will run in SVC mode on ARMv7
+
+//UINT32
+//EFIAPI
+//ArmGicGetControlSystemRegisterEnable (
+// VOID
+// );
+ASM_FUNC(ArmGicV3GetControlSystemRegisterEnable)
+ mrc p15, 0, r0, c12, c12, 5 // ICC_SRE
+ bx lr
+
+//VOID
+//EFIAPI
+//ArmGicSetControlSystemRegisterEnable (
+// IN UINT32 ControlSystemRegisterEnable
+// );
+ASM_FUNC(ArmGicV3SetControlSystemRegisterEnable)
+ mcr p15, 0, r0, c12, c12, 5 // ICC_SRE
+ isb
+ bx lr
+
+//VOID
+//ArmGicV3EnableInterruptInterface (
+// VOID
+// );
+ASM_FUNC(ArmGicV3EnableInterruptInterface)
+ mov r0, #1
+ mcr p15, 0, r0, c12, c12, 7 // ICC_IGRPEN1
+ bx lr
+
+//VOID
+//ArmGicV3DisableInterruptInterface (
+// VOID
+// );
+ASM_FUNC(ArmGicV3DisableInterruptInterface)
+ mov r0, #0
+ mcr p15, 0, r0, c12, c12, 7 // ICC_IGRPEN1
+ bx lr
+
+//VOID
+//ArmGicV3EndOfInterrupt (
+// IN UINTN InterruptId
+// );
+ASM_FUNC(ArmGicV3EndOfInterrupt)
+ mcr p15, 0, r0, c12, c12, 1 //ICC_EOIR1
+ bx lr
+
+//UINTN
+//ArmGicV3AcknowledgeInterrupt (
+// VOID
+// );
+ASM_FUNC(ArmGicV3AcknowledgeInterrupt)
+ mrc p15, 0, r0, c12, c12, 0 //ICC_IAR1
+ bx lr
+
+//VOID
+//ArmGicV3SetPriorityMask (
+// IN UINTN Priority
+// );
+ASM_FUNC(ArmGicV3SetPriorityMask)
+ mcr p15, 0, r0, c4, c6, 0 //ICC_PMR
+ bx lr
+
+//VOID
+//ArmGicV3SetBinaryPointer (
+// IN UINTN BinaryPoint
+// );
+ASM_FUNC(ArmGicV3SetBinaryPointer)
+ mcr p15, 0, r0, c12, c12, 3 //ICC_BPR1
+ bx lr
diff --git a/ArmPkg/Drivers/ArmGicDxe/GicV3/ArmGicV3Dxe.c b/ArmPkg/Drivers/ArmGicDxe/GicV3/ArmGicV3Dxe.c
new file mode 100644
index 0000000000..2b6c0fc9f1
--- /dev/null
+++ b/ArmPkg/Drivers/ArmGicDxe/GicV3/ArmGicV3Dxe.c
@@ -0,0 +1,721 @@
+/** @file
+*
+* Copyright (c) 2011-2023, Arm Limited. All rights reserved.
+*
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#include <Library/ArmGicLib.h>
+
+#include "ArmGicDxe.h"
+
+#define ARM_GIC_DEFAULT_PRIORITY 0x80
+
+// In GICv3, there are 2 x 64KB frames:
+// Redistributor control frame + SGI Control & Generation frame
+#define GIC_V3_REDISTRIBUTOR_GRANULARITY (ARM_GICR_CTLR_FRAME_SIZE \
+ + ARM_GICR_SGI_PPI_FRAME_SIZE)
+
+// In GICv4, there are 2 additional 64KB frames:
+// VLPI frame + Reserved page frame
+#define GIC_V4_REDISTRIBUTOR_GRANULARITY (GIC_V3_REDISTRIBUTOR_GRANULARITY \
+ + ARM_GICR_SGI_VLPI_FRAME_SIZE \
+ + ARM_GICR_SGI_RESERVED_FRAME_SIZE)
+
+#define ISENABLER_ADDRESS(base, offset) ((base) +\
+ ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ISENABLER + 4 * (offset))
+
+#define ICENABLER_ADDRESS(base, offset) ((base) +\
+ ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ICENABLER + 4 * (offset))
+
+#define IPRIORITY_ADDRESS(base, offset) ((base) +\
+ ARM_GICR_CTLR_FRAME_SIZE + ARM_GIC_ICDIPR + 4 * (offset))
+
+extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol;
+extern EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V3Protocol;
+
+STATIC UINTN mGicDistributorBase;
+STATIC UINTN mGicRedistributorsBase;
+
+/**
+ *
+ * Return whether the Source interrupt index refers to a shared interrupt (SPI)
+ */
+STATIC
+BOOLEAN
+SourceIsSpi (
+ IN UINTN Source
+ )
+{
+ return Source >= 32 && Source < 1020;
+}
+
+/**
+ * Return the base address of the GIC redistributor for the current CPU
+ *
+ * @retval Base address of the associated GIC Redistributor
+ */
+STATIC
+UINTN
+GicGetCpuRedistributorBase (
+ IN UINTN GicRedistributorBase
+ )
+{
+ UINTN MpId;
+ UINTN CpuAffinity;
+ UINTN Affinity;
+ UINTN GicCpuRedistributorBase;
+ UINT64 TypeRegister;
+
+ MpId = ArmReadMpidr ();
+ // Define CPU affinity as:
+ // Affinity0[0:8], Affinity1[9:15], Affinity2[16:23], Affinity3[24:32]
+ // whereas Affinity3 is defined at [32:39] in MPIDR
+ CpuAffinity = (MpId & (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2)) |
+ ((MpId & ARM_CORE_AFF3) >> 8);
+
+ GicCpuRedistributorBase = GicRedistributorBase;
+
+ do {
+ TypeRegister = MmioRead64 (GicCpuRedistributorBase + ARM_GICR_TYPER);
+ Affinity = ARM_GICR_TYPER_GET_AFFINITY (TypeRegister);
+ if (Affinity == CpuAffinity) {
+ return GicCpuRedistributorBase;
+ }
+
+ // Move to the next GIC Redistributor frame.
+ // The GIC specification does not forbid a mixture of redistributors
+ // with or without support for virtual LPIs, so we test Virtual LPIs
+ // Support (VLPIS) bit for each frame to decide the granularity.
+ // Note: The assumption here is that the redistributors are adjacent
+ // for all CPUs. However this may not be the case for NUMA systems.
+ GicCpuRedistributorBase += (((ARM_GICR_TYPER_VLPIS & TypeRegister) != 0)
+ ? GIC_V4_REDISTRIBUTOR_GRANULARITY
+ : GIC_V3_REDISTRIBUTOR_GRANULARITY);
+ } while ((TypeRegister & ARM_GICR_TYPER_LAST) == 0);
+
+ // The Redistributor has not been found for the current CPU
+ ASSERT_EFI_ERROR (EFI_NOT_FOUND);
+ return 0;
+}
+
+STATIC
+VOID
+ArmGicSetInterruptPriority (
+ IN UINTN GicDistributorBase,
+ IN UINTN GicRedistributorBase,
+ IN UINTN Source,
+ IN UINT32 Priority
+ )
+{
+ UINT32 RegOffset;
+ UINT8 RegShift;
+ UINTN GicCpuRedistributorBase;
+
+ // Calculate register offset and bit position
+ RegOffset = (UINT32)(Source / 4);
+ RegShift = (UINT8)((Source % 4) * 8);
+
+ if (SourceIsSpi (Source)) {
+ MmioAndThenOr32 (
+ GicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset),
+ ~(0xff << RegShift),
+ Priority << RegShift
+ );
+ } else {
+ GicCpuRedistributorBase = GicGetCpuRedistributorBase (
+ GicRedistributorBase
+ );
+ if (GicCpuRedistributorBase == 0) {
+ return;
+ }
+
+ MmioAndThenOr32 (
+ IPRIORITY_ADDRESS (GicCpuRedistributorBase, RegOffset),
+ ~(0xff << RegShift),
+ Priority << RegShift
+ );
+ }
+}
+
+STATIC
+VOID
+ArmGicEnableInterrupt (
+ IN UINTN GicDistributorBase,
+ IN UINTN GicRedistributorBase,
+ IN UINTN Source
+ )
+{
+ UINT32 RegOffset;
+ UINT8 RegShift;
+ UINTN GicCpuRedistributorBase;
+
+ // Calculate enable register offset and bit position
+ RegOffset = (UINT32)(Source / 32);
+ RegShift = (UINT8)(Source % 32);
+
+ if (SourceIsSpi (Source)) {
+ // Write set-enable register
+ MmioWrite32 (
+ GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset),
+ 1 << RegShift
+ );
+ } else {
+ GicCpuRedistributorBase = GicGetCpuRedistributorBase (
+ GicRedistributorBase
+ );
+ if (GicCpuRedistributorBase == 0) {
+ ASSERT_EFI_ERROR (EFI_NOT_FOUND);
+ return;
+ }
+
+ // Write set-enable register
+ MmioWrite32 (
+ ISENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset),
+ 1 << RegShift
+ );
+ }
+}
+
+STATIC
+VOID
+ArmGicDisableInterrupt (
+ IN UINTN GicDistributorBase,
+ IN UINTN GicRedistributorBase,
+ IN UINTN Source
+ )
+{
+ UINT32 RegOffset;
+ UINT8 RegShift;
+ UINTN GicCpuRedistributorBase;
+
+ // Calculate enable register offset and bit position
+ RegOffset = (UINT32)(Source / 32);
+ RegShift = (UINT8)(Source % 32);
+
+ if (SourceIsSpi (Source)) {
+ // Write clear-enable register
+ MmioWrite32 (
+ GicDistributorBase + ARM_GIC_ICDICER + (4 * RegOffset),
+ 1 << RegShift
+ );
+ } else {
+ GicCpuRedistributorBase = GicGetCpuRedistributorBase (
+ GicRedistributorBase
+ );
+ if (GicCpuRedistributorBase == 0) {
+ return;
+ }
+
+ // Write clear-enable register
+ MmioWrite32 (
+ ICENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset),
+ 1 << RegShift
+ );
+ }
+}
+
+STATIC
+BOOLEAN
+ArmGicIsInterruptEnabled (
+ IN UINTN GicDistributorBase,
+ IN UINTN GicRedistributorBase,
+ IN UINTN Source
+ )
+{
+ UINT32 RegOffset;
+ UINT8 RegShift;
+ UINTN GicCpuRedistributorBase;
+ UINT32 Interrupts;
+
+ // Calculate enable register offset and bit position
+ RegOffset = (UINT32)(Source / 32);
+ RegShift = (UINT8)(Source % 32);
+
+ if (SourceIsSpi (Source)) {
+ Interrupts = MmioRead32 (
+ GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset)
+ );
+ } else {
+ GicCpuRedistributorBase = GicGetCpuRedistributorBase (
+ GicRedistributorBase
+ );
+ if (GicCpuRedistributorBase == 0) {
+ return 0;
+ }
+
+ // Read set-enable register
+ Interrupts = MmioRead32 (
+ ISENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset)
+ );
+ }
+
+ return ((Interrupts & (1 << RegShift)) != 0);
+}
+
+/**
+ Enable interrupt source Source.
+
+ @param This Instance pointer for this protocol
+ @param Source Hardware source of the interrupt
+
+ @retval EFI_SUCCESS Source interrupt enabled.
+ @retval EFI_DEVICE_ERROR Hardware could not be programmed.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicV3EnableInterruptSource (
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
+ IN HARDWARE_INTERRUPT_SOURCE Source
+ )
+{
+ if (Source >= mGicNumInterrupts) {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ ArmGicEnableInterrupt (mGicDistributorBase, mGicRedistributorsBase, Source);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Disable interrupt source Source.
+
+ @param This Instance pointer for this protocol
+ @param Source Hardware source of the interrupt
+
+ @retval EFI_SUCCESS Source interrupt disabled.
+ @retval EFI_DEVICE_ERROR Hardware could not be programmed.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicV3DisableInterruptSource (
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
+ IN HARDWARE_INTERRUPT_SOURCE Source
+ )
+{
+ if (Source >= mGicNumInterrupts) {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ ArmGicDisableInterrupt (mGicDistributorBase, mGicRedistributorsBase, Source);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return current state of interrupt source Source.
+
+ @param This Instance pointer for this protocol
+ @param Source Hardware source of the interrupt
+ @param InterruptState TRUE: source enabled, FALSE: source disabled.
+
+ @retval EFI_SUCCESS InterruptState is valid
+ @retval EFI_DEVICE_ERROR InterruptState is not valid
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicV3GetInterruptSourceState (
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
+ IN HARDWARE_INTERRUPT_SOURCE Source,
+ IN BOOLEAN *InterruptState
+ )
+{
+ if (Source >= mGicNumInterrupts) {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ *InterruptState = ArmGicIsInterruptEnabled (
+ mGicDistributorBase,
+ mGicRedistributorsBase,
+ Source
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Signal to the hardware that the End Of Interrupt state
+ has been reached.
+
+ @param This Instance pointer for this protocol
+ @param Source Hardware source of the interrupt
+
+ @retval EFI_SUCCESS Source interrupt ended successfully.
+ @retval EFI_DEVICE_ERROR Hardware could not be programmed.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicV3EndOfInterrupt (
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
+ IN HARDWARE_INTERRUPT_SOURCE Source
+ )
+{
+ if (Source >= mGicNumInterrupts) {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ ArmGicV3EndOfInterrupt (Source);
+ return EFI_SUCCESS;
+}
+
+/**
+ EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
+
+ @param InterruptType Defines the type of interrupt or exception that
+ occurred on the processor. This parameter is
+ processor architecture specific.
+ @param SystemContext A pointer to the processor context when
+ the interrupt occurred on the processor.
+
+ @return None
+
+**/
+STATIC
+VOID
+EFIAPI
+GicV3IrqInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN GicInterrupt;
+ HARDWARE_INTERRUPT_HANDLER InterruptHandler;
+
+ GicInterrupt = ArmGicV3AcknowledgeInterrupt ();
+
+ // Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the
+ // number of interrupt (ie: Spurious interrupt).
+ if ((GicInterrupt & ARM_GIC_ICCIAR_ACKINTID) >= mGicNumInterrupts) {
+ // The special interrupt do not need to be acknowledge
+ return;
+ }
+
+ InterruptHandler = gRegisteredInterruptHandlers[GicInterrupt];
+ if (InterruptHandler != NULL) {
+ // Call the registered interrupt handler.
+ InterruptHandler (GicInterrupt, SystemContext);
+ } else {
+ DEBUG ((DEBUG_ERROR, "Spurious GIC interrupt: 0x%x\n", (UINT32)GicInterrupt));
+ GicV3EndOfInterrupt (&gHardwareInterruptV3Protocol, GicInterrupt);
+ }
+}
+
+// The protocol instance produced by this driver
+EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol = {
+ RegisterInterruptSource,
+ GicV3EnableInterruptSource,
+ GicV3DisableInterruptSource,
+ GicV3GetInterruptSourceState,
+ GicV3EndOfInterrupt
+};
+
+/**
+ Get interrupt trigger type of an interrupt
+
+ @param This Instance pointer for this protocol
+ @param Source Hardware source of the interrupt.
+ @param TriggerType Returns interrupt trigger type.
+
+ @retval EFI_SUCCESS Source interrupt supported.
+ @retval EFI_UNSUPPORTED Source interrupt is not supported.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicV3GetTriggerType (
+ IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This,
+ IN HARDWARE_INTERRUPT_SOURCE Source,
+ OUT EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE *TriggerType
+ )
+{
+ UINTN RegAddress;
+ UINTN Config1Bit;
+ EFI_STATUS Status;
+
+ Status = GicGetDistributorIcfgBaseAndBit (
+ Source,
+ &RegAddress,
+ &Config1Bit
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((MmioRead32 (RegAddress) & (1 << Config1Bit)) == 0) {
+ *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH;
+ } else {
+ *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set interrupt trigger type of an interrupt
+
+ @param This Instance pointer for this protocol
+ @param Source Hardware source of the interrupt.
+ @param TriggerType Interrupt trigger type.
+
+ @retval EFI_SUCCESS Source interrupt supported.
+ @retval EFI_UNSUPPORTED Source interrupt is not supported.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicV3SetTriggerType (
+ IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This,
+ IN HARDWARE_INTERRUPT_SOURCE Source,
+ IN EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE TriggerType
+ )
+{
+ UINTN RegAddress;
+ UINTN Config1Bit;
+ UINT32 Value;
+ EFI_STATUS Status;
+ BOOLEAN SourceEnabled;
+
+ if ( (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)
+ && (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH))
+ {
+ DEBUG ((
+ DEBUG_ERROR,
+ "Invalid interrupt trigger type: %d\n", \
+ TriggerType
+ ));
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = GicGetDistributorIcfgBaseAndBit (
+ Source,
+ &RegAddress,
+ &Config1Bit
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = GicV3GetInterruptSourceState (
+ (EFI_HARDWARE_INTERRUPT_PROTOCOL *)This,
+ Source,
+ &SourceEnabled
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Value = (TriggerType == EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)
+ ? ARM_GIC_ICDICFR_EDGE_TRIGGERED
+ : ARM_GIC_ICDICFR_LEVEL_TRIGGERED;
+
+ // Before changing the value, we must disable the interrupt,
+ // otherwise GIC behavior is UNPREDICTABLE.
+ if (SourceEnabled) {
+ GicV3DisableInterruptSource (
+ (EFI_HARDWARE_INTERRUPT_PROTOCOL *)This,
+ Source
+ );
+ }
+
+ MmioAndThenOr32 (
+ RegAddress,
+ ~(0x1 << Config1Bit),
+ Value << Config1Bit
+ );
+ // Restore interrupt state
+ if (SourceEnabled) {
+ GicV3EnableInterruptSource (
+ (EFI_HARDWARE_INTERRUPT_PROTOCOL *)This,
+ Source
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+ArmGicEnableDistributor (
+ IN UINTN GicDistributorBase
+ )
+{
+ UINT32 GicDistributorCtl;
+
+ GicDistributorCtl = MmioRead32 (GicDistributorBase + ARM_GIC_ICDDCR);
+ if ((GicDistributorCtl & ARM_GIC_ICDDCR_ARE) != 0) {
+ MmioOr32 (GicDistributorBase + ARM_GIC_ICDDCR, 0x2);
+ } else {
+ MmioOr32 (GicDistributorBase + ARM_GIC_ICDDCR, 0x1);
+ }
+}
+
+EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V3Protocol = {
+ (HARDWARE_INTERRUPT2_REGISTER)RegisterInterruptSource,
+ (HARDWARE_INTERRUPT2_ENABLE)GicV3EnableInterruptSource,
+ (HARDWARE_INTERRUPT2_DISABLE)GicV3DisableInterruptSource,
+ (HARDWARE_INTERRUPT2_INTERRUPT_STATE)GicV3GetInterruptSourceState,
+ (HARDWARE_INTERRUPT2_END_OF_INTERRUPT)GicV3EndOfInterrupt,
+ GicV3GetTriggerType,
+ GicV3SetTriggerType
+};
+
+/**
+ Shutdown our hardware
+
+ DXE Core will disable interrupts and turn off the timer and disable interrupts
+ after all the event handlers have run.
+
+ @param[in] Event The Event that is being processed
+ @param[in] Context Event Context
+**/
+VOID
+EFIAPI
+GicV3ExitBootServicesEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINTN Index;
+
+ // Acknowledge all pending interrupts
+ for (Index = 0; Index < mGicNumInterrupts; Index++) {
+ GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol, Index);
+ }
+
+ // Disable Gic Interface
+ ArmGicV3DisableInterruptInterface ();
+
+ // Disable Gic Distributor
+ ArmGicDisableDistributor (mGicDistributorBase);
+}
+
+/**
+ Initialize the state information for the CPU Architectural Protocol
+
+ @param ImageHandle of the loaded driver
+ @param SystemTable Pointer to the System Table
+
+ @retval EFI_SUCCESS Protocol registered
+ @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
+ @retval EFI_DEVICE_ERROR Hardware problems
+
+**/
+EFI_STATUS
+GicV3DxeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT64 MpId;
+ UINT64 CpuTarget;
+ UINT64 RegValue;
+
+ // Make sure the Interrupt Controller Protocol is not already installed in
+ // the system.
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);
+
+ mGicDistributorBase = (UINTN)PcdGet64 (PcdGicDistributorBase);
+ mGicRedistributorsBase = PcdGet64 (PcdGicRedistributorsBase);
+ mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase);
+
+ RegValue = ArmGicV3GetControlSystemRegisterEnable ();
+ if ((RegValue & ICC_SRE_EL2_SRE) == 0) {
+ ArmGicV3SetControlSystemRegisterEnable (RegValue | ICC_SRE_EL2_SRE);
+ ASSERT ((ArmGicV3GetControlSystemRegisterEnable () & ICC_SRE_EL2_SRE) != 0);
+ }
+
+ // We will be driving this GIC in native v3 mode, i.e., with Affinity
+ // Routing enabled. So ensure that the ARE bit is set.
+ MmioOr32 (mGicDistributorBase + ARM_GIC_ICDDCR, ARM_GIC_ICDDCR_ARE);
+
+ for (Index = 0; Index < mGicNumInterrupts; Index++) {
+ GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol, Index);
+
+ // Set Priority
+ ArmGicSetInterruptPriority (
+ mGicDistributorBase,
+ mGicRedistributorsBase,
+ Index,
+ ARM_GIC_DEFAULT_PRIORITY
+ );
+ }
+
+ // Targets the interrupts to the Primary Cpu
+
+ MpId = ArmReadMpidr ();
+ CpuTarget = MpId &
+ (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2 | ARM_CORE_AFF3);
+
+ if ((MmioRead32 (
+ mGicDistributorBase + ARM_GIC_ICDDCR
+ ) & ARM_GIC_ICDDCR_DS) != 0)
+ {
+ // If the Disable Security (DS) control bit is set, we are dealing with a
+ // GIC that has only one security state. In this case, let's assume we are
+ // executing in non-secure state (which is appropriate for DXE modules)
+ // and that no other firmware has performed any configuration on the GIC.
+ // This means we need to reconfigure all interrupts to non-secure Group 1
+ // first.
+
+ MmioWrite32 (
+ mGicRedistributorsBase + ARM_GICR_CTLR_FRAME_SIZE + ARM_GIC_ICDISR,
+ 0xffffffff
+ );
+
+ for (Index = 32; Index < mGicNumInterrupts; Index += 32) {
+ MmioWrite32 (
+ mGicDistributorBase + ARM_GIC_ICDISR + Index / 8,
+ 0xffffffff
+ );
+ }
+
+ // Route the SPIs to the primary CPU. SPIs start at the INTID 32
+ for (Index = 0; Index < (mGicNumInterrupts - 32); Index++) {
+ MmioWrite64 (
+ mGicDistributorBase + ARM_GICD_IROUTER + (Index * 8),
+ CpuTarget
+ );
+ }
+ }
+
+ // Set binary point reg to 0x7 (no preemption)
+ ArmGicV3SetBinaryPointer (0x7);
+
+ // Set priority mask reg to 0xff to allow all priorities through
+ ArmGicV3SetPriorityMask (0xff);
+
+ // Enable gic cpu interface
+ ArmGicV3EnableInterruptInterface ();
+
+ // Enable gic distributor
+ ArmGicEnableDistributor (mGicDistributorBase);
+
+ Status = InstallAndRegisterInterruptService (
+ &gHardwareInterruptV3Protocol,
+ &gHardwareInterrupt2V3Protocol,
+ GicV3IrqInterruptHandler,
+ GicV3ExitBootServicesEvent
+ );
+
+ return Status;
+}