ArmPkg/Gic: force GIC driver to run before CPU arch protocol driver

Currently, the GIC driver has a static dependency on the CPU arch protocol
driver, so it can register its IRQ handler at init time. This means there
is a window between dispatch of the CPU driver and dispatch of the GIC
driver where any unexpected GIC state may trigger an interrupt which we
are not set up to handle yet. Note that this is even the case if we enter
UEFI with interrupts disabled at the CPU, given that any TPL manipulation
involving TPL_HIGH_LEVEL will unconditionally enable IRQs at the CPU side
regardless of whether they were enabled to begin with (but only as soon as
the CPU arch protocol is actually installed)

So let's reorder the GIC driver with the CPU driver, and let it run its
initialization that puts the GIC into a known state before enabling
interrupts. Move its installation of its IRQ handler to a protocol notify
callback on the CPU arch protocol so that it runs as soon as it becomes
available.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
Tested-by: Marc Zyngier <marc.zyngier@arm.com>
This commit is contained in:
Ard Biesheuvel 2018-02-06 11:58:12 +00:00
parent e537d87817
commit 61a7b0ec63
5 changed files with 54 additions and 25 deletions

View File

@ -48,6 +48,8 @@
# Include/Guid/ArmMpCoreInfo.h # Include/Guid/ArmMpCoreInfo.h
gArmMpCoreInfoGuid = { 0xa4ee0728, 0xe5d7, 0x4ac5, {0xb2, 0x1e, 0x65, 0x8e, 0xd8, 0x57, 0xe8, 0x34} } gArmMpCoreInfoGuid = { 0xa4ee0728, 0xe5d7, 0x4ac5, {0xb2, 0x1e, 0x65, 0x8e, 0xd8, 0x57, 0xe8, 0x34} }
gArmGicDxeFileGuid = { 0xde371f7c, 0xdec4, 0x4d21, { 0xad, 0xf1, 0x59, 0x3a, 0xbc, 0xc1, 0x58, 0x82 } }
[Ppis] [Ppis]
## Include/Ppi/ArmMpCoreInfo.h ## Include/Ppi/ArmMpCoreInfo.h
gArmMpCoreInfoPpiGuid = { 0x6847cc74, 0xe9ec, 0x4f8f, {0xa2, 0x9d, 0xab, 0x44, 0xe7, 0x54, 0xa8, 0xfc} } gArmMpCoreInfoPpiGuid = { 0x6847cc74, 0xe9ec, 0x4f8f, {0xa2, 0x9d, 0xab, 0x44, 0xe7, 0x54, 0xa8, 0xfc} }

View File

@ -121,6 +121,44 @@ RegisterInterruptSource (
} }
} }
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",
__FUNCTION__, 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",
__FUNCTION__, Status));
}
gBS->CloseEvent (Event);
}
EFI_STATUS EFI_STATUS
InstallAndRegisterInterruptService ( InstallAndRegisterInterruptService (
IN EFI_HARDWARE_INTERRUPT_PROTOCOL *InterruptProtocol, IN EFI_HARDWARE_INTERRUPT_PROTOCOL *InterruptProtocol,
@ -130,7 +168,6 @@ InstallAndRegisterInterruptService (
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
EFI_CPU_ARCH_PROTOCOL *Cpu;
CONST UINTN RihArraySize = CONST UINTN RihArraySize =
(sizeof(HARDWARE_INTERRUPT_HANDLER) * mGicNumInterrupts); (sizeof(HARDWARE_INTERRUPT_HANDLER) * mGicNumInterrupts);
@ -152,27 +189,15 @@ InstallAndRegisterInterruptService (
return Status; return Status;
} }
// Get the CPU protocol that this driver requires. //
Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu); // Install the interrupt handler as soon as the CPU arch protocol appears.
if (EFI_ERROR (Status)) { //
return Status; EfiCreateProtocolNotifyEvent (
} &gEfiCpuArchProtocolGuid,
TPL_CALLBACK,
// Unregister the default exception handler. CpuArchEventProtocolNotify,
Status = Cpu->RegisterInterruptHandler (Cpu, ARM_ARCH_EXCEPTION_IRQ, NULL); InterruptHandler,
if (EFI_ERROR (Status)) { &mCpuArchProtocolNotifyEventRegistration);
return Status;
}
// Register to receive interrupts
Status = Cpu->RegisterInterruptHandler (
Cpu,
ARM_ARCH_EXCEPTION_IRQ,
InterruptHandler
);
if (EFI_ERROR (Status)) {
return Status;
}
// Register for an ExitBootServicesEvent // Register for an ExitBootServicesEvent
Status = gBS->CreateEvent ( Status = gBS->CreateEvent (

View File

@ -21,6 +21,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Library/IoLib.h> #include <Library/IoLib.h>
#include <Library/MemoryAllocationLib.h> #include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h> #include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Protocol/Cpu.h> #include <Protocol/Cpu.h>
#include <Protocol/HardwareInterrupt.h> #include <Protocol/HardwareInterrupt.h>

View File

@ -16,7 +16,7 @@
[Defines] [Defines]
INF_VERSION = 0x00010005 INF_VERSION = 0x00010005
BASE_NAME = ArmGicDxe BASE_NAME = ArmGicDxe
FILE_GUID = DE371F7C-DEC4-4D21-ADF1-593ABCC15882 FILE_GUID = DE371F7C-DEC4-4D21-ADF1-593ABCC15882 # gArmGicDxeFileGuid
MODULE_TYPE = DXE_DRIVER MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0 VERSION_STRING = 1.0
@ -45,6 +45,7 @@
UefiDriverEntryPoint UefiDriverEntryPoint
IoLib IoLib
PcdLib PcdLib
UefiLib
[Protocols] [Protocols]
gHardwareInterruptProtocolGuid gHardwareInterruptProtocolGuid
@ -58,4 +59,4 @@
gArmTokenSpaceGuid.PcdArmGicV3WithV2Legacy gArmTokenSpaceGuid.PcdArmGicV3WithV2Legacy
[Depex] [Depex]
gEfiCpuArchProtocolGuid TRUE

View File

@ -74,4 +74,4 @@
gArmTokenSpaceGuid.PcdDebuggerExceptionSupport gArmTokenSpaceGuid.PcdDebuggerExceptionSupport
[Depex] [Depex]
TRUE AFTER gArmGicDxeFileGuid