/*++ Copyright (c) 2013-2014, ARM Ltd. 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" 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; }