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