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
RegisterInterruptSource(IN EFI_HARDWARE_INTERRUPT_PROTOCOL * This,IN HARDWARE_INTERRUPT_SOURCE Source,IN HARDWARE_INTERRUPT_HANDLER Handler)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
InstallAndRegisterInterruptService(IN EFI_HARDWARE_INTERRUPT_PROTOCOL * InterruptProtocol,IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler,IN EFI_EVENT_NOTIFY ExitBootServicesEvent)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