]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Drivers/ArmGic/ArmGicCommonDxe.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / ArmPkg / Drivers / ArmGic / ArmGicCommonDxe.c
1 /*++
2
3 Copyright (c) 2013-2017, ARM Ltd. All rights reserved.<BR>
4
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 --*/
8
9 #include "ArmGicDxe.h"
10
11 VOID
12 EFIAPI
13 IrqInterruptHandler (
14 IN EFI_EXCEPTION_TYPE InterruptType,
15 IN EFI_SYSTEM_CONTEXT SystemContext
16 );
17
18 VOID
19 EFIAPI
20 ExitBootServicesEvent (
21 IN EFI_EVENT Event,
22 IN VOID *Context
23 );
24
25 // Making this global saves a few bytes in image size
26 EFI_HANDLE gHardwareInterruptHandle = NULL;
27
28 // Notifications
29 EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;
30
31 // Maximum Number of Interrupts
32 UINTN mGicNumInterrupts = 0;
33
34 HARDWARE_INTERRUPT_HANDLER *gRegisteredInterruptHandlers = NULL;
35
36 /**
37 Calculate GICD_ICFGRn base address and corresponding bit
38 field Int_config[1] of the GIC distributor register.
39
40 @param Source Hardware source of the interrupt.
41 @param RegAddress Corresponding GICD_ICFGRn base address.
42 @param Config1Bit Bit number of F Int_config[1] bit in the register.
43
44 @retval EFI_SUCCESS Source interrupt supported.
45 @retval EFI_UNSUPPORTED Source interrupt is not supported.
46 **/
47 EFI_STATUS
48 GicGetDistributorIcfgBaseAndBit (
49 IN HARDWARE_INTERRUPT_SOURCE Source,
50 OUT UINTN *RegAddress,
51 OUT UINTN *Config1Bit
52 )
53 {
54 UINTN RegIndex;
55 UINTN Field;
56
57 if (Source >= mGicNumInterrupts) {
58 ASSERT (Source < mGicNumInterrupts);
59 return EFI_UNSUPPORTED;
60 }
61
62 RegIndex = Source / ARM_GIC_ICDICFR_F_STRIDE; // NOTE: truncation is significant
63 Field = Source % ARM_GIC_ICDICFR_F_STRIDE;
64 *RegAddress = PcdGet64 (PcdGicDistributorBase)
65 + ARM_GIC_ICDICFR
66 + (ARM_GIC_ICDICFR_BYTES * RegIndex);
67 *Config1Bit = ((Field * ARM_GIC_ICDICFR_F_WIDTH)
68 + ARM_GIC_ICDICFR_F_CONFIG1_BIT);
69
70 return EFI_SUCCESS;
71 }
72
73 /**
74 Register Handler for the specified interrupt source.
75
76 @param This Instance pointer for this protocol
77 @param Source Hardware source of the interrupt
78 @param Handler Callback for interrupt. NULL to unregister
79
80 @retval EFI_SUCCESS Source was updated to support Handler.
81 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
82
83 **/
84 EFI_STATUS
85 EFIAPI
86 RegisterInterruptSource (
87 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
88 IN HARDWARE_INTERRUPT_SOURCE Source,
89 IN HARDWARE_INTERRUPT_HANDLER Handler
90 )
91 {
92 if (Source >= mGicNumInterrupts) {
93 ASSERT (FALSE);
94 return EFI_UNSUPPORTED;
95 }
96
97 if ((Handler == NULL) && (gRegisteredInterruptHandlers[Source] == NULL)) {
98 return EFI_INVALID_PARAMETER;
99 }
100
101 if ((Handler != NULL) && (gRegisteredInterruptHandlers[Source] != NULL)) {
102 return EFI_ALREADY_STARTED;
103 }
104
105 gRegisteredInterruptHandlers[Source] = Handler;
106
107 // If the interrupt handler is unregistered then disable the interrupt
108 if (NULL == Handler) {
109 return This->DisableInterruptSource (This, Source);
110 } else {
111 return This->EnableInterruptSource (This, Source);
112 }
113 }
114
115 STATIC VOID *mCpuArchProtocolNotifyEventRegistration;
116
117 STATIC
118 VOID
119 EFIAPI
120 CpuArchEventProtocolNotify (
121 IN EFI_EVENT Event,
122 IN VOID *Context
123 )
124 {
125 EFI_CPU_ARCH_PROTOCOL *Cpu;
126 EFI_STATUS Status;
127
128 // Get the CPU protocol that this driver requires.
129 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);
130 if (EFI_ERROR (Status)) {
131 return;
132 }
133
134 // Unregister the default exception handler.
135 Status = Cpu->RegisterInterruptHandler (Cpu, ARM_ARCH_EXCEPTION_IRQ, NULL);
136 if (EFI_ERROR (Status)) {
137 DEBUG ((
138 DEBUG_ERROR,
139 "%a: Cpu->RegisterInterruptHandler() - %r\n",
140 __FUNCTION__,
141 Status
142 ));
143 return;
144 }
145
146 // Register to receive interrupts
147 Status = Cpu->RegisterInterruptHandler (
148 Cpu,
149 ARM_ARCH_EXCEPTION_IRQ,
150 Context
151 );
152 if (EFI_ERROR (Status)) {
153 DEBUG ((
154 DEBUG_ERROR,
155 "%a: Cpu->RegisterInterruptHandler() - %r\n",
156 __FUNCTION__,
157 Status
158 ));
159 }
160
161 gBS->CloseEvent (Event);
162 }
163
164 EFI_STATUS
165 InstallAndRegisterInterruptService (
166 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *InterruptProtocol,
167 IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *Interrupt2Protocol,
168 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler,
169 IN EFI_EVENT_NOTIFY ExitBootServicesEvent
170 )
171 {
172 EFI_STATUS Status;
173 CONST UINTN RihArraySize =
174 (sizeof (HARDWARE_INTERRUPT_HANDLER) * mGicNumInterrupts);
175
176 // Initialize the array for the Interrupt Handlers
177 gRegisteredInterruptHandlers = AllocateZeroPool (RihArraySize);
178 if (gRegisteredInterruptHandlers == NULL) {
179 return EFI_OUT_OF_RESOURCES;
180 }
181
182 Status = gBS->InstallMultipleProtocolInterfaces (
183 &gHardwareInterruptHandle,
184 &gHardwareInterruptProtocolGuid,
185 InterruptProtocol,
186 &gHardwareInterrupt2ProtocolGuid,
187 Interrupt2Protocol,
188 NULL
189 );
190 if (EFI_ERROR (Status)) {
191 return Status;
192 }
193
194 //
195 // Install the interrupt handler as soon as the CPU arch protocol appears.
196 //
197 EfiCreateProtocolNotifyEvent (
198 &gEfiCpuArchProtocolGuid,
199 TPL_CALLBACK,
200 CpuArchEventProtocolNotify,
201 InterruptHandler,
202 &mCpuArchProtocolNotifyEventRegistration
203 );
204
205 // Register for an ExitBootServicesEvent
206 Status = gBS->CreateEvent (
207 EVT_SIGNAL_EXIT_BOOT_SERVICES,
208 TPL_NOTIFY,
209 ExitBootServicesEvent,
210 NULL,
211 &EfiExitBootServicesEvent
212 );
213
214 return Status;
215 }