diff --git a/ArmPkg/Drivers/ArmGic/ArmGicDxe.c b/ArmPkg/Drivers/ArmGic/ArmGicDxe.c index 8be2d6fe5e..2bb064f89a 100644 --- a/ArmPkg/Drivers/ArmGic/ArmGicDxe.c +++ b/ArmPkg/Drivers/ArmGic/ArmGicDxe.c @@ -49,6 +49,8 @@ InterruptDxeInitialize ( if (Revision == ARM_GIC_ARCH_REVISION_2) { Status = GicV2DxeInitialize (ImageHandle, SystemTable); + } else if (Revision == ARM_GIC_ARCH_REVISION_3) { + Status = GicV3DxeInitialize (ImageHandle, SystemTable); } else { Status = EFI_UNSUPPORTED; } diff --git a/ArmPkg/Drivers/ArmGic/ArmGicDxe.h b/ArmPkg/Drivers/ArmGic/ArmGicDxe.h index 43bb88863d..af33aa90b0 100644 --- a/ArmPkg/Drivers/ArmGic/ArmGicDxe.h +++ b/ArmPkg/Drivers/ArmGic/ArmGicDxe.h @@ -55,4 +55,13 @@ GicV2DxeInitialize ( IN EFI_SYSTEM_TABLE *SystemTable ); +// +// GicV3 API +// +EFI_STATUS +GicV3DxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + #endif diff --git a/ArmPkg/Drivers/ArmGic/ArmGicDxe.inf b/ArmPkg/Drivers/ArmGic/ArmGicDxe.inf index 27303e5792..2d46706a76 100644 --- a/ArmPkg/Drivers/ArmGic/ArmGicDxe.inf +++ b/ArmPkg/Drivers/ArmGic/ArmGicDxe.inf @@ -27,6 +27,7 @@ ArmGicCommonDxe.c GicV2/ArmGicV2Dxe.c + GicV3/ArmGicV3Dxe.c [Packages] MdePkg/MdePkg.dec diff --git a/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c b/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c index 3f9e37b5f2..f37e95ede9 100644 --- a/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c +++ b/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c @@ -29,8 +29,8 @@ Abstract: extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol; -UINT32 mGicInterruptInterfaceBase; -UINT32 mGicDistributorBase; +STATIC UINT32 mGicInterruptInterfaceBase; +STATIC UINT32 mGicDistributorBase; /** Enable interrupt source Source. diff --git a/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Lib.h b/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Lib.h index bfe9040c83..6803467346 100644 --- a/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Lib.h +++ b/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Lib.h @@ -15,53 +15,6 @@ #ifndef _ARM_GIC_V2_H_ #define _ARM_GIC_V2_H_ -// -// GIC definitions -// - -// -// GIC Distributor -// -#define ARM_GIC_ICDDCR 0x000 // Distributor Control Register -#define ARM_GIC_ICDICTR 0x004 // Interrupt Controller Type Register -#define ARM_GIC_ICDIIDR 0x008 // Implementer Identification Register - -// Each reg base below repeats for VE_NUM_ARM_GIC_REG_PER_INT_BITS (see GIC spec) -#define ARM_GIC_ICDISR 0x080 // Interrupt Security Registers -#define ARM_GIC_ICDISER 0x100 // Interrupt Set-Enable Registers -#define ARM_GIC_ICDICER 0x180 // Interrupt Clear-Enable Registers -#define ARM_GIC_ICDSPR 0x200 // Interrupt Set-Pending Registers -#define ARM_GIC_ICDICPR 0x280 // Interrupt Clear-Pending Registers -#define ARM_GIC_ICDABR 0x300 // Active Bit Registers - -// Each reg base below repeats for VE_NUM_ARM_GIC_REG_PER_INT_BYTES -#define ARM_GIC_ICDIPR 0x400 // Interrupt Priority Registers - -// Each reg base below repeats for VE_NUM_ARM_GIC_INTERRUPTS -#define ARM_GIC_ICDIPTR 0x800 // Interrupt Processor Target Registers -#define ARM_GIC_ICDICFR 0xC00 // Interrupt Configuration Registers - -#define ARM_GIC_ICDPPISR 0xD00 // PPI Status register - -// just one of these -#define ARM_GIC_ICDSGIR 0xF00 // Software Generated Interrupt Register - -// -// GIC Cpu interface -// -#define ARM_GIC_ICCICR 0x00 // CPU Interface Control Register -#define ARM_GIC_ICCPMR 0x04 // Interrupt Priority Mask Register -#define ARM_GIC_ICCBPR 0x08 // Binary Point Register -#define ARM_GIC_ICCIAR 0x0C // Interrupt Acknowledge Register -#define ARM_GIC_ICCEIOR 0x10 // End Of Interrupt Register -#define ARM_GIC_ICCRPR 0x14 // Running Priority Register -#define ARM_GIC_ICCPIR 0x18 // Highest Pending Interrupt Register -#define ARM_GIC_ICCABPR 0x1C // Aliased Binary Point Register -#define ARM_GIC_ICCIIDR 0xFC // Identification Register - -// Bit Mask for -#define ARM_GIC_ICCIAR_ACKINTID 0x3FF - // Interrupts from 1020 to 1023 are considered as special interrupts (eg: spurious interrupts) #define ARM_GIC_IS_SPECIAL_INTERRUPTS(Interrupt) (((Interrupt) >= 1020) && ((Interrupt) <= 1023)) diff --git a/ArmPkg/Drivers/ArmGic/GicV3/AArch64/ArmGicV3.S b/ArmPkg/Drivers/ArmGic/GicV3/AArch64/ArmGicV3.S index 793e8aa5b3..c30ae76d94 100644 --- a/ArmPkg/Drivers/ArmGic/GicV3/AArch64/ArmGicV3.S +++ b/ArmPkg/Drivers/ArmGic/GicV3/AArch64/ArmGicV3.S @@ -25,8 +25,8 @@ .text .align 2 -GCC_ASM_EXPORT(ArmGicGetControlSystemRegisterEnable) -GCC_ASM_EXPORT(ArmGicSetControlSystemRegisterEnable) +GCC_ASM_EXPORT(ArmGicV3GetControlSystemRegisterEnable) +GCC_ASM_EXPORT(ArmGicV3SetControlSystemRegisterEnable) GCC_ASM_EXPORT(ArmGicV3EnableInterruptInterface) GCC_ASM_EXPORT(ArmGicV3DisableInterruptInterface) GCC_ASM_EXPORT(ArmGicV3EndOfInterrupt) @@ -36,10 +36,10 @@ GCC_ASM_EXPORT(ArmGicV3SetBinaryPointer) //UINT32 //EFIAPI -//ArmGicGetControlSystemRegisterEnable ( +//ArmGicV3GetControlSystemRegisterEnable ( // VOID // ); -ASM_PFX(ArmGicGetControlSystemRegisterEnable): +ASM_PFX(ArmGicV3GetControlSystemRegisterEnable): EL1_OR_EL2_OR_EL3(x1) 1: mrs x0, ICC_SRE_EL1 b 4f @@ -50,10 +50,10 @@ ASM_PFX(ArmGicGetControlSystemRegisterEnable): //VOID //EFIAPI -//ArmGicSetControlSystemRegisterEnable ( +//ArmGicV3SetControlSystemRegisterEnable ( // IN UINT32 ControlSystemRegisterEnable // ); -ASM_PFX(ArmGicSetControlSystemRegisterEnable): +ASM_PFX(ArmGicV3SetControlSystemRegisterEnable): EL1_OR_EL2_OR_EL3(x1) 1: msr ICC_SRE_EL1, x0 b 4f diff --git a/ArmPkg/Drivers/ArmGic/GicV3/Arm/ArmGicV3.S b/ArmPkg/Drivers/ArmGic/GicV3/Arm/ArmGicV3.S index 5c64ec6cd0..af14b91b9c 100644 --- a/ArmPkg/Drivers/ArmGic/GicV3/Arm/ArmGicV3.S +++ b/ArmPkg/Drivers/ArmGic/GicV3/Arm/ArmGicV3.S @@ -19,8 +19,8 @@ .text .align 2 -GCC_ASM_EXPORT(ArmGicGetControlSystemRegisterEnable) -GCC_ASM_EXPORT(ArmGicSetControlSystemRegisterEnable) +GCC_ASM_EXPORT(ArmGicV3GetControlSystemRegisterEnable) +GCC_ASM_EXPORT(ArmGicV3SetControlSystemRegisterEnable) GCC_ASM_EXPORT(ArmGicV3EnableInterruptInterface) GCC_ASM_EXPORT(ArmGicV3DisableInterruptInterface) GCC_ASM_EXPORT(ArmGicV3EndOfInterrupt) @@ -33,7 +33,7 @@ GCC_ASM_EXPORT(ArmGicV3SetBinaryPointer) //ArmGicGetControlSystemRegisterEnable ( // VOID // ); -ASM_PFX(ArmGicGetControlSystemRegisterEnable): +ASM_PFX(ArmGicV3GetControlSystemRegisterEnable): mrc p15, 0, r0, c12, c12, 5 // ICC_SRE bx lr @@ -42,7 +42,7 @@ ASM_PFX(ArmGicGetControlSystemRegisterEnable): //ArmGicSetControlSystemRegisterEnable ( // IN UINT32 ControlSystemRegisterEnable // ); -ASM_PFX(ArmGicSetControlSystemRegisterEnable): +ASM_PFX(ArmGicV3SetControlSystemRegisterEnable): mcr p15, 0, r0, c12, c12, 5 // ICC_SRE isb bx lr diff --git a/ArmPkg/Drivers/ArmGic/GicV3/Arm/ArmGicV3.asm b/ArmPkg/Drivers/ArmGic/GicV3/Arm/ArmGicV3.asm index 08d9d4d9f0..92c3236b25 100644 --- a/ArmPkg/Drivers/ArmGic/GicV3/Arm/ArmGicV3.asm +++ b/ArmPkg/Drivers/ArmGic/GicV3/Arm/ArmGicV3.asm @@ -13,8 +13,8 @@ // For the moment we assume this will run in SVC mode on ARMv7 - EXPORT ArmGicGetControlSystemRegisterEnable - EXPORT ArmGicSetControlSystemRegisterEnable + EXPORT ArmGicV3GetControlSystemRegisterEnable + EXPORT ArmGicV3SetControlSystemRegisterEnable EXPORT ArmGicV3EnableInterruptInterface EXPORT ArmGicV3DisableInterruptInterface EXPORT ArmGicV3EndOfInterrupt @@ -29,7 +29,7 @@ //ArmGicGetControlSystemRegisterEnable ( // VOID // ); -ArmGicGetControlSystemRegisterEnable +ArmGicV3GetControlSystemRegisterEnable mrc p15, 0, r0, c12, c12, 5 // ICC_SRE bx lr @@ -38,7 +38,7 @@ ArmGicGetControlSystemRegisterEnable //ArmGicSetControlSystemRegisterEnable ( // IN UINT32 ControlSystemRegisterEnable // ); -ArmGicSetControlSystemRegisterEnable +ArmGicV3SetControlSystemRegisterEnable mcr p15, 0, r0, c12, c12, 5 // ICC_SRE isb bx lr diff --git a/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c b/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c new file mode 100644 index 0000000000..8042f718f5 --- /dev/null +++ b/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c @@ -0,0 +1,308 @@ +/** @file +* +* Copyright (c) 2011-2014, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include "ArmGicDxe.h" +#include "GicV3/ArmGicV3Lib.h" + +#define ARM_GIC_DEFAULT_PRIORITY 0x80 + +extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol; + +STATIC UINTN mGicDistributorBase; + +/** + 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. + +**/ +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, 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. + +**/ +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, 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 + +**/ +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, 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 EOI'ed. + @retval EFI_DEVICE_ERROR Hardware could not be programmed. + +**/ +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 + +**/ +VOID +EFIAPI +GicV3IrqInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINT32 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 ((EFI_D_ERROR, "Spurious GIC interrupt: 0x%x\n", GicInterrupt)); + } + + GicV3EndOfInterrupt (&gHardwareInterruptV3Protocol, GicInterrupt); +} + +// +// The protocol instance produced by this driver +// +EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol = { + RegisterInterruptSource, + GicV3EnableInterruptSource, + GicV3DisableInterruptSource, + GicV3GetInterruptSourceState, + GicV3EndOfInterrupt +}; + +/** + 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); + } + + for (Index = 0; Index < mGicNumInterrupts; Index++) { + GicV3EndOfInterrupt (&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; + UINT32 RegOffset; + UINTN RegShift; + UINT32 CpuTarget; + + // Make sure the Interrupt Controller Protocol is not already installed in the system. + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid); + + mGicDistributorBase = PcdGet32 (PcdGicDistributorBase); + mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase); + + for (Index = 0; Index < mGicNumInterrupts; Index++) { + GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol, Index); + + // Set Priority + RegOffset = Index / 4; + RegShift = (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); + } + } + + // Make sure System Register access is enabled (SRE). This depends on the + // lower levels giving us permission, otherwise we will cause an exception + // here. + // 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. + ArmGicV3SetControlSystemRegisterEnable (ArmGicV3GetControlSystemRegisterEnable () | ICC_SRE_EL2_SRE); + + // 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, GicV3IrqInterruptHandler, GicV3ExitBootServicesEvent); + + return Status; +} diff --git a/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Lib.h b/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Lib.h index 70731c3483..ac4bb2f77f 100644 --- a/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Lib.h +++ b/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Lib.h @@ -15,6 +15,20 @@ #ifndef _ARM_GIC_V3_H_ #define _ARM_GIC_V3_H_ +#define ICC_SRE_EL2_SRE (1 << 0) + +UINT32 +EFIAPI +ArmGicV3GetControlSystemRegisterEnable ( + VOID + ); + +VOID +EFIAPI +ArmGicV3SetControlSystemRegisterEnable ( + IN UINT32 ControlSystemRegisterEnable + ); + VOID EFIAPI ArmGicV3EnableInterruptInterface ( diff --git a/ArmPkg/Include/Library/ArmGicLib.h b/ArmPkg/Include/Library/ArmGicLib.h index 4f0164ab88..d00159b356 100644 --- a/ArmPkg/Include/Library/ArmGicLib.h +++ b/ArmPkg/Include/Library/ArmGicLib.h @@ -80,6 +80,9 @@ typedef enum { #define ARM_GIC_ICCIIDR_GET_REVISION(IccIidr) (((IccIidr) >> 12) & 0xF) #define ARM_GIC_ICCIIDR_GET_IMPLEMENTER(IccIidr) ((IccIidr) & 0xFFF) +// Bit Mask for +#define ARM_GIC_ICCIAR_ACKINTID 0x3FF + ARM_GIC_ARCH_REVISION EFIAPI ArmGicGetSupportedArchRevision (