ArmPkg/ArmGicDxe: Map GIC MMIO regions before use

The GIC driver itself has intimate knowledge of the hardware, and so it
is the best suited to create the mappings of the MMIO control regions,
in case they have not been mapped yet by the platform code.

So call in the the CPU arch protocol to map the CPU interface,
distributor and redistributor regions as they are discovered by the GIC
driver startup code.

Note that creating these mappings has no effect if the regions in
question have already been mapped with the correct attributes.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:
Ard Biesheuvel 2025-01-28 17:15:11 +01:00 committed by mergify[bot]
parent 3c4c7a0fc9
commit c558a3b18b
3 changed files with 62 additions and 11 deletions

View File

@ -111,10 +111,6 @@ InstallAndRegisterInterruptService (
CONST UINTN RihArraySize =
(sizeof (HARDWARE_INTERRUPT_HANDLER) * mGicNumInterrupts);
// Locate the CPU arch protocol - cannot fail because of DEPEX
Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpuArch);
ASSERT_EFI_ERROR (Status);
// Initialize the array for the Interrupt Handlers
gRegisteredInterruptHandlers = AllocateZeroPool (RihArraySize);
if (gRegisteredInterruptHandlers == NULL) {

View File

@ -22,6 +22,9 @@ Abstract:
#define ARM_GIC_DEFAULT_PRIORITY 0x80
#define GICD_V2_SIZE SIZE_4KB
#define GICC_V2_SIZE SIZE_8KB
// Interrupts from 1020 to 1023 are considered as special interrupts
// (eg: spurious interrupts)
#define ARM_GIC_IS_SPECIAL_INTERRUPTS(Interrupt) \
@ -529,9 +532,28 @@ GicV2DxeInitialize (
ASSERT (PcdGet64 (PcdGicInterruptInterfaceBase) <= MAX_UINTN);
ASSERT (PcdGet64 (PcdGicDistributorBase) <= MAX_UINTN);
// Locate the CPU arch protocol - cannot fail because of DEPEX
Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpuArch);
ASSERT_EFI_ERROR (Status);
mGicInterruptInterfaceBase = (UINTN)PcdGet64 (PcdGicInterruptInterfaceBase);
mGicDistributorBase = (UINTN)PcdGet64 (PcdGicDistributorBase);
mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase);
Status = gCpuArch->SetMemoryAttributes (gCpuArch, mGicDistributorBase, GICD_V2_SIZE, EFI_MEMORY_UC | EFI_MEMORY_XP);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Failed to map GICv2 distributor MMIO interface: %r\n", __func__, Status));
ASSERT_EFI_ERROR (Status);
return Status;
}
mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase);
Status = gCpuArch->SetMemoryAttributes (gCpuArch, mGicInterruptInterfaceBase, GICC_V2_SIZE, EFI_MEMORY_UC | EFI_MEMORY_XP);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Failed to map GICv2 CPU MMIO interface: %r\n", __func__, Status));
ASSERT_EFI_ERROR (Status);
return Status;
}
for (Index = 0; Index < mGicNumInterrupts; Index++) {
GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol, Index);

View File

@ -23,6 +23,8 @@
+ ARM_GICR_SGI_VLPI_FRAME_SIZE \
+ ARM_GICR_SGI_RESERVED_FRAME_SIZE)
#define GICD_V3_SIZE SIZE_64KB
#define ISENABLER_ADDRESS(base, offset) ((base) +\
ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ISENABLER + 4 * (offset))
@ -62,11 +64,12 @@ GicGetCpuRedistributorBase (
IN UINTN GicRedistributorBase
)
{
UINTN MpId;
UINTN CpuAffinity;
UINTN Affinity;
UINTN GicCpuRedistributorBase;
UINT64 TypeRegister;
UINTN MpId;
UINTN CpuAffinity;
UINTN Affinity;
UINTN GicCpuRedistributorBase;
UINT64 TypeRegister;
EFI_STATUS Status;
MpId = ArmReadMpidr ();
// Define CPU affinity as:
@ -78,6 +81,24 @@ GicGetCpuRedistributorBase (
GicCpuRedistributorBase = GicRedistributorBase;
do {
Status = gCpuArch->SetMemoryAttributes (
gCpuArch,
GicCpuRedistributorBase,
GIC_V3_REDISTRIBUTOR_GRANULARITY,
EFI_MEMORY_UC | EFI_MEMORY_XP
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"%a: Failed to map GICv3 redistributor MMIO interface at 0x%lx: %r\n",
__func__,
GicCpuRedistributorBase,
Status
));
ASSERT_EFI_ERROR (Status);
return 0;
}
TypeRegister = MmioRead64 (GicCpuRedistributorBase + ARM_GICR_TYPER);
Affinity = ARM_GICR_TYPER_GET_AFFINITY (TypeRegister);
if (Affinity == CpuAffinity) {
@ -589,7 +610,19 @@ GicV3DxeInitialize (
// the system.
ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);
mGicDistributorBase = (UINTN)PcdGet64 (PcdGicDistributorBase);
// Locate the CPU arch protocol - cannot fail because of DEPEX
Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpuArch);
ASSERT_EFI_ERROR (Status);
mGicDistributorBase = (UINTN)PcdGet64 (PcdGicDistributorBase);
Status = gCpuArch->SetMemoryAttributes (gCpuArch, mGicDistributorBase, GICD_V3_SIZE, EFI_MEMORY_UC | EFI_MEMORY_XP);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Failed to map GICv3 distributor MMIO interface: %r\n", __func__, Status));
ASSERT_EFI_ERROR (Status);
return Status;
}
mGicRedistributorBase = GicGetCpuRedistributorBase (PcdGet64 (PcdGicRedistributorsBase));
mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase);