Skip to content

Commit 899a5e4

Browse files
ArmPkg/Drivers/ArmGicDxe: Add Extended SPI support for GICv3
This commit enables extended SPI support for GicV3. GicV3 must decide, based on the source intid, whether to access the SPI-range registers, PPI-range registers in the redistributor, or the extended SPI-range registers. The protocol interfaces must also support registering an interrupt handler with an extended SPI intid. To save ~24KB of memory, handler allocation and access is delegated to GicV2 and GicV3. GicV2 retains the existing handler mapping scheme using intids literally. GicV3 remaps extended SPI intids to be immediately after the highest SPI intids. Tested on qemu with the BSA test suite. Signed-off-by: Nick Graves <[email protected]>
1 parent 7711e8a commit 899a5e4

File tree

5 files changed

+463
-156
lines changed

5 files changed

+463
-156
lines changed

ArmPkg/Drivers/ArmGicDxe/ArmGicCommonDxe.c

+75-36
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,63 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
77
--*/
88

99
#include "ArmGicDxe.h"
10+
#include "Uefi/UefiBaseType.h"
1011

1112
// Making this global saves a few bytes in image size
1213
EFI_HANDLE gHardwareInterruptHandle = NULL;
1314

1415
// Notifications
1516
EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;
1617

17-
// Maximum Number of Interrupts
18-
UINTN mGicNumInterrupts = 0;
18+
EFI_CPU_ARCH_PROTOCOL *gCpuArch;
1919

20-
HARDWARE_INTERRUPT_HANDLER *gRegisteredInterruptHandlers = NULL;
21-
EFI_CPU_ARCH_PROTOCOL *gCpuArch;
20+
/**
21+
*
22+
* Return whether the Source interrupt index refers to an extended shared
23+
* interrupt.
24+
*
25+
* @param Source The source intid to test
26+
*
27+
* @return True if Source is an extended SPI intid, false otherwise.
28+
*/
29+
BOOLEAN
30+
GicCommonSourceIsExtSpi (
31+
IN UINTN Source
32+
)
33+
{
34+
return Source >= ARM_GIC_ARCH_EXT_SPI_MIN && Source <= ARM_GIC_ARCH_EXT_SPI_MAX;
35+
}
36+
37+
/**
38+
* Return whether this is a special interrupt.
39+
*
40+
* @param Source The source intid to test
41+
*
42+
* @return True if Source is a special interrupt intid, false otherwise.
43+
*/
44+
BOOLEAN
45+
GicCommonSourceIsSpecialInterrupt (
46+
IN UINTN Source
47+
)
48+
{
49+
return Source >= 1020 && Source <= 1023;
50+
}
51+
52+
/**
53+
*
54+
* Return whether the Source interrupt index refers to a shared interrupt (SPI)
55+
*
56+
* @param Source The source intid to test
57+
*
58+
* @return True if Source is a SPI intid, false otherwise.
59+
*/
60+
BOOLEAN
61+
GicCommonSourceIsSpi (
62+
IN UINTN Source
63+
)
64+
{
65+
return Source >= 32 && Source <= 1019;
66+
}
2267

2368
/**
2469
Calculate GICD_ICFGRn base address and corresponding bit
@@ -32,24 +77,26 @@ EFI_CPU_ARCH_PROTOCOL *gCpuArch;
3277
@retval EFI_UNSUPPORTED Source interrupt is not supported.
3378
**/
3479
EFI_STATUS
35-
GicGetDistributorIcfgBaseAndBit (
80+
GicCommonGetDistributorIcfgBaseAndBit (
3681
IN HARDWARE_INTERRUPT_SOURCE Source,
3782
OUT UINTN *RegAddress,
3883
OUT UINTN *Config1Bit
3984
)
4085
{
41-
UINTN RegIndex;
42-
UINTN Field;
86+
UINTN RegIndex;
87+
UINTN Field;
88+
UINTN RegOffset;
89+
HARDWARE_INTERRUPT_SOURCE AdjustedSource;
4390

44-
if (Source >= mGicNumInterrupts) {
45-
ASSERT (Source < mGicNumInterrupts);
46-
return EFI_UNSUPPORTED;
47-
}
91+
// Translate ESPI sources into the SPI range for indexing purposes.
92+
AdjustedSource = Source & ~(ARM_GIC_ARCH_EXT_SPI_MIN);
93+
94+
RegOffset = (GicCommonSourceIsExtSpi (Source)) ? ARM_GIC_ICDICFR_E : ARM_GIC_ICDICFR;
4895

49-
RegIndex = Source / ARM_GIC_ICDICFR_F_STRIDE; // NOTE: truncation is significant
50-
Field = Source % ARM_GIC_ICDICFR_F_STRIDE;
96+
RegIndex = AdjustedSource / ARM_GIC_ICDICFR_F_STRIDE; // NOTE: truncation is significant
97+
Field = AdjustedSource % ARM_GIC_ICDICFR_F_STRIDE;
5198
*RegAddress = (UINTN)PcdGet64 (PcdGicDistributorBase)
52-
+ ARM_GIC_ICDICFR
99+
+ RegOffset
53100
+ (ARM_GIC_ICDICFR_BYTES * RegIndex);
54101
*Config1Bit = ((Field * ARM_GIC_ICDICFR_F_WIDTH)
55102
+ ARM_GIC_ICDICFR_F_CONFIG1_BIT);
@@ -60,36 +107,37 @@ GicGetDistributorIcfgBaseAndBit (
60107
/**
61108
Register Handler for the specified interrupt source.
62109
63-
@param This Instance pointer for this protocol
64-
@param Source Hardware source of the interrupt
65-
@param Handler Callback for interrupt. NULL to unregister
110+
@param This Instance pointer for this protocol
111+
@param Source Hardware source of the interrupt
112+
@param Handler Callback for interrupt. NULL to unregister
113+
@param HandlerDest Address of where to store Handler.
66114
67115
@retval EFI_SUCCESS Source was updated to support Handler.
68116
@retval EFI_DEVICE_ERROR Hardware could not be programmed.
69117
70118
**/
71119
EFI_STATUS
72120
EFIAPI
73-
RegisterInterruptSource (
121+
GicCommonRegisterInterruptSource (
74122
IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
75123
IN HARDWARE_INTERRUPT_SOURCE Source,
76-
IN HARDWARE_INTERRUPT_HANDLER Handler
124+
IN HARDWARE_INTERRUPT_HANDLER Handler,
125+
IN HARDWARE_INTERRUPT_HANDLER *HandlerDest
77126
)
78127
{
79-
if (Source >= mGicNumInterrupts) {
80-
ASSERT (FALSE);
81-
return EFI_UNSUPPORTED;
128+
if (HandlerDest == NULL) {
129+
return EFI_INVALID_PARAMETER;
82130
}
83131

84-
if ((Handler == NULL) && (gRegisteredInterruptHandlers[Source] == NULL)) {
132+
if ((Handler == NULL) && (*HandlerDest == NULL)) {
85133
return EFI_INVALID_PARAMETER;
86134
}
87135

88-
if ((Handler != NULL) && (gRegisteredInterruptHandlers[Source] != NULL)) {
136+
if ((Handler != NULL) && (*HandlerDest != NULL)) {
89137
return EFI_ALREADY_STARTED;
90138
}
91139

92-
gRegisteredInterruptHandlers[Source] = Handler;
140+
*HandlerDest = Handler;
93141

94142
// If the interrupt handler is unregistered then disable the interrupt
95143
if (NULL == Handler) {
@@ -100,28 +148,19 @@ RegisterInterruptSource (
100148
}
101149

102150
EFI_STATUS
103-
InstallAndRegisterInterruptService (
151+
GicCommonInstallAndRegisterInterruptService (
104152
IN EFI_HARDWARE_INTERRUPT_PROTOCOL *InterruptProtocol,
105153
IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *Interrupt2Protocol,
106154
IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler,
107155
IN EFI_EVENT_NOTIFY ExitBootServicesEvent
108156
)
109157
{
110-
EFI_STATUS Status;
111-
CONST UINTN RihArraySize =
112-
(sizeof (HARDWARE_INTERRUPT_HANDLER) * mGicNumInterrupts);
113-
114-
// Initialize the array for the Interrupt Handlers
115-
gRegisteredInterruptHandlers = AllocateZeroPool (RihArraySize);
116-
if (gRegisteredInterruptHandlers == NULL) {
117-
return EFI_OUT_OF_RESOURCES;
118-
}
158+
EFI_STATUS Status;
119159

120160
// Register to receive interrupts
121161
Status = gCpuArch->RegisterInterruptHandler (gCpuArch, ARM_ARCH_EXCEPTION_IRQ, InterruptHandler);
122162
if (EFI_ERROR (Status)) {
123163
DEBUG ((DEBUG_ERROR, "%a: Cpu->RegisterInterruptHandler() - %r\n", __func__, Status));
124-
FreePool (gRegisteredInterruptHandlers);
125164
return Status;
126165
}
127166

ArmPkg/Drivers/ArmGicDxe/ArmGicDxe.h

+60-22
Original file line numberDiff line numberDiff line change
@@ -21,42 +21,80 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
2121
#include <Protocol/HardwareInterrupt.h>
2222
#include <Protocol/HardwareInterrupt2.h>
2323

24-
extern UINTN mGicNumInterrupts;
25-
extern HARDWARE_INTERRUPT_HANDLER *gRegisteredInterruptHandlers;
26-
extern EFI_CPU_ARCH_PROTOCOL *gCpuArch;
24+
extern EFI_CPU_ARCH_PROTOCOL *gCpuArch;
2725

28-
// Common API
26+
// GicV2 API
2927
EFI_STATUS
30-
InstallAndRegisterInterruptService (
31-
IN EFI_HARDWARE_INTERRUPT_PROTOCOL *InterruptProtocol,
32-
IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *Interrupt2Protocol,
33-
IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler,
34-
IN EFI_EVENT_NOTIFY ExitBootServicesEvent
28+
GicV2DxeInitialize (
29+
IN EFI_HANDLE ImageHandle,
30+
IN EFI_SYSTEM_TABLE *SystemTable
3531
);
3632

33+
// GicV3 API
34+
EFI_STATUS
35+
GicV3DxeInitialize (
36+
IN EFI_HANDLE ImageHandle,
37+
IN EFI_SYSTEM_TABLE *SystemTable
38+
);
39+
40+
// Shared code
41+
3742
EFI_STATUS
3843
EFIAPI
39-
RegisterInterruptSource (
44+
GicCommonRegisterInterruptSource (
4045
IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
4146
IN HARDWARE_INTERRUPT_SOURCE Source,
42-
IN HARDWARE_INTERRUPT_HANDLER Handler
47+
IN HARDWARE_INTERRUPT_HANDLER Handler,
48+
IN HARDWARE_INTERRUPT_HANDLER *HandlerDest
4349
);
4450

45-
// GicV2 API
4651
EFI_STATUS
47-
GicV2DxeInitialize (
48-
IN EFI_HANDLE ImageHandle,
49-
IN EFI_SYSTEM_TABLE *SystemTable
52+
EFIAPI
53+
GicCommonInstallAndRegisterInterruptService (
54+
IN EFI_HARDWARE_INTERRUPT_PROTOCOL *InterruptProtocol,
55+
IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *Interrupt2Protocol,
56+
IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler,
57+
IN EFI_EVENT_NOTIFY ExitBootServicesEvent
5058
);
5159

52-
// GicV3 API
53-
EFI_STATUS
54-
GicV3DxeInitialize (
55-
IN EFI_HANDLE ImageHandle,
56-
IN EFI_SYSTEM_TABLE *SystemTable
60+
/**
61+
*
62+
* Return whether the Source interrupt index refers to an extended shared
63+
* interrupt.
64+
*
65+
* @param Source The source intid to test
66+
*
67+
* @return True if Source is an extended SPI intid, false otherwise.
68+
*/
69+
BOOLEAN
70+
GicCommonSourceIsExtSpi (
71+
IN UINTN Source
5772
);
5873

59-
// Shared code
74+
/**
75+
* Return whether this is a special interrupt.
76+
*
77+
* @param Source The source intid to test
78+
*
79+
* @return True if Source is a special interrupt intid, false otherwise.
80+
*/
81+
BOOLEAN
82+
GicCommonSourceIsSpecialInterrupt (
83+
IN UINTN Source
84+
);
85+
86+
/**
87+
*
88+
* Return whether the Source interrupt index refers to a shared interrupt (SPI)
89+
*
90+
* @param Source The source intid to test
91+
*
92+
* @return True if Source is a SPI intid, false otherwise.
93+
*/
94+
BOOLEAN
95+
GicCommonSourceIsSpi (
96+
IN UINTN Source
97+
);
6098

6199
/**
62100
Calculate GICD_ICFGRn base address and corresponding bit
@@ -70,7 +108,7 @@ GicV3DxeInitialize (
70108
@retval EFI_UNSUPPORTED Source interrupt is not supported.
71109
**/
72110
EFI_STATUS
73-
GicGetDistributorIcfgBaseAndBit (
111+
GicCommonGetDistributorIcfgBaseAndBit (
74112
IN HARDWARE_INTERRUPT_SOURCE Source,
75113
OUT UINTN *RegAddress,
76114
OUT UINTN *Config1Bit

0 commit comments

Comments
 (0)