bff8d983cf02f7fd1fa6165824cb6556cdea5c6f
[mirror_edk2.git] / ArmPkg / Drivers / ArmGic / ArmGicCommonDxe.c
1 /*++
2
3 Copyright (c) 2013-2017, 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 // Making this global saves a few bytes in image size
32 EFI_HANDLE gHardwareInterruptHandle = NULL;
33
34 // Notifications
35 EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;
36
37 // Maximum Number of Interrupts
38 UINTN mGicNumInterrupts = 0;
39
40 HARDWARE_INTERRUPT_HANDLER *gRegisteredInterruptHandlers = NULL;
41
42
43 /**
44 Calculate GICD_ICFGRn base address and corresponding bit
45 field Int_config[1] of the GIC distributor register.
46
47 @param Source Hardware source of the interrupt.
48 @param RegAddress Corresponding GICD_ICFGRn base address.
49 @param Config1Bit Bit number of F Int_config[1] bit in the register.
50
51 @retval EFI_SUCCESS Source interrupt supported.
52 @retval EFI_UNSUPPORTED Source interrupt is not supported.
53 **/
54 EFI_STATUS
55 GicGetDistributorIcfgBaseAndBit (
56 IN HARDWARE_INTERRUPT_SOURCE Source,
57 OUT UINTN *RegAddress,
58 OUT UINTN *Config1Bit
59 )
60 {
61 UINTN RegIndex;
62 UINTN Field;
63
64 if (Source >= mGicNumInterrupts) {
65 ASSERT(Source < mGicNumInterrupts);
66 return EFI_UNSUPPORTED;
67 }
68
69 RegIndex = Source / ARM_GIC_ICDICFR_F_STRIDE; // NOTE: truncation is significant
70 Field = Source % ARM_GIC_ICDICFR_F_STRIDE;
71 *RegAddress = PcdGet64 (PcdGicDistributorBase)
72 + ARM_GIC_ICDICFR
73 + (ARM_GIC_ICDICFR_BYTES * RegIndex);
74 *Config1Bit = ((Field * ARM_GIC_ICDICFR_F_WIDTH)
75 + ARM_GIC_ICDICFR_F_CONFIG1_BIT);
76
77 return EFI_SUCCESS;
78 }
79
80
81
82 /**
83 Register Handler for the specified interrupt source.
84
85 @param This Instance pointer for this protocol
86 @param Source Hardware source of the interrupt
87 @param Handler Callback for interrupt. NULL to unregister
88
89 @retval EFI_SUCCESS Source was updated to support Handler.
90 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
91
92 **/
93 EFI_STATUS
94 EFIAPI
95 RegisterInterruptSource (
96 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
97 IN HARDWARE_INTERRUPT_SOURCE Source,
98 IN HARDWARE_INTERRUPT_HANDLER Handler
99 )
100 {
101 if (Source >= mGicNumInterrupts) {
102 ASSERT(FALSE);
103 return EFI_UNSUPPORTED;
104 }
105
106 if ((Handler == NULL) && (gRegisteredInterruptHandlers[Source] == NULL)) {
107 return EFI_INVALID_PARAMETER;
108 }
109
110 if ((Handler != NULL) && (gRegisteredInterruptHandlers[Source] != NULL)) {
111 return EFI_ALREADY_STARTED;
112 }
113
114 gRegisteredInterruptHandlers[Source] = Handler;
115
116 // If the interrupt handler is unregistered then disable the interrupt
117 if (NULL == Handler){
118 return This->DisableInterruptSource (This, Source);
119 } else {
120 return This->EnableInterruptSource (This, Source);
121 }
122 }
123
124 EFI_STATUS
125 InstallAndRegisterInterruptService (
126 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *InterruptProtocol,
127 IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *Interrupt2Protocol,
128 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler,
129 IN EFI_EVENT_NOTIFY ExitBootServicesEvent
130 )
131 {
132 EFI_STATUS Status;
133 EFI_CPU_ARCH_PROTOCOL *Cpu;
134 CONST UINTN RihArraySize =
135 (sizeof(HARDWARE_INTERRUPT_HANDLER) * mGicNumInterrupts);
136
137 // Initialize the array for the Interrupt Handlers
138 gRegisteredInterruptHandlers = AllocateZeroPool (RihArraySize);
139 if (gRegisteredInterruptHandlers == NULL) {
140 return EFI_OUT_OF_RESOURCES;
141 }
142
143 Status = gBS->InstallMultipleProtocolInterfaces (
144 &gHardwareInterruptHandle,
145 &gHardwareInterruptProtocolGuid,
146 InterruptProtocol,
147 &gHardwareInterrupt2ProtocolGuid,
148 Interrupt2Protocol,
149 NULL
150 );
151 if (EFI_ERROR (Status)) {
152 return Status;
153 }
154
155 // Get the CPU protocol that this driver requires.
156 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);
157 if (EFI_ERROR (Status)) {
158 return Status;
159 }
160
161 // Unregister the default exception handler.
162 Status = Cpu->RegisterInterruptHandler (Cpu, ARM_ARCH_EXCEPTION_IRQ, NULL);
163 if (EFI_ERROR (Status)) {
164 return Status;
165 }
166
167 // Register to receive interrupts
168 Status = Cpu->RegisterInterruptHandler (
169 Cpu,
170 ARM_ARCH_EXCEPTION_IRQ,
171 InterruptHandler
172 );
173 if (EFI_ERROR (Status)) {
174 return Status;
175 }
176
177 // Register for an ExitBootServicesEvent
178 Status = gBS->CreateEvent (
179 EVT_SIGNAL_EXIT_BOOT_SERVICES,
180 TPL_NOTIFY,
181 ExitBootServicesEvent,
182 NULL,
183 &EfiExitBootServicesEvent
184 );
185
186 return Status;
187 }