/*++ | |
Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR> | |
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" | |
VOID | |
EFIAPI | |
IrqInterruptHandler ( | |
IN EFI_EXCEPTION_TYPE InterruptType, | |
IN EFI_SYSTEM_CONTEXT SystemContext | |
); | |
VOID | |
EFIAPI | |
ExitBootServicesEvent ( | |
IN EFI_EVENT Event, | |
IN VOID *Context | |
); | |
// | |
// 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; | |
/** | |
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); | |
} | |
} | |
EFI_STATUS | |
InstallAndRegisterInterruptService ( | |
IN EFI_HARDWARE_INTERRUPT_PROTOCOL *InterruptProtocol, | |
IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler, | |
IN EFI_EVENT_NOTIFY ExitBootServicesEvent | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_CPU_ARCH_PROTOCOL *Cpu; | |
// Initialize the array for the Interrupt Handlers | |
gRegisteredInterruptHandlers = (HARDWARE_INTERRUPT_HANDLER*)AllocateZeroPool (sizeof(HARDWARE_INTERRUPT_HANDLER) * mGicNumInterrupts); | |
if (gRegisteredInterruptHandlers == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Status = gBS->InstallMultipleProtocolInterfaces ( | |
&gHardwareInterruptHandle, | |
&gHardwareInterruptProtocolGuid, InterruptProtocol, | |
NULL | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Get the CPU protocol that this driver requires. | |
// | |
Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Unregister the default exception handler. | |
// | |
Status = Cpu->RegisterInterruptHandler (Cpu, ARM_ARCH_EXCEPTION_IRQ, NULL); | |
if (EFI_ERROR (Status)) { | |
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 | |
Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent); | |
return Status; | |
} |