2319 lines
71 KiB
C
2319 lines
71 KiB
C
/** @file
|
|
Functions for Dmitool
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2012 - 2021, 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 "PnpSmm.h"
|
|
#include <Protocol/LegacyBios.h>
|
|
#include <Protocol/SmmCpu.h>
|
|
#include <Library/FlashRegionLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
|
|
SMBIOS_TABLE_ENTRY_POINT *mSmbiosTableEntryPoint = NULL;
|
|
SMBIOS_TABLE_3_0_ENTRY_POINT *mSmbiosTableEntryPoint64Bit = NULL;
|
|
SMBIOS_STRUCTURE *mSmbiosTable = NULL;
|
|
SMBIOS_STRUCTURE *mSmbiosTable64Bit = NULL;
|
|
INT32 mTotalIncreasedStringLength = 0;
|
|
INT32 mTotalIncreasedStringLength64Bit = 0;
|
|
EFI_PHYSICAL_ADDRESS mSMBIOSTableEntryAddress = 0;
|
|
EFI_PHYSICAL_ADDRESS mSMBIOSTableEntryAddress64Bit = 0;
|
|
CHAR8 mSmbio30Signature[] = SMBIOS_30_SIGNATURE;
|
|
|
|
PNP_REDIRECTED_ENTRY_POINT mPnpDmiFunctions[] = {
|
|
Pnp0x50,
|
|
Pnp0x51,
|
|
Pnp0x52,
|
|
UnsupportedPnpFunction, //Pnp0x53,
|
|
Pnp0x54,
|
|
Pnp0x55,
|
|
Pnp0x56,
|
|
Pnp0x57
|
|
};
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
ClearBiosEventLog (
|
|
IN UINTN GPNVBase,
|
|
IN UINTN GPNVLength
|
|
);
|
|
|
|
|
|
/**
|
|
Ensures that mSmbiosTableEntryPoint and mSmbiosTable are filled in.
|
|
|
|
@param none
|
|
|
|
**/
|
|
VOID
|
|
LocateSmbiosTable (
|
|
)
|
|
{
|
|
UINT32 *Address;
|
|
BOOLEAN IsSmbios64BitTable;
|
|
BOOLEAN IsSmbios32BitTable;
|
|
BOOLEAN LegacySmbios64BitTableFound;
|
|
BOOLEAN LegacySmbios32BitTableFound;
|
|
|
|
IsSmbios32BitTable = FALSE;
|
|
IsSmbios64BitTable = FALSE;
|
|
LegacySmbios32BitTableFound = FALSE;
|
|
LegacySmbios64BitTableFound = FALSE;
|
|
|
|
if (((PcdGet16 (PcdSmbiosVersion) >> 8) < 0x3) ||
|
|
(((PcdGet16 (PcdSmbiosVersion) >> 8) >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT0) == BIT0))) {
|
|
IsSmbios32BitTable = TRUE;
|
|
}
|
|
|
|
if (((PcdGet16 (PcdSmbiosVersion) >> 8) >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT1) == BIT1)) {
|
|
IsSmbios64BitTable = TRUE;
|
|
}
|
|
|
|
//
|
|
// Locate SMBIOS structure table entry point when Legacy boot.
|
|
//
|
|
if (IsSmbios32BitTable && ((mSmbiosTableEntryPoint == NULL) || ((UINT32)(UINTN)mSmbiosTableEntryPoint->AnchorString != (UINT32)SMBIOS_SIGNATURE))) {
|
|
// CODE ANALYSIS (VS19.0.2) - Reports C28182. Added typecast to Address = Address + 4.
|
|
for (Address = (UINT32 *)(UINTN) 0xF0000; (UINTN)Address < 0x100000; Address = (UINT32*) ((UINTN) Address + 4)) {
|
|
mSmbiosTableEntryPoint = (SMBIOS_TABLE_ENTRY_POINT *)(UINTN) Address;
|
|
if (*(UINT32 *)mSmbiosTableEntryPoint == (UINT32)SMBIOS_SIGNATURE) {
|
|
mSmbiosTable = (SMBIOS_STRUCTURE *)(UINTN)mSmbiosTableEntryPoint->TableAddress;
|
|
LegacySmbios32BitTableFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (IsSmbios64BitTable && ((mSmbiosTableEntryPoint64Bit == NULL) || (AsciiStrnCmp ((CHAR8*)mSmbiosTableEntryPoint64Bit->AnchorString, mSmbio30Signature, sizeof(mSmbio30Signature)) != 0 ))) {
|
|
// CODE ANALYSIS (VS19.0.2) - Reports C28182. Added typecast to Address = Address + 4.
|
|
for (Address = (UINT32 *)(UINTN) 0xF0000; (UINTN)Address < 0x100000; Address = (UINT32*) ((UINTN) Address + 4)) {
|
|
mSmbiosTableEntryPoint64Bit = (SMBIOS_TABLE_3_0_ENTRY_POINT *)(UINTN) Address;
|
|
if (AsciiStrnCmp ((CHAR8*)mSmbiosTableEntryPoint64Bit->AnchorString, mSmbio30Signature, AsciiStrLen (mSmbio30Signature)) == 0 ) {
|
|
mSmbiosTable64Bit = (SMBIOS_STRUCTURE *)(UINTN)mSmbiosTableEntryPoint64Bit->TableAddress;
|
|
LegacySmbios64BitTableFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (IsSmbios32BitTable && IsSmbios64BitTable){
|
|
if (LegacySmbios32BitTableFound == TRUE && LegacySmbios64BitTableFound == TRUE){
|
|
return;
|
|
}
|
|
} else if (IsSmbios32BitTable){
|
|
if (LegacySmbios32BitTableFound == TRUE){
|
|
return;
|
|
}
|
|
} else if (IsSmbios64BitTable){
|
|
if (LegacySmbios64BitTableFound == TRUE){
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If the entry point is not found in CSM,
|
|
// locate SMBIOS structure table entry point at Runtime.
|
|
//
|
|
if (IsSmbios32BitTable) {
|
|
mSmbiosTableEntryPoint = (SMBIOS_TABLE_ENTRY_POINT*)(UINTN)mSMBIOSTableEntryAddress;
|
|
mSmbiosTable = (SMBIOS_STRUCTURE*)(UINTN)mSmbiosTableEntryPoint->TableAddress;
|
|
}
|
|
|
|
if (IsSmbios64BitTable) {
|
|
mSmbiosTableEntryPoint64Bit = (SMBIOS_TABLE_3_0_ENTRY_POINT*)(UINTN)mSMBIOSTableEntryAddress64Bit;
|
|
mSmbiosTable64Bit = (SMBIOS_STRUCTURE*)(UINTN)((SMBIOS_TABLE_3_0_ENTRY_POINT*)mSmbiosTableEntryPoint64Bit)->TableAddress;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Locates the smbios structure with a handle of *Structure.
|
|
|
|
@param[In] Structure Handle of structure to attempt to locate.
|
|
- If 0 on entry, then the first avaiable structure is found.
|
|
- On exit, *Structure is updated with the next structure handle.
|
|
A return handle of 0xffff indicates there are no more structures.
|
|
*Structure is always updated with useful information.
|
|
@param[Out] Location Return the structure location if it was found.
|
|
@param[Out] Size The size of structure location if it was found.
|
|
|
|
@retval EFI_SUCCESS The structure was found. **Location and *Size are valid.
|
|
@retval EFI_NOT_FOUND The structure was not found.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
LocateSmbiosStructure (
|
|
IN BOOLEAN IsSmbios32BitTable,
|
|
IN OUT UINT16 *Structure,
|
|
OUT SMBIOS_STRUCTURE **Location,
|
|
OUT UINTN *Size
|
|
)
|
|
{
|
|
INT32 TotalIncreasedStringLength;
|
|
SMBIOS_STRUCTURE *Iter;
|
|
SMBIOS_STRUCTURE *Next;
|
|
SMBIOS_STRUCTURE *End;
|
|
|
|
if (IsSmbios32BitTable &&(*Structure == 0) && ((*Location) != NULL) && (*(UINT32 *)(*Location) == (UINT32)SMBIOS_SIGNATURE)) {
|
|
*Structure = mSmbiosTable->Handle;
|
|
}
|
|
|
|
if (!IsSmbios32BitTable &&(*Structure == 0) && ((*Location) != NULL) && ( AsciiStrnCmp ((CHAR8*)*Location, mSmbio30Signature, AsciiStrLen(mSmbio30Signature)) == 0)) {
|
|
*Structure = mSmbiosTable64Bit->Handle;
|
|
}
|
|
|
|
if (IsSmbios32BitTable){
|
|
Iter = mSmbiosTable;
|
|
} else {
|
|
Iter = mSmbiosTable64Bit;
|
|
}
|
|
|
|
if (Iter == NULL){
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
//
|
|
// Adjust the end pointer if SMBIOS data is modified, such as strings.
|
|
//
|
|
if (IsSmbios32BitTable) {
|
|
End = (SMBIOS_STRUCTURE *)(UINTN)(((SMBIOS_TABLE_ENTRY_POINT*)mSmbiosTableEntryPoint)->TableAddress + ((SMBIOS_TABLE_ENTRY_POINT*)mSmbiosTableEntryPoint)->TableLength);
|
|
} else {
|
|
End = (SMBIOS_STRUCTURE *)(UINTN)(((SMBIOS_TABLE_3_0_ENTRY_POINT*)mSmbiosTableEntryPoint64Bit)->TableAddress + ((SMBIOS_TABLE_3_0_ENTRY_POINT*)mSmbiosTableEntryPoint64Bit)->TableMaximumSize);
|
|
}
|
|
|
|
if (IsSmbios32BitTable) {
|
|
TotalIncreasedStringLength = mTotalIncreasedStringLength;
|
|
} else {
|
|
TotalIncreasedStringLength = mTotalIncreasedStringLength64Bit;
|
|
}
|
|
if (TotalIncreasedStringLength >= 0x00) {
|
|
End = (SMBIOS_STRUCTURE *)((UINTN)End + (UINTN)TotalIncreasedStringLength);
|
|
} else {
|
|
End = (SMBIOS_STRUCTURE *)((UINTN)End - (UINTN)(~(TotalIncreasedStringLength - 1)));
|
|
}
|
|
|
|
while (TRUE) {
|
|
for (Next = (SMBIOS_STRUCTURE *)((UINT8 *)Iter + Iter->Length); *(UINT16 *)Next != 0; Next = (SMBIOS_STRUCTURE *)((UINTN)Next + 1));
|
|
Next = (SMBIOS_STRUCTURE *)((UINTN)Next + 2);
|
|
if (Iter >= End) {
|
|
//
|
|
// End-of-list indicator
|
|
//
|
|
*Structure = 0xffff;
|
|
return EFI_NOT_FOUND;
|
|
} else if (Iter->Handle == *Structure) {
|
|
*Structure = (UINT16)((Next < End) ? Next->Handle : 0xffff);
|
|
*Location = Iter;
|
|
*Size = (UINTN)Next - (UINTN)Iter;
|
|
return EFI_SUCCESS;
|
|
}
|
|
Iter = Next;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Find the location and size of a string within a smbios structure.
|
|
|
|
@param[In] StringRef The string number to search for within the structure.
|
|
@param[In] Structure The Pointer to the structure to search.
|
|
@param[Out] Location Return the string location if it was found.
|
|
@param[Out] Size The size of string location if it was found.
|
|
|
|
@retval EFI_SUCCESS the string was found. **Location and *Size are valid.
|
|
@retval EFI_NOT_FOUND The structure was not found.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
LocateStringOfStructure (
|
|
IN UINT8 StringRef,
|
|
IN SMBIOS_STRUCTURE *Structure,
|
|
OUT CHAR8 **Location,
|
|
OUT UINTN *Size
|
|
)
|
|
{
|
|
CHAR8 *Next;
|
|
|
|
if (StringRef == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Next = (CHAR8 *)(((UINTN)Structure) + Structure->Length);
|
|
do {
|
|
*Location = Next;
|
|
*Size = AsciiStrLen (*Location);
|
|
Next = *Location + *Size + 1;
|
|
} while ((--StringRef) != 0 && (*Next != 0));
|
|
|
|
return (StringRef == 0) ? EFI_SUCCESS : EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
Set FieldOffset of structure to zero,
|
|
and adjust number of strings base on FieldOffset within a smbios structure.
|
|
|
|
@param Structure The Pointer to the smbios structure.
|
|
@param FieldOffset The FieldOffset of structure is expected to be set to zero.
|
|
@param OffsetTable The Pointer to the OffsetTable.
|
|
@param OffsetTableEnd The Pointer to the end of the OffsetTable.
|
|
|
|
@return EFI_SUCCESS The function completed successfully.
|
|
@return EFI_NOT_FOUND The type can not be found at OffsetTable
|
|
|
|
**/
|
|
EFI_STATUS
|
|
AdjustStringNumbersOfStructure (
|
|
IN OUT SMBIOS_STRUCTURE *Structure,
|
|
IN UINT8 FieldOffset,
|
|
IN STRING_OFFSET_TABLE *OffsetTable,
|
|
IN STRING_OFFSET_TABLE *OffsetTableEnd
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 StringNum;
|
|
UINT8 OffSetValue;
|
|
UINT8 Index;
|
|
|
|
Status = EFI_NOT_FOUND;
|
|
while (OffsetTable < OffsetTableEnd) {
|
|
if (OffsetTable->Type == Structure->Type) {
|
|
Status = EFI_SUCCESS;
|
|
break;
|
|
}
|
|
OffsetTable = (STRING_OFFSET_TABLE *)((CHAR8 *)OffsetTable + sizeof(STRING_OFFSET_TABLE) + OffsetTable->OffsetCount - sizeof(UINT8));
|
|
}
|
|
if (EFI_ERROR(Status)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
StringNum = ((UINT8 *)Structure)[FieldOffset];
|
|
if (StringNum == 0) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
((UINT8 *)Structure)[FieldOffset] = 0;
|
|
|
|
for (Index = 0; Index < OffsetTable->OffsetCount; Index++) {
|
|
OffSetValue = OffsetTable->Offset[Index];
|
|
if ((((UINT8 *)Structure)[OffSetValue] != 0) && (((UINT8 *)Structure)[OffSetValue] > StringNum)) {
|
|
((UINT8 *)Structure)[OffSetValue]--;
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get the total number of existing strings within a smbios structure
|
|
|
|
@param Structure The Pointer to the smbios structure.
|
|
|
|
@return The total number of existing strings within a smbios structure
|
|
**/
|
|
UINT8
|
|
GetNumberStringOfStructure (
|
|
IN SMBIOS_STRUCTURE *Structure
|
|
)
|
|
{
|
|
CHAR8 *Next;
|
|
UINT8 NumberOfStrings;
|
|
|
|
Next = (CHAR8 *)(((UINTN)Structure) + Structure->Length);
|
|
if (*Next == 0 && *(Next + 1) == 0) {
|
|
return 0;
|
|
}
|
|
|
|
NumberOfStrings = 0;
|
|
while (TRUE) {
|
|
if (*Next == 0) {
|
|
NumberOfStrings += 1;
|
|
if (*(Next + 1) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
Next++;
|
|
}
|
|
|
|
return NumberOfStrings;
|
|
}
|
|
|
|
/**
|
|
Find the double null location within a smbios structure
|
|
|
|
@param Structure The Pointer to the smbios structure.
|
|
@param Location The double null location if it was found.
|
|
|
|
@retval EFI_SUCCESS The function return valid value.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
LocateDoubleNullOfStructure (
|
|
IN SMBIOS_STRUCTURE *Structure,
|
|
OUT CHAR8 **Location
|
|
)
|
|
{
|
|
CHAR8 *Next;
|
|
|
|
Next = (CHAR8 *)(((UINTN)Structure) + Structure->Length);
|
|
while (*Next != 0 || *(Next + 1) != 0) {
|
|
Next++;
|
|
}
|
|
*Location = Next;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
If OEM_DMI_STORE address full to arrange.
|
|
|
|
@param[Out] DmiEnd Pointer to function 0x52 data buffer input.
|
|
|
|
@retval EFI_SUCCESS The function return valid value.
|
|
@retval EFI_NOT_FOUND Error occurs.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
DMISpaceNotEnough (
|
|
OUT UINT16 *DmiEnd
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN DmiSize;
|
|
UINTN NvStorageDmiBase;
|
|
UINTN NvSpareAddr;
|
|
UINTN NvSpareSize;
|
|
UINTN UsingSpareSize;
|
|
UINT16 NotEnoughPtr;
|
|
UINTN Size;
|
|
DMI_RECLAIM_IN_FTW_SPARE DmiReclaimInFtwSpare;
|
|
UINT8 *NotEnoughBuffer;
|
|
UINT8 *Buffer;
|
|
DMI_STRING_STRUCTURE *CurrentPtr;
|
|
UINT8 *Ptr;
|
|
|
|
NotEnoughBuffer = NULL;
|
|
|
|
CurrentPtr = NULL;
|
|
NotEnoughPtr = 4;
|
|
|
|
NvStorageDmiBase = (UINTN) FdmGetNAtAddr (&gH2OFlashMapRegionSmbiosUpdateGuid, 1);
|
|
if (NvStorageDmiBase == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
DmiSize = (UINTN) FdmGetNAtSize (&gH2OFlashMapRegionSmbiosUpdateGuid, 1);
|
|
|
|
NotEnoughBuffer = AllocateRuntimePool (DmiSize);
|
|
if (NotEnoughBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
SetMem (NotEnoughBuffer, DmiSize, 0xFF);
|
|
*(UINT32 *)NotEnoughBuffer = DMI_UPDATE_STRING_SIGNATURE;
|
|
|
|
//
|
|
// Search smbios Valid, If it is found, set OEM_DMI_STORE address
|
|
//
|
|
Buffer = (UINT8 *)(NvStorageDmiBase + sizeof (DMI_UPDATE_STRING_SIGNATURE));
|
|
while ((UINTN)Buffer < (NvStorageDmiBase + DmiSize)) {
|
|
CurrentPtr = (DMI_STRING_STRUCTURE *)Buffer;
|
|
if (CurrentPtr->Type == 0xFF) {
|
|
break;
|
|
}
|
|
if (CurrentPtr->Valid == 0xFF) {
|
|
if ((UINTN) (NotEnoughPtr + CurrentPtr->Length) > DmiSize) {
|
|
FreePool(NotEnoughBuffer);
|
|
return EFI_BAD_BUFFER_SIZE;
|
|
}
|
|
CopyMem ((NotEnoughBuffer+NotEnoughPtr), Buffer, CurrentPtr->Length);
|
|
NotEnoughPtr = NotEnoughPtr + CurrentPtr->Length;
|
|
}
|
|
Buffer = Buffer + CurrentPtr->Length;
|
|
}
|
|
|
|
//
|
|
// Flash whole buffer to NV_FTW_SPARE
|
|
//
|
|
NvSpareAddr = (UINTN) FdmGetNAtAddr (&gH2OFlashMapRegionFtwBackupGuid, 1);
|
|
if (NvSpareAddr == 0) {
|
|
FreePool(NotEnoughBuffer);
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
NvSpareSize = (UINTN) FdmGetNAtSize(&gH2OFlashMapRegionFtwBackupGuid, 1);
|
|
UsingSpareSize = DmiSize * DMI_USING_FTW_BACKUP_MULTIPLE_OF_DMI_REGION;
|
|
if (UsingSpareSize > NvSpareSize) {
|
|
FreePool(NotEnoughBuffer);
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
Status = mSmmFwBlockService->EraseBlocks (
|
|
mSmmFwBlockService,
|
|
NvSpareAddr,
|
|
&UsingSpareSize
|
|
);
|
|
if (!EFI_ERROR(Status)) {
|
|
Status = mSmmFwBlockService->Write (
|
|
mSmmFwBlockService,
|
|
NvSpareAddr + sizeof (DMI_RECLAIM_IN_FTW_SPARE),
|
|
&DmiSize,
|
|
NotEnoughBuffer
|
|
);
|
|
}
|
|
if (EFI_ERROR(Status)) {
|
|
FreePool(NotEnoughBuffer);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Write DmiReclaimGuid and DataLength wtihout Valid Byte in NV_FTW_SPARE
|
|
//
|
|
CopyGuid(&DmiReclaimInFtwSpare.DmiReclaimGuid, &gH2OFlashMapRegionSmbiosUpdateGuid);
|
|
DmiReclaimInFtwSpare.DataLength = (UINT32) (DmiSize + sizeof (DMI_RECLAIM_IN_FTW_SPARE));
|
|
Size = (sizeof (DMI_RECLAIM_IN_FTW_SPARE) - sizeof (DmiReclaimInFtwSpare.Valid));
|
|
Ptr = (UINT8 *) &DmiReclaimInFtwSpare;
|
|
Status = mSmmFwBlockService->Write (
|
|
mSmmFwBlockService,
|
|
NvSpareAddr,
|
|
&Size,
|
|
Ptr
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
FreePool(NotEnoughBuffer);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Write Valid Byte in NV_FTW_SPARE
|
|
//
|
|
DmiReclaimInFtwSpare.Valid = DMI_USING_FTW_BACKUP_VALID_FLAG;
|
|
Size = sizeof (DmiReclaimInFtwSpare.Valid);
|
|
Status = mSmmFwBlockService->Write (
|
|
mSmmFwBlockService,
|
|
NvSpareAddr + sizeof (DMI_RECLAIM_IN_FTW_SPARE) - sizeof (DmiReclaimInFtwSpare.Valid),
|
|
&Size,
|
|
&DmiReclaimInFtwSpare.Valid
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
FreePool(NotEnoughBuffer);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Flash whole buffer to OEM_DMI_STORE
|
|
//
|
|
Status = mSmmFwBlockService->EraseBlocks (
|
|
mSmmFwBlockService,
|
|
NvStorageDmiBase,
|
|
&DmiSize
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = mSmmFwBlockService->Write (
|
|
mSmmFwBlockService,
|
|
NvStorageDmiBase,
|
|
&DmiSize,
|
|
NotEnoughBuffer
|
|
);
|
|
}
|
|
FreePool(NotEnoughBuffer);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Erase backup in NV_FTW_SPARE
|
|
//
|
|
Status = mSmmFwBlockService->EraseBlocks (
|
|
mSmmFwBlockService,
|
|
NvSpareAddr,
|
|
&UsingSpareSize
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (DmiEnd!= NULL) {
|
|
*DmiEnd = NotEnoughPtr;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get the remaining size and expected reclaim size from OEM_DMI_STORE
|
|
|
|
@param[out] RemainingSize The pointer to the remaining Size
|
|
@param[out] ReclaimSize The pointer to the reclaim size
|
|
|
|
@retval EFI_SUCCESS The function return valid value.
|
|
@retval Others Failed to get the valid value.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
GetDmiReclaimInfo (
|
|
OUT UINTN *RemainSize,
|
|
OUT UINTN *ReclaimSize
|
|
)
|
|
{
|
|
UINTN Remaining;
|
|
UINTN Reclaim;
|
|
UINTN DmiSize;
|
|
UINTN DmiAddr;
|
|
UINT16 DmiEnd;
|
|
UINT8 *Buffer;
|
|
DMI_STRING_STRUCTURE *CurrentPtr;
|
|
|
|
if (RemainSize == NULL || ReclaimSize == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
DmiAddr = (UINTN) FdmGetNAtAddr(&gH2OFlashMapRegionSmbiosUpdateGuid, 1);
|
|
if (DmiAddr == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
DmiSize = (UINTN) FdmGetNAtSize(&gH2OFlashMapRegionSmbiosUpdateGuid, 1);
|
|
if (DmiSize == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// First 4 bytes are "$DMI"
|
|
//
|
|
Buffer = (UINT8 *)(UINTN) DmiAddr;
|
|
if (!(*(UINT32 *)Buffer == DMI_UPDATE_STRING_SIGNATURE)){
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
Buffer += sizeof (DMI_UPDATE_STRING_SIGNATURE);
|
|
DmiEnd = sizeof (DMI_UPDATE_STRING_SIGNATURE);
|
|
|
|
Reclaim = 0;
|
|
Remaining = 0;
|
|
while (DmiEnd < (DmiSize - DMI_TOTAL_RECLAIM_RESERVERED_SIZE)) {
|
|
CurrentPtr = (DMI_STRING_STRUCTURE *) Buffer;
|
|
if (CurrentPtr->Type == 0xFF) {
|
|
//
|
|
// Remaining size
|
|
//
|
|
Remaining += (UINTN) (DmiSize - DMI_TOTAL_RECLAIM_RESERVERED_SIZE - DmiEnd);
|
|
break;
|
|
}
|
|
|
|
if (CurrentPtr->Valid == 0) {
|
|
//
|
|
// Reclaim size
|
|
//
|
|
Reclaim += CurrentPtr->Length;
|
|
}
|
|
|
|
//
|
|
// Try to find next.
|
|
//
|
|
DmiEnd = DmiEnd + CurrentPtr->Length;
|
|
Buffer = Buffer + CurrentPtr->Length;
|
|
}
|
|
|
|
*RemainSize = Remaining;
|
|
*ReclaimSize = Reclaim;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Set SMBIOS Structure to OEM_DMI_STORE address.
|
|
|
|
@param[In] Data Pointer to function 0x52 data buffer input.
|
|
@param[In] Structure The Pointer to the structure to search.
|
|
|
|
@retval EFI_SUCCESS The function sets valid value for Data.
|
|
@retval EFI_NOT_FOUND Error occurs.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
SetDMI (
|
|
IN FUNC_0x52_DATA_BUFFER *Data,
|
|
IN SMBIOS_STRUCTURE *Structure
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
UINTN BlockSize;
|
|
UINTN BSize;
|
|
UINT8 Invalid;
|
|
UINT32 ReclaimFlag;
|
|
UINT16 DmiEnd;
|
|
UINT64 DmiAddr;
|
|
UINT64 DmiSize;
|
|
UINT64 NewDataEnd;
|
|
UINTN RemainingSize;
|
|
UINTN ReclaimSize;
|
|
UINTN Size;
|
|
UINT8 *Buffer;
|
|
UINT8 *Ptr;
|
|
UINT8 *SavePtr;
|
|
DMI_STRING_STRUCTURE *CurrentPtr;
|
|
|
|
BSize = 0x1;
|
|
Invalid = 0;
|
|
SavePtr = NULL;
|
|
CurrentPtr = NULL;
|
|
|
|
DmiAddr = FdmGetNAtAddr(&gH2OFlashMapRegionSmbiosUpdateGuid, 1);
|
|
if (DmiAddr == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
DmiSize = FdmGetNAtSize(&gH2OFlashMapRegionSmbiosUpdateGuid, 1);
|
|
if (DmiSize == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// First 4 bytes are "$DMI"
|
|
//
|
|
Ptr = (UINT8 *)(UINTN) DmiAddr;
|
|
Buffer = Ptr + sizeof (DMI_UPDATE_STRING_SIGNATURE);
|
|
|
|
//
|
|
// Search OEM_DMI_STORE free space
|
|
//
|
|
DmiEnd = 4;
|
|
while (DmiEnd < (DmiSize - DMI_TOTAL_RECLAIM_RESERVERED_SIZE)) {
|
|
CurrentPtr = (DMI_STRING_STRUCTURE *)Buffer;
|
|
|
|
if (CurrentPtr->Type == 0xFF) {
|
|
//
|
|
// The space is free, we could use it, so break.
|
|
//
|
|
break;
|
|
}
|
|
//
|
|
// Try to find next.
|
|
//
|
|
DmiEnd = DmiEnd + CurrentPtr->Length;
|
|
Buffer = Buffer + CurrentPtr->Length;
|
|
}
|
|
|
|
if ((DmiEnd + Data->DataLength + (sizeof (DMI_STRING_STRUCTURE) - sizeof(UINT8)) >
|
|
(DmiSize - DMI_TOTAL_RECLAIM_RESERVERED_SIZE))) {
|
|
RemainingSize = 0;
|
|
ReclaimSize = 0;
|
|
Status = GetDmiReclaimInfo (&RemainingSize, &ReclaimSize);
|
|
if (EFI_ERROR(Status) || ReclaimSize == 0) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
if (mSmmSmbiosEndOfDxe) {
|
|
//
|
|
// Writting flag for next post to reclaim
|
|
//
|
|
Ptr = (UINT8 *)(UINTN) DmiAddr;
|
|
Ptr += (DmiSize - sizeof (DMI_RECLAIM_STRING_SIGNATURE));
|
|
if ((*(UINT32 *) Ptr == 0xFFFFFFFF)) {
|
|
ReclaimFlag = DMI_RECLAIM_STRING_SIGNATURE;
|
|
Ptr = (UINT8 *) &ReclaimFlag;
|
|
Size = sizeof (DMI_RECLAIM_STRING_SIGNATURE);
|
|
mSmmFwBlockService->Write (
|
|
mSmmFwBlockService,
|
|
(UINTN)(DmiAddr + DmiSize - sizeof(DMI_RECLAIM_STRING_SIGNATURE)),
|
|
&Size,
|
|
Ptr
|
|
);
|
|
}
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
Status = DMISpaceNotEnough (&DmiEnd);
|
|
if (EFI_ERROR(Status)){
|
|
return Status;
|
|
}
|
|
}
|
|
//
|
|
// Set update data to OEM_DMI_STORE address.
|
|
//
|
|
SavePtr = AllocateRuntimePool (Data->DataLength + (sizeof (DMI_STRING_STRUCTURE) - sizeof (UINT8)));
|
|
if (SavePtr == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
CurrentPtr = (DMI_STRING_STRUCTURE *)SavePtr;
|
|
CurrentPtr->Type = Structure->Type;
|
|
CurrentPtr->Offset = Data->FieldOffset;
|
|
CurrentPtr->Valid = 0xFF;
|
|
|
|
switch (Data->Command) {
|
|
|
|
case DMI_STRING_CHANGE:
|
|
CurrentPtr->Length = Data->DataLength + (sizeof (DMI_STRING_STRUCTURE) - sizeof (UINT8) - 1);
|
|
for (Index = 0; Index + 1 < Data->DataLength; Index++) {
|
|
CurrentPtr->String[Index] = Data->StructureData[Index];
|
|
}
|
|
break;
|
|
|
|
default:
|
|
CurrentPtr->Length = Data->DataLength + (sizeof (DMI_STRING_STRUCTURE) - sizeof (UINT8));
|
|
for (Index = 0; Index < Data->DataLength; Index++) {
|
|
CurrentPtr->String[Index] = Data->StructureData[Index];
|
|
}
|
|
break;
|
|
}
|
|
|
|
BlockSize = CurrentPtr->Length;
|
|
if (DmiEnd + BlockSize > (DmiSize - DMI_TOTAL_RECLAIM_RESERVERED_SIZE)) {
|
|
FreePool (SavePtr);
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
NewDataEnd = (UINT64) (DmiAddr + DmiEnd);
|
|
Status = mSmmFwBlockService->Write (
|
|
mSmmFwBlockService,
|
|
(UINTN) NewDataEnd,
|
|
&BlockSize,
|
|
SavePtr
|
|
);
|
|
FreePool (SavePtr);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Set invalid byte in OEM_DMI_STORE space if we find the same data
|
|
//
|
|
DmiEnd = 4;
|
|
Ptr = (UINT8 *)(UINTN) DmiAddr;
|
|
Buffer = Ptr + sizeof (DMI_UPDATE_STRING_SIGNATURE);
|
|
while (DmiEnd < (NewDataEnd - DmiAddr)) {
|
|
CurrentPtr = (DMI_STRING_STRUCTURE *)Buffer;
|
|
if (CurrentPtr->Type == 0xFF) {
|
|
//
|
|
// The space is free, we could use it, so break.
|
|
//
|
|
break;
|
|
}
|
|
|
|
if ((CurrentPtr->Type == Structure->Type) &&
|
|
(CurrentPtr->Offset == Data->FieldOffset) &&
|
|
(CurrentPtr->Valid == 0xFF)) {
|
|
//
|
|
// Set invalid byte in it.
|
|
//
|
|
Status = mSmmFwBlockService->Write (
|
|
mSmmFwBlockService,
|
|
(UINTN)(DmiAddr + DmiEnd + 2),
|
|
&BSize,
|
|
&Invalid
|
|
);
|
|
}
|
|
//
|
|
// Try to find next.
|
|
//
|
|
DmiEnd = DmiEnd + CurrentPtr->Length;
|
|
Buffer = Buffer + CurrentPtr->Length;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN
|
|
VaildGPNVCheck (
|
|
IN OUT UINT16 *Index,
|
|
IN UINT16 Handle
|
|
)
|
|
{
|
|
UINT16 TempIndex;
|
|
|
|
if (mIsOemGPNVMap == FALSE ||
|
|
OemGPNVHandleCount >= FixedPcdGet16 (PcdDefaultGpnvMapBufferSize) ||
|
|
*Index >= FixedPcdGet16 (PcdDefaultGpnvMapBufferSize) ||
|
|
*Index >= OemGPNVHandleCount) {
|
|
return FALSE;
|
|
}
|
|
|
|
for (TempIndex = *Index; TempIndex < OemGPNVHandleCount; TempIndex++) {
|
|
if (GPNVMapBuffer.PlatFormGPNVMap[TempIndex].Handle == Handle) {
|
|
*Index = TempIndex;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
EFI_STATUS
|
|
WriteGPNV (
|
|
IN UINT16 Handle,
|
|
IN UINT8 *GPNVBuffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN BlockSize;
|
|
UINT8 *WritingBuffer;
|
|
UINTN BlockBaseAddress;
|
|
UINTN WritingBufferOffset;
|
|
UINT8 EraseCount;
|
|
UINT8 WriteCount;
|
|
|
|
BlockSize = 0x10000;
|
|
WritingBuffer = AllocateRuntimePool (BlockSize);
|
|
if (WritingBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
BlockBaseAddress = (GPNVMapBuffer.PlatFormGPNVMap[Handle].BaseAddress) & (~0xFFFF);
|
|
//
|
|
// Copy whole block data to buffer
|
|
//
|
|
CopyMem (WritingBuffer, (VOID *)(UINTN)BlockBaseAddress, BlockSize);
|
|
|
|
//
|
|
// Copy modified GPNV data to buffer
|
|
//
|
|
WritingBufferOffset = GPNVMapBuffer.PlatFormGPNVMap[Handle].BaseAddress - BlockBaseAddress;
|
|
if (GPNVMapBuffer.PlatFormGPNVMap[Handle].GPNVSize > (BlockSize - WritingBufferOffset)) {
|
|
FreePool (WritingBuffer);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
CopyMem ((VOID *)(WritingBuffer + WritingBufferOffset), (VOID *)GPNVBuffer, GPNVMapBuffer.PlatFormGPNVMap[Handle].GPNVSize);
|
|
|
|
//
|
|
// Flash whole buffer to rom
|
|
//
|
|
EraseCount = 0;
|
|
WriteCount = 0;
|
|
do {
|
|
Status = mSmmFwBlockService->EraseBlocks (
|
|
mSmmFwBlockService,
|
|
BlockBaseAddress,
|
|
(UINTN *)&BlockSize
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = mSmmFwBlockService->Write (
|
|
mSmmFwBlockService,
|
|
BlockBaseAddress,
|
|
(UINTN *)&BlockSize,
|
|
WritingBuffer
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
FreePool (WritingBuffer);
|
|
return Status;
|
|
} else {
|
|
WriteCount++;
|
|
}
|
|
} else {
|
|
EraseCount++;
|
|
}
|
|
} while ((EraseCount < 100) && (WriteCount < 100));
|
|
|
|
FreePool (WritingBuffer);
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Does a quick conversion from a 16-bit C far pointer to a linear address.
|
|
Unfortunately, this can only support far pointers from 16-bit real mode.
|
|
|
|
@param[In] Ptr 16-bit far pointer.
|
|
|
|
@return VOID* The linear address of Ptr.
|
|
|
|
**/
|
|
VOID *
|
|
PnpFarToLinear (
|
|
IN PNP_FAR_PTR Ptr
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 Ebx;
|
|
UINT32 ParamsBufferSize;
|
|
H2O_IHISI_PARAMS *ParamsBuffer;
|
|
|
|
Status = H2OGetParamBuffer (&ParamsBuffer, &ParamsBufferSize);
|
|
if (EFI_ERROR (Status)) {
|
|
return NULL;
|
|
}
|
|
Ebx = (UINT32) ParamsBuffer->Param2;
|
|
|
|
//
|
|
// Call by new way that AP trigger software SMI directly when the signature is "$ISB'
|
|
//
|
|
if (Ebx == SIGNATURE_32 ('$', 'I', 'S', 'B')) {
|
|
return (VOID *)(UINTN)(UINT32)(Ptr.Offset | Ptr.Segment << 16);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Helper function for Pnp0x52, process command DMI_BYTE_CHANGE, DMI_WORD_CHANGE, and DMI_DWORD_CHANGE.
|
|
|
|
@param[In] Data Buffer of data to SetStructure.
|
|
@param[In] Structure The structure to be set.
|
|
|
|
@retval DMI_SUCCESS The function executed successfully.
|
|
@retval DMI_READ_ONLY The structure is not Type1, the block to be set is not at offset 8.
|
|
@retval DMI_BAD_PARAMETER Parameter is invalid
|
|
|
|
**/
|
|
INT16
|
|
Pnp0x52ChangeFixedLength (
|
|
IN FUNC_0x52_DATA_BUFFER *Data,
|
|
IN SMBIOS_STRUCTURE *Structure
|
|
)
|
|
{
|
|
UINT8 *ByteTmpPtr;
|
|
UINT16 *WordTmpPtr;
|
|
UINT32 *DWordTmpPtr;
|
|
EFI_STATUS Status;
|
|
UINT8 ByteTemp;
|
|
UINT16 WordTemp;
|
|
UINT32 DWordTemp;
|
|
UINTN Index;
|
|
|
|
ByteTmpPtr = NULL;
|
|
WordTmpPtr = NULL;
|
|
DWordTmpPtr = NULL;
|
|
ByteTemp = 0;
|
|
WordTemp = 0;
|
|
DWordTemp = 0;
|
|
|
|
for (Index = 0; Index < UpdateableStringCount; Index++) {
|
|
if ((Structure->Type == mUpdatableStrings[Index].Type) &&
|
|
(Data->FieldOffset == mUpdatableStrings[Index].FixedOffset)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Index == UpdateableStringCount) {
|
|
return DMI_READ_ONLY;
|
|
}
|
|
|
|
switch (Data->Command) {
|
|
|
|
case DMI_BYTE_CHANGE:
|
|
ByteTmpPtr = (UINT8 *)((UINTN)Structure + Data->FieldOffset);
|
|
if (ByteTmpPtr == NULL) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
ByteTemp = *ByteTmpPtr;
|
|
ByteTemp = ByteTemp & ((UINT8)(Data->ChangeMask));
|
|
ByteTemp = ByteTemp | ((UINT8)((Data->ChangeValue) & ~(Data->ChangeMask)));
|
|
|
|
Data->DataLength = sizeof (UINT8);
|
|
CopyMem ((VOID *)&Data->StructureData, (VOID *)&ByteTemp, Data->DataLength);
|
|
break;
|
|
|
|
case DMI_WORD_CHANGE:
|
|
WordTmpPtr = (UINT16 *) ((UINTN)Structure + Data->FieldOffset);
|
|
if (WordTmpPtr == NULL) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
WordTemp = *WordTmpPtr;
|
|
WordTemp = WordTemp & ((UINT16)(Data->ChangeMask));
|
|
WordTemp = WordTemp | ((UINT16)((Data->ChangeValue) & ~(Data->ChangeMask)));
|
|
|
|
Data->DataLength = sizeof (UINT16);
|
|
CopyMem ((VOID *)&Data->StructureData, (VOID *)&WordTemp, Data->DataLength);
|
|
break;
|
|
|
|
case DMI_DWORD_CHANGE:
|
|
DWordTmpPtr = (UINT32 *) ((UINTN)Structure + Data->FieldOffset);
|
|
if (DWordTmpPtr == NULL) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
DWordTemp = *DWordTmpPtr;
|
|
DWordTemp = DWordTemp & ((UINT32)(Data->ChangeMask));
|
|
DWordTemp = DWordTemp | ((UINT32)((Data->ChangeValue) & ~(Data->ChangeMask)));
|
|
|
|
Data->DataLength = sizeof (UINT32);
|
|
CopyMem ((VOID *)&Data->StructureData, (VOID *)&DWordTemp, Data->DataLength);
|
|
|
|
break;
|
|
}
|
|
|
|
Status = SetDMI (Data, Structure);
|
|
if (EFI_ERROR (Status)) {
|
|
return DMI_READ_ONLY;
|
|
}
|
|
|
|
switch (Data->Command) {
|
|
|
|
case DMI_BYTE_CHANGE:
|
|
if (ByteTmpPtr == NULL) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
CopyMem (ByteTmpPtr, &ByteTemp, sizeof (UINT8));
|
|
break;
|
|
|
|
case DMI_WORD_CHANGE:
|
|
if (WordTmpPtr == NULL) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
CopyMem (WordTmpPtr, &WordTemp, sizeof (UINT16));
|
|
break;
|
|
|
|
case DMI_DWORD_CHANGE:
|
|
if (DWordTmpPtr == NULL) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
CopyMem (DWordTmpPtr, &DWordTemp, sizeof (UINT32));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return DMI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Helper function for Pnp0x52, process command DMI_STRING_CHANGE.
|
|
|
|
@param[In] Data Buffer of data to SetStructure.
|
|
@param[In] Structure The structure to be set.
|
|
|
|
@retval DMI_SUCCESS The function executed successfully.
|
|
@retval DMI_BAD_PARAMETER The length of data is invalid or can not locate the string in the structure.
|
|
@retval DMI_READ_ONLY Cannot set the data in the structure.
|
|
|
|
**/
|
|
INT16
|
|
Pnp0x52ChangeString (
|
|
IN BOOLEAN IsSmbios32BitTable,
|
|
IN FUNC_0x52_DATA_BUFFER *Data,
|
|
IN SMBIOS_STRUCTURE *Structure
|
|
)
|
|
{
|
|
CHAR8 *StructureString;
|
|
CHAR8 *TempstructureString;
|
|
UINTN StructureStringSize;
|
|
UINTN TempstructureStringSize;
|
|
UINTN Index;
|
|
EFI_STATUS Status;
|
|
UINT8 *SmbiosStoreArea;
|
|
UINTN CurrentTableSize;
|
|
UINT8 *DmiPtr;
|
|
UINTN TotalSmbiosBufferSize;
|
|
UINTN NewTableSize;
|
|
STRING_COUNT_TABLE *CountFieldTable;
|
|
STRING_OFFSET_TABLE *OffsetTable;
|
|
STRING_OFFSET_TABLE *OffsetTableEnd;
|
|
UINTN CountFieldTableSize;
|
|
UINT8 RecordLength;
|
|
BOOLEAN CountFieldType = FALSE;
|
|
EFI_PCD_PROTOCOL *Pcd;
|
|
UINT32 SmbiosTableLength;
|
|
UINT64 SmbiosTableAddress;
|
|
UINT8 NumberOfStrings;
|
|
UINTN Offset;
|
|
INT32 TotalIncreasedStringLength;
|
|
|
|
TempstructureString = NULL;
|
|
TempstructureStringSize = 0;
|
|
SmbiosStoreArea = NULL;
|
|
NumberOfStrings = 0;
|
|
Offset = 1;
|
|
|
|
DmiPtr = (UINT8 *)(UINTN) FdmGetNAtAddr(&gH2OFlashMapRegionSmbiosUpdateGuid, 1);
|
|
if (DmiPtr == NULL) {
|
|
return DMI_READ_ONLY;
|
|
}
|
|
|
|
if (!(*(UINT32 *)DmiPtr == DMI_UPDATE_STRING_SIGNATURE)){
|
|
return DMI_READ_ONLY;
|
|
}
|
|
|
|
if ((Data->DataLength > 0xff) || (Data->DataLength < 1)) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
|
|
Status = mSmst->SmmLocateProtocol (
|
|
&gEfiPcdProtocolGuid,
|
|
NULL,
|
|
(VOID **)&Pcd
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return DMI_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
CountFieldTable = (STRING_COUNT_TABLE *)Pcd->GetPtr (&gSmbiosTokenSpaceGuid, PcdToken (PcdSmbiosStringCountFieldOffset));
|
|
CountFieldTableSize = Pcd->GetSize (&gSmbiosTokenSpaceGuid, PcdToken (PcdSmbiosStringCountFieldOffset)) / sizeof (STRING_COUNT_TABLE);
|
|
RecordLength = 0;
|
|
for (Index = 0; Index < CountFieldTableSize; Index++) {
|
|
if (Structure->Type == CountFieldTable[Index].Type) {
|
|
RecordLength = (UINT8)Pcd->GetSize (&gSmbiosTokenSpaceGuid, PcdToken (PcdType000Record) + CountFieldTable[Index].Type) - 1;
|
|
CountFieldType = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((CountFieldType == TRUE) && (Data->DataLength == 1)) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
//
|
|
// Find string within the SMBIOS structure
|
|
//
|
|
if (CountFieldType) {
|
|
Status = LocateStringOfStructure (
|
|
(UINT8)Data->FieldOffset,
|
|
Structure,
|
|
&StructureString,
|
|
&StructureStringSize
|
|
);
|
|
Data->FieldOffset += RecordLength;
|
|
} else if (((UINT8 *)Structure)[Data->FieldOffset] == 0) {
|
|
NumberOfStrings = GetNumberStringOfStructure (Structure);
|
|
LocateDoubleNullOfStructure(
|
|
Structure,
|
|
&StructureString
|
|
);
|
|
if (NumberOfStrings != 0) {
|
|
StructureString++;
|
|
} else {
|
|
Offset = 2;
|
|
}
|
|
StructureStringSize = 0;
|
|
} else {
|
|
Status = LocateStringOfStructure (
|
|
((UINT8 *)Structure)[Data->FieldOffset],
|
|
Structure,
|
|
&StructureString,
|
|
&StructureStringSize
|
|
);
|
|
NumberOfStrings = GetNumberStringOfStructure (Structure);
|
|
if (NumberOfStrings == 1) {
|
|
Offset = 0;
|
|
}
|
|
}
|
|
if (EFI_ERROR (Status)) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
|
|
for (Index = 0; Index < UpdateableStringCount; Index++) {
|
|
if ((Structure->Type == mUpdatableStrings[Index].Type) &&
|
|
(Data->FieldOffset == mUpdatableStrings[Index].FixedOffset)) {
|
|
break;
|
|
}
|
|
}
|
|
if (Index == UpdateableStringCount) {
|
|
return DMI_READ_ONLY;
|
|
}
|
|
|
|
Status = SetDMI (Data, Structure);
|
|
if (EFI_ERROR (Status)) {
|
|
return DMI_READ_ONLY;
|
|
}
|
|
|
|
if (IsSmbios32BitTable) {
|
|
SmbiosTableLength = ((SMBIOS_TABLE_ENTRY_POINT*)mSmbiosTableEntryPoint)->TableLength;
|
|
SmbiosTableAddress = ((SMBIOS_TABLE_ENTRY_POINT*)mSmbiosTableEntryPoint)->TableAddress;
|
|
} else {
|
|
SmbiosTableLength = ((SMBIOS_TABLE_3_0_ENTRY_POINT*)mSmbiosTableEntryPoint64Bit)->TableMaximumSize;
|
|
SmbiosTableAddress = ((SMBIOS_TABLE_3_0_ENTRY_POINT*)mSmbiosTableEntryPoint64Bit)->TableAddress;
|
|
}
|
|
|
|
//
|
|
// This value is based on SmbiosDxe driver. If the buffer allocation method is changed, this size will be different.
|
|
//
|
|
TotalSmbiosBufferSize = EFI_PAGES_TO_SIZE ((UINTN) EFI_SIZE_TO_PAGES (SmbiosTableLength + PcdGet32(PcdH2OSmbiosTableExtraMemorySize)));
|
|
TempstructureString = StructureString + StructureStringSize + Offset;
|
|
if (IsSmbios32BitTable) {
|
|
TotalIncreasedStringLength = mTotalIncreasedStringLength;
|
|
} else {
|
|
TotalIncreasedStringLength = mTotalIncreasedStringLength64Bit;
|
|
}
|
|
if (TotalIncreasedStringLength >= 0x00) {
|
|
CurrentTableSize = (UINTN)SmbiosTableLength + (UINTN)TotalIncreasedStringLength;
|
|
TempstructureStringSize = (UINTN)SmbiosTableLength + (UINTN)TotalIncreasedStringLength -
|
|
(UINTN)(TempstructureString - SmbiosTableAddress);
|
|
} else {
|
|
CurrentTableSize = (UINTN)SmbiosTableLength - (UINTN)(~(TotalIncreasedStringLength - 1));
|
|
TempstructureStringSize = (UINTN)SmbiosTableLength - (UINTN)(~(TotalIncreasedStringLength - 1)) -
|
|
(UINTN)(TempstructureString - SmbiosTableAddress);
|
|
}
|
|
|
|
//
|
|
// If new SMBIOS data is over than the buffer, nothing will change.
|
|
// Data->DataLength : new string length, including '0'
|
|
// structureStringSize : original string length
|
|
//
|
|
if ((UINTN)Data->DataLength > (StructureStringSize + 1)) {
|
|
NewTableSize = CurrentTableSize + (UINTN)Data->DataLength - (StructureStringSize + 1);
|
|
if (NewTableSize > TotalSmbiosBufferSize) {
|
|
return DMI_NO_CHANGE;
|
|
}
|
|
}
|
|
SmbiosStoreArea = AllocateRuntimePool (CurrentTableSize);
|
|
if (SmbiosStoreArea == NULL) {
|
|
return PNP_BUFFER_TOO_SMALL;
|
|
}
|
|
CopyMem (SmbiosStoreArea, TempstructureString, TempstructureStringSize);
|
|
if (Data->StructureData[0] != 0) {
|
|
CopyMem (StructureString, Data->StructureData, Data->DataLength);
|
|
TempstructureString = StructureString + Data->DataLength;
|
|
if (StructureStringSize == 0) {
|
|
*TempstructureString = 0;
|
|
TempstructureString++;
|
|
((UINT8 *)Structure)[Data->FieldOffset] = NumberOfStrings + 1;
|
|
}
|
|
} else {
|
|
if (StructureStringSize != 0) {
|
|
TempstructureString = StructureString;
|
|
}
|
|
}
|
|
CopyMem (TempstructureString, SmbiosStoreArea, TempstructureStringSize);
|
|
|
|
//
|
|
// Adjust the string numbers of the structure if the new string is NULL
|
|
//
|
|
if (Data->StructureData[0] == 0) {
|
|
OffsetTable = (STRING_OFFSET_TABLE *)Pcd->GetPtr (&gSmbiosTokenSpaceGuid, PcdToken(PcdSmbiosStringFieldOffset));
|
|
OffsetTableEnd = (STRING_OFFSET_TABLE *)((CHAR8 *)OffsetTable + Pcd->GetSize(&gSmbiosTokenSpaceGuid, PcdToken(PcdSmbiosStringFieldOffset)));
|
|
AdjustStringNumbersOfStructure(Structure, Data->FieldOffset, OffsetTable, OffsetTableEnd);
|
|
}
|
|
|
|
FreePool (SmbiosStoreArea);
|
|
|
|
TotalIncreasedStringLength = TotalIncreasedStringLength + (UINT32)Data->DataLength - (UINT32)(StructureStringSize + 1);
|
|
if (IsSmbios32BitTable) {
|
|
mTotalIncreasedStringLength = TotalIncreasedStringLength;
|
|
} else {
|
|
mTotalIncreasedStringLength64Bit = TotalIncreasedStringLength;
|
|
}
|
|
return DMI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Helper function for Pnp0x52, process command DMI_BLOCK_CHANGE.
|
|
|
|
@param[In] Data Buffer of data to SetStructure.
|
|
@param[In] Structure The structure to be set.
|
|
|
|
@retval DMI_SUCCESS The function executed successfully.
|
|
@retval DMI_BAD_PARAMETER The length of data is invalid or can not locate the string in the structure.
|
|
@retval DMI_READ_ONLY The structure is not Type1, the block to be set is not at offset 8.
|
|
|
|
**/
|
|
INT16
|
|
Pnp0x52ChangeBlock (
|
|
IN FUNC_0x52_DATA_BUFFER *Data,
|
|
IN SMBIOS_STRUCTURE *Structure
|
|
)
|
|
{
|
|
UINT8 *TmpPtr;
|
|
UINT8 *DataPtr;
|
|
UINTN CopyLength;
|
|
EFI_STATUS Status;
|
|
|
|
|
|
TmpPtr = (UINT8 *)((UINTN)Structure + Data->FieldOffset);
|
|
DataPtr = (UINT8 *)Data->StructureData;
|
|
CopyLength = (UINTN)Data->DataLength;
|
|
|
|
if ((Structure->Type != 1) || (Data->FieldOffset != 8)) {
|
|
return DMI_READ_ONLY;
|
|
}
|
|
|
|
if (CopyLength != sizeof (EFI_GUID)){
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
|
|
Status = SetDMI (Data, Structure);
|
|
if (EFI_ERROR (Status)) {
|
|
return DMI_READ_ONLY;
|
|
}
|
|
CopyMem (TmpPtr, Data->StructureData, Data->DataLength);
|
|
|
|
return DMI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
Get the full size of SMBIOS structure including optional strings that follow the formatted structure.
|
|
|
|
@param This The EFI_SMBIOS_PROTOCOL instance.
|
|
@param Head Pointer to the beginning of SMBIOS structure.
|
|
@param Size The returned size.
|
|
@param NumberOfStrings The returned number of optional strings that follow the formatted structure.
|
|
|
|
@retval EFI_SUCCESS Size retured in Size.
|
|
@retval EFI_INVALID_PARAMETER Input SMBIOS structure mal-formed or Size is NULL.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
GetSmbiosStructureSize (
|
|
IN EFI_SMBIOS_TABLE_HEADER *Head,
|
|
OUT UINTN *Size,
|
|
OUT UINTN *NumberOfStrings
|
|
)
|
|
{
|
|
UINTN FullSize;
|
|
UINTN StrLen;
|
|
UINTN MaxLen;
|
|
INT8* CharInStr;
|
|
|
|
if (Size == NULL || NumberOfStrings == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
FullSize = Head->Length;
|
|
CharInStr = (INT8*)Head + Head->Length;
|
|
*Size = FullSize;
|
|
*NumberOfStrings = 0;
|
|
StrLen = 0;
|
|
|
|
//
|
|
// SMBIOS 3.0 defines the Structure table maximum size as DWORD field limited to 0xFFFFFFFF bytes.
|
|
// Locate the end of string as long as possible.
|
|
//
|
|
MaxLen = SMBIOS_3_0_TABLE_MAX_LENGTH;
|
|
|
|
//
|
|
// look for the two consecutive zeros, check the string limit by the way.
|
|
//
|
|
while (*CharInStr != 0 || *(CharInStr+1) != 0) {
|
|
if (*CharInStr == 0) {
|
|
*Size += 1;
|
|
CharInStr++;
|
|
}
|
|
|
|
for (StrLen = 0 ; StrLen < MaxLen; StrLen++) {
|
|
if (*(CharInStr+StrLen) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (StrLen == MaxLen) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// forward the pointer
|
|
//
|
|
CharInStr += StrLen;
|
|
*Size += StrLen;
|
|
*NumberOfStrings += 1;
|
|
}
|
|
|
|
//
|
|
// count ending two zeros.
|
|
//
|
|
*Size += 2;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
PnP function 0x50, Get SMBIOS Information.
|
|
|
|
@param[In] Frame Pointer to input stack frame of the PnP call.
|
|
|
|
@retval DMI_SUCCESS The function was executed successfully.
|
|
|
|
**/
|
|
INT16
|
|
Pnp0x50 (
|
|
IN VOID *Frame
|
|
)
|
|
{
|
|
UINT8 *DmiBIOSRevision;
|
|
UINT16 *NumStructures;
|
|
UINT16 *StructureSize;
|
|
UINT32 *DmiStorageBase;
|
|
UINT16 *DmiStorageSize;
|
|
BOOLEAN IsSmbios32BitTable;
|
|
|
|
if (!BufferInCmdBufferPnp (Frame, sizeof(PNP_FUNCTION_0x50_FRAME))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
|
|
IsSmbios32BitTable = FALSE;
|
|
|
|
if (((PcdGet16 (PcdSmbiosVersion) >> 8) < 0x3) ||
|
|
(((PcdGet16 (PcdSmbiosVersion) >> 8) >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT0) == BIT0))) {
|
|
IsSmbios32BitTable = TRUE;
|
|
}
|
|
|
|
LocateSmbiosTable ();
|
|
|
|
if (IsSmbios32BitTable){
|
|
|
|
DmiBIOSRevision = (UINT8 *)PnpFarToLinear (((PNP_FUNCTION_0x50_FRAME *)Frame)->DmiBIOSRevision);
|
|
if (!BufferInCmdBufferPnp ((VOID *) DmiBIOSRevision, sizeof(UINT8))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
*DmiBIOSRevision = mSmbiosTableEntryPoint->SmbiosBcdRevision;
|
|
|
|
NumStructures = (UINT16 *)PnpFarToLinear (((PNP_FUNCTION_0x50_FRAME *)Frame)->NumStructures);
|
|
if (!BufferInCmdBufferPnp ((VOID *) NumStructures, sizeof(UINT16))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
*NumStructures = mSmbiosTableEntryPoint->NumberOfSmbiosStructures;
|
|
|
|
StructureSize = (UINT16 *)PnpFarToLinear (((PNP_FUNCTION_0x50_FRAME *)Frame)->StructureSize);
|
|
if (!BufferInCmdBufferPnp ((VOID *) StructureSize, sizeof(UINT16))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
*StructureSize = mSmbiosTableEntryPoint->MaxStructureSize;
|
|
|
|
DmiStorageBase = (UINT32 *)PnpFarToLinear (((PNP_FUNCTION_0x50_FRAME *)Frame)->DmiStorageBase);
|
|
if (!BufferInCmdBufferPnp ((VOID *) DmiStorageBase, sizeof(UINT32))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
*DmiStorageBase = (UINT32)(UINTN)mSmbiosTable;
|
|
|
|
DmiStorageSize = (UINT16 *)PnpFarToLinear(((PNP_FUNCTION_0x50_FRAME *)Frame)->DmiStorageSize);
|
|
if (!BufferInCmdBufferPnp ((VOID *) DmiStorageSize, sizeof(UINT16))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
*DmiStorageSize = mSmbiosTableEntryPoint->TableLength;
|
|
|
|
} else {
|
|
|
|
UINT64 TableAddress;
|
|
UINT64 TableEndAddress;
|
|
UINTN NumberOfStrings;
|
|
UINTN Size;
|
|
UINT16 NumberOfStructure;
|
|
UINTN MaxStructureSize;
|
|
EFI_STATUS Status;
|
|
|
|
NumberOfStructure = 0;
|
|
MaxStructureSize = 0;
|
|
|
|
if (mSmbiosTableEntryPoint64Bit == NULL){
|
|
return DMI_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
TableAddress = mSmbiosTableEntryPoint64Bit->TableAddress;
|
|
TableEndAddress = mSmbiosTableEntryPoint64Bit->TableAddress + mSmbiosTableEntryPoint64Bit->TableMaximumSize;
|
|
|
|
while (TableAddress < TableEndAddress){
|
|
Status = GetSmbiosStructureSize ((EFI_SMBIOS_TABLE_HEADER*)(UINTN)TableAddress, &Size, &NumberOfStrings);
|
|
if (EFI_ERROR(Status)){
|
|
break;
|
|
}
|
|
|
|
if (MaxStructureSize < Size){
|
|
MaxStructureSize = Size;
|
|
}
|
|
NumberOfStructure++;
|
|
TableAddress += Size;
|
|
}
|
|
|
|
DmiBIOSRevision = (UINT8 *)PnpFarToLinear (((PNP_FUNCTION_0x50_FRAME *)Frame)->DmiBIOSRevision);
|
|
if (!BufferInCmdBufferPnp ((VOID *) DmiBIOSRevision, sizeof(UINT8))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
*DmiBIOSRevision = (UINT8) ((PcdGet16 (PcdSmbiosVersion) >> 4) & 0xf0) | (UINT8) (PcdGet16 (PcdSmbiosVersion) & 0x0f);
|
|
|
|
NumStructures = (UINT16 *)PnpFarToLinear (((PNP_FUNCTION_0x50_FRAME *)Frame)->NumStructures);
|
|
if (!BufferInCmdBufferPnp ((VOID *) NumStructures, sizeof(UINT16))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
*NumStructures = NumberOfStructure;
|
|
|
|
StructureSize = (UINT16 *)PnpFarToLinear (((PNP_FUNCTION_0x50_FRAME *)Frame)->StructureSize);
|
|
if (!BufferInCmdBufferPnp ((VOID *) StructureSize, sizeof(UINT16))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
*StructureSize = (UINT16) MaxStructureSize;
|
|
|
|
DmiStorageBase = (UINT32 *)PnpFarToLinear (((PNP_FUNCTION_0x50_FRAME *)Frame)->DmiStorageBase);
|
|
if (!BufferInCmdBufferPnp ((VOID *) DmiStorageBase, sizeof(UINT32))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
*DmiStorageBase = (UINT32)(UINTN)mSmbiosTable64Bit;
|
|
|
|
DmiStorageSize = (UINT16 *)PnpFarToLinear(((PNP_FUNCTION_0x50_FRAME *)Frame)->DmiStorageSize);
|
|
if (!BufferInCmdBufferPnp ((VOID *) DmiStorageSize, sizeof(UINT16))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
*DmiStorageSize = (UINT16)((SMBIOS_TABLE_3_0_ENTRY_POINT*)mSmbiosTableEntryPoint64Bit)->TableMaximumSize;
|
|
}
|
|
|
|
return DMI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
PnP function 0x51, Get SMBIOS Structure.
|
|
|
|
@param[In] Frame Pointer to input stack frame of the PnP call.
|
|
|
|
@retval DMI_SUCCESS The function was executed successfully.
|
|
@retval DMI_INVALID_HANDLE Invalid handle.
|
|
|
|
**/
|
|
INT16
|
|
Pnp0x51 (
|
|
IN VOID *Frame
|
|
)
|
|
{
|
|
UINT16 *Structure;
|
|
UINT8 *DmiStrucBuffer;
|
|
SMBIOS_STRUCTURE *Location;
|
|
UINTN Size;
|
|
BOOLEAN IsSmbios32BitTable;
|
|
|
|
if (!BufferInCmdBufferPnp (Frame, sizeof(PNP_FUNCTION_0x51_FRAME))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
|
|
IsSmbios32BitTable = FALSE;
|
|
|
|
if (((PcdGet16 (PcdSmbiosVersion) >> 8) < 0x3) ||
|
|
(((PcdGet16 (PcdSmbiosVersion) >> 8) >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT0) == BIT0))) {
|
|
IsSmbios32BitTable = TRUE;
|
|
} else {
|
|
IsSmbios32BitTable = FALSE;
|
|
}
|
|
|
|
LocateSmbiosTable ();
|
|
|
|
Structure = (UINT16 *)PnpFarToLinear (((PNP_FUNCTION_0x51_FRAME *)Frame)->Structure);
|
|
DmiStrucBuffer = (UINT8 *)PnpFarToLinear (((PNP_FUNCTION_0x51_FRAME *)Frame)->DmiStrucBuffer);
|
|
Location = (SMBIOS_STRUCTURE *)DmiStrucBuffer;
|
|
if (!BufferInCmdBufferPnp ((VOID *) Structure, sizeof(UINT16))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
if (!EFI_ERROR (LocateSmbiosStructure (IsSmbios32BitTable, Structure, &Location, &Size))) {
|
|
if (!BufferInCmdBufferPnp ((VOID *) DmiStrucBuffer, Size)) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
CopyMem (DmiStrucBuffer, (VOID *)Location, Size);
|
|
return DMI_SUCCESS;
|
|
} else {
|
|
return DMI_INVALID_HANDLE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
PnP function 0x52, Set SMBIOS Structure.
|
|
|
|
@param[In] Frame Pointer to input stack frame of the PnP call.
|
|
|
|
@retval DMI_SUCCESS The function was executed successfully.
|
|
@retval DMI_BAD_PARAMETER Invalid command.
|
|
|
|
**/
|
|
INT16
|
|
Pnp0x52 (
|
|
IN VOID *Frame
|
|
)
|
|
{
|
|
FUNC_0x52_DATA_BUFFER *Data;
|
|
SMBIOS_STRUCTURE *StructureLocation;
|
|
SMBIOS_STRUCTURE *StructureLocation64Bit;
|
|
UINT16 StructureHandle;
|
|
UINT16 StructureHandle64Bit;
|
|
UINT8 OldFieldOffset;
|
|
UINTN StructureSize;
|
|
UINTN StructureSize64Bit;
|
|
INT16 ReturnStatus;
|
|
INT16 ReturnStatus64Bit;
|
|
EFI_STATUS Status;
|
|
BOOLEAN IsSmbios32BitTable;
|
|
BOOLEAN IsSmbios64BitTable;
|
|
FUNC_0x52_DATA_BUFFER *OrgData;
|
|
|
|
if (!BufferInCmdBufferPnp (Frame, sizeof(PNP_FUNCTION_0x52_FRAME))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
|
|
IsSmbios32BitTable = FALSE;
|
|
IsSmbios64BitTable = FALSE;
|
|
ReturnStatus = DMI_SUCCESS;
|
|
ReturnStatus64Bit = DMI_SUCCESS;
|
|
StructureLocation = NULL;
|
|
StructureLocation64Bit = NULL;
|
|
|
|
Data = (FUNC_0x52_DATA_BUFFER *)PnpFarToLinear (((PNP_FUNCTION_0x52_FRAME *)Frame)->DmiDataBuffer + Data->DataLength - sizeof(UINT8));
|
|
if (!BufferInCmdBufferPnp ((VOID *) Data, sizeof(FUNC_0x52_DATA_BUFFER))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
//
|
|
// Copy FUNC_0x52_DATA_BUFFER to SMRAM to prevent from TOCTOU attack.
|
|
//
|
|
OrgData = Data;
|
|
Data = AllocateCopyPool (sizeof(FUNC_0x52_DATA_BUFFER) + Data->DataLength - sizeof(UINT8), OrgData);
|
|
if (Data == NULL) {
|
|
return DMI_SUCCESS;
|
|
}
|
|
StructureLocation = NULL;
|
|
StructureHandle = Data->StructureHeader.Handle;
|
|
|
|
if (((PcdGet16 (PcdSmbiosVersion) >> 8) < 0x3) ||
|
|
(((PcdGet16 (PcdSmbiosVersion) >> 8) >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT0) == BIT0))) {
|
|
IsSmbios32BitTable = TRUE;
|
|
}
|
|
|
|
if (((PcdGet16 (PcdSmbiosVersion) >> 8) >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT1) == BIT1)) {
|
|
IsSmbios64BitTable = TRUE;
|
|
}
|
|
|
|
StructureHandle64Bit = StructureHandle;
|
|
|
|
if (IsSmbios32BitTable) {
|
|
Status = LocateSmbiosStructure (IsSmbios32BitTable, &StructureHandle, &StructureLocation, &StructureSize);
|
|
if(EFI_ERROR(Status)){
|
|
goto Done;
|
|
}
|
|
}
|
|
|
|
if (IsSmbios64BitTable) {
|
|
Status = LocateSmbiosStructure (FALSE, &StructureHandle64Bit, &StructureLocation64Bit, &StructureSize64Bit);
|
|
if(EFI_ERROR(Status)){
|
|
goto Done;
|
|
}
|
|
}
|
|
|
|
|
|
switch (Data->Command) {
|
|
|
|
case DMI_BYTE_CHANGE:
|
|
case DMI_WORD_CHANGE:
|
|
case DMI_DWORD_CHANGE:
|
|
if (IsSmbios32BitTable){
|
|
ReturnStatus = Pnp0x52ChangeFixedLength (Data, StructureLocation);
|
|
}
|
|
|
|
if (IsSmbios64BitTable){
|
|
ReturnStatus64Bit = Pnp0x52ChangeFixedLength (Data, StructureLocation64Bit);
|
|
}
|
|
break;
|
|
|
|
case DMI_STRING_CHANGE:
|
|
if (Data->StructureData == NULL) {
|
|
ReturnStatus = DMI_BAD_PARAMETER;
|
|
break;
|
|
}
|
|
OldFieldOffset = Data->FieldOffset;
|
|
if (IsSmbios32BitTable){
|
|
ReturnStatus = Pnp0x52ChangeString (IsSmbios32BitTable, Data, StructureLocation);
|
|
}
|
|
|
|
if (IsSmbios64BitTable){
|
|
if (Data->FieldOffset != OldFieldOffset) {
|
|
Data->FieldOffset = OldFieldOffset;
|
|
}
|
|
ReturnStatus64Bit = Pnp0x52ChangeString (FALSE, Data, StructureLocation64Bit);
|
|
}
|
|
break;
|
|
|
|
case DMI_BLOCK_CHANGE:
|
|
if (Data->StructureData == NULL){
|
|
ReturnStatus = DMI_BAD_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
if (IsSmbios32BitTable){
|
|
ReturnStatus = Pnp0x52ChangeBlock (Data, StructureLocation);
|
|
}
|
|
|
|
if (IsSmbios64BitTable){
|
|
ReturnStatus64Bit = Pnp0x52ChangeBlock (Data, StructureLocation64Bit);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ReturnStatus = DMI_BAD_PARAMETER;
|
|
break;
|
|
}
|
|
Done:
|
|
//
|
|
// Restore data from SMRAM to IHISI command buffer.
|
|
//
|
|
CopyMem (OrgData, Data, sizeof(FUNC_0x52_DATA_BUFFER) + Data->DataLength - sizeof(UINT8));
|
|
FreePool (Data);
|
|
ReturnStatus = EFI_ERROR (ReturnStatus64Bit) ? ReturnStatus64Bit : ReturnStatus;
|
|
|
|
return ReturnStatus;
|
|
}
|
|
|
|
/**
|
|
default function returning that the call was to an unsupported function.
|
|
|
|
@param[In] Frame Pointer to input stack frame of the PnP call.(unused)
|
|
|
|
@retval DMI_SUCCESS The function was executed successfully.
|
|
@retval DMI_INVALID_SUBFUNCTION Invalid command.
|
|
|
|
**/
|
|
INT16
|
|
UnsupportedPnpFunction (
|
|
IN VOID *Frame
|
|
)
|
|
{
|
|
return PNP_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
/**
|
|
PnP function 0x54.
|
|
|
|
@param[In] Frame Pointer to input stack frame of the PnP call.
|
|
|
|
@retval DMI_SUCCESS The function was executed successfully.
|
|
|
|
**/
|
|
INT16
|
|
Pnp0x54 (
|
|
IN VOID *Frame
|
|
)
|
|
{
|
|
INT16 SubFunction;
|
|
UINT8 *Data;
|
|
UINT8 Control;
|
|
UINTN Index;
|
|
|
|
if (!BufferInCmdBufferPnp (Frame, sizeof(PNP_FUNCTION_0x54_FRAME))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
|
|
SubFunction = (UINT16)((PNP_FUNCTION_0x54_FRAME *)Frame)->SubFunction;
|
|
Data = (UINT8 *)PnpFarToLinear (((PNP_FUNCTION_0x54_FRAME *)Frame)->Data);
|
|
if (!BufferInCmdBufferPnp ((VOID *) Data, sizeof(UINT8))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
Control = (UINT8)((PNP_FUNCTION_0x54_FRAME *)Frame)->Control;
|
|
|
|
if ((Control & 0x01) == 0) {
|
|
if (SubFunction >= 1) {
|
|
return DMI_INVALID_SUBFUNCTION;
|
|
}
|
|
return DMI_SUCCESS;
|
|
}
|
|
|
|
switch (SubFunction) {
|
|
|
|
case 0:
|
|
//
|
|
// for event log
|
|
//
|
|
if (!mIsOemGPNVMap) {
|
|
return DMI_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
for (Index = 0; Index < OemGPNVHandleCount; Index++) {
|
|
ClearBiosEventLog (GPNVMapBuffer.PlatFormGPNVMap[Index].BaseAddress, GPNVMapBuffer.PlatFormGPNVMap[Index].GPNVSize);
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
return DMI_INVALID_SUBFUNCTION;
|
|
break;
|
|
|
|
case 2:
|
|
return DMI_INVALID_SUBFUNCTION;
|
|
break;
|
|
|
|
default:
|
|
return DMI_INVALID_SUBFUNCTION;
|
|
break;
|
|
}
|
|
|
|
return DMI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
PnP function 0x55, Set SMBIOS Structure.
|
|
|
|
@param[In] Frame Pointer to input stack frame of the PnP call.
|
|
|
|
@retval DMI_SUCCESS The function was executed successfully.
|
|
@retval DMI_INVALID_HANDLE Invalid handle.
|
|
|
|
**/
|
|
INT16
|
|
Pnp0x55 (
|
|
IN VOID *Frame
|
|
)
|
|
{
|
|
UINT16 *Handle;
|
|
UINT16 HandleTemp;
|
|
UINT16 *MinGPNVRWSize;
|
|
UINT16 *GPNVSize;
|
|
UINT32 *NVStorageBase;
|
|
UINT16 Index;
|
|
|
|
if (!BufferInCmdBufferPnp (Frame, sizeof(PNP_FUNCTION_0x55_FRAME))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
|
|
Handle = (UINT16 *)PnpFarToLinear (((PNP_FUNCTION_0x55_FRAME *)Frame)->Handle);
|
|
if (!BufferInCmdBufferPnp ((VOID *) Handle, sizeof(UINT16))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
|
|
Index = HandleTemp = *Handle;
|
|
|
|
if (!VaildGPNVCheck (&Index, HandleTemp)) {
|
|
return DMI_INVALID_HANDLE;
|
|
}
|
|
|
|
MinGPNVRWSize = (UINT16 *)PnpFarToLinear (((PNP_FUNCTION_0x55_FRAME *)Frame)->MinGPNVRWSize);
|
|
if (!BufferInCmdBufferPnp ((VOID *) MinGPNVRWSize, sizeof(UINT16))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
*MinGPNVRWSize = (UINT16)GPNVMapBuffer.PlatFormGPNVMap[Index].MinGPNVSize;
|
|
|
|
GPNVSize = (UINT16 *)PnpFarToLinear (((PNP_FUNCTION_0x55_FRAME *)Frame)->GPNVSize);
|
|
if (!BufferInCmdBufferPnp ((VOID *) GPNVSize, sizeof(UINT16))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
*GPNVSize = (UINT16)GPNVMapBuffer.PlatFormGPNVMap[Index].GPNVSize;
|
|
|
|
NVStorageBase = (UINT32 *)PnpFarToLinear (((PNP_FUNCTION_0x55_FRAME *)Frame)->NVStorageBase);
|
|
if (!BufferInCmdBufferPnp ((VOID *) NVStorageBase, sizeof(UINT32))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
*NVStorageBase = (UINT32)GPNVMapBuffer.PlatFormGPNVMap[Index].BaseAddress;
|
|
|
|
Index++;
|
|
if (Index >= FixedPcdGet16 (PcdDefaultGpnvMapBufferSize)) {
|
|
return DMI_INVALID_HANDLE;
|
|
}
|
|
|
|
*Handle = GPNVMapBuffer.PlatFormGPNVMap[Index].Handle;
|
|
|
|
return DMI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
PnP function 0x56, Set SMBIOS Structure.
|
|
|
|
@param[In] Frame Pointer to input stack frame of the PnP call.
|
|
|
|
@retval DMI_SUCCESS The function was executed successfully.
|
|
@retval DMI_INVALID_HANDLE Invalid handle.
|
|
|
|
**/
|
|
INT16
|
|
Pnp0x56 (
|
|
IN VOID *Frame
|
|
)
|
|
{
|
|
UINT16 Handle;
|
|
UINT8 *GPNVBuffer;
|
|
UINT16 Index;
|
|
|
|
if (!BufferInCmdBufferPnp (Frame, sizeof(PNP_FUNCTION_0x56_FRAME))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
|
|
Handle = (UINT16)((PNP_FUNCTION_0x56_FRAME *)Frame)->Handle;
|
|
GPNVBuffer = (UINT8 *)PnpFarToLinear (((PNP_FUNCTION_0x56_FRAME *)Frame)->GPNVBuffer);
|
|
|
|
Index = Handle;
|
|
if (!VaildGPNVCheck (&Index, Handle)) {
|
|
return DMI_INVALID_HANDLE;
|
|
}
|
|
|
|
if (!BufferInCmdBufferPnp ((VOID *) GPNVBuffer, GPNVMapBuffer.PlatFormGPNVMap[Index].GPNVSize)) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
|
|
CopyMem (
|
|
GPNVBuffer,
|
|
(VOID *)(UINTN)GPNVMapBuffer.PlatFormGPNVMap[Index].BaseAddress,
|
|
GPNVMapBuffer.PlatFormGPNVMap[Index].GPNVSize
|
|
);
|
|
|
|
return DMI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
PnP function 0x57, Set SMBIOS Structure.
|
|
|
|
@param[In] Frame Pointer to input stack frame of the PnP call.
|
|
|
|
@retval DMI_SUCCESS The function was executed successfully.
|
|
@retval DMI_INVALID_HANDLE Invalid handle.
|
|
|
|
**/
|
|
INT16
|
|
Pnp0x57 (
|
|
IN VOID *Frame
|
|
)
|
|
{
|
|
UINT16 Handle;
|
|
UINT8 *GPNVBuffer;
|
|
UINT16 Index;
|
|
|
|
if (!BufferInCmdBufferPnp (Frame, sizeof(PNP_FUNCTION_0x57_FRAME))) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
|
|
Handle = (UINT16)((PNP_FUNCTION_0x57_FRAME *)Frame)->Handle;
|
|
GPNVBuffer = (UINT8 *)PnpFarToLinear (((PNP_FUNCTION_0x57_FRAME *)Frame)->GPNVBuffer);
|
|
|
|
Index = Handle;
|
|
if (! VaildGPNVCheck (&Index, Handle)) {
|
|
return DMI_INVALID_HANDLE;
|
|
}
|
|
|
|
if (!BufferInCmdBufferPnp ((VOID *) GPNVBuffer, GPNVMapBuffer.PlatFormGPNVMap[Index].GPNVSize)) {
|
|
return DMI_BAD_PARAMETER;
|
|
}
|
|
WriteGPNV (Index, GPNVBuffer);
|
|
|
|
return DMI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This fucntion is triggered by SMI function call 0x47.
|
|
|
|
@param[In] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
|
|
@param[In] Context Points to an optional handler context which was specified when the
|
|
handler was registered.
|
|
@param[In] CommBuffer A pointer to a collection of data in memory that will
|
|
be conveyed from a non-SMM environment into an SMM environment.
|
|
@param[In] CommBufferSize The size of the CommBuffer.
|
|
|
|
@retval EFI_SUCCESS The callabck was handled successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PnPBiosCallback (
|
|
IN EFI_HANDLE DispatchHandle,
|
|
IN CONST VOID *DispatchContext,
|
|
IN OUT VOID *CommBuffer,
|
|
IN OUT UINTN *CommBufferSize
|
|
)
|
|
{
|
|
PNP_GENERIC_ENTRY_FRAME *Frame;
|
|
H2O_IHISI_PARAMS *ParamsBuffer;
|
|
INT16 ReturnStatus;
|
|
EFI_STATUS Status;
|
|
UINT32 Eax;
|
|
UINT32 Ebx;
|
|
UINT32 Esi;
|
|
UINT32 ParamsBufferSize;
|
|
H2O_IHISI_PARAMS *OrgParamsBuffer;
|
|
|
|
OrgParamsBuffer = NULL;
|
|
Status = H2OGetParamBuffer (&ParamsBuffer, &ParamsBufferSize);
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// Copy H2O_IHISI_PARAMS to SMRAM to prevent from TOCTOU attack.
|
|
//
|
|
OrgParamsBuffer = ParamsBuffer;
|
|
ParamsBuffer = AllocateCopyPool (ParamsBufferSize, OrgParamsBuffer);
|
|
if (ParamsBuffer == NULL) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
Ebx = (UINT32) ParamsBuffer->Param2;
|
|
Esi = (UINT32) ParamsBuffer->Param5;
|
|
if (Ebx == SIGNATURE_32 ('$', 'I', 'S', 'B')) {
|
|
//
|
|
// Call by new way that AP trigger software SMI directly when the signature is "$ISB'
|
|
//
|
|
Frame = (PNP_GENERIC_ENTRY_FRAME *)(UINTN)Esi;
|
|
if ((Frame->Function & ~0x7) == 0x50) {
|
|
ReturnStatus = mPnpDmiFunctions[Frame->Function & 0x7](Frame);
|
|
} else {
|
|
ReturnStatus = PNP_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
Eax = (UINT32) ReturnStatus;
|
|
ParamsBuffer->Param1 = Eax;
|
|
}
|
|
//
|
|
// Restore data from SMRAM to IHISI parameter buffer.
|
|
//
|
|
CopyMem (OrgParamsBuffer, ParamsBuffer, ParamsBufferSize);
|
|
FreePool (ParamsBuffer);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function is SMM Communication call back for SMBIOS PNP functions.
|
|
|
|
@param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
|
|
@param[in] Context Points to an optional handler context which was specified when the
|
|
handler was registered.
|
|
@param[in,out] CommBuffer A pointer to a collection of data in memory that will
|
|
be conveyed from a non-SMM environment into an SMM environment.
|
|
@param[in,out] CommBufferSize The size of the CommBuffer.
|
|
|
|
@retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
|
|
should still be called.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SmmSmbiosPnpHandler (
|
|
IN EFI_HANDLE DispatchHandle,
|
|
IN CONST VOID *RegisterContext,
|
|
IN OUT VOID *CommBuffer,
|
|
IN OUT UINTN *CommBufferSize
|
|
)
|
|
{
|
|
SMM_SMBIOS_PNP_COMMUNICATE_HEADER *SmmSmbiosPnpHeader;
|
|
SMM_SMBIOS_PNP_ADDRESS *SmmSmbiosPnpEntry;
|
|
UINTN SmmSmbiosPnpCommBufferSize;
|
|
|
|
if (CommBuffer == NULL || CommBufferSize == NULL) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
//
|
|
// Check buffer size, address, must be the memory which is allocated in DXE part entry point to make sure
|
|
// the memory will not overlap SMM RAM.
|
|
//
|
|
if (*CommBufferSize != SMM_SMBIOS_PNP_COMM_BUFF_SIZE - SMM_COMMUNICATE_HEADER_SIZE ||
|
|
(UINTN)CommBuffer != (UINTN)mSmmSMBIOSPnpBuffer + SMM_COMMUNICATE_HEADER_SIZE) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Copy SMM_SMBIOS_PNP_COMM_BUFF to SMRAM to prevent from TOCTOU attack.
|
|
//
|
|
SmmSmbiosPnpCommBufferSize = sizeof (SMM_SMBIOS_PNP_COMMUNICATE_HEADER) + sizeof(SMM_SMBIOS_PNP_ADDRESS) - sizeof(UINT8);
|
|
SmmSmbiosPnpHeader = AllocateCopyPool (SmmSmbiosPnpCommBufferSize, CommBuffer);
|
|
if (SmmSmbiosPnpHeader == NULL) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
SmmSmbiosPnpEntry = (SMM_SMBIOS_PNP_ADDRESS *) SmmSmbiosPnpHeader->Data;
|
|
|
|
switch (SmmSmbiosPnpHeader->Function) {
|
|
case SMM_COMM_SMBIOS_PNP_ENTRY_SET:
|
|
if (mSMBIOSTableEntryAddress == 0) {
|
|
mSMBIOSTableEntryAddress = (EFI_PHYSICAL_ADDRESS) SmmSmbiosPnpEntry->Address;
|
|
}
|
|
|
|
if (mSMBIOSTableEntryAddress64Bit == 0) {
|
|
mSMBIOSTableEntryAddress64Bit = (EFI_PHYSICAL_ADDRESS) SmmSmbiosPnpEntry->Address64Bit;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
//
|
|
// Restore data from SMRAM to parameter communication buffer.
|
|
//
|
|
CopyMem (CommBuffer, SmmSmbiosPnpHeader, SmmSmbiosPnpCommBufferSize);
|
|
FreePool (SmmSmbiosPnpHeader);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Clear BIOS event log data from GPNV area.
|
|
|
|
@param[In] GPNVBase GPNV Start address
|
|
@param[In] GPNVLength GPNV Length
|
|
|
|
@retval DMI_SUCCESS The function was executed successfully.
|
|
@retval DMI_INVALID_HANDLE Invalid handle.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
ClearBiosEventLog (
|
|
IN UINTN GPNVBase,
|
|
IN UINTN GPNVLength
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_STATUS EraseStatus;
|
|
UINT8 *Buffer;
|
|
UINT32 Index;
|
|
UINTN BlockSize;
|
|
UINTN FdSupportEraseSize;
|
|
UINTN EraseCount;
|
|
UINTN EraseStartAddress;
|
|
|
|
FdSupportEraseSize = GetFlashBlockSize();
|
|
EraseStartAddress = GPNVBase & (~(FdSupportEraseSize - 1));
|
|
EraseCount = GET_ERASE_SECTOR_NUM (
|
|
GPNVBase,
|
|
GPNVLength,
|
|
EraseStartAddress,
|
|
FdSupportEraseSize
|
|
);
|
|
|
|
BlockSize = FdSupportEraseSize * EraseCount;
|
|
|
|
Buffer = AllocateRuntimePool (BlockSize);
|
|
if (Buffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
//Copy whole block data to buffer
|
|
//
|
|
CopyMem(Buffer, (VOID *)(UINTN)EraseStartAddress, BlockSize);
|
|
|
|
//
|
|
//Copy modified GPNV data to buffer
|
|
//
|
|
for (Index = 0; Index < GPNVLength; Index++) {
|
|
*(UINT8 *)((Buffer + (GPNVBase) - (GPNVBase & ((UINT32)(~0)) & (~(FdSupportEraseSize - 1))))+Index) = 0xFF;
|
|
}
|
|
|
|
//
|
|
//Flash GPNV
|
|
//
|
|
Status = EFI_SUCCESS;
|
|
for (Index = 0; Index < EraseCount; Index++) {
|
|
|
|
EraseStatus = FlashErase (
|
|
EraseStartAddress + FdSupportEraseSize * Index,
|
|
FdSupportEraseSize
|
|
);
|
|
if (EFI_ERROR (EraseStatus)) {
|
|
Status = EraseStatus;
|
|
}
|
|
}
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = FlashProgram (
|
|
(UINT8 *)EraseStartAddress,
|
|
Buffer,
|
|
&BlockSize,
|
|
EraseStartAddress
|
|
);
|
|
|
|
FreePool (Buffer);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Restore data from NV_FTW_SPARE to OEM_DMI_STORE if needed
|
|
|
|
@retval EFI_SUCCESS Success
|
|
@retval Others Error occurs
|
|
|
|
**/
|
|
EFI_STATUS
|
|
FtwSpareToDmiIfNeeded (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT64 DmiAddr;
|
|
UINT64 DmiSize;
|
|
UINT64 SpareSize;
|
|
UINT64 NvSpareAddr;
|
|
UINT64 NvSpareSize;
|
|
UINT8 *DmiBuffer;
|
|
UINT8 *Ptr;
|
|
DMI_RECLAIM_IN_FTW_SPARE *DmiReclaimInFtwSparePtr;
|
|
|
|
DmiAddr = FdmGetNAtAddr(&gH2OFlashMapRegionSmbiosUpdateGuid, 1);
|
|
if (DmiAddr == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
DmiSize = FdmGetNAtSize(&gH2OFlashMapRegionSmbiosUpdateGuid, 1);
|
|
if (DmiSize == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
NvSpareAddr = FdmGetNAtAddr (&gH2OFlashMapRegionFtwBackupGuid, 1);
|
|
if (NvSpareAddr == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
NvSpareSize = FdmGetNAtSize(&gH2OFlashMapRegionFtwBackupGuid, 1);
|
|
if (NvSpareSize < DmiSize * DMI_USING_FTW_BACKUP_MULTIPLE_OF_DMI_REGION) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
Ptr = (UINT8 *)(UINTN) NvSpareAddr;
|
|
DmiReclaimInFtwSparePtr = (DMI_RECLAIM_IN_FTW_SPARE *) Ptr;
|
|
if (!CompareGuid(&gH2OFlashMapRegionSmbiosUpdateGuid, &DmiReclaimInFtwSparePtr->DmiReclaimGuid) ||
|
|
DmiReclaimInFtwSparePtr->Valid != DMI_USING_FTW_BACKUP_VALID_FLAG) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Status = mSmmFwBlockService->EraseBlocks (
|
|
mSmmFwBlockService,
|
|
(UINTN) DmiAddr,
|
|
(UINTN *) &DmiSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
DmiBuffer = AllocateRuntimePool ((UINTN) DmiSize);
|
|
if (DmiBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
Ptr = (UINT8 *)(UINTN) NvSpareAddr;
|
|
CopyMem (DmiBuffer, Ptr + sizeof (DMI_RECLAIM_IN_FTW_SPARE), (UINTN) DmiSize);
|
|
Status = mSmmFwBlockService->Write (
|
|
mSmmFwBlockService,
|
|
(UINTN) DmiAddr,
|
|
(UINTN *)&DmiSize,
|
|
DmiBuffer
|
|
);
|
|
FreePool(DmiBuffer);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
SpareSize = DmiSize * DMI_USING_FTW_BACKUP_MULTIPLE_OF_DMI_REGION;
|
|
Status = mSmmFwBlockService->EraseBlocks (
|
|
mSmmFwBlockService,
|
|
(UINTN) NvSpareAddr,
|
|
(UINTN *) &SpareSize
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Perform DMI reclaim before EndOfDxe if neeeded
|
|
|
|
@retval EFI_SUCCESS Success
|
|
@retval Others Error occurs
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DmiReclaimBeforeEndOfDxe (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN DmiSize;
|
|
UINTN RemainSize;
|
|
UINTN ReclaimSize;
|
|
UINT16 DmiEnd;
|
|
UINT8 *Ptr;
|
|
|
|
if (mSmmSmbiosEndOfDxe) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Restore DMI data from NV_FTW_SPARE to OEM_DMI_STORE if needed
|
|
//
|
|
Status = FtwSpareToDmiIfNeeded();
|
|
if(!EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Perform DMI reclaim from OEM_DMI_STORE if needed
|
|
//
|
|
RemainSize = 0;
|
|
ReclaimSize = 0;
|
|
Status = GetDmiReclaimInfo (&RemainSize, &ReclaimSize);
|
|
if (EFI_ERROR(Status) || ReclaimSize == 0) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
DmiSize = (UINTN) FdmGetNAtSize(&gH2OFlashMapRegionSmbiosUpdateGuid, 1);
|
|
if (DmiSize == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
Ptr = (UINT8 *)(UINTN) FdmGetNAtAddr(&gH2OFlashMapRegionSmbiosUpdateGuid, 1);
|
|
if (Ptr == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
Ptr += (DmiSize - sizeof (DMI_RECLAIM_STRING_SIGNATURE));
|
|
if ((*(UINT32 *) Ptr == DMI_RECLAIM_STRING_SIGNATURE) || (RemainSize < DMI_RECLAIM_THRESHOLD)) {
|
|
Status = DMISpaceNotEnough(&DmiEnd);
|
|
}
|
|
return Status;
|
|
} |