From 81e2cd329efc0ed240234f475426cb81bf5d9c84 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 17 Jan 2025 09:59:02 +0100 Subject: ArmPkg/ArmGic: Rename directory to ArmGicDxe Now that ArmPkg/Drivers/ArmGic no longer carries a combination of libraries and DXE drivers, rename the directory to the more idiomatic ArmPkg/Drivers/ArmGicDxe Continuous-integration-options: PatchCheck.ignore-multi-package Signed-off-by: Ard Biesheuvel --- ArmPkg/ArmPkg.dsc | 6 +- ArmPkg/Drivers/ArmGic/ArmGicCommonDxe.c | 244 -------- ArmPkg/Drivers/ArmGic/ArmGicDxe.c | 84 --- ArmPkg/Drivers/ArmGic/ArmGicDxe.h | 142 ----- ArmPkg/Drivers/ArmGic/ArmGicDxe.inf | 62 -- ArmPkg/Drivers/ArmGic/ArmGicV2Dxe.inf | 51 -- ArmPkg/Drivers/ArmGic/ArmGicV3Dxe.inf | 57 -- ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c | 593 ------------------ ArmPkg/Drivers/ArmGic/GicV3/AArch64/ArmGicV3.S | 101 --- ArmPkg/Drivers/ArmGic/GicV3/Arm/ArmGicV3.S | 80 --- ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c | 721 ---------------------- ArmPkg/Drivers/ArmGicDxe/ArmGicCommonDxe.c | 244 ++++++++ ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.c | 84 +++ ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.h | 142 +++++ ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.inf | 62 ++ ArmPkg/Drivers/ArmGicDxe/ArmGicV2Dxe.inf | 51 ++ ArmPkg/Drivers/ArmGicDxe/ArmGicV3Dxe.inf | 57 ++ ArmPkg/Drivers/ArmGicDxe/GicV2/ArmGicV2Dxe.c | 593 ++++++++++++++++++ ArmPkg/Drivers/ArmGicDxe/GicV3/AArch64/ArmGicV3.S | 101 +++ ArmPkg/Drivers/ArmGicDxe/GicV3/Arm/ArmGicV3.S | 80 +++ ArmPkg/Drivers/ArmGicDxe/GicV3/ArmGicV3Dxe.c | 721 ++++++++++++++++++++++ 21 files changed, 2138 insertions(+), 2138 deletions(-) delete mode 100644 ArmPkg/Drivers/ArmGic/ArmGicCommonDxe.c delete mode 100644 ArmPkg/Drivers/ArmGic/ArmGicDxe.c delete mode 100644 ArmPkg/Drivers/ArmGic/ArmGicDxe.h delete mode 100644 ArmPkg/Drivers/ArmGic/ArmGicDxe.inf delete mode 100644 ArmPkg/Drivers/ArmGic/ArmGicV2Dxe.inf delete mode 100644 ArmPkg/Drivers/ArmGic/ArmGicV3Dxe.inf delete mode 100644 ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c delete mode 100644 ArmPkg/Drivers/ArmGic/GicV3/AArch64/ArmGicV3.S delete mode 100644 ArmPkg/Drivers/ArmGic/GicV3/Arm/ArmGicV3.S delete mode 100644 ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c create mode 100644 ArmPkg/Drivers/ArmGicDxe/ArmGicCommonDxe.c create mode 100644 ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.c create mode 100644 ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.h create mode 100644 ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.inf create mode 100644 ArmPkg/Drivers/ArmGicDxe/ArmGicV2Dxe.inf create mode 100644 ArmPkg/Drivers/ArmGicDxe/ArmGicV3Dxe.inf create mode 100644 ArmPkg/Drivers/ArmGicDxe/GicV2/ArmGicV2Dxe.c create mode 100644 ArmPkg/Drivers/ArmGicDxe/GicV3/AArch64/ArmGicV3.S create mode 100644 ArmPkg/Drivers/ArmGicDxe/GicV3/Arm/ArmGicV3.S create mode 100644 ArmPkg/Drivers/ArmGicDxe/GicV3/ArmGicV3Dxe.c (limited to 'ArmPkg') diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc index ecfbada222..b8817b4d7e 100644 --- a/ArmPkg/ArmPkg.dsc +++ b/ArmPkg/ArmPkg.dsc @@ -124,9 +124,9 @@ ArmPkg/Drivers/CpuDxe/CpuDxe.inf ArmPkg/Drivers/CpuPei/CpuPei.inf - ArmPkg/Drivers/ArmGic/ArmGicDxe.inf - ArmPkg/Drivers/ArmGic/ArmGicV2Dxe.inf - ArmPkg/Drivers/ArmGic/ArmGicV3Dxe.inf + ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.inf + ArmPkg/Drivers/ArmGicDxe/ArmGicV2Dxe.inf + ArmPkg/Drivers/ArmGicDxe/ArmGicV3Dxe.inf ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.inf ArmPkg/Drivers/TimerDxe/TimerDxe.inf diff --git a/ArmPkg/Drivers/ArmGic/ArmGicCommonDxe.c b/ArmPkg/Drivers/ArmGic/ArmGicCommonDxe.c deleted file mode 100644 index 8e845511d6..0000000000 --- a/ArmPkg/Drivers/ArmGic/ArmGicCommonDxe.c +++ /dev/null @@ -1,244 +0,0 @@ -/*++ - -Copyright (c) 2013-2023, Arm Ltd. All rights reserved.
- -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/ArmGic/ArmGicDxe.c b/ArmPkg/Drivers/ArmGic/ArmGicDxe.c deleted file mode 100644 index b0da48e3a3..0000000000 --- a/ArmPkg/Drivers/ArmGic/ArmGicDxe.c +++ /dev/null @@ -1,84 +0,0 @@ -/*++ - -Copyright (c) 2013-2014, ARM Ltd. All rights reserved.
- -SPDX-License-Identifier: BSD-2-Clause-Patent - -Module Name: - - ArmGicDxe.c - -Abstract: - - Driver implementing the GIC interrupt controller protocol - ---*/ - -#include - -#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/ArmGic/ArmGicDxe.h b/ArmPkg/Drivers/ArmGic/ArmGicDxe.h deleted file mode 100644 index 733984265b..0000000000 --- a/ArmPkg/Drivers/ArmGic/ArmGicDxe.h +++ /dev/null @@ -1,142 +0,0 @@ -/*++ - -Copyright (c) 2013-2017, ARM Ltd. All rights reserved.
- -SPDX-License-Identifier: BSD-2-Clause-Patent - ---*/ - -#ifndef ARM_GIC_DXE_H_ -#define ARM_GIC_DXE_H_ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -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/ArmGic/ArmGicDxe.inf b/ArmPkg/Drivers/ArmGic/ArmGicDxe.inf deleted file mode 100644 index 26cc1b740b..0000000000 --- a/ArmPkg/Drivers/ArmGic/ArmGicDxe.inf +++ /dev/null @@ -1,62 +0,0 @@ -#/** @file -# -# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
-# Copyright (c) 2012 - 2017, ARM Ltd. All rights reserved.
-# -# 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/ArmGic/ArmGicV2Dxe.inf b/ArmPkg/Drivers/ArmGic/ArmGicV2Dxe.inf deleted file mode 100644 index 21db74c07a..0000000000 --- a/ArmPkg/Drivers/ArmGic/ArmGicV2Dxe.inf +++ /dev/null @@ -1,51 +0,0 @@ -#/** @file -# -# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
-# Copyright (c) 2012 - 2017, ARM Ltd. All rights reserved.
-# Copyright (c) 2025, Google LLC. All rights reserved.
-# -# 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/ArmGic/ArmGicV3Dxe.inf b/ArmPkg/Drivers/ArmGic/ArmGicV3Dxe.inf deleted file mode 100644 index 9136677084..0000000000 --- a/ArmPkg/Drivers/ArmGic/ArmGicV3Dxe.inf +++ /dev/null @@ -1,57 +0,0 @@ -#/** @file -# -# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
-# Copyright (c) 2012 - 2017, ARM Ltd. All rights reserved.
-# Copyright (c) 2025, Google LLC. All rights reserved.
-# -# 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/ArmGic/GicV2/ArmGicV2Dxe.c b/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c deleted file mode 100644 index 258869b2c7..0000000000 --- a/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c +++ /dev/null @@ -1,593 +0,0 @@ -/*++ - -Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.
-Portions copyright (c) 2010, Apple Inc. All rights reserved.
-Portions copyright (c) 2011-2023, Arm Ltd. All rights reserved.
- -SPDX-License-Identifier: BSD-2-Clause-Patent - -Module Name: - - GicV2/ArmGicV2Dxe.c - -Abstract: - - Driver implementing the GicV2 interrupt controller protocol - ---*/ - -#include - -#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/ArmGic/GicV3/AArch64/ArmGicV3.S b/ArmPkg/Drivers/ArmGic/GicV3/AArch64/ArmGicV3.S deleted file mode 100644 index 504f026a1d..0000000000 --- a/ArmPkg/Drivers/ArmGic/GicV3/AArch64/ArmGicV3.S +++ /dev/null @@ -1,101 +0,0 @@ -# -# Copyright (c) 2014, ARM Limited. All rights reserved. -# -# SPDX-License-Identifier: BSD-2-Clause-Patent -# -# - -#include - -#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/ArmGic/GicV3/Arm/ArmGicV3.S b/ArmPkg/Drivers/ArmGic/GicV3/Arm/ArmGicV3.S deleted file mode 100644 index 33c0a58464..0000000000 --- a/ArmPkg/Drivers/ArmGic/GicV3/Arm/ArmGicV3.S +++ /dev/null @@ -1,80 +0,0 @@ -# -# Copyright (c) 2014, ARM Limited. All rights reserved. -# -# SPDX-License-Identifier: BSD-2-Clause-Patent -# -# - -#include -#include - -// 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/ArmGic/GicV3/ArmGicV3Dxe.c b/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c deleted file mode 100644 index 2b6c0fc9f1..0000000000 --- a/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c +++ /dev/null @@ -1,721 +0,0 @@ -/** @file -* -* Copyright (c) 2011-2023, Arm Limited. All rights reserved. -* -* SPDX-License-Identifier: BSD-2-Clause-Patent -* -**/ - -#include - -#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; -} 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.
+ +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.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +Module Name: + + ArmGicDxe.c + +Abstract: + + Driver implementing the GIC interrupt controller protocol + +--*/ + +#include + +#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.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +--*/ + +#ifndef ARM_GIC_DXE_H_ +#define ARM_GIC_DXE_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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.
+# Copyright (c) 2012 - 2017, ARM Ltd. All rights reserved.
+# +# 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.
+# Copyright (c) 2012 - 2017, ARM Ltd. All rights reserved.
+# Copyright (c) 2025, Google LLC. All rights reserved.
+# +# 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.
+# Copyright (c) 2012 - 2017, ARM Ltd. All rights reserved.
+# Copyright (c) 2025, Google LLC. All rights reserved.
+# +# 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.
+Portions copyright (c) 2010, Apple Inc. All rights reserved.
+Portions copyright (c) 2011-2023, Arm Ltd. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +Module Name: + + GicV2/ArmGicV2Dxe.c + +Abstract: + + Driver implementing the GicV2 interrupt controller protocol + +--*/ + +#include + +#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 + +#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 +#include + +// 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 + +#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; +} -- cgit