/** @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 #include #include #include 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; }