374 lines
12 KiB
C
374 lines
12 KiB
C
/** @file
|
|
Provide support functions for MultiConfig Update.
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2012 - 2020, Insyde Software Corp. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
#include <Uefi.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/UefiLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/MultiConfigBaseLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/UefiDriverEntryPoint.h>
|
|
#include <Library/FlashRegionLib.h>
|
|
#include <Protocol/Smbios.h>
|
|
#include <Guid/EventGroup.h>
|
|
#include <Guid/DebugMask.h>
|
|
#include "MultiConfigUpdateDxe.h"
|
|
#include "DmiStringInformation.h"
|
|
|
|
STATIC UINT8 *mDmiStart = NULL;
|
|
STATIC UINT8 *mDmiEnd = NULL;
|
|
STATIC UINT8 *mVarStart = NULL;
|
|
STATIC UINT8 *mVarEnd = NULL;
|
|
|
|
/**
|
|
Check if SmbiosTool or variable update the same data
|
|
|
|
@param[in] Type Update Smbios data Type
|
|
@param[in] Offset Update Smbios data Offset
|
|
|
|
@retval TRUE SmbiosTool or Variable update the same data
|
|
@retval FALSE No one update the same data
|
|
**/
|
|
BOOLEAN
|
|
CheckReplaceDataFromSmbiosTool (
|
|
IN UINT8 Type,
|
|
IN UINT8 Offset
|
|
)
|
|
{
|
|
DMI_STRING_STRUCTURE *DmiEntry;
|
|
UINTN MinSize;
|
|
|
|
if (mDmiStart == NULL && mVarStart == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (mDmiStart != NULL) {
|
|
DmiEntry = (DMI_STRING_STRUCTURE *)mDmiStart;
|
|
while ((UINT8 *)DmiEntry < mDmiEnd && DmiEntry->Type != 0xFF && DmiEntry->Length != 0) {
|
|
if (DmiEntry->Valid == SMBIOS_DMI_VALID && DmiEntry->Type == Type && DmiEntry->Offset == Offset) {
|
|
return TRUE;
|
|
}
|
|
DmiEntry = (DMI_STRING_STRUCTURE *)((CHAR8 *)DmiEntry + DmiEntry->Length);
|
|
}
|
|
}
|
|
|
|
if (mVarStart != NULL) {
|
|
DmiEntry = (DMI_STRING_STRUCTURE *)mVarStart;
|
|
MinSize = sizeof(DMI_STRING_STRUCTURE) - sizeof(UINT8);
|
|
while (((UINT8 *)DmiEntry + MinSize - 1) < mVarEnd && DmiEntry->Type != 0xFF && DmiEntry->Length != 0) {
|
|
if (DmiEntry->Valid == SMBIOS_DMI_VALID && DmiEntry->Type == Type && DmiEntry->Offset == Offset) {
|
|
return TRUE;
|
|
}
|
|
DmiEntry = (DMI_STRING_STRUCTURE *)((CHAR8 *)DmiEntry + DmiEntry->Length);
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Update Smbios Data function
|
|
|
|
@param[in] This Smbios protocol
|
|
@param[in] DMIData Update Smbios Data
|
|
**/
|
|
VOID
|
|
UpdateSmbiosData (
|
|
IN EFI_SMBIOS_PROTOCOL *This,
|
|
IN MC_SMBIOS_SETTING *SmbiosData
|
|
)
|
|
{
|
|
EFI_SMBIOS_TABLE_HEADER *Record;
|
|
UINT16 Instance;
|
|
UINT8 *Data;
|
|
EFI_STATUS Status;
|
|
EFI_SMBIOS_HANDLE SmbiosHandle;
|
|
BOOLEAN SmbiosToolUpdateData;
|
|
|
|
Record = NULL;
|
|
Data = NULL;
|
|
Instance = 0;
|
|
SmbiosHandle = MC_SMBIOS_HANDLE_PI_RESERVED;
|
|
|
|
if ((This == NULL) || (SmbiosData == NULL)) {
|
|
return;
|
|
}
|
|
|
|
while (TRUE) {
|
|
Status = This->GetNext (This, &SmbiosHandle, &SmbiosData->Type, &Record, NULL);
|
|
if (EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
if (SmbiosData->Instance != Instance) {
|
|
Instance ++;
|
|
continue;
|
|
}
|
|
if (SmbiosData->DataAttr == SMBIOS_REMOVE_ATTR) {
|
|
DEBUG ((EFI_D_ERROR, "Remove Smbios Type:%Xh Instance:%d \n", SmbiosData->Type, SmbiosData->Instance));
|
|
Record->Type = SMBIOS_REMOVE_TYPE;
|
|
} else {
|
|
//
|
|
// Check DMI Update the same data
|
|
//
|
|
SmbiosToolUpdateData = FALSE;
|
|
if (mDmiStart != NULL || mVarStart != NULL) {
|
|
SmbiosToolUpdateData = CheckReplaceDataFromSmbiosTool (SmbiosData->Type, (UINT8) SmbiosData->SmbiosOffset);
|
|
}
|
|
if (!SmbiosToolUpdateData) {
|
|
Data = (UINT8 *) Record;
|
|
CopyMem ((VOID *)(Data + SmbiosData->SmbiosOffset), (VOID *) SmbiosData->Data, SmbiosData->DataSize);
|
|
DEBUG ((EFI_D_ERROR, "Update Smbios Type:%Xh Instance:%d Offset:%d, Size:%d\n", SmbiosData->Type, SmbiosData->Instance, SmbiosData->SmbiosOffset, SmbiosData->DataSize));
|
|
} else {
|
|
DEBUG ((EFI_D_ERROR, "Smbios Tool update the same Data\n"));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Update Smbios String function
|
|
|
|
@param[in] This Smbios protocol
|
|
@param[in] DMIData Update Smbios Data
|
|
**/
|
|
VOID
|
|
UpdateSmbiosString (
|
|
IN EFI_SMBIOS_PROTOCOL *This,
|
|
IN MC_SMBIOS_SETTING *SmbiosData
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOLEAN SmbiosToolUpdateString;
|
|
UINTN StringNum;
|
|
CHAR8 *UpdateString;
|
|
EFI_SMBIOS_TABLE_HEADER *Record;
|
|
UINT8 *RecordData;
|
|
EFI_SMBIOS_HANDLE SmbiosHandle;
|
|
UINT16 Instance;
|
|
UINTN Index;
|
|
|
|
SmbiosToolUpdateString = FALSE;
|
|
StringNum = 0;
|
|
UpdateString = NULL;
|
|
SmbiosHandle = 0xFFFE;
|
|
Instance = 0;
|
|
|
|
if ((This == NULL) || (SmbiosData == NULL)) {
|
|
return;
|
|
}
|
|
|
|
do {
|
|
Status = This->GetNext (This, &SmbiosHandle, &SmbiosData->Type, &Record, NULL);
|
|
Instance ++;
|
|
} while (!((Instance == SmbiosData->Instance + 1) || EFI_ERROR (Status)));
|
|
|
|
RecordData = (UINT8 *)Record;
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// Check DMI Update the same string
|
|
//
|
|
if (mDmiStart != NULL || mVarStart != NULL) {
|
|
SmbiosToolUpdateString = CheckReplaceDataFromSmbiosTool (SmbiosData->Type, (UINT8) SmbiosData->SmbiosOffset);
|
|
}
|
|
//
|
|
// If DMI not update the same string, MultiConfig Update this string
|
|
//
|
|
if (!SmbiosToolUpdateString) {
|
|
StringNum = RecordData[SmbiosData->SmbiosOffset];
|
|
UpdateString = AllocateZeroPool (SmbiosData->DataSize + 1);
|
|
if (UpdateString != NULL) {
|
|
CopyMem ((VOID *) UpdateString, (VOID *) (SmbiosData->Data), SmbiosData->DataSize);
|
|
This->UpdateString (This, &SmbiosHandle, &StringNum, UpdateString);
|
|
|
|
DEBUG_CODE_BEGIN ();
|
|
DEBUG ((EFI_D_ERROR, "Update Smbios Type:%Xh Instance:%d Offset:%d String:", SmbiosData->Type, SmbiosData->Instance, SmbiosData->SmbiosOffset));
|
|
for (Index = 0; Index < SmbiosData->DataSize; Index ++) {
|
|
DEBUG ((EFI_D_ERROR, "%c", UpdateString[Index]));
|
|
}
|
|
DEBUG ((EFI_D_ERROR, "\n"));
|
|
DEBUG_CODE_END ();
|
|
|
|
FreePool (UpdateString);
|
|
UpdateString = NULL;
|
|
}
|
|
} else {
|
|
DEBUG ((EFI_D_ERROR, "Smbios Tool update the same String\n"));
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
Update Smbios information function
|
|
|
|
@param[in] Event Event whose notification function is being invoked
|
|
@param[in] Context Pointer to the notification function's context
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
UpdateSmbiosInfo (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VOID *MultiConfigRegionBase;
|
|
UINT16 ConfigCount;
|
|
CONFIG_HEADER *TempConfigHeader;
|
|
UINT16 Index;
|
|
MC_SMBIOS_HEADER *SmbiosStart;
|
|
UINT16 Totalitems;
|
|
EFI_SMBIOS_PROTOCOL *SmbiosProtocol;
|
|
UINT16 ItemIndex;
|
|
MC_SMBIOS_SETTING *SmbiosData;
|
|
UINTN VarSize;
|
|
UINT64 Signature;
|
|
|
|
ConfigCount = 0;
|
|
SmbiosStart = NULL;
|
|
Totalitems = 0;
|
|
SmbiosProtocol= NULL;
|
|
SmbiosData = NULL;
|
|
|
|
Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID**)&SmbiosProtocol);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "Locate SMBIOS protocol failed (%r)!!\n", Status));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Get Dmi & Variable
|
|
// If Dmi or Variable Update the same string as Multiconfig
|
|
// Multiconfig will not update this string
|
|
//
|
|
mDmiStart = (UINT8*)(UINTN) FdmGetNAtAddr (&gH2OFlashMapRegionSmbiosUpdateGuid, 1);
|
|
if (mDmiStart == NULL) {
|
|
return;
|
|
}
|
|
if (*(UINT32*)mDmiStart != DMI_UPDATE_STRING_SIGNATURE) {
|
|
DEBUG ((EFI_D_ERROR, "DMI region signature error!!\n"));
|
|
mDmiStart = NULL;
|
|
} else {
|
|
mDmiEnd = mDmiStart + FdmGetNAtSize (&gH2OFlashMapRegionSmbiosUpdateGuid, 1);
|
|
mDmiStart += sizeof (DMI_UPDATE_STRING_SIGNATURE);
|
|
}
|
|
|
|
Status = GetVariable2 (L"PnpRuntime", &gEfiGenericVariableGuid, (VOID **)&mVarStart, &VarSize);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "Get Variable PnpRuntime Fail - %r!!\n", Status));
|
|
|
|
if (mVarStart != NULL) {
|
|
FreePool (mVarStart);
|
|
mVarStart = NULL;
|
|
}
|
|
} else if (mVarStart != NULL) {
|
|
if ((VarSize < sizeof (DMI_UPDATE_STRING_SIGNATURE)) || (*(UINT32 *) mVarStart != DMI_UPDATE_STRING_SIGNATURE)) {
|
|
DEBUG ((EFI_D_ERROR, "Variable PnpRuntime signature error!!\n"));
|
|
FreePool (mVarStart);
|
|
mVarStart = NULL;
|
|
} else {
|
|
mVarEnd = mVarStart + VarSize;
|
|
mVarStart += sizeof (DMI_UPDATE_STRING_SIGNATURE);
|
|
}
|
|
}
|
|
|
|
MultiConfigRegionBase = (VOID*) (UINTN)FdmGetNAtAddr (&gH2OFlashMapRegionMultiConfigGuid, 1);
|
|
if (MultiConfigRegionBase == NULL) {
|
|
return;
|
|
}
|
|
//
|
|
// Check MultiConfig Header
|
|
//
|
|
Signature = MULTI_CONFIG_SIGNATURE;
|
|
if (CompareMem (&Signature, MultiConfigRegionBase, sizeof (UINT64)) != 0) {
|
|
return;
|
|
}
|
|
//
|
|
// Check CRC32 for Multi Config Header
|
|
//
|
|
Status = CheckMultiConfigHeaderCrc32 (MultiConfigRegionBase);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
ConfigCount = GetConfigCount ();
|
|
|
|
for (Index = 0; Index < ConfigCount; Index ++) {
|
|
TempConfigHeader = GetConfigHeaderByOrder (Index);
|
|
|
|
if ((TempConfigHeader->Type == SMBIOS_MC_UPDATE_SMBIOS) && (TempConfigHeader->SkuId == MC_VALID_SKUID) && (TempConfigHeader->Attribute & MULTI_CONFIG_ATTRIBUTE_DEFAULT)) {
|
|
SmbiosStart = (MC_SMBIOS_HEADER *) GetConfigDataByOrder (Index, MultiConfigRegionBase);
|
|
Status = CheckMultiConfigDataCrc32 (TempConfigHeader->Crc32, TempConfigHeader->ConfigDataSize, SmbiosStart);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
Totalitems = SmbiosStart->TotalItem;
|
|
SmbiosData = &SmbiosStart->FirstData;
|
|
|
|
for (ItemIndex = 0; ItemIndex < Totalitems; ItemIndex ++) {
|
|
DEBUG ((EFI_D_ERROR, "Try to Update Smbios Type:%Xh Instance:%d Offset:%d Attribute:%d\n", SmbiosData->Type, SmbiosData->Instance, SmbiosData->SmbiosOffset, SmbiosData->DataAttr));
|
|
if (SmbiosData->DataSize > MC_UPDATE_SMBIOS_MAX_LENGTH) {
|
|
break;
|
|
}
|
|
if (SmbiosData->DataAttr == SMBIOS_STRING_ATTR) {
|
|
UpdateSmbiosString (SmbiosProtocol, SmbiosData);
|
|
} else {
|
|
UpdateSmbiosData (SmbiosProtocol, SmbiosData);
|
|
}
|
|
SmbiosData = (MC_SMBIOS_SETTING *) ((UINT8 *)SmbiosData + SmbiosData->DataSize + sizeof (MC_SMBIOS_SETTING_L));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mVarStart != NULL) {
|
|
FreePool (mVarStart);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
Entry point of Smbios Update Entry
|
|
|
|
@param[in] ImageHandle A handle for this module
|
|
@param[in] SystemTable A pointer to the EFI System Table
|
|
|
|
@retval EFI_SUCCESS No Multiconfig or set call back success
|
|
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
|
@retval EFI_OUT_OF_RESOURCES The event could not be allocated.
|
|
**/
|
|
EFI_STATUS
|
|
MultiConfigUpdateEntry (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_EVENT EndOfDxeEvent;
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE Handle;
|
|
|
|
Handle = NULL;
|
|
Status = EFI_SUCCESS;
|
|
Status = gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_NOTIFY,
|
|
UpdateSmbiosInfo,
|
|
NULL,
|
|
&gEfiEndOfDxeEventGroupGuid,
|
|
&EndOfDxeEvent
|
|
);
|
|
return Status;
|
|
}
|
|
|