/** @file | |
This module provides help function for finding ACPI table. | |
Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "UefiLibInternal.h" | |
#include <IndustryStandard/Acpi.h> | |
#include <Guid/Acpi.h> | |
/** | |
This function scans ACPI table in XSDT/RSDT. | |
@param Sdt ACPI XSDT/RSDT. | |
@param TablePointerSize Size of table pointer: 8(XSDT) or 4(RSDT). | |
@param Signature ACPI table signature. | |
@param PreviousTable Pointer to previous returned table to locate | |
next table, or NULL to locate first table. | |
@param PreviousTableLocated Pointer to the indicator about whether the | |
previous returned table could be located, or | |
NULL if PreviousTable is NULL. | |
If PreviousTable is NULL and PreviousTableLocated is not NULL, then ASSERT(). | |
If PreviousTable is not NULL and PreviousTableLocated is NULL, then ASSERT(). | |
@return ACPI table or NULL if not found. | |
**/ | |
EFI_ACPI_COMMON_HEADER * | |
ScanTableInSDT ( | |
IN EFI_ACPI_DESCRIPTION_HEADER *Sdt, | |
IN UINTN TablePointerSize, | |
IN UINT32 Signature, | |
IN EFI_ACPI_COMMON_HEADER *PreviousTable OPTIONAL, | |
OUT BOOLEAN *PreviousTableLocated OPTIONAL | |
) | |
{ | |
UINTN Index; | |
UINTN EntryCount; | |
UINT64 EntryPtr; | |
UINTN BasePtr; | |
EFI_ACPI_COMMON_HEADER *Table; | |
if (PreviousTableLocated != NULL) { | |
ASSERT (PreviousTable != NULL); | |
*PreviousTableLocated = FALSE; | |
} else { | |
ASSERT (PreviousTable == NULL); | |
} | |
if (Sdt == NULL) { | |
return NULL; | |
} | |
EntryCount = (Sdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / TablePointerSize; | |
BasePtr = (UINTN)(Sdt + 1); | |
for (Index = 0; Index < EntryCount; Index++) { | |
EntryPtr = 0; | |
CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * TablePointerSize), TablePointerSize); | |
Table = (EFI_ACPI_COMMON_HEADER *)((UINTN)(EntryPtr)); | |
if ((Table != NULL) && (Table->Signature == Signature)) { | |
if (PreviousTable != NULL) { | |
if (Table == PreviousTable) { | |
*PreviousTableLocated = TRUE; | |
} else if (*PreviousTableLocated) { | |
// | |
// Return next table. | |
// | |
return Table; | |
} | |
} else { | |
// | |
// Return first table. | |
// | |
return Table; | |
} | |
} | |
} | |
return NULL; | |
} | |
/** | |
To locate FACS in FADT. | |
@param Fadt FADT table pointer. | |
@return FACS table pointer or NULL if not found. | |
**/ | |
EFI_ACPI_COMMON_HEADER * | |
LocateAcpiFacsFromFadt ( | |
IN EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt | |
) | |
{ | |
EFI_ACPI_COMMON_HEADER *Facs; | |
UINT64 Data64; | |
if (Fadt == NULL) { | |
return NULL; | |
} | |
if (Fadt->Header.Revision < EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION) { | |
Facs = (EFI_ACPI_COMMON_HEADER *)(UINTN)Fadt->FirmwareCtrl; | |
} else { | |
CopyMem (&Data64, &Fadt->XFirmwareCtrl, sizeof (UINT64)); | |
if (Data64 != 0) { | |
Facs = (EFI_ACPI_COMMON_HEADER *)(UINTN)Data64; | |
} else { | |
Facs = (EFI_ACPI_COMMON_HEADER *)(UINTN)Fadt->FirmwareCtrl; | |
} | |
} | |
return Facs; | |
} | |
/** | |
To locate DSDT in FADT. | |
@param Fadt FADT table pointer. | |
@return DSDT table pointer or NULL if not found. | |
**/ | |
EFI_ACPI_COMMON_HEADER * | |
LocateAcpiDsdtFromFadt ( | |
IN EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt | |
) | |
{ | |
EFI_ACPI_COMMON_HEADER *Dsdt; | |
UINT64 Data64; | |
if (Fadt == NULL) { | |
return NULL; | |
} | |
if (Fadt->Header.Revision < EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION) { | |
Dsdt = (EFI_ACPI_COMMON_HEADER *)(UINTN)Fadt->Dsdt; | |
} else { | |
CopyMem (&Data64, &Fadt->XDsdt, sizeof (UINT64)); | |
if (Data64 != 0) { | |
Dsdt = (EFI_ACPI_COMMON_HEADER *)(UINTN)Data64; | |
} else { | |
Dsdt = (EFI_ACPI_COMMON_HEADER *)(UINTN)Fadt->Dsdt; | |
} | |
} | |
return Dsdt; | |
} | |
/** | |
To locate ACPI table in ACPI ConfigurationTable. | |
@param AcpiGuid The GUID used to get ACPI ConfigurationTable. | |
@param Signature ACPI table signature. | |
@param PreviousTable Pointer to previous returned table to locate | |
next table, or NULL to locate first table. | |
@param PreviousTableLocated Pointer to the indicator to return whether the | |
previous returned table could be located or not, | |
or NULL if PreviousTable is NULL. | |
If PreviousTable is NULL and PreviousTableLocated is not NULL, then ASSERT(). | |
If PreviousTable is not NULL and PreviousTableLocated is NULL, then ASSERT(). | |
If AcpiGuid is NULL, then ASSERT(). | |
@return ACPI table or NULL if not found. | |
**/ | |
EFI_ACPI_COMMON_HEADER * | |
LocateAcpiTableInAcpiConfigurationTable ( | |
IN EFI_GUID *AcpiGuid, | |
IN UINT32 Signature, | |
IN EFI_ACPI_COMMON_HEADER *PreviousTable OPTIONAL, | |
OUT BOOLEAN *PreviousTableLocated OPTIONAL | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_ACPI_COMMON_HEADER *Table; | |
EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp; | |
EFI_ACPI_DESCRIPTION_HEADER *Rsdt; | |
EFI_ACPI_DESCRIPTION_HEADER *Xsdt; | |
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt; | |
if (PreviousTableLocated != NULL) { | |
ASSERT (PreviousTable != NULL); | |
*PreviousTableLocated = FALSE; | |
} else { | |
ASSERT (PreviousTable == NULL); | |
} | |
Rsdp = NULL; | |
// | |
// Get ACPI ConfigurationTable (RSD_PTR) | |
// | |
Status = EfiGetSystemConfigurationTable (AcpiGuid, (VOID **)&Rsdp); | |
if (EFI_ERROR (Status) || (Rsdp == NULL)) { | |
return NULL; | |
} | |
Table = NULL; | |
// | |
// Search XSDT | |
// | |
if (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION) { | |
Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Rsdp->XsdtAddress; | |
if (Signature == EFI_ACPI_2_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) { | |
ASSERT (PreviousTable == NULL); | |
// | |
// It is to locate DSDT, | |
// need to locate FADT first. | |
// | |
Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *)ScanTableInSDT ( | |
Xsdt, | |
sizeof (UINT64), | |
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, | |
NULL, | |
NULL | |
); | |
Table = LocateAcpiDsdtFromFadt (Fadt); | |
} else if (Signature == EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) { | |
ASSERT (PreviousTable == NULL); | |
// | |
// It is to locate FACS, | |
// need to locate FADT first. | |
// | |
Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *)ScanTableInSDT ( | |
Xsdt, | |
sizeof (UINT64), | |
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, | |
NULL, | |
NULL | |
); | |
Table = LocateAcpiFacsFromFadt (Fadt); | |
} else { | |
Table = ScanTableInSDT ( | |
Xsdt, | |
sizeof (UINT64), | |
Signature, | |
PreviousTable, | |
PreviousTableLocated | |
); | |
} | |
} | |
if (Table != NULL) { | |
return Table; | |
} else if ((PreviousTableLocated != NULL) && | |
*PreviousTableLocated) | |
{ | |
// | |
// PreviousTable could be located in XSDT, | |
// but next table could not be located in XSDT. | |
// | |
return NULL; | |
} | |
// | |
// Search RSDT | |
// | |
Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Rsdp->RsdtAddress; | |
if (Signature == EFI_ACPI_2_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) { | |
ASSERT (PreviousTable == NULL); | |
// | |
// It is to locate DSDT, | |
// need to locate FADT first. | |
// | |
Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *)ScanTableInSDT ( | |
Rsdt, | |
sizeof (UINT32), | |
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, | |
NULL, | |
NULL | |
); | |
Table = LocateAcpiDsdtFromFadt (Fadt); | |
} else if (Signature == EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) { | |
ASSERT (PreviousTable == NULL); | |
// | |
// It is to locate FACS, | |
// need to locate FADT first. | |
// | |
Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *)ScanTableInSDT ( | |
Rsdt, | |
sizeof (UINT32), | |
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, | |
NULL, | |
NULL | |
); | |
Table = LocateAcpiFacsFromFadt (Fadt); | |
} else { | |
Table = ScanTableInSDT ( | |
Rsdt, | |
sizeof (UINT32), | |
Signature, | |
PreviousTable, | |
PreviousTableLocated | |
); | |
} | |
return Table; | |
} | |
/** | |
This function locates next ACPI table in XSDT/RSDT based on Signature and | |
previous returned Table. | |
If PreviousTable is NULL: | |
This function will locate the first ACPI table in XSDT/RSDT based on | |
Signature in gEfiAcpi20TableGuid system configuration table first, and then | |
gEfiAcpi10TableGuid system configuration table. | |
This function will locate in XSDT first, and then RSDT. | |
For DSDT, this function will locate XDsdt in FADT first, and then Dsdt in | |
FADT. | |
For FACS, this function will locate XFirmwareCtrl in FADT first, and then | |
FirmwareCtrl in FADT. | |
If PreviousTable is not NULL: | |
1. If it could be located in XSDT in gEfiAcpi20TableGuid system configuration | |
table, then this function will just locate next table in XSDT in | |
gEfiAcpi20TableGuid system configuration table. | |
2. If it could be located in RSDT in gEfiAcpi20TableGuid system configuration | |
table, then this function will just locate next table in RSDT in | |
gEfiAcpi20TableGuid system configuration table. | |
3. If it could be located in RSDT in gEfiAcpi10TableGuid system configuration | |
table, then this function will just locate next table in RSDT in | |
gEfiAcpi10TableGuid system configuration table. | |
It's not supported that PreviousTable is not NULL but PreviousTable->Signature | |
is not same with Signature, NULL will be returned. | |
@param Signature ACPI table signature. | |
@param PreviousTable Pointer to previous returned table to locate next | |
table, or NULL to locate first table. | |
@return Next ACPI table or NULL if not found. | |
**/ | |
EFI_ACPI_COMMON_HEADER * | |
EFIAPI | |
EfiLocateNextAcpiTable ( | |
IN UINT32 Signature, | |
IN EFI_ACPI_COMMON_HEADER *PreviousTable OPTIONAL | |
) | |
{ | |
EFI_ACPI_COMMON_HEADER *Table; | |
BOOLEAN TempPreviousTableLocated; | |
BOOLEAN *PreviousTableLocated; | |
if (PreviousTable != NULL) { | |
if (PreviousTable->Signature != Signature) { | |
// | |
// PreviousTable->Signature is not same with Signature. | |
// | |
return NULL; | |
} else if ((Signature == EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) || | |
(Signature == EFI_ACPI_2_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) || | |
(Signature == EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE)) | |
{ | |
// | |
// There is only one FADT/DSDT/FACS table, | |
// so don't try to locate next one. | |
// | |
return NULL; | |
} | |
PreviousTableLocated = &TempPreviousTableLocated; | |
*PreviousTableLocated = FALSE; | |
} else { | |
PreviousTableLocated = NULL; | |
} | |
Table = LocateAcpiTableInAcpiConfigurationTable ( | |
&gEfiAcpi20TableGuid, | |
Signature, | |
PreviousTable, | |
PreviousTableLocated | |
); | |
if (Table != NULL) { | |
return Table; | |
} else if ((PreviousTableLocated != NULL) && | |
*PreviousTableLocated) | |
{ | |
// | |
// PreviousTable could be located in gEfiAcpi20TableGuid system | |
// configuration table, but next table could not be located in | |
// gEfiAcpi20TableGuid system configuration table. | |
// | |
return NULL; | |
} | |
return LocateAcpiTableInAcpiConfigurationTable ( | |
&gEfiAcpi10TableGuid, | |
Signature, | |
PreviousTable, | |
PreviousTableLocated | |
); | |
} | |
/** | |
This function locates first ACPI table in XSDT/RSDT based on Signature. | |
This function will locate the first ACPI table in XSDT/RSDT based on | |
Signature in gEfiAcpi20TableGuid system configuration table first, and then | |
gEfiAcpi10TableGuid system configuration table. | |
This function will locate in XSDT first, and then RSDT. | |
For DSDT, this function will locate XDsdt in FADT first, and then Dsdt in | |
FADT. | |
For FACS, this function will locate XFirmwareCtrl in FADT first, and then | |
FirmwareCtrl in FADT. | |
@param Signature ACPI table signature. | |
@return First ACPI table or NULL if not found. | |
**/ | |
EFI_ACPI_COMMON_HEADER * | |
EFIAPI | |
EfiLocateFirstAcpiTable ( | |
IN UINT32 Signature | |
) | |
{ | |
return EfiLocateNextAcpiTable (Signature, NULL); | |
} |