TianoCore EDK2 master
Loading...
Searching...
No Matches
ArmGicV3Dxe.c
Go to the documentation of this file.
1
9#include <Library/ArmGicLib.h>
10
11#include "ArmGicDxe.h"
12
13#define ARM_GIC_DEFAULT_PRIORITY 0x80
14
15extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol;
16extern EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V3Protocol;
17
18STATIC UINTN mGicDistributorBase;
19STATIC UINTN mGicRedistributorsBase;
20
33EFIAPI
36 IN HARDWARE_INTERRUPT_SOURCE Source
37 )
38{
39 if (Source >= mGicNumInterrupts) {
40 ASSERT (FALSE);
41 return EFI_UNSUPPORTED;
42 }
43
44 ArmGicEnableInterrupt (mGicDistributorBase, mGicRedistributorsBase, Source);
45
46 return EFI_SUCCESS;
47}
48
61EFIAPI
64 IN HARDWARE_INTERRUPT_SOURCE Source
65 )
66{
67 if (Source >= mGicNumInterrupts) {
68 ASSERT (FALSE);
69 return EFI_UNSUPPORTED;
70 }
71
72 ArmGicDisableInterrupt (mGicDistributorBase, mGicRedistributorsBase, Source);
73
74 return EFI_SUCCESS;
75}
76
90EFIAPI
93 IN HARDWARE_INTERRUPT_SOURCE Source,
94 IN BOOLEAN *InterruptState
95 )
96{
97 if (Source >= mGicNumInterrupts) {
98 ASSERT (FALSE);
99 return EFI_UNSUPPORTED;
100 }
101
102 *InterruptState = ArmGicIsInterruptEnabled (
103 mGicDistributorBase,
104 mGicRedistributorsBase,
105 Source
106 );
107
108 return EFI_SUCCESS;
109}
110
122STATIC
124EFIAPI
127 IN HARDWARE_INTERRUPT_SOURCE Source
128 )
129{
130 if (Source >= mGicNumInterrupts) {
131 ASSERT (FALSE);
132 return EFI_UNSUPPORTED;
133 }
134
135 ArmGicV3EndOfInterrupt (Source);
136 return EFI_SUCCESS;
137}
138
151STATIC
152VOID
153EFIAPI
155 IN EFI_EXCEPTION_TYPE InterruptType,
156 IN EFI_SYSTEM_CONTEXT SystemContext
157 )
158{
159 UINTN GicInterrupt;
160 HARDWARE_INTERRUPT_HANDLER InterruptHandler;
161
162 GicInterrupt = ArmGicV3AcknowledgeInterrupt ();
163
164 // Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the
165 // number of interrupt (ie: Spurious interrupt).
166 if ((GicInterrupt & ARM_GIC_ICCIAR_ACKINTID) >= mGicNumInterrupts) {
167 // The special interrupt do not need to be acknowledge
168 return;
169 }
170
171 InterruptHandler = gRegisteredInterruptHandlers[GicInterrupt];
172 if (InterruptHandler != NULL) {
173 // Call the registered interrupt handler.
174 InterruptHandler (GicInterrupt, SystemContext);
175 } else {
176 DEBUG ((DEBUG_ERROR, "Spurious GIC interrupt: 0x%x\n", (UINT32)GicInterrupt));
177 GicV3EndOfInterrupt (&gHardwareInterruptV3Protocol, GicInterrupt);
178 }
179}
180
181// The protocol instance produced by this driver
182EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol = {
183 RegisterInterruptSource,
188};
189
200STATIC
202EFIAPI
205 IN HARDWARE_INTERRUPT_SOURCE Source,
206 OUT EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE *TriggerType
207 )
208{
209 UINTN RegAddress;
210 UINTN Config1Bit;
211 EFI_STATUS Status;
212
213 Status = GicGetDistributorIcfgBaseAndBit (
214 Source,
215 &RegAddress,
216 &Config1Bit
217 );
218
219 if (EFI_ERROR (Status)) {
220 return Status;
221 }
222
223 if ((MmioRead32 (RegAddress) & (1 << Config1Bit)) == 0) {
224 *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH;
225 } else {
226 *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING;
227 }
228
229 return EFI_SUCCESS;
230}
231
242STATIC
244EFIAPI
247 IN HARDWARE_INTERRUPT_SOURCE Source,
248 IN EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE TriggerType
249 )
250{
251 UINTN RegAddress;
252 UINTN Config1Bit;
253 UINT32 Value;
254 EFI_STATUS Status;
255 BOOLEAN SourceEnabled;
256
257 if ( (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)
258 && (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH))
259 {
260 DEBUG ((
261 DEBUG_ERROR,
262 "Invalid interrupt trigger type: %d\n", \
263 TriggerType
264 ));
265 ASSERT (FALSE);
266 return EFI_UNSUPPORTED;
267 }
268
269 Status = GicGetDistributorIcfgBaseAndBit (
270 Source,
271 &RegAddress,
272 &Config1Bit
273 );
274
275 if (EFI_ERROR (Status)) {
276 return Status;
277 }
278
281 Source,
282 &SourceEnabled
283 );
284
285 if (EFI_ERROR (Status)) {
286 return Status;
287 }
288
289 Value = (TriggerType == EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)
290 ? ARM_GIC_ICDICFR_EDGE_TRIGGERED
291 : ARM_GIC_ICDICFR_LEVEL_TRIGGERED;
292
293 // Before changing the value, we must disable the interrupt,
294 // otherwise GIC behavior is UNPREDICTABLE.
295 if (SourceEnabled) {
298 Source
299 );
300 }
301
303 RegAddress,
304 ~(0x1 << Config1Bit),
305 Value << Config1Bit
306 );
307 // Restore interrupt state
308 if (SourceEnabled) {
311 Source
312 );
313 }
314
315 return EFI_SUCCESS;
316}
317
318EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V3Protocol = {
319 (HARDWARE_INTERRUPT2_REGISTER)RegisterInterruptSource,
326};
327
337VOID
338EFIAPI
340 IN EFI_EVENT Event,
341 IN VOID *Context
342 )
343{
344 UINTN Index;
345
346 // Acknowledge all pending interrupts
347 for (Index = 0; Index < mGicNumInterrupts; Index++) {
348 GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol, Index);
349 }
350
351 // Disable Gic Interface
352 ArmGicV3DisableInterruptInterface ();
353
354 // Disable Gic Distributor
355 ArmGicDisableDistributor (mGicDistributorBase);
356}
357
371 IN EFI_HANDLE ImageHandle,
372 IN EFI_SYSTEM_TABLE *SystemTable
373 )
374{
375 EFI_STATUS Status;
376 UINTN Index;
377 UINT64 CpuTarget;
378 UINT64 MpId;
379
380 // Make sure the Interrupt Controller Protocol is not already installed in
381 // the system.
382 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);
383
384 mGicDistributorBase = (UINTN)PcdGet64 (PcdGicDistributorBase);
385 mGicRedistributorsBase = PcdGet64 (PcdGicRedistributorsBase);
386 mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase);
387
388 // We will be driving this GIC in native v3 mode, i.e., with Affinity
389 // Routing enabled. So ensure that the ARE bit is set.
390 if (!FeaturePcdGet (PcdArmGicV3WithV2Legacy)) {
391 MmioOr32 (mGicDistributorBase + ARM_GIC_ICDDCR, ARM_GIC_ICDDCR_ARE);
392 }
393
394 for (Index = 0; Index < mGicNumInterrupts; Index++) {
395 GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol, Index);
396
397 // Set Priority
398 ArmGicSetInterruptPriority (
399 mGicDistributorBase,
400 mGicRedistributorsBase,
401 Index,
402 ARM_GIC_DEFAULT_PRIORITY
403 );
404 }
405
406 // Targets the interrupts to the Primary Cpu
407
408 if (FeaturePcdGet (PcdArmGicV3WithV2Legacy)) {
409 // Only Primary CPU will run this code. We can identify our GIC CPU ID by
410 // reading the GIC Distributor Target register. The 8 first
411 // GICD_ITARGETSRn are banked to each connected CPU. These 8 registers
412 // hold the CPU targets fields for interrupts 0-31. More Info in the GIC
413 // Specification about "Interrupt Processor Targets Registers"
414
415 // Read the first Interrupt Processor Targets Register (that corresponds
416 // to the 4 first SGIs)
417 CpuTarget = MmioRead32 (mGicDistributorBase + ARM_GIC_ICDIPTR);
418
419 // The CPU target is a bit field mapping each CPU to a GIC CPU Interface.
420 // This value is 0 when we run on a uniprocessor platform.
421 if (CpuTarget != 0) {
422 // The 8 first Interrupt Processor Targets Registers are read-only
423 for (Index = 8; Index < (mGicNumInterrupts / 4); Index++) {
425 mGicDistributorBase + ARM_GIC_ICDIPTR + (Index * 4),
426 CpuTarget
427 );
428 }
429 }
430 } else {
431 MpId = ArmReadMpidr ();
432 CpuTarget = MpId &
433 (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2 | ARM_CORE_AFF3);
434
435 if ((MmioRead32 (
436 mGicDistributorBase + ARM_GIC_ICDDCR
437 ) & ARM_GIC_ICDDCR_DS) != 0)
438 {
439 // If the Disable Security (DS) control bit is set, we are dealing with a
440 // GIC that has only one security state. In this case, let's assume we are
441 // executing in non-secure state (which is appropriate for DXE modules)
442 // and that no other firmware has performed any configuration on the GIC.
443 // This means we need to reconfigure all interrupts to non-secure Group 1
444 // first.
445
447 mGicRedistributorsBase + ARM_GICR_CTLR_FRAME_SIZE + ARM_GIC_ICDISR,
448 0xffffffff
449 );
450
451 for (Index = 32; Index < mGicNumInterrupts; Index += 32) {
453 mGicDistributorBase + ARM_GIC_ICDISR + Index / 8,
454 0xffffffff
455 );
456 }
457 }
458
459 // Route the SPIs to the primary CPU. SPIs start at the INTID 32
460 for (Index = 0; Index < (mGicNumInterrupts - 32); Index++) {
462 mGicDistributorBase + ARM_GICD_IROUTER + (Index * 8),
463 CpuTarget
464 );
465 }
466 }
467
468 // Set binary point reg to 0x7 (no preemption)
469 ArmGicV3SetBinaryPointer (0x7);
470
471 // Set priority mask reg to 0xff to allow all priorities through
472 ArmGicV3SetPriorityMask (0xff);
473
474 // Enable gic cpu interface
475 ArmGicV3EnableInterruptInterface ();
476
477 // Enable gic distributor
478 ArmGicEnableDistributor (mGicDistributorBase);
479
480 Status = InstallAndRegisterInterruptService (
481 &gHardwareInterruptV3Protocol,
482 &gHardwareInterrupt2V3Protocol,
485 );
486
487 return Status;
488}
UINT64 UINTN
STATIC EFI_STATUS EFIAPI GicV3DisableInterruptSource(IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, IN HARDWARE_INTERRUPT_SOURCE Source)
Definition: ArmGicV3Dxe.c:62
STATIC VOID EFIAPI GicV3IrqInterruptHandler(IN EFI_EXCEPTION_TYPE InterruptType, IN EFI_SYSTEM_CONTEXT SystemContext)
Definition: ArmGicV3Dxe.c:154
VOID EFIAPI GicV3ExitBootServicesEvent(IN EFI_EVENT Event, IN VOID *Context)
Definition: ArmGicV3Dxe.c:339
STATIC EFI_STATUS EFIAPI GicV3GetInterruptSourceState(IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, IN HARDWARE_INTERRUPT_SOURCE Source, IN BOOLEAN *InterruptState)
Definition: ArmGicV3Dxe.c:91
STATIC EFI_STATUS EFIAPI GicV3EnableInterruptSource(IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, IN HARDWARE_INTERRUPT_SOURCE Source)
Definition: ArmGicV3Dxe.c:34
STATIC EFI_STATUS EFIAPI GicV3GetTriggerType(IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This, IN HARDWARE_INTERRUPT_SOURCE Source, OUT EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE *TriggerType)
Definition: ArmGicV3Dxe.c:203
STATIC EFI_STATUS EFIAPI GicV3SetTriggerType(IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This, IN HARDWARE_INTERRUPT_SOURCE Source, IN EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE TriggerType)
Definition: ArmGicV3Dxe.c:245
STATIC EFI_STATUS EFIAPI GicV3EndOfInterrupt(IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, IN HARDWARE_INTERRUPT_SOURCE Source)
Definition: ArmGicV3Dxe.c:125
EFI_STATUS GicV3DxeInitialize(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
Definition: ArmGicV3Dxe.c:370
EFI_STATUS(EFIAPI * HARDWARE_INTERRUPT2_DISABLE)(IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This, IN HARDWARE_INTERRUPT_SOURCE Source)
EFI_STATUS(EFIAPI * HARDWARE_INTERRUPT2_REGISTER)(IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This, IN HARDWARE_INTERRUPT_SOURCE Source, IN HARDWARE_INTERRUPT_HANDLER Handler)
EFI_STATUS(EFIAPI * HARDWARE_INTERRUPT2_END_OF_INTERRUPT)(IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This, IN HARDWARE_INTERRUPT_SOURCE Source)
EFI_STATUS(EFIAPI * HARDWARE_INTERRUPT2_ENABLE)(IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This, IN HARDWARE_INTERRUPT_SOURCE Source)
EFI_STATUS(EFIAPI * HARDWARE_INTERRUPT2_INTERRUPT_STATE)(IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This, IN HARDWARE_INTERRUPT_SOURCE Source, IN BOOLEAN *InterruptState)
VOID(EFIAPI * HARDWARE_INTERRUPT_HANDLER)(IN HARDWARE_INTERRUPT_SOURCE Source, IN EFI_SYSTEM_CONTEXT SystemContext)
UINT64 EFIAPI MmioWrite64(IN UINTN Address, IN UINT64 Value)
Definition: IoLib.c:400
UINT32 EFIAPI MmioOr32(IN UINTN Address, IN UINT32 OrData)
Definition: IoHighLevel.c:1785
UINT32 EFIAPI MmioRead32(IN UINTN Address)
Definition: IoLib.c:262
UINT32 EFIAPI MmioAndThenOr32(IN UINTN Address, IN UINT32 AndData, IN UINT32 OrData)
Definition: IoHighLevel.c:1845
UINT32 EFIAPI MmioWrite32(IN UINTN Address, IN UINT32 Value)
Definition: IoLib.c:309
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define ASSERT_PROTOCOL_ALREADY_INSTALLED(Handle, Guid)
Definition: DebugLib.h:535
INTN EFI_EXCEPTION_TYPE
Definition: DebugSupport.h:35
#define PcdGet64(TokenName)
Definition: PcdLib.h:375
#define FeaturePcdGet(TokenName)
Definition: PcdLib.h:50
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112