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