You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
325 lines
9.3 KiB
325 lines
9.3 KiB
4 years ago
|
/** @file
|
||
|
MADT table parser
|
||
|
|
||
|
Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
|
||
|
This program and the accompanying materials
|
||
|
are licensed and made available under the terms and conditions of the BSD License
|
||
|
which accompanies this distribution. The full text of the license may be found at
|
||
|
http://opensource.org/licenses/bsd-license.php
|
||
|
|
||
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||
|
|
||
|
@par Reference(s):
|
||
|
- ACPI 6.2 Specification - Errata A, September 2017
|
||
|
**/
|
||
|
|
||
|
#include <IndustryStandard/Acpi.h>
|
||
|
#include <Library/UefiLib.h>
|
||
|
#include "AcpiParser.h"
|
||
|
#include "AcpiTableParser.h"
|
||
|
|
||
|
// Local Variables
|
||
|
STATIC CONST UINT8* MadtInterruptControllerType;
|
||
|
STATIC CONST UINT8* MadtInterruptControllerLength;
|
||
|
STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;
|
||
|
|
||
|
/**
|
||
|
This function validates the System Vector Base in the GICD.
|
||
|
|
||
|
@param [in] Ptr Pointer to the start of the field data.
|
||
|
@param [in] Context Pointer to context specific information e.g. this
|
||
|
could be a pointer to the ACPI table header.
|
||
|
**/
|
||
|
STATIC
|
||
|
VOID
|
||
|
EFIAPI
|
||
|
ValidateGICDSystemVectorBase (
|
||
|
IN UINT8* Ptr,
|
||
|
IN VOID* Context
|
||
|
);
|
||
|
|
||
|
/**
|
||
|
An ACPI_PARSER array describing the GICC Interrupt Controller Structure.
|
||
|
**/
|
||
|
STATIC CONST ACPI_PARSER GicCParser[] = {
|
||
|
{L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
{L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},
|
||
|
{L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
|
||
|
{L"CPU Interface Number", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
{L"ACPI Processor UID", 4, 8, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
{L"Flags", 4, 12, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
{L"Parking Protocol Version", 4, 16, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
|
||
|
{L"Performance Interrupt GSIV", 4, 20, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
{L"Parked Address", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL},
|
||
|
{L"Physical Base Address", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL},
|
||
|
{L"GICV", 8, 40, L"0x%lx", NULL, NULL, NULL, NULL},
|
||
|
{L"GICH", 8, 48, L"0x%lx", NULL, NULL, NULL, NULL},
|
||
|
{L"VGIC Maintenance interrupt", 4, 56, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
{L"GICR Base Address", 8, 60, L"0x%lx", NULL, NULL, NULL, NULL},
|
||
|
{L"MPIDR", 8, 68, L"0x%lx", NULL, NULL, NULL, NULL},
|
||
|
{L"Processor Power Efficiency Class", 1, 76, L"0x%x", NULL, NULL, NULL,
|
||
|
NULL},
|
||
|
{L"Reserved", 3, 77, L"%x %x %x", Dump3Chars, NULL, NULL, NULL}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
An ACPI_PARSER array describing the GICD Interrupt Controller Structure.
|
||
|
**/
|
||
|
STATIC CONST ACPI_PARSER GicDParser[] = {
|
||
|
{L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
{L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},
|
||
|
{L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
|
||
|
{L"GIC ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
{L"Physical Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL},
|
||
|
{L"System Vector Base", 4, 16, L"0x%x", NULL, NULL,
|
||
|
ValidateGICDSystemVectorBase, NULL},
|
||
|
{L"GIC Version", 1, 20, L"%d", NULL, NULL, NULL, NULL},
|
||
|
{L"Reserved", 3, 21, L"%x %x %x", Dump3Chars, NULL, NULL, NULL}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
An ACPI_PARSER array describing the MSI Frame Interrupt Controller Structure.
|
||
|
**/
|
||
|
STATIC CONST ACPI_PARSER GicMSIFrameParser[] = {
|
||
|
{L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
{L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},
|
||
|
{L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
|
||
|
{L"MSI Frame ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
{L"Physical Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL},
|
||
|
{L"Flags", 4, 16, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
|
||
|
{L"SPI Count", 2, 20, L"%d", NULL, NULL, NULL, NULL},
|
||
|
{L"SPI Base", 2, 22, L"0x%x", NULL, NULL, NULL, NULL}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
An ACPI_PARSER array describing the GICR Interrupt Controller Structure.
|
||
|
**/
|
||
|
STATIC CONST ACPI_PARSER GicRParser[] = {
|
||
|
{L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
{L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},
|
||
|
{L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
|
||
|
{L"Discovery Range Base Address", 8, 4, L"0x%lx", NULL, NULL, NULL,
|
||
|
NULL},
|
||
|
{L"Discovery Range Length", 4, 12, L"0x%x", NULL, NULL, NULL, NULL}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
An ACPI_PARSER array describing the GIC ITS Interrupt Controller Structure.
|
||
|
**/
|
||
|
STATIC CONST ACPI_PARSER GicITSParser[] = {
|
||
|
{L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
{L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},
|
||
|
{L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
|
||
|
{L"GIC ITS ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},
|
||
|
{L"Physical Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL},
|
||
|
{L"Reserved", 4, 16, L"0x%x", NULL, NULL, NULL, NULL}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
An ACPI_PARSER array describing the ACPI MADT Table.
|
||
|
**/
|
||
|
STATIC CONST ACPI_PARSER MadtParser[] = {
|
||
|
PARSE_ACPI_HEADER (&AcpiHdrInfo),
|
||
|
{L"Local Interrupt Controller Address", 4, 36, L"0x%x", NULL, NULL, NULL,
|
||
|
NULL},
|
||
|
{L"Flags", 4, 40, L"0x%x", NULL, NULL, NULL, NULL}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
An ACPI_PARSER array describing the MADT Interrupt Controller Structure Header Structure.
|
||
|
**/
|
||
|
STATIC CONST ACPI_PARSER MadtInterruptControllerHeaderParser[] = {
|
||
|
{NULL, 1, 0, NULL, NULL, (VOID**)&MadtInterruptControllerType, NULL, NULL},
|
||
|
{L"Length", 1, 1, NULL, NULL, (VOID**)&MadtInterruptControllerLength, NULL,
|
||
|
NULL},
|
||
|
{L"Reserved", 2, 2, NULL, NULL, NULL, NULL, NULL}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
This function validates the System Vector Base in the GICD.
|
||
|
|
||
|
@param [in] Ptr Pointer to the start of the field data.
|
||
|
@param [in] Context Pointer to context specific information e.g. this
|
||
|
could be a pointer to the ACPI table header.
|
||
|
**/
|
||
|
STATIC
|
||
|
VOID
|
||
|
EFIAPI
|
||
|
ValidateGICDSystemVectorBase (
|
||
|
IN UINT8* Ptr,
|
||
|
IN VOID* Context
|
||
|
)
|
||
|
{
|
||
|
if (*(UINT32*)Ptr != 0) {
|
||
|
IncrementErrorCount ();
|
||
|
Print (
|
||
|
L"\nERROR: System Vector Base must be zero."
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
This function parses the ACPI MADT table.
|
||
|
When trace is enabled this function parses the MADT table and
|
||
|
traces the ACPI table fields.
|
||
|
|
||
|
This function currently parses the following Interrupt Controller
|
||
|
Structures:
|
||
|
- GICC
|
||
|
- GICD
|
||
|
- GIC MSI Frame
|
||
|
- GICR
|
||
|
- GIC ITS
|
||
|
|
||
|
This function also performs validation of the ACPI table fields.
|
||
|
|
||
|
@param [in] Trace If TRUE, trace the ACPI fields.
|
||
|
@param [in] Ptr Pointer to the start of the buffer.
|
||
|
@param [in] AcpiTableLength Length of the ACPI table.
|
||
|
@param [in] AcpiTableRevision Revision of the ACPI table.
|
||
|
**/
|
||
|
VOID
|
||
|
EFIAPI
|
||
|
ParseAcpiMadt (
|
||
|
IN BOOLEAN Trace,
|
||
|
IN UINT8* Ptr,
|
||
|
IN UINT32 AcpiTableLength,
|
||
|
IN UINT8 AcpiTableRevision
|
||
|
)
|
||
|
{
|
||
|
UINT32 Offset;
|
||
|
UINT8* InterruptContollerPtr;
|
||
|
UINT32 GICDCount;
|
||
|
|
||
|
GICDCount = 0;
|
||
|
|
||
|
if (!Trace) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Offset = ParseAcpi (
|
||
|
TRUE,
|
||
|
0,
|
||
|
"MADT",
|
||
|
Ptr,
|
||
|
AcpiTableLength,
|
||
|
PARSER_PARAMS (MadtParser)
|
||
|
);
|
||
|
InterruptContollerPtr = Ptr + Offset;
|
||
|
|
||
|
while (Offset < AcpiTableLength) {
|
||
|
// Parse Interrupt Controller Structure to obtain Length.
|
||
|
ParseAcpi (
|
||
|
FALSE,
|
||
|
0,
|
||
|
NULL,
|
||
|
InterruptContollerPtr,
|
||
|
2, // Length is 1 byte at offset 1
|
||
|
PARSER_PARAMS (MadtInterruptControllerHeaderParser)
|
||
|
);
|
||
|
|
||
|
if (((Offset + (*MadtInterruptControllerLength)) > AcpiTableLength) ||
|
||
|
(*MadtInterruptControllerLength < 4)) {
|
||
|
IncrementErrorCount ();
|
||
|
Print (
|
||
|
L"ERROR: Invalid Interrupt Controller Length,"
|
||
|
L" Type = %d, Length = %d\n",
|
||
|
*MadtInterruptControllerType,
|
||
|
*MadtInterruptControllerLength
|
||
|
);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch (*MadtInterruptControllerType) {
|
||
|
case EFI_ACPI_6_2_GIC: {
|
||
|
ParseAcpi (
|
||
|
TRUE,
|
||
|
2,
|
||
|
"GICC",
|
||
|
InterruptContollerPtr,
|
||
|
*MadtInterruptControllerLength,
|
||
|
PARSER_PARAMS (GicCParser)
|
||
|
);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case EFI_ACPI_6_2_GICD: {
|
||
|
if (++GICDCount > 1) {
|
||
|
IncrementErrorCount ();
|
||
|
Print (
|
||
|
L"ERROR: Only one GICD must be present,"
|
||
|
L" GICDCount = %d\n",
|
||
|
GICDCount
|
||
|
);
|
||
|
}
|
||
|
ParseAcpi (
|
||
|
TRUE,
|
||
|
2,
|
||
|
"GICD",
|
||
|
InterruptContollerPtr,
|
||
|
*MadtInterruptControllerLength,
|
||
|
PARSER_PARAMS (GicDParser)
|
||
|
);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case EFI_ACPI_6_2_GIC_MSI_FRAME: {
|
||
|
ParseAcpi (
|
||
|
TRUE,
|
||
|
2,
|
||
|
"GIC MSI Frame",
|
||
|
InterruptContollerPtr,
|
||
|
*MadtInterruptControllerLength,
|
||
|
PARSER_PARAMS (GicMSIFrameParser)
|
||
|
);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case EFI_ACPI_6_2_GICR: {
|
||
|
ParseAcpi (
|
||
|
TRUE,
|
||
|
2,
|
||
|
"GICR",
|
||
|
InterruptContollerPtr,
|
||
|
*MadtInterruptControllerLength,
|
||
|
PARSER_PARAMS (GicRParser)
|
||
|
);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case EFI_ACPI_6_2_GIC_ITS: {
|
||
|
ParseAcpi (
|
||
|
TRUE,
|
||
|
2,
|
||
|
"GIC ITS",
|
||
|
InterruptContollerPtr,
|
||
|
*MadtInterruptControllerLength,
|
||
|
PARSER_PARAMS (GicITSParser)
|
||
|
);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default: {
|
||
|
IncrementErrorCount ();
|
||
|
Print (
|
||
|
L"ERROR: Unknown Interrupt Controller Structure,"
|
||
|
L" Type = %d, Length = %d\n",
|
||
|
*MadtInterruptControllerType,
|
||
|
*MadtInterruptControllerLength
|
||
|
);
|
||
|
}
|
||
|
} // switch
|
||
|
|
||
|
InterruptContollerPtr += *MadtInterruptControllerLength;
|
||
|
Offset += *MadtInterruptControllerLength;
|
||
|
} // while
|
||
|
}
|