ArmPkg/ArmGic: Added GicV3 support to ArmGicDxe

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Olivier Martin <olivier.martin@arm.com>



git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16234 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Olivier Martin
2014-10-27 10:30:53 +00:00
committed by oliviermartin
parent d71338597e
commit 5f81082e38
11 changed files with 353 additions and 63 deletions

View File

@@ -49,6 +49,8 @@ InterruptDxeInitialize (
if (Revision == ARM_GIC_ARCH_REVISION_2) { if (Revision == ARM_GIC_ARCH_REVISION_2) {
Status = GicV2DxeInitialize (ImageHandle, SystemTable); Status = GicV2DxeInitialize (ImageHandle, SystemTable);
} else if (Revision == ARM_GIC_ARCH_REVISION_3) {
Status = GicV3DxeInitialize (ImageHandle, SystemTable);
} else { } else {
Status = EFI_UNSUPPORTED; Status = EFI_UNSUPPORTED;
} }

View File

@@ -55,4 +55,13 @@ GicV2DxeInitialize (
IN EFI_SYSTEM_TABLE *SystemTable IN EFI_SYSTEM_TABLE *SystemTable
); );
//
// GicV3 API
//
EFI_STATUS
GicV3DxeInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
);
#endif #endif

View File

@@ -27,6 +27,7 @@
ArmGicCommonDxe.c ArmGicCommonDxe.c
GicV2/ArmGicV2Dxe.c GicV2/ArmGicV2Dxe.c
GicV3/ArmGicV3Dxe.c
[Packages] [Packages]
MdePkg/MdePkg.dec MdePkg/MdePkg.dec

View File

@@ -29,8 +29,8 @@ Abstract:
extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol; extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol;
UINT32 mGicInterruptInterfaceBase; STATIC UINT32 mGicInterruptInterfaceBase;
UINT32 mGicDistributorBase; STATIC UINT32 mGicDistributorBase;
/** /**
Enable interrupt source Source. Enable interrupt source Source.

View File

@@ -15,53 +15,6 @@
#ifndef _ARM_GIC_V2_H_ #ifndef _ARM_GIC_V2_H_
#define _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) // Interrupts from 1020 to 1023 are considered as special interrupts (eg: spurious interrupts)
#define ARM_GIC_IS_SPECIAL_INTERRUPTS(Interrupt) (((Interrupt) >= 1020) && ((Interrupt) <= 1023)) #define ARM_GIC_IS_SPECIAL_INTERRUPTS(Interrupt) (((Interrupt) >= 1020) && ((Interrupt) <= 1023))

View File

@@ -25,8 +25,8 @@
.text .text
.align 2 .align 2
GCC_ASM_EXPORT(ArmGicGetControlSystemRegisterEnable) GCC_ASM_EXPORT(ArmGicV3GetControlSystemRegisterEnable)
GCC_ASM_EXPORT(ArmGicSetControlSystemRegisterEnable) GCC_ASM_EXPORT(ArmGicV3SetControlSystemRegisterEnable)
GCC_ASM_EXPORT(ArmGicV3EnableInterruptInterface) GCC_ASM_EXPORT(ArmGicV3EnableInterruptInterface)
GCC_ASM_EXPORT(ArmGicV3DisableInterruptInterface) GCC_ASM_EXPORT(ArmGicV3DisableInterruptInterface)
GCC_ASM_EXPORT(ArmGicV3EndOfInterrupt) GCC_ASM_EXPORT(ArmGicV3EndOfInterrupt)
@@ -36,10 +36,10 @@ GCC_ASM_EXPORT(ArmGicV3SetBinaryPointer)
//UINT32 //UINT32
//EFIAPI //EFIAPI
//ArmGicGetControlSystemRegisterEnable ( //ArmGicV3GetControlSystemRegisterEnable (
// VOID // VOID
// ); // );
ASM_PFX(ArmGicGetControlSystemRegisterEnable): ASM_PFX(ArmGicV3GetControlSystemRegisterEnable):
EL1_OR_EL2_OR_EL3(x1) EL1_OR_EL2_OR_EL3(x1)
1: mrs x0, ICC_SRE_EL1 1: mrs x0, ICC_SRE_EL1
b 4f b 4f
@@ -50,10 +50,10 @@ ASM_PFX(ArmGicGetControlSystemRegisterEnable):
//VOID //VOID
//EFIAPI //EFIAPI
//ArmGicSetControlSystemRegisterEnable ( //ArmGicV3SetControlSystemRegisterEnable (
// IN UINT32 ControlSystemRegisterEnable // IN UINT32 ControlSystemRegisterEnable
// ); // );
ASM_PFX(ArmGicSetControlSystemRegisterEnable): ASM_PFX(ArmGicV3SetControlSystemRegisterEnable):
EL1_OR_EL2_OR_EL3(x1) EL1_OR_EL2_OR_EL3(x1)
1: msr ICC_SRE_EL1, x0 1: msr ICC_SRE_EL1, x0
b 4f b 4f

View File

@@ -19,8 +19,8 @@
.text .text
.align 2 .align 2
GCC_ASM_EXPORT(ArmGicGetControlSystemRegisterEnable) GCC_ASM_EXPORT(ArmGicV3GetControlSystemRegisterEnable)
GCC_ASM_EXPORT(ArmGicSetControlSystemRegisterEnable) GCC_ASM_EXPORT(ArmGicV3SetControlSystemRegisterEnable)
GCC_ASM_EXPORT(ArmGicV3EnableInterruptInterface) GCC_ASM_EXPORT(ArmGicV3EnableInterruptInterface)
GCC_ASM_EXPORT(ArmGicV3DisableInterruptInterface) GCC_ASM_EXPORT(ArmGicV3DisableInterruptInterface)
GCC_ASM_EXPORT(ArmGicV3EndOfInterrupt) GCC_ASM_EXPORT(ArmGicV3EndOfInterrupt)
@@ -33,7 +33,7 @@ GCC_ASM_EXPORT(ArmGicV3SetBinaryPointer)
//ArmGicGetControlSystemRegisterEnable ( //ArmGicGetControlSystemRegisterEnable (
// VOID // VOID
// ); // );
ASM_PFX(ArmGicGetControlSystemRegisterEnable): ASM_PFX(ArmGicV3GetControlSystemRegisterEnable):
mrc p15, 0, r0, c12, c12, 5 // ICC_SRE mrc p15, 0, r0, c12, c12, 5 // ICC_SRE
bx lr bx lr
@@ -42,7 +42,7 @@ ASM_PFX(ArmGicGetControlSystemRegisterEnable):
//ArmGicSetControlSystemRegisterEnable ( //ArmGicSetControlSystemRegisterEnable (
// IN UINT32 ControlSystemRegisterEnable // IN UINT32 ControlSystemRegisterEnable
// ); // );
ASM_PFX(ArmGicSetControlSystemRegisterEnable): ASM_PFX(ArmGicV3SetControlSystemRegisterEnable):
mcr p15, 0, r0, c12, c12, 5 // ICC_SRE mcr p15, 0, r0, c12, c12, 5 // ICC_SRE
isb isb
bx lr bx lr

View File

@@ -13,8 +13,8 @@
// For the moment we assume this will run in SVC mode on ARMv7 // For the moment we assume this will run in SVC mode on ARMv7
EXPORT ArmGicGetControlSystemRegisterEnable EXPORT ArmGicV3GetControlSystemRegisterEnable
EXPORT ArmGicSetControlSystemRegisterEnable EXPORT ArmGicV3SetControlSystemRegisterEnable
EXPORT ArmGicV3EnableInterruptInterface EXPORT ArmGicV3EnableInterruptInterface
EXPORT ArmGicV3DisableInterruptInterface EXPORT ArmGicV3DisableInterruptInterface
EXPORT ArmGicV3EndOfInterrupt EXPORT ArmGicV3EndOfInterrupt
@@ -29,7 +29,7 @@
//ArmGicGetControlSystemRegisterEnable ( //ArmGicGetControlSystemRegisterEnable (
// VOID // VOID
// ); // );
ArmGicGetControlSystemRegisterEnable ArmGicV3GetControlSystemRegisterEnable
mrc p15, 0, r0, c12, c12, 5 // ICC_SRE mrc p15, 0, r0, c12, c12, 5 // ICC_SRE
bx lr bx lr
@@ -38,7 +38,7 @@ ArmGicGetControlSystemRegisterEnable
//ArmGicSetControlSystemRegisterEnable ( //ArmGicSetControlSystemRegisterEnable (
// IN UINT32 ControlSystemRegisterEnable // IN UINT32 ControlSystemRegisterEnable
// ); // );
ArmGicSetControlSystemRegisterEnable ArmGicV3SetControlSystemRegisterEnable
mcr p15, 0, r0, c12, c12, 5 // ICC_SRE mcr p15, 0, r0, c12, c12, 5 // ICC_SRE
isb isb
bx lr bx lr

View File

@@ -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;
}

View File

@@ -15,6 +15,20 @@
#ifndef _ARM_GIC_V3_H_ #ifndef _ARM_GIC_V3_H_
#define _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 VOID
EFIAPI EFIAPI
ArmGicV3EnableInterruptInterface ( ArmGicV3EnableInterruptInterface (

View File

@@ -80,6 +80,9 @@ typedef enum {
#define ARM_GIC_ICCIIDR_GET_REVISION(IccIidr) (((IccIidr) >> 12) & 0xF) #define ARM_GIC_ICCIIDR_GET_REVISION(IccIidr) (((IccIidr) >> 12) & 0xF)
#define ARM_GIC_ICCIIDR_GET_IMPLEMENTER(IccIidr) ((IccIidr) & 0xFFF) #define ARM_GIC_ICCIIDR_GET_IMPLEMENTER(IccIidr) ((IccIidr) & 0xFFF)
// Bit Mask for
#define ARM_GIC_ICCIAR_ACKINTID 0x3FF
ARM_GIC_ARCH_REVISION ARM_GIC_ARCH_REVISION
EFIAPI EFIAPI
ArmGicGetSupportedArchRevision ( ArmGicGetSupportedArchRevision (