You've already forked slimbootloader
mirror of
https://github.com/Dasharo/slimbootloader.git
synced 2026-03-06 15:26:20 -08:00
cd2f00fe2c
This patch will add support for updating multiple firmwares using a single capsule image. Following modifications are made for existing firmware update flow 1) Gather and validate capsule image 2) State Machine will be set to capsule processing state. 3) Signature of the capsule image is now stored in reserved region During each reboot until the end of firmware update, stored signature will be compared against the capsule image signature to make sure capsule image is not modified until the end of firmware update. 4) Process Capsule image to gather firmware images 5) Each Firmware image information will be stored in reserved region using FW_UPDATE_COMP_STATUS. Update pending will be marked to update pending state indicating that this image is not processed. 6) Firmware update will use the reserved region comp structures starting with the first image with update pending state, update the comp update pending field to processing and applies the image. After the update, pending field will be updated to Done and updates the status of the update in the component structure and moves on to next image found. 7) After all the component structure in the reserved region updating pending field are set to Done. Firmware update mode is exited. Signed-off-by: Raghava Gudla <raghava.gudla@intel.com>
686 lines
22 KiB
C
686 lines
22 KiB
C
/** @file
|
|
|
|
Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
|
|
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.
|
|
|
|
**/
|
|
|
|
#include <PiPei.h>
|
|
#include <Library/PcdLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/SocInitLib.h>
|
|
#include <Library/BoardInitLib.h>
|
|
#include <Library/AcpiInitLib.h>
|
|
#include <Library/DebugDataLib.h>
|
|
#include <Library/AcpiInitLib.h>
|
|
#include <Service/PlatformService.h>
|
|
#include <IndustryStandard/Acpi.h>
|
|
#include <IndustryStandard/HighPrecisionEventTimerTable.h>
|
|
#include <IndustryStandard/AcpiAml.h>
|
|
#include <Mcfg.h>
|
|
#include <Library/DebugDataLib.h>
|
|
#include <Library/MpInitLib.h>
|
|
#include <Library/FirmwareUpdateLib.h>
|
|
#include <Guid/BootLoaderVersionGuid.h>
|
|
|
|
#define ACPI_ALLOC(x) (Current = (UINT8 *)(((UINT32)Current - (x)) & ~0x0F))
|
|
#define ACPI_ALLOC_PAGE(x) (Current = (UINT8 *)(((UINT32)Current - (x)) & ~0x0FFF))
|
|
|
|
#define EFI_ACPI_OEM_ID {'O','E','M','I','D',' '} // OEMID 6 bytes long
|
|
#define EFI_ACPI_OEM_TABLE_ID SIGNATURE_64('O','E','M','T','A','B','L','E') // OEM table id 8 bytes long
|
|
#define EFI_ACPI_OEM_REVISION 0x00000005
|
|
#define EFI_ACPI_CREATOR_ID SIGNATURE_32('C','R','E','A')
|
|
#define EFI_ACPI_CREATOR_REVISION 0x0100000D
|
|
|
|
#define ACPI_SKIP 0
|
|
#define ACPI_APPEND 1
|
|
#define ACPI_REPLACE 2
|
|
|
|
extern UINT32 WakeUpBuffer;
|
|
extern CHAR8 WakeUp;
|
|
extern UINT32 WakeUpSize;
|
|
|
|
/**
|
|
Update Firmware Performance Data Table (FPDT).
|
|
|
|
@param[in] Table Pointer of ACPI FPDT Table.
|
|
|
|
@retval EFI_SUCCESS Update ACPI FPDT table successfully.
|
|
@retval Others Failed to update FPDT table.
|
|
**/
|
|
EFI_STATUS
|
|
UpdateFpdt (
|
|
IN VOID *Table
|
|
);
|
|
|
|
const EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER RsdpTmp = {
|
|
.Signature = EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE,
|
|
.Checksum = 0,
|
|
.OemId = EFI_ACPI_OEM_ID,
|
|
.Revision = EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION,
|
|
.Length = sizeof (EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER),
|
|
.ExtendedChecksum = 0,
|
|
.Reserved = {0, 0, 0}
|
|
};
|
|
|
|
const EFI_ACPI_DESCRIPTION_HEADER XsdtTmp = {
|
|
.Signature = EFI_ACPI_5_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
|
|
.Checksum = 0,
|
|
.Length = 0,
|
|
.Revision = EFI_ACPI_5_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_REVISION,
|
|
.OemId = EFI_ACPI_OEM_ID,
|
|
.OemTableId = EFI_ACPI_OEM_TABLE_ID,
|
|
.OemRevision = EFI_ACPI_OEM_REVISION,
|
|
.CreatorId = EFI_ACPI_CREATOR_ID,
|
|
.CreatorRevision = EFI_ACPI_CREATOR_REVISION
|
|
};
|
|
|
|
/**
|
|
This function calculates and updates an UINT8 checksum.
|
|
|
|
@param[in] Buffer Pointer to buffer to checksum
|
|
@param[in] Size Number of bytes to checksum
|
|
|
|
**/
|
|
VOID
|
|
AcpiPlatformChecksum (
|
|
IN UINT8 *Buffer,
|
|
IN UINTN Size
|
|
)
|
|
{
|
|
UINTN ChecksumOffset;
|
|
|
|
ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum);
|
|
|
|
//
|
|
// Set checksum to 0 first
|
|
//
|
|
Buffer[ChecksumOffset] = 0;
|
|
|
|
//
|
|
// Update checksum value
|
|
//
|
|
Buffer[ChecksumOffset] = CalculateCheckSum8 (Buffer, Size);
|
|
}
|
|
|
|
/**
|
|
This function updates GNVS data structure base address dynamically.
|
|
|
|
@param[in] Dsdt Pointer to DSDT table
|
|
@param[in] GnvsBase Physical address of the GNVS data structure
|
|
|
|
**/
|
|
VOID
|
|
UpdateAcpiGnvs (
|
|
IN EFI_ACPI_DESCRIPTION_HEADER *Dsdt,
|
|
IN UINT32 GnvsBase
|
|
)
|
|
{
|
|
UINT8 *Ptr;
|
|
UINT8 *End;
|
|
|
|
Ptr = (UINT8 *)Dsdt;
|
|
End = (UINT8 *)Dsdt + Dsdt->Length;
|
|
|
|
/*
|
|
* Loop through the ASL looking for values that we must fix up.
|
|
*/
|
|
for (; Ptr < End; Ptr++) {
|
|
if (* (UINT32 *)Ptr != SIGNATURE_32 ('G', 'N', 'V', 'S')) {
|
|
continue;
|
|
}
|
|
if (* (Ptr - 1) != AML_EXT_REGION_OP) {
|
|
continue;
|
|
}
|
|
* (UINT32 *) (Ptr + 6) = GnvsBase;
|
|
* (UINT16 *) (Ptr + 11) = (UINT16)GetAcpiGnvsSize();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Update ACPI tables using the new table provided.
|
|
|
|
@param[in] Rsdt ACPI table RSDT pointer.
|
|
@param[in] Signature ACPI table signature to find.
|
|
@param[in] EntryIndex Address to receive the entry index if found.
|
|
|
|
@retval ACPI table pointer if found. And EntryIndex is updated.
|
|
NULL if not found.
|
|
|
|
**/
|
|
EFI_ACPI_DESCRIPTION_HEADER *
|
|
FindAcpiTableBySignature (
|
|
IN EFI_ACPI_DESCRIPTION_HEADER *Rsdt,
|
|
IN UINT32 Signature,
|
|
IN UINT32 *EntryIndex OPTIONAL
|
|
)
|
|
{
|
|
EFI_ACPI_DESCRIPTION_HEADER *CurrHdr;
|
|
UINT32 *RsdtEntry;
|
|
UINT32 EntryNum;
|
|
UINT32 Index;
|
|
|
|
RsdtEntry = (UINT32 *) ((UINT8 *)Rsdt + sizeof (EFI_ACPI_DESCRIPTION_HEADER));
|
|
EntryNum = (Rsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof (UINT32);
|
|
for (Index = 0; Index < EntryNum; Index++) {
|
|
CurrHdr = (EFI_ACPI_DESCRIPTION_HEADER *)RsdtEntry[Index];
|
|
if ((CurrHdr != NULL) && (CurrHdr->Signature == Signature)) {
|
|
if (EntryIndex != NULL) {
|
|
*EntryIndex = Index;
|
|
}
|
|
return CurrHdr;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Update ACPI tables using the new table provided.
|
|
|
|
@param[in] AcpiTable ACPI table address to update.
|
|
@param[in] Length ACPI table buffer length.
|
|
|
|
@retval EFI_SUCCESS Read success
|
|
@retval EFI_INVALID_PARAMETER Invalid region type given
|
|
@retval EFI_UNSUPPORTED Not supported
|
|
@retval EFI_ABORTED Error occrued
|
|
**/
|
|
EFI_STATUS
|
|
AcpiTableUpdate (
|
|
IN UINT8 *AcpiTable,
|
|
IN UINT32 Length
|
|
)
|
|
{
|
|
EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
|
|
EFI_ACPI_DESCRIPTION_HEADER *Xsdt;
|
|
EFI_ACPI_DESCRIPTION_HEADER *Rsdt;
|
|
EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *Facp;
|
|
EFI_ACPI_DESCRIPTION_HEADER *AcpiHdr;
|
|
UINT8 *Current;
|
|
UINT8 *Previous;
|
|
UINT8 *NewTable;
|
|
UINT32 *RsdtEntry;
|
|
UINT64 *XsdtEntry;
|
|
UINT32 EntryIndex;
|
|
UINT32 Policy;
|
|
UINT32 Size;
|
|
UINT32 EntryNum;
|
|
EFI_STATUS Status;
|
|
|
|
if ((AcpiTable == NULL) || (Length < sizeof (EFI_ACPI_DESCRIPTION_HEADER))) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Rsdp = (EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)PcdGet32 (PcdAcpiTablesRsdp);
|
|
Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Rsdp->RsdtAddress;
|
|
Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Rsdp->XsdtAddress;
|
|
RsdtEntry = (UINT32 *) ((UINT8 *)Rsdt + sizeof (EFI_ACPI_DESCRIPTION_HEADER));
|
|
XsdtEntry = (UINT64 *) ((UINT8 *)Xsdt + sizeof (EFI_ACPI_DESCRIPTION_HEADER));
|
|
EntryNum = (Rsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof (UINT32);
|
|
|
|
Current = (UINT8 *)Rsdp;
|
|
|
|
Status = EFI_SUCCESS;
|
|
Size = 0;
|
|
while (Size < Length) {
|
|
AcpiHdr = (EFI_ACPI_DESCRIPTION_HEADER *)(AcpiTable + Size);
|
|
if (CalculateCheckSum8 ((UINT8 *)AcpiHdr, AcpiHdr->Length) != 0) {
|
|
Status = EFI_ABORTED;
|
|
break;
|
|
}
|
|
|
|
if (Size + AcpiHdr->Length > Size) {
|
|
Size += AcpiHdr->Length;
|
|
} else {
|
|
Status = EFI_ABORTED;
|
|
break;
|
|
}
|
|
|
|
// Determine policy
|
|
Previous = Current;
|
|
NewTable = (UINT8 *)ACPI_ALLOC (AcpiHdr->Length);
|
|
if ((UINT32)Current < PcdGet32 (PcdAcpiGnvsAddress) - PcdGet32 (PcdLoaderAcpiReclaimSize)) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
CopyMem (NewTable, AcpiHdr, AcpiHdr->Length);
|
|
|
|
// Update the ACPI header to pointer to the new copy
|
|
// And then update the table if required
|
|
AcpiHdr = (EFI_ACPI_DESCRIPTION_HEADER *)NewTable;
|
|
Status = PlatformUpdateAcpiTable (NewTable);
|
|
if (Status != EFI_SUCCESS) {
|
|
Current = Previous;
|
|
continue;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "ACPI Table 0x%08X - ", AcpiHdr->Signature));
|
|
if (AcpiHdr->Signature == EFI_ACPI_5_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
|
|
Facp = (EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *)FindAcpiTableBySignature (
|
|
Rsdt, EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, &EntryIndex);
|
|
if (Facp != NULL) {
|
|
DEBUG ((DEBUG_INFO, "Replaced\n"));
|
|
Facp->Dsdt = (UINT32)(UINTN)AcpiHdr;
|
|
Facp->XDsdt = (UINT64)(UINTN)AcpiHdr;
|
|
AcpiPlatformChecksum ((UINT8 *)Facp, Facp->Header.Length);
|
|
UpdateAcpiGnvs (AcpiHdr, PcdGet32 (PcdAcpiGnvsAddress));
|
|
} else {
|
|
Status = EFI_ABORTED;
|
|
break;
|
|
}
|
|
} else {
|
|
Policy = ACPI_APPEND;
|
|
if ( (AcpiHdr->Signature == SIGNATURE_32 ('$', 'V', 'B', 'T')) ||
|
|
(AcpiHdr->Signature != EFI_ACPI_5_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) ) {
|
|
// Try to find the table
|
|
if (FindAcpiTableBySignature (Rsdt, AcpiHdr->Signature, &EntryIndex) != NULL) {
|
|
Policy = ACPI_REPLACE;
|
|
}
|
|
}
|
|
if (Policy == ACPI_APPEND) {
|
|
DEBUG ((DEBUG_INFO, "Appended\n"));
|
|
RsdtEntry [EntryNum] = (UINT32)(UINTN)AcpiHdr;
|
|
XsdtEntry [EntryNum] = (UINT32)(UINTN)AcpiHdr;
|
|
EntryNum++;
|
|
if (EntryNum > PcdGet32 (PcdAcpiTablesMaxEntry)) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
break;
|
|
}
|
|
} else if (Policy == ACPI_REPLACE) {
|
|
DEBUG ((DEBUG_INFO, "Replaced\n"));
|
|
RsdtEntry [EntryIndex] = (UINT32)(UINTN)AcpiHdr;
|
|
XsdtEntry [EntryIndex] = (UINT32)(UINTN)AcpiHdr;
|
|
}
|
|
}
|
|
AcpiPlatformChecksum ((UINT8 *)AcpiHdr, AcpiHdr->Length);
|
|
}
|
|
|
|
Rsdt->Length = sizeof (EFI_ACPI_DESCRIPTION_HEADER) + EntryNum * sizeof (UINT32);
|
|
AcpiPlatformChecksum ((UINT8 *)Rsdt, Rsdt->Length);
|
|
|
|
Xsdt->Length = sizeof (EFI_ACPI_DESCRIPTION_HEADER) + EntryNum * sizeof (UINT64);
|
|
AcpiPlatformChecksum ((UINT8 *)Xsdt, Xsdt->Length);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Acpi update failed - %r\n", Status));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This function updates MADT data structure based on Sysinfo APICID
|
|
for number of active cores dynamically.
|
|
|
|
@param[in] Current Pointer to MADT table
|
|
@retval EFI_SUCCESS Patched the MADT
|
|
EFI_UNSUPPORTED Sysinfo table not found.
|
|
EFI_OUT_OF_RESOURCES If less MADT entries
|
|
**/
|
|
EFI_STATUS
|
|
UpdateMadt (
|
|
IN UINT8 *Current
|
|
)
|
|
{
|
|
EFI_ACPI_5_0_PROCESSOR_LOCAL_APIC_STRUCTURE *LocalApic;
|
|
EFI_ACPI_5_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *Temp;
|
|
SYS_CPU_INFO *SysCpuInfo;
|
|
UINT32 CpuCount;
|
|
UINT32 MarkCpuCount;
|
|
UINT32 Idx;
|
|
UINT32 EndOfMadt;
|
|
UINT8 *Madt;
|
|
|
|
Temp = (EFI_ACPI_5_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *)Current;
|
|
EndOfMadt = Temp->Header.Length + (UINT32)Current;
|
|
|
|
Madt = Current;
|
|
//Skip the header
|
|
Madt = Madt + sizeof (EFI_ACPI_5_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER);
|
|
|
|
//Get the Mp Table info
|
|
SysCpuInfo = MpGetInfo ();
|
|
if (SysCpuInfo != NULL) {
|
|
CpuCount = SysCpuInfo->CpuCount;
|
|
MarkCpuCount = CpuCount;
|
|
} else {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//Search for Processor Local APIC
|
|
while ((UINT32)Madt < EndOfMadt) {
|
|
LocalApic = (EFI_ACPI_5_0_PROCESSOR_LOCAL_APIC_STRUCTURE *)Madt;
|
|
if (LocalApic->Type == EFI_ACPI_5_0_PROCESSOR_LOCAL_APIC) {
|
|
LocalApic->Flags = 0;
|
|
for (Idx = 0 ; Idx < CpuCount; Idx ++) {
|
|
if ((LocalApic->ApicId == SysCpuInfo->CpuInfo[Idx].ApicId) && (LocalApic->Flags == 0)) {
|
|
LocalApic->Flags = 1;
|
|
MarkCpuCount--;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
Madt = Madt + LocalApic->Length;
|
|
}
|
|
|
|
if (MarkCpuCount != 0) {
|
|
DEBUG ((DEBUG_ERROR, "Less MADT entries than Number of cores..\n"));
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function updates FWST ACPI data structure.
|
|
|
|
@param[in] Current Pointer to FWST table
|
|
@retval EFI_SUCCESS Patched the FWST
|
|
EFI_NOT_FOUND Reserved region component information not found.
|
|
**/
|
|
EFI_STATUS
|
|
UpdateFwst (
|
|
IN UINT8 *Current
|
|
)
|
|
{
|
|
UINT8 Count;
|
|
UINT32 RsvdBase;
|
|
EFI_STATUS Status;
|
|
EFI_FWST_ACPI_DESCRIPTION_TABLE *FwstAcpiTablePtr;
|
|
FW_UPDATE_COMP_STATUS *FwUpdCompStatus;
|
|
|
|
//
|
|
// We do not need to populate ACPI table during firmware update
|
|
//
|
|
if (GetBootMode () == BOOT_ON_FLASH_UPDATE) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Get bootloader reserved region base
|
|
//
|
|
Status = GetComponentInfo (FLASH_MAP_SIG_BLRESERVED, &RsvdBase, NULL);
|
|
if (EFI_ERROR(Status)) {
|
|
DEBUG((DEBUG_ERROR, "Could not get reserved region base\n"));
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Fill in details for FWST ACPI table
|
|
//
|
|
FwstAcpiTablePtr = (EFI_FWST_ACPI_DESCRIPTION_TABLE *)Current;
|
|
FwUpdCompStatus = (FW_UPDATE_COMP_STATUS *)(RsvdBase + sizeof(FW_UPDATE_STATUS));
|
|
for (Count = 0; Count < MAX_FW_COMPONENTS; Count ++) {
|
|
CopyMem(&(FwstAcpiTablePtr->EsrtTableEntry[Count].FwClass), &(FwUpdCompStatus->FirmwareId), sizeof(EFI_GUID));
|
|
FwstAcpiTablePtr->EsrtTableEntry[Count].FwType = ESRT_FW_TYPE_SYSTEMFIRMWARE;
|
|
FwstAcpiTablePtr->EsrtTableEntry[Count].LastAttemptVersion = FwUpdCompStatus->LastAttemptVersion;
|
|
FwstAcpiTablePtr->EsrtTableEntry[Count].LastAttemptStatus = FwUpdCompStatus->LastAttemptStatus;
|
|
FwUpdCompStatus = (FW_UPDATE_COMP_STATUS *)((UINT32)FwUpdCompStatus + sizeof(FW_UPDATE_COMP_STATUS));
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function creates necessary ACPI tables and puts the RSDP
|
|
table in F segment so that OS can locate it.
|
|
|
|
@param[in] AcpiMemTop ACPI memory top address.
|
|
|
|
@retval EFI_SUCCESS ACPI tables are created successfully.
|
|
EFI_NOT_FOUND Required ACPI tables could not be found.
|
|
EFI_UNSUPPORTED Sysinfo table not found.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AcpiInit (
|
|
IN UINT32 *AcpiMemTop
|
|
)
|
|
{
|
|
UINT8 *TblPtr;
|
|
UINT8 *EndPtr;
|
|
EFI_ACPI_COMMON_HEADER *Table;
|
|
UINT8 *Current;
|
|
UINT8 *Previous;
|
|
EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
|
|
EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *Facp;
|
|
EFI_ACPI_DESCRIPTION_HEADER *Dsdt;
|
|
EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
|
|
EFI_ACPI_DESCRIPTION_HEADER *Xsdt;
|
|
EFI_ACPI_DESCRIPTION_HEADER *Rsdt;
|
|
EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE *Mcfg;
|
|
PLATFORM_SERVICE *PlatformService;
|
|
UINT32 *RsdtEntry;
|
|
UINT64 *XsdtEntry;
|
|
UINT32 TotalSize;
|
|
UINT32 XsdtIndex;
|
|
UINT32 SectionLen;
|
|
UINT32 UpdateRdstXsdt;
|
|
EFI_STATUS Status;
|
|
|
|
Facs = NULL;
|
|
Dsdt = NULL;
|
|
Facp = NULL;
|
|
UpdateRdstXsdt = 0;
|
|
|
|
Current = (UINT8 *) (*AcpiMemTop);
|
|
|
|
//
|
|
// Create RSDT structures and allocate buffers.
|
|
//
|
|
TotalSize = sizeof (EFI_ACPI_DESCRIPTION_HEADER) + PcdGet32 (PcdAcpiTablesMaxEntry) * sizeof (UINT32);
|
|
Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) ACPI_ALLOC (TotalSize);
|
|
CopyMem (Rsdt, &XsdtTmp, sizeof (EFI_ACPI_DESCRIPTION_HEADER));
|
|
Rsdt->Signature = EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE;
|
|
Rsdt->Revision = EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION;
|
|
RsdtEntry = (UINT32 *) ((UINT8 *)Rsdt + sizeof (EFI_ACPI_DESCRIPTION_HEADER));
|
|
SetMem (RsdtEntry, PcdGet32 (PcdAcpiTablesMaxEntry) * sizeof (UINT32), 0);
|
|
|
|
//
|
|
// Create XSDT structures and allocate buffers.
|
|
//
|
|
TotalSize = sizeof (EFI_ACPI_DESCRIPTION_HEADER) + PcdGet32 (PcdAcpiTablesMaxEntry) * sizeof (UINT64);
|
|
Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) ACPI_ALLOC (TotalSize);
|
|
CopyMem (Xsdt, &XsdtTmp, sizeof (EFI_ACPI_DESCRIPTION_HEADER));
|
|
XsdtEntry = (UINT64 *) ((UINT8 *)Xsdt + sizeof (EFI_ACPI_DESCRIPTION_HEADER));
|
|
XsdtIndex = 0;
|
|
SetMem (XsdtEntry, PcdGet32 (PcdAcpiTablesMaxEntry) * sizeof (UINT64), 0);
|
|
|
|
TblPtr = (UINT8 *)PcdGet32 (PcdAcpiTablesAddress);
|
|
EndPtr = TblPtr + ((* ((UINT32 *) (TblPtr - 8)) & 0xFFFFFF) - 28);
|
|
while (TblPtr < EndPtr) {
|
|
Previous = Current;
|
|
|
|
Table = (EFI_ACPI_COMMON_HEADER *)TblPtr;
|
|
ACPI_ALLOC (Table->Length);
|
|
CopyMem (Current, Table, Table->Length);
|
|
|
|
Status = PlatformUpdateAcpiTable (Current);
|
|
if (Status != EFI_SUCCESS) {
|
|
Current = Previous;
|
|
DEBUG ((DEBUG_WARN, "Not adding ACPI table \n"));
|
|
SectionLen = * (UINT32 *) (TblPtr - 4) & 0x00FFFFFF;
|
|
TblPtr = TblPtr + ((SectionLen + 3) & ~3);
|
|
continue;
|
|
}
|
|
|
|
UpdateRdstXsdt = 1;
|
|
|
|
switch (Table->Signature) {
|
|
case EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:
|
|
// FACP
|
|
Facp = (EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *)Current;
|
|
break;
|
|
case EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE:
|
|
// FACS
|
|
Facs = (EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)Current;
|
|
UpdateRdstXsdt = 0;
|
|
break;
|
|
case EFI_ACPI_5_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
|
|
// DSDT
|
|
Dsdt = (EFI_ACPI_DESCRIPTION_HEADER *)Current;
|
|
UpdateAcpiGnvs (Dsdt, PcdGet32 (PcdAcpiGnvsAddress));
|
|
UpdateRdstXsdt = 0;
|
|
break;
|
|
case EFI_ACPI_5_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE:
|
|
// MCFG
|
|
Mcfg = (EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE *)Current;
|
|
Mcfg->Segment.BaseAddress = PcdGet64 (PcdPciExpressBaseAddress);
|
|
break;
|
|
case EFI_ACPI_5_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE:
|
|
// MADT
|
|
Status = UpdateMadt (Current);
|
|
if (Status != EFI_SUCCESS) {
|
|
return Status;
|
|
}
|
|
break;
|
|
case EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE:
|
|
// FPDT
|
|
Status = UpdateFpdt (Current);
|
|
if (Status != EFI_SUCCESS) {
|
|
return Status;
|
|
}
|
|
break;
|
|
case EFI_FIRMWARE_UPDATE_STATUS_TABLE_SIGNATURE:
|
|
// FWST
|
|
Status = UpdateFwst (Current);
|
|
if (Status != EFI_SUCCESS) {
|
|
return Status;
|
|
}
|
|
break;
|
|
default:
|
|
// Misc
|
|
break;
|
|
}
|
|
|
|
if (UpdateRdstXsdt == 1) {
|
|
RsdtEntry[XsdtIndex] = (UINT32) (UINTN)Current;
|
|
XsdtEntry[XsdtIndex++] = (UINT64) (UINTN)Current;
|
|
}
|
|
ASSERT (XsdtIndex < PcdGet32 (PcdAcpiTablesMaxEntry));
|
|
|
|
if (Current != (UINT8 *)Facp) {
|
|
AcpiPlatformChecksum (
|
|
Current,
|
|
((EFI_ACPI_COMMON_HEADER *)Current)->Length
|
|
);
|
|
}
|
|
|
|
SectionLen = * (UINT32 *) (TblPtr - 4) & 0x00FFFFFF;
|
|
TblPtr = TblPtr + ((SectionLen + 3) & ~3);
|
|
}
|
|
|
|
if (Facp == NULL || Facs == NULL || Dsdt == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Facp->FirmwareCtrl = (UINT32)(UINTN)Facs;
|
|
Facp->XFirmwareCtrl = (UINT64)(UINTN)Facs;
|
|
Facp->Dsdt = (UINT32)(UINTN)Dsdt;
|
|
Facp->XDsdt = (UINT64)(UINTN)Dsdt;
|
|
|
|
AcpiPlatformChecksum ((UINT8 *)Facp, Facp->Header.Length);
|
|
|
|
Rsdt->Length = sizeof (EFI_ACPI_DESCRIPTION_HEADER) + XsdtIndex * sizeof (UINT32);
|
|
AcpiPlatformChecksum ((UINT8 *)Rsdt, Rsdt->Length);
|
|
|
|
Xsdt->Length = sizeof (EFI_ACPI_DESCRIPTION_HEADER) + XsdtIndex * sizeof (UINT64);
|
|
AcpiPlatformChecksum ((UINT8 *)Xsdt, Xsdt->Length);
|
|
|
|
//
|
|
// Make Rsdp page aligned
|
|
//
|
|
Rsdp = (EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER *) \
|
|
ACPI_ALLOC_PAGE (sizeof (EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER));
|
|
CopyMem (Rsdp, &RsdpTmp, sizeof (RsdpTmp));
|
|
Rsdp->RsdtAddress = (UINT32)Rsdt;
|
|
Rsdp->XsdtAddress = (UINT64) (UINTN)Xsdt;
|
|
Rsdp->Checksum = CalculateCheckSum8 ((UINT8 *)Rsdp, sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER));
|
|
Rsdp->ExtendedChecksum = CalculateCheckSum8 ((UINT8 *)Rsdp, Rsdp->Length);
|
|
*AcpiMemTop = (UINT32)Current;
|
|
|
|
//
|
|
// Keep a copy at F segment so that non-UEFI OS will find ACPI tables
|
|
//
|
|
Status = PcdSet32S (PcdAcpiTablesRsdp, (UINT32)Rsdp);
|
|
CopyMem ((VOID *)0xFFF80, Rsdp, sizeof (RsdpTmp));
|
|
|
|
// Update ACPI update service so that payload can have opportunity to update ACPI tables
|
|
PlatformService = (PLATFORM_SERVICE *) GetServiceBySignature (PLATFORM_SERVICE_SIGNATURE);
|
|
if (PlatformService != NULL) {
|
|
PlatformService->AcpiTableUpdate = AcpiTableUpdate;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
typedef VOID (*DOWAKEUP) (UINT32 WakeVector);
|
|
|
|
|
|
/**
|
|
This function is called on S3 boot flow only.
|
|
|
|
It will locate the S3 waking vector from the ACPI table and then
|
|
jump into it. The control will never return.
|
|
|
|
@param AcpiTableBase ACPI table base address
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
FindAcpiWakeVectorAndJump (
|
|
IN UINT32 AcpiTableBase
|
|
)
|
|
{
|
|
EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
|
|
EFI_ACPI_DESCRIPTION_HEADER *Xsdt;
|
|
EFI_ACPI_COMMON_HEADER *Hdr;
|
|
UINT64 *XsdtEntry;
|
|
UINT8 Index;
|
|
EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
|
|
EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *Facp;
|
|
UINT32 WakeVector;
|
|
DOWAKEUP DoWake;
|
|
|
|
Rsdp = (EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER *) AcpiTableBase;
|
|
Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN)Rsdp->XsdtAddress;
|
|
XsdtEntry = (UINT64 *) ((UINT8 *)Xsdt + sizeof (EFI_ACPI_DESCRIPTION_HEADER));
|
|
|
|
for (Index = 0; Index < PcdGet32 (PcdAcpiTablesMaxEntry); ++Index) {
|
|
Hdr = (EFI_ACPI_COMMON_HEADER *) (UINTN)XsdtEntry[Index];
|
|
if (Hdr->Signature == EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
|
|
Facp = (EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *) Hdr;
|
|
Facs = (EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) Facp->FirmwareCtrl;
|
|
if (Facs->Signature == EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) {
|
|
WakeVector = Facs->FirmwareWakingVector;
|
|
// Calculate CRC32 for 0x00000000 ---> BootLoaderRsvdMemBase and
|
|
// compare with the one calculated and saved in Stage1B.
|
|
if (PcdGetBool (PcdS3DebugEnabled)) {
|
|
if (!S3DebugRestoreAndCompareCRC32 () ) {
|
|
return;
|
|
}
|
|
}
|
|
CopyMem ((VOID *)WakeUpBuffer, &WakeUp, WakeUpSize);
|
|
DoWake = (DOWAKEUP)WakeUpBuffer;
|
|
DEBUG ((DEBUG_INIT, "Jump to Wake vector = 0x%x\n", WakeVector));
|
|
DoWake (WakeVector);
|
|
//
|
|
// Should never reach here!
|
|
//
|
|
}
|
|
}
|
|
}
|
|
}
|