Home | History | Annotate | Download | only in ArmGic
      1 /*++
      2 
      3 Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>
      4 
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 --*/
     14 
     15 #include "ArmGicDxe.h"
     16 
     17 VOID
     18 EFIAPI
     19 IrqInterruptHandler (
     20   IN EFI_EXCEPTION_TYPE           InterruptType,
     21   IN EFI_SYSTEM_CONTEXT           SystemContext
     22   );
     23 
     24 VOID
     25 EFIAPI
     26 ExitBootServicesEvent (
     27   IN EFI_EVENT  Event,
     28   IN VOID       *Context
     29   );
     30 
     31 //
     32 // Making this global saves a few bytes in image size
     33 //
     34 EFI_HANDLE  gHardwareInterruptHandle = NULL;
     35 
     36 //
     37 // Notifications
     38 //
     39 EFI_EVENT EfiExitBootServicesEvent      = (EFI_EVENT)NULL;
     40 
     41 // Maximum Number of Interrupts
     42 UINTN mGicNumInterrupts                 = 0;
     43 
     44 HARDWARE_INTERRUPT_HANDLER  *gRegisteredInterruptHandlers = NULL;
     45 
     46 /**
     47   Register Handler for the specified interrupt source.
     48 
     49   @param This     Instance pointer for this protocol
     50   @param Source   Hardware source of the interrupt
     51   @param Handler  Callback for interrupt. NULL to unregister
     52 
     53   @retval EFI_SUCCESS Source was updated to support Handler.
     54   @retval EFI_DEVICE_ERROR  Hardware could not be programmed.
     55 
     56 **/
     57 EFI_STATUS
     58 EFIAPI
     59 RegisterInterruptSource (
     60   IN EFI_HARDWARE_INTERRUPT_PROTOCOL    *This,
     61   IN HARDWARE_INTERRUPT_SOURCE          Source,
     62   IN HARDWARE_INTERRUPT_HANDLER         Handler
     63   )
     64 {
     65   if (Source > mGicNumInterrupts) {
     66     ASSERT(FALSE);
     67     return EFI_UNSUPPORTED;
     68   }
     69 
     70   if ((Handler == NULL) && (gRegisteredInterruptHandlers[Source] == NULL)) {
     71     return EFI_INVALID_PARAMETER;
     72   }
     73 
     74   if ((Handler != NULL) && (gRegisteredInterruptHandlers[Source] != NULL)) {
     75     return EFI_ALREADY_STARTED;
     76   }
     77 
     78   gRegisteredInterruptHandlers[Source] = Handler;
     79 
     80   // If the interrupt handler is unregistered then disable the interrupt
     81   if (NULL == Handler){
     82     return This->DisableInterruptSource (This, Source);
     83   } else {
     84     return This->EnableInterruptSource (This, Source);
     85   }
     86 }
     87 
     88 EFI_STATUS
     89 InstallAndRegisterInterruptService (
     90   IN EFI_HARDWARE_INTERRUPT_PROTOCOL   *InterruptProtocol,
     91   IN EFI_CPU_INTERRUPT_HANDLER          InterruptHandler,
     92   IN EFI_EVENT_NOTIFY                   ExitBootServicesEvent
     93   )
     94 {
     95   EFI_STATUS               Status;
     96   EFI_CPU_ARCH_PROTOCOL   *Cpu;
     97 
     98   // Initialize the array for the Interrupt Handlers
     99   gRegisteredInterruptHandlers = (HARDWARE_INTERRUPT_HANDLER*)AllocateZeroPool (sizeof(HARDWARE_INTERRUPT_HANDLER) * mGicNumInterrupts);
    100   if (gRegisteredInterruptHandlers == NULL) {
    101     return EFI_OUT_OF_RESOURCES;
    102   }
    103 
    104   Status = gBS->InstallMultipleProtocolInterfaces (
    105                   &gHardwareInterruptHandle,
    106                   &gHardwareInterruptProtocolGuid, InterruptProtocol,
    107                   NULL
    108                   );
    109   if (EFI_ERROR (Status)) {
    110     return Status;
    111   }
    112 
    113   //
    114   // Get the CPU protocol that this driver requires.
    115   //
    116   Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);
    117   if (EFI_ERROR (Status)) {
    118     return Status;
    119   }
    120 
    121   //
    122   // Unregister the default exception handler.
    123   //
    124   Status = Cpu->RegisterInterruptHandler (Cpu, ARM_ARCH_EXCEPTION_IRQ, NULL);
    125   if (EFI_ERROR (Status)) {
    126     return Status;
    127   }
    128 
    129   //
    130   // Register to receive interrupts
    131   //
    132   Status = Cpu->RegisterInterruptHandler (Cpu, ARM_ARCH_EXCEPTION_IRQ, InterruptHandler);
    133   if (EFI_ERROR (Status)) {
    134     return Status;
    135   }
    136 
    137   // Register for an ExitBootServicesEvent
    138   Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent);
    139 
    140   return Status;
    141 }
    142