Skip to content

Commit

Permalink
DynamicTablesPkg/ArmGicCParser: Parse VGIC interrupt for all CPUs
Browse files Browse the repository at this point in the history
There are two issues in the GIC FDT parsing code:
- the GICC Flags 'Enabled' bit is overwritten when parsing the VGIC
  Maintenance Interrupt, whose trigger type occupies another bit in the
  same field;
- only the first CPU's Flags field is updated.

This breaks both SMP boot and KVM support on Linux, given that the boot
CPU is disabled in the MADT, and the VGIC maintenance interrupt is set
to 0x0 on all others.

Fix this, by OR'ing the trigger type into the field, and by iterating
over all discovered CPUs.

Signed-off-by: Ard Biesheuvel <[email protected]>
  • Loading branch information
ardbiesheuvel committed Nov 23, 2024
1 parent 0d12945 commit a6f1433
Showing 1 changed file with 21 additions and 11 deletions.
32 changes: 21 additions & 11 deletions DynamicTablesPkg/Library/FdtHwInfoParserLib/Arm/Gic/ArmGicCParser.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ CpusNodeParser (
IN CONST VOID *Fdt,
IN INT32 CpusNode,
IN UINT32 GicVersion,
OUT CM_OBJ_DESCRIPTOR **NewGicCmObjDesc
OUT CM_OBJ_DESCRIPTOR **NewGicCmObjDesc,
OUT UINTN *CpuCount
)
{
EFI_STATUS Status;
Expand Down Expand Up @@ -202,6 +203,8 @@ CpusNodeParser (
return EFI_NOT_FOUND;
}

*CpuCount = CpuNodeCount;

// Allocate memory for CpuNodeCount CM_ARM_GICC_INFO structures.
GicCInfoBufferSize = CpuNodeCount * sizeof (CM_ARM_GICC_INFO);
GicCInfoBuffer = AllocateZeroPool (GicCInfoBufferSize);
Expand Down Expand Up @@ -280,6 +283,7 @@ EFIAPI
GicCIntcNodeParser (
IN CONST VOID *Fdt,
IN INT32 GicIntcNode,
IN UINTN CpuCount,
IN OUT CM_OBJ_DESCRIPTOR *GicCCmObjDesc
)
{
Expand All @@ -289,6 +293,8 @@ GicCIntcNodeParser (

CONST UINT8 *Data;
INT32 DataSize;
UINT32 MaintenanceInterrupt;
UINT32 Flags;

if (GicCCmObjDesc == NULL) {
ASSERT (0);
Expand All @@ -308,14 +314,17 @@ GicCIntcNodeParser (
// but it is assumed that only one Gic is available.
Data = fdt_getprop (Fdt, GicIntcNode, "interrupts", &DataSize);
if ((Data != NULL) && (DataSize == (IntCells * sizeof (UINT32)))) {
GicCInfo = (CM_ARM_GICC_INFO *)GicCCmObjDesc->Data;
GicCInfo->VGICMaintenanceInterrupt =
FdtGetInterruptId ((CONST UINT32 *)Data);
GicCInfo->Flags = DT_IRQ_IS_EDGE_TRIGGERED (
fdt32_to_cpu (((UINT32 *)Data)[IRQ_FLAGS_OFFSET])
) ?
EFI_ACPI_6_3_VGIC_MAINTENANCE_INTERRUPT_MODE_FLAGS :
0;
MaintenanceInterrupt = FdtGetInterruptId ((CONST UINT32 *)Data);
Flags = DT_IRQ_IS_EDGE_TRIGGERED (
fdt32_to_cpu (((UINT32 *)Data)[IRQ_FLAGS_OFFSET])
) ?
EFI_ACPI_6_3_VGIC_MAINTENANCE_INTERRUPT_MODE_FLAGS :
0;
for (GicCInfo = (CM_ARM_GICC_INFO *)GicCCmObjDesc->Data; CpuCount--; GicCInfo++) {
GicCInfo->VGICMaintenanceInterrupt = MaintenanceInterrupt;
GicCInfo->Flags |= Flags;
}

return Status;
} else if (DataSize < 0) {
// This property is optional and was not found. Just return.
Expand Down Expand Up @@ -816,6 +825,7 @@ ArmGicCInfoParser (
UINT32 GicVersion;
CM_OBJ_DESCRIPTOR *NewCmObjDesc;
VOID *Fdt;
UINTN CpuCount;

if (FdtParserHandle == NULL) {
ASSERT (0);
Expand Down Expand Up @@ -846,7 +856,7 @@ ArmGicCInfoParser (

// Parse the "cpus" nodes and its children "cpu" nodes,
// and create a CM_OBJ_DESCRIPTOR.
Status = CpusNodeParser (Fdt, FdtBranch, GicVersion, &NewCmObjDesc);
Status = CpusNodeParser (Fdt, FdtBranch, GicVersion, &NewCmObjDesc, &CpuCount);
if (EFI_ERROR (Status)) {
ASSERT (0);
return Status;
Expand Down Expand Up @@ -878,7 +888,7 @@ ArmGicCInfoParser (
}

// Parse the Gic information common to Gic v2 and v3.
Status = GicCIntcNodeParser (Fdt, IntcNode, NewCmObjDesc);
Status = GicCIntcNodeParser (Fdt, IntcNode, CpuCount, NewCmObjDesc);
if (EFI_ERROR (Status)) {
ASSERT (0);
goto exit_handler;
Expand Down

0 comments on commit a6f1433

Please sign in to comment.