| /** @file | |
| This code produces the Smbios protocol. It also responsible for constructing | |
| SMBIOS table into system table. | |
| Copyright (c) 2009 - 2021, Intel Corporation. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include "SmbiosDxe.h" | |
| // | |
| // Module Global: | |
| // Since this driver will only ever produce one instance of the | |
| // protocol you are not required to dynamically allocate the PrivateData. | |
| // | |
| SMBIOS_INSTANCE mPrivateData; | |
| UINTN mPreAllocatedPages = 0; | |
| UINTN mPre64BitAllocatedPages = 0; | |
| // | |
| // Chassis for SMBIOS entry point structure that is to be installed into EFI system config table. | |
| // | |
| SMBIOS_TABLE_ENTRY_POINT *EntryPointStructure = NULL; | |
| SMBIOS_TABLE_ENTRY_POINT EntryPointStructureData = { | |
| // | |
| // AnchorString | |
| // | |
| { | |
| 0x5f, | |
| 0x53, | |
| 0x4d, | |
| 0x5f | |
| }, | |
| // | |
| // EntryPointStructureChecksum,TO BE FILLED | |
| // | |
| 0, | |
| // | |
| // EntryPointStructure Length | |
| // | |
| 0x1f, | |
| // | |
| // MajorVersion | |
| // | |
| 0, | |
| // | |
| // MinorVersion | |
| // | |
| 0, | |
| // | |
| // MaxStructureSize, TO BE FILLED | |
| // | |
| 0, | |
| // | |
| // EntryPointRevision | |
| // | |
| 0, | |
| // | |
| // FormattedArea | |
| // | |
| { | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| 0 | |
| }, | |
| // | |
| // IntermediateAnchorString | |
| // | |
| { | |
| 0x5f, | |
| 0x44, | |
| 0x4d, | |
| 0x49, | |
| 0x5f | |
| }, | |
| // | |
| // IntermediateChecksum, TO BE FILLED | |
| // | |
| 0, | |
| // | |
| // TableLength, TO BE FILLED | |
| // | |
| 0, | |
| // | |
| // TableAddress, TO BE FILLED | |
| // | |
| 0, | |
| // | |
| // NumberOfSmbiosStructures, TO BE FILLED | |
| // | |
| 0, | |
| // | |
| // SmbiosBcdRevision | |
| // | |
| 0 | |
| }; | |
| SMBIOS_TABLE_3_0_ENTRY_POINT *Smbios30EntryPointStructure = NULL; | |
| SMBIOS_TABLE_3_0_ENTRY_POINT Smbios30EntryPointStructureData = { | |
| // | |
| // AnchorString _SM3_ | |
| // | |
| { | |
| 0x5f, | |
| 0x53, | |
| 0x4d, | |
| 0x33, | |
| 0x5f, | |
| }, | |
| // | |
| // EntryPointStructureChecksum,TO BE FILLED | |
| // | |
| 0, | |
| // | |
| // EntryPointLength | |
| // | |
| 0x18, | |
| // | |
| // MajorVersion | |
| // | |
| 0, | |
| // | |
| // MinorVersion | |
| // | |
| 0, | |
| // | |
| // DocRev | |
| // | |
| 0, | |
| // | |
| // EntryPointRevision | |
| // | |
| 0x01, | |
| // | |
| // Reserved | |
| // | |
| 0, | |
| // | |
| // TableMaximumSize,TO BE FILLED | |
| // | |
| 0, | |
| // | |
| // TableAddress,TO BE FILLED | |
| // | |
| 0 | |
| }; | |
| IS_SMBIOS_TABLE_VALID_ENTRY mIsSmbiosTableValid[] = { | |
| { &gUniversalPayloadSmbios3TableGuid, IsValidSmbios30Table }, | |
| { &gUniversalPayloadSmbiosTableGuid, IsValidSmbios20Table } | |
| }; | |
| /** | |
| 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 CONST EFI_SMBIOS_PROTOCOL *This, | |
| 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; | |
| // | |
| // 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++; | |
| } | |
| if ((This->MajorVersion < 2) || ((This->MajorVersion == 2) && (This->MinorVersion < 7))) { | |
| MaxLen = SMBIOS_STRING_MAX_LENGTH; | |
| } else if (This->MajorVersion < 3) { | |
| // | |
| // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string. | |
| // However, the length of the entire structure table (including all strings) must be reported | |
| // in the Structure Table Length field of the SMBIOS Structure Table Entry Point, | |
| // which is a WORD field limited to 65,535 bytes. | |
| // | |
| MaxLen = SMBIOS_TABLE_MAX_LENGTH; | |
| } else { | |
| // | |
| // 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; | |
| } | |
| 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; | |
| } | |
| /** | |
| Determin whether an SmbiosHandle has already in use. | |
| @param Head Pointer to the beginning of SMBIOS structure. | |
| @param Handle A unique handle will be assigned to the SMBIOS record. | |
| @retval TRUE Smbios handle already in use. | |
| @retval FALSE Smbios handle is NOT used. | |
| **/ | |
| BOOLEAN | |
| EFIAPI | |
| CheckSmbiosHandleExistance ( | |
| IN LIST_ENTRY *Head, | |
| IN EFI_SMBIOS_HANDLE Handle | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| SMBIOS_HANDLE_ENTRY *HandleEntry; | |
| for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) { | |
| HandleEntry = SMBIOS_HANDLE_ENTRY_FROM_LINK (Link); | |
| if (HandleEntry->SmbiosHandle == Handle) { | |
| return TRUE; | |
| } | |
| } | |
| return FALSE; | |
| } | |
| /** | |
| Get the max SmbiosHandle that could be use. | |
| @param This The EFI_SMBIOS_PROTOCOL instance. | |
| @param MaxHandle The max handle that could be assigned to the SMBIOS record. | |
| **/ | |
| VOID | |
| EFIAPI | |
| GetMaxSmbiosHandle ( | |
| IN CONST EFI_SMBIOS_PROTOCOL *This, | |
| IN OUT EFI_SMBIOS_HANDLE *MaxHandle | |
| ) | |
| { | |
| if ((This->MajorVersion == 2) && (This->MinorVersion == 0)) { | |
| *MaxHandle = 0xFFFE; | |
| } else { | |
| *MaxHandle = 0xFEFF; | |
| } | |
| } | |
| /** | |
| Get an SmbiosHandle that could use. | |
| @param This The EFI_SMBIOS_PROTOCOL instance. | |
| @param SmbiosHandle A unique handle will be assigned to the SMBIOS record. | |
| @retval EFI_SUCCESS Smbios handle got. | |
| @retval EFI_OUT_OF_RESOURCES Smbios handle is NOT available. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| GetAvailableSmbiosHandle ( | |
| IN CONST EFI_SMBIOS_PROTOCOL *This, | |
| IN OUT EFI_SMBIOS_HANDLE *Handle | |
| ) | |
| { | |
| LIST_ENTRY *Head; | |
| SMBIOS_INSTANCE *Private; | |
| EFI_SMBIOS_HANDLE MaxSmbiosHandle; | |
| EFI_SMBIOS_HANDLE AvailableHandle; | |
| GetMaxSmbiosHandle (This, &MaxSmbiosHandle); | |
| Private = SMBIOS_INSTANCE_FROM_THIS (This); | |
| Head = &Private->AllocatedHandleListHead; | |
| for (AvailableHandle = 0; AvailableHandle < MaxSmbiosHandle; AvailableHandle++) { | |
| if (!CheckSmbiosHandleExistance (Head, AvailableHandle)) { | |
| *Handle = AvailableHandle; | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| /** | |
| Add an SMBIOS record. | |
| @param This The EFI_SMBIOS_PROTOCOL instance. | |
| @param ProducerHandle The handle of the controller or driver associated with the SMBIOS information. NULL | |
| means no handle. | |
| @param SmbiosHandle On entry, the handle of the SMBIOS record to add. If FFFEh, then a unique handle | |
| will be assigned to the SMBIOS record. If the SMBIOS handle is already in use, | |
| EFI_ALREADY_STARTED is returned and the SMBIOS record is not updated. | |
| @param Record The data for the fixed portion of the SMBIOS record. The format of the record is | |
| determined by EFI_SMBIOS_TABLE_HEADER.Type. The size of the formatted area is defined | |
| by EFI_SMBIOS_TABLE_HEADER.Length and either followed by a double-null (0x0000) or | |
| a set of null terminated strings and a null. | |
| @retval EFI_SUCCESS Record was added. | |
| @retval EFI_OUT_OF_RESOURCES Record was not added due to lack of system resources. | |
| @retval EFI_ALREADY_STARTED The SmbiosHandle passed in was already in use. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmbiosAdd ( | |
| IN CONST EFI_SMBIOS_PROTOCOL *This, | |
| IN EFI_HANDLE ProducerHandle OPTIONAL, | |
| IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle, | |
| IN EFI_SMBIOS_TABLE_HEADER *Record | |
| ) | |
| { | |
| VOID *Raw; | |
| UINTN TotalSize; | |
| UINTN RecordSize; | |
| UINTN StructureSize; | |
| UINTN NumberOfStrings; | |
| EFI_STATUS Status; | |
| LIST_ENTRY *Head; | |
| SMBIOS_INSTANCE *Private; | |
| EFI_SMBIOS_ENTRY *SmbiosEntry; | |
| EFI_SMBIOS_HANDLE MaxSmbiosHandle; | |
| SMBIOS_HANDLE_ENTRY *HandleEntry; | |
| EFI_SMBIOS_RECORD_HEADER *InternalRecord; | |
| BOOLEAN Smbios32BitTable; | |
| BOOLEAN Smbios64BitTable; | |
| if (SmbiosHandle == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Private = SMBIOS_INSTANCE_FROM_THIS (This); | |
| // | |
| // Check whether SmbiosHandle is already in use | |
| // | |
| Head = &Private->AllocatedHandleListHead; | |
| if ((*SmbiosHandle != SMBIOS_HANDLE_PI_RESERVED) && CheckSmbiosHandleExistance (Head, *SmbiosHandle)) { | |
| return EFI_ALREADY_STARTED; | |
| } | |
| // | |
| // when SmbiosHandle is 0xFFFE, an available handle will be assigned | |
| // | |
| if (*SmbiosHandle == SMBIOS_HANDLE_PI_RESERVED) { | |
| Status = GetAvailableSmbiosHandle (This, SmbiosHandle); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } else { | |
| // | |
| // Check this handle validity | |
| // | |
| GetMaxSmbiosHandle (This, &MaxSmbiosHandle); | |
| if (*SmbiosHandle > MaxSmbiosHandle) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| } | |
| // | |
| // Calculate record size and string number | |
| // | |
| Status = GetSmbiosStructureSize (This, Record, &StructureSize, &NumberOfStrings); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Smbios32BitTable = FALSE; | |
| Smbios64BitTable = FALSE; | |
| if ((This->MajorVersion < 0x3) || | |
| ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT0) == BIT0))) | |
| { | |
| // | |
| // For SMBIOS 32-bit table, the length of the entire structure table (including all strings) must be reported | |
| // in the Structure Table Length field of the SMBIOS Structure Table Entry Point, | |
| // which is a WORD field limited to 65,535 bytes. So the max size of 32-bit table should not exceed 65,535 bytes. | |
| // | |
| if ((EntryPointStructure != NULL) && | |
| (EntryPointStructure->TableLength + StructureSize > SMBIOS_TABLE_MAX_LENGTH)) | |
| { | |
| DEBUG ((DEBUG_INFO, "SmbiosAdd: Total length exceeds max 32-bit table length with type = %d size = 0x%x\n", Record->Type, StructureSize)); | |
| } else { | |
| Smbios32BitTable = TRUE; | |
| DEBUG ((DEBUG_INFO, "SmbiosAdd: Smbios type %d with size 0x%x is added to 32-bit table\n", Record->Type, StructureSize)); | |
| } | |
| } | |
| // | |
| // For SMBIOS 3.0, Structure table maximum size in Entry Point structure is DWORD field limited to 0xFFFFFFFF bytes. | |
| // | |
| if ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT1) == BIT1)) { | |
| // | |
| // For SMBIOS 64-bit table, Structure table maximum size in SMBIOS 3.0 (64-bit) Entry Point | |
| // is a DWORD field limited to 0xFFFFFFFF bytes. So the max size of 64-bit table should not exceed 0xFFFFFFFF bytes. | |
| // | |
| if ((Smbios30EntryPointStructure != NULL) && | |
| (Smbios30EntryPointStructure->TableMaximumSize + StructureSize > SMBIOS_3_0_TABLE_MAX_LENGTH)) | |
| { | |
| DEBUG ((DEBUG_INFO, "SmbiosAdd: Total length exceeds max 64-bit table length with type = %d size = 0x%x\n", Record->Type, StructureSize)); | |
| } else { | |
| DEBUG ((DEBUG_INFO, "SmbiosAdd: Smbios type %d with size 0x%x is added to 64-bit table\n", Record->Type, StructureSize)); | |
| Smbios64BitTable = TRUE; | |
| } | |
| } | |
| if ((!Smbios32BitTable) && (!Smbios64BitTable)) { | |
| // | |
| // If both 32-bit and 64-bit table are not updated, quit | |
| // | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Enter into critical section | |
| // | |
| Status = EfiAcquireLockOrFail (&Private->DataLock); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| RecordSize = sizeof (EFI_SMBIOS_RECORD_HEADER) + StructureSize; | |
| TotalSize = sizeof (EFI_SMBIOS_ENTRY) + RecordSize; | |
| // | |
| // Allocate internal buffer | |
| // | |
| SmbiosEntry = AllocateZeroPool (TotalSize); | |
| if (SmbiosEntry == NULL) { | |
| EfiReleaseLock (&Private->DataLock); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| HandleEntry = AllocateZeroPool (sizeof (SMBIOS_HANDLE_ENTRY)); | |
| if (HandleEntry == NULL) { | |
| EfiReleaseLock (&Private->DataLock); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Build Handle Entry and insert into linked list | |
| // | |
| HandleEntry->Signature = SMBIOS_HANDLE_ENTRY_SIGNATURE; | |
| HandleEntry->SmbiosHandle = *SmbiosHandle; | |
| InsertTailList (&Private->AllocatedHandleListHead, &HandleEntry->Link); | |
| InternalRecord = (EFI_SMBIOS_RECORD_HEADER *)(SmbiosEntry + 1); | |
| Raw = (VOID *)(InternalRecord + 1); | |
| // | |
| // Build internal record Header | |
| // | |
| InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION; | |
| InternalRecord->HeaderSize = (UINT16)sizeof (EFI_SMBIOS_RECORD_HEADER); | |
| InternalRecord->RecordSize = RecordSize; | |
| InternalRecord->ProducerHandle = ProducerHandle; | |
| InternalRecord->NumberOfStrings = NumberOfStrings; | |
| // | |
| // Insert record into the internal linked list | |
| // | |
| SmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE; | |
| SmbiosEntry->RecordHeader = InternalRecord; | |
| SmbiosEntry->RecordSize = TotalSize; | |
| SmbiosEntry->Smbios32BitTable = Smbios32BitTable; | |
| SmbiosEntry->Smbios64BitTable = Smbios64BitTable; | |
| InsertTailList (&Private->DataListHead, &SmbiosEntry->Link); | |
| CopyMem (Raw, Record, StructureSize); | |
| ((EFI_SMBIOS_TABLE_HEADER *)Raw)->Handle = *SmbiosHandle; | |
| // | |
| // Some UEFI drivers (such as network) need some information in SMBIOS table. | |
| // Here we create SMBIOS table and publish it in | |
| // configuration table, so other UEFI drivers can get SMBIOS table from | |
| // configuration table without depending on PI SMBIOS protocol. | |
| // | |
| SmbiosTableConstruction (Smbios32BitTable, Smbios64BitTable); | |
| // | |
| // Leave critical section | |
| // | |
| EfiReleaseLock (&Private->DataLock); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Update the string associated with an existing SMBIOS record. | |
| @param This The EFI_SMBIOS_PROTOCOL instance. | |
| @param SmbiosHandle SMBIOS Handle of structure that will have its string updated. | |
| @param StringNumber The non-zero string number of the string to update | |
| @param String Update the StringNumber string with String. | |
| @retval EFI_SUCCESS SmbiosHandle had its StringNumber String updated. | |
| @retval EFI_INVALID_PARAMETER SmbiosHandle does not exist. | |
| @retval EFI_UNSUPPORTED String was not added because it is longer than the SMBIOS Table supports. | |
| @retval EFI_NOT_FOUND The StringNumber.is not valid for this SMBIOS record. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmbiosUpdateString ( | |
| IN CONST EFI_SMBIOS_PROTOCOL *This, | |
| IN EFI_SMBIOS_HANDLE *SmbiosHandle, | |
| IN UINTN *StringNumber, | |
| IN CHAR8 *String | |
| ) | |
| { | |
| UINTN InputStrLen; | |
| UINTN TargetStrLen; | |
| UINTN StrIndex; | |
| UINTN TargetStrOffset; | |
| UINTN NewEntrySize; | |
| CHAR8 *StrStart; | |
| VOID *Raw; | |
| LIST_ENTRY *Link; | |
| LIST_ENTRY *Head; | |
| EFI_STATUS Status; | |
| SMBIOS_INSTANCE *Private; | |
| EFI_SMBIOS_ENTRY *SmbiosEntry; | |
| EFI_SMBIOS_ENTRY *ResizedSmbiosEntry; | |
| EFI_SMBIOS_HANDLE MaxSmbiosHandle; | |
| EFI_SMBIOS_TABLE_HEADER *Record; | |
| EFI_SMBIOS_RECORD_HEADER *InternalRecord; | |
| // | |
| // Check args validity | |
| // | |
| GetMaxSmbiosHandle (This, &MaxSmbiosHandle); | |
| if (*SmbiosHandle > MaxSmbiosHandle) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (String == NULL) { | |
| return EFI_ABORTED; | |
| } | |
| if (*StringNumber == 0) { | |
| return EFI_NOT_FOUND; | |
| } | |
| InputStrLen = AsciiStrLen (String); | |
| if ((This->MajorVersion < 2) || ((This->MajorVersion == 2) && (This->MinorVersion < 7))) { | |
| if (InputStrLen > SMBIOS_STRING_MAX_LENGTH) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| } else if (This->MajorVersion < 3) { | |
| // | |
| // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string. | |
| // However, the length of the entire structure table (including all strings) must be reported | |
| // in the Structure Table Length field of the SMBIOS Structure Table Entry Point, | |
| // which is a WORD field limited to 65,535 bytes. | |
| // | |
| if (InputStrLen > SMBIOS_TABLE_MAX_LENGTH) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| } else { | |
| if (InputStrLen > SMBIOS_3_0_TABLE_MAX_LENGTH) { | |
| // | |
| // SMBIOS 3.0 defines the Structure table maximum size as DWORD field limited to 0xFFFFFFFF bytes. | |
| // The input string length should not exceed 0xFFFFFFFF bytes. | |
| // | |
| return EFI_UNSUPPORTED; | |
| } | |
| } | |
| Private = SMBIOS_INSTANCE_FROM_THIS (This); | |
| // | |
| // Enter into critical section | |
| // | |
| Status = EfiAcquireLockOrFail (&Private->DataLock); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Head = &Private->DataListHead; | |
| for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) { | |
| SmbiosEntry = SMBIOS_ENTRY_FROM_LINK (Link); | |
| Record = (EFI_SMBIOS_TABLE_HEADER *)(SmbiosEntry->RecordHeader + 1); | |
| if (Record->Handle == *SmbiosHandle) { | |
| // | |
| // Find out the specified SMBIOS record | |
| // | |
| if (*StringNumber > SmbiosEntry->RecordHeader->NumberOfStrings) { | |
| EfiReleaseLock (&Private->DataLock); | |
| return EFI_NOT_FOUND; | |
| } | |
| // | |
| // Point to unformed string section | |
| // | |
| StrStart = (CHAR8 *)Record + Record->Length; | |
| for (StrIndex = 1, TargetStrOffset = 0; StrIndex < *StringNumber; StrStart++, TargetStrOffset++) { | |
| // | |
| // A string ends in 00h | |
| // | |
| if (*StrStart == 0) { | |
| StrIndex++; | |
| } | |
| // | |
| // String section ends in double-null (0000h) | |
| // | |
| if ((*StrStart == 0) && (*(StrStart + 1) == 0)) { | |
| EfiReleaseLock (&Private->DataLock); | |
| return EFI_NOT_FOUND; | |
| } | |
| } | |
| if (*StrStart == 0) { | |
| StrStart++; | |
| TargetStrOffset++; | |
| } | |
| // | |
| // Now we get the string target | |
| // | |
| TargetStrLen = AsciiStrLen (StrStart); | |
| if (InputStrLen == TargetStrLen) { | |
| AsciiStrCpyS (StrStart, TargetStrLen + 1, String); | |
| // | |
| // Some UEFI drivers (such as network) need some information in SMBIOS table. | |
| // Here we create SMBIOS table and publish it in | |
| // configuration table, so other UEFI drivers can get SMBIOS table from | |
| // configuration table without depending on PI SMBIOS protocol. | |
| // | |
| SmbiosTableConstruction (SmbiosEntry->Smbios32BitTable, SmbiosEntry->Smbios64BitTable); | |
| EfiReleaseLock (&Private->DataLock); | |
| return EFI_SUCCESS; | |
| } | |
| SmbiosEntry->Smbios32BitTable = FALSE; | |
| SmbiosEntry->Smbios64BitTable = FALSE; | |
| if ((This->MajorVersion < 0x3) || | |
| ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT0) == BIT0))) | |
| { | |
| // | |
| // 32-bit table is produced, check the valid length. | |
| // | |
| if ((EntryPointStructure != NULL) && | |
| (EntryPointStructure->TableLength + InputStrLen - TargetStrLen > SMBIOS_TABLE_MAX_LENGTH)) | |
| { | |
| // | |
| // The length of the entire structure table (including all strings) must be reported | |
| // in the Structure Table Length field of the SMBIOS Structure Table Entry Point, | |
| // which is a WORD field limited to 65,535 bytes. | |
| // | |
| DEBUG ((DEBUG_INFO, "SmbiosUpdateString: Total length exceeds max 32-bit table length\n")); | |
| } else { | |
| DEBUG ((DEBUG_INFO, "SmbiosUpdateString: New smbios record add to 32-bit table\n")); | |
| SmbiosEntry->Smbios32BitTable = TRUE; | |
| } | |
| } | |
| if ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT1) == BIT1)) { | |
| // | |
| // 64-bit table is produced, check the valid length. | |
| // | |
| if ((Smbios30EntryPointStructure != NULL) && | |
| (Smbios30EntryPointStructure->TableMaximumSize + InputStrLen - TargetStrLen > SMBIOS_3_0_TABLE_MAX_LENGTH)) | |
| { | |
| DEBUG ((DEBUG_INFO, "SmbiosUpdateString: Total length exceeds max 64-bit table length\n")); | |
| } else { | |
| DEBUG ((DEBUG_INFO, "SmbiosUpdateString: New smbios record add to 64-bit table\n")); | |
| SmbiosEntry->Smbios64BitTable = TRUE; | |
| } | |
| } | |
| if ((!SmbiosEntry->Smbios32BitTable) && (!SmbiosEntry->Smbios64BitTable)) { | |
| EfiReleaseLock (&Private->DataLock); | |
| return EFI_UNSUPPORTED; | |
| } | |
| // | |
| // Original string buffer size is not exactly match input string length. | |
| // Re-allocate buffer is needed. | |
| // | |
| NewEntrySize = SmbiosEntry->RecordSize + InputStrLen - TargetStrLen; | |
| ResizedSmbiosEntry = AllocateZeroPool (NewEntrySize); | |
| if (ResizedSmbiosEntry == NULL) { | |
| EfiReleaseLock (&Private->DataLock); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| InternalRecord = (EFI_SMBIOS_RECORD_HEADER *)(ResizedSmbiosEntry + 1); | |
| Raw = (VOID *)(InternalRecord + 1); | |
| // | |
| // Build internal record Header | |
| // | |
| InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION; | |
| InternalRecord->HeaderSize = (UINT16)sizeof (EFI_SMBIOS_RECORD_HEADER); | |
| InternalRecord->RecordSize = SmbiosEntry->RecordHeader->RecordSize + InputStrLen - TargetStrLen; | |
| InternalRecord->ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle; | |
| InternalRecord->NumberOfStrings = SmbiosEntry->RecordHeader->NumberOfStrings; | |
| // | |
| // Copy SMBIOS structure and optional strings. | |
| // | |
| CopyMem (Raw, SmbiosEntry->RecordHeader + 1, Record->Length + TargetStrOffset); | |
| CopyMem ((VOID *)((UINTN)Raw + Record->Length + TargetStrOffset), String, InputStrLen + 1); | |
| CopyMem ( | |
| (CHAR8 *)((UINTN)Raw + Record->Length + TargetStrOffset + InputStrLen + 1), | |
| (CHAR8 *)Record + Record->Length + TargetStrOffset + TargetStrLen + 1, | |
| SmbiosEntry->RecordHeader->RecordSize - sizeof (EFI_SMBIOS_RECORD_HEADER) - Record->Length - TargetStrOffset - TargetStrLen - 1 | |
| ); | |
| // | |
| // Insert new record | |
| // | |
| ResizedSmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE; | |
| ResizedSmbiosEntry->RecordHeader = InternalRecord; | |
| ResizedSmbiosEntry->RecordSize = NewEntrySize; | |
| ResizedSmbiosEntry->Smbios32BitTable = SmbiosEntry->Smbios32BitTable; | |
| ResizedSmbiosEntry->Smbios64BitTable = SmbiosEntry->Smbios64BitTable; | |
| InsertTailList (Link->ForwardLink, &ResizedSmbiosEntry->Link); | |
| // | |
| // Remove old record | |
| // | |
| RemoveEntryList (Link); | |
| FreePool (SmbiosEntry); | |
| // | |
| // Some UEFI drivers (such as network) need some information in SMBIOS table. | |
| // Here we create SMBIOS table and publish it in | |
| // configuration table, so other UEFI drivers can get SMBIOS table from | |
| // configuration table without depending on PI SMBIOS protocol. | |
| // | |
| SmbiosTableConstruction (ResizedSmbiosEntry->Smbios32BitTable, ResizedSmbiosEntry->Smbios64BitTable); | |
| EfiReleaseLock (&Private->DataLock); | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| EfiReleaseLock (&Private->DataLock); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| /** | |
| Remove an SMBIOS record. | |
| @param This The EFI_SMBIOS_PROTOCOL instance. | |
| @param SmbiosHandle The handle of the SMBIOS record to remove. | |
| @retval EFI_SUCCESS SMBIOS record was removed. | |
| @retval EFI_INVALID_PARAMETER SmbiosHandle does not specify a valid SMBIOS record. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmbiosRemove ( | |
| IN CONST EFI_SMBIOS_PROTOCOL *This, | |
| IN EFI_SMBIOS_HANDLE SmbiosHandle | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| LIST_ENTRY *Head; | |
| EFI_STATUS Status; | |
| EFI_SMBIOS_HANDLE MaxSmbiosHandle; | |
| SMBIOS_INSTANCE *Private; | |
| EFI_SMBIOS_ENTRY *SmbiosEntry; | |
| SMBIOS_HANDLE_ENTRY *HandleEntry; | |
| EFI_SMBIOS_TABLE_HEADER *Record; | |
| // | |
| // Check args validity | |
| // | |
| GetMaxSmbiosHandle (This, &MaxSmbiosHandle); | |
| if (SmbiosHandle > MaxSmbiosHandle) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Private = SMBIOS_INSTANCE_FROM_THIS (This); | |
| // | |
| // Enter into critical section | |
| // | |
| Status = EfiAcquireLockOrFail (&Private->DataLock); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Head = &Private->DataListHead; | |
| for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) { | |
| SmbiosEntry = SMBIOS_ENTRY_FROM_LINK (Link); | |
| Record = (EFI_SMBIOS_TABLE_HEADER *)(SmbiosEntry->RecordHeader + 1); | |
| if (Record->Handle == SmbiosHandle) { | |
| // | |
| // Remove specified smobios record from DataList | |
| // | |
| RemoveEntryList (Link); | |
| // | |
| // Remove this handle from AllocatedHandleList | |
| // | |
| Head = &Private->AllocatedHandleListHead; | |
| for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) { | |
| HandleEntry = SMBIOS_HANDLE_ENTRY_FROM_LINK (Link); | |
| if (HandleEntry->SmbiosHandle == SmbiosHandle) { | |
| RemoveEntryList (Link); | |
| FreePool (HandleEntry); | |
| break; | |
| } | |
| } | |
| // | |
| // Some UEFI drivers (such as network) need some information in SMBIOS table. | |
| // Here we create SMBIOS table and publish it in | |
| // configuration table, so other UEFI drivers can get SMBIOS table from | |
| // configuration table without depending on PI SMBIOS protocol. | |
| // | |
| if (SmbiosEntry->Smbios32BitTable) { | |
| DEBUG ((DEBUG_INFO, "SmbiosRemove: remove from 32-bit table\n")); | |
| } | |
| if (SmbiosEntry->Smbios64BitTable) { | |
| DEBUG ((DEBUG_INFO, "SmbiosRemove: remove from 64-bit table\n")); | |
| } | |
| // | |
| // Update the whole SMBIOS table again based on which table the removed SMBIOS record is in. | |
| // | |
| SmbiosTableConstruction (SmbiosEntry->Smbios32BitTable, SmbiosEntry->Smbios64BitTable); | |
| FreePool (SmbiosEntry); | |
| EfiReleaseLock (&Private->DataLock); | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| // | |
| // Leave critical section | |
| // | |
| EfiReleaseLock (&Private->DataLock); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| /** | |
| Allow the caller to discover all or some of the SMBIOS records. | |
| @param This The EFI_SMBIOS_PROTOCOL instance. | |
| @param SmbiosHandle On entry, points to the previous handle of the SMBIOS record. On exit, points to the | |
| next SMBIOS record handle. If it is FFFEh on entry, then the first SMBIOS record | |
| handle will be returned. If it returns FFFEh on exit, then there are no more SMBIOS records. | |
| @param Type On entry it means return the next SMBIOS record of type Type. If a NULL is passed in | |
| this functionally it ignored. Type is not modified by the GetNext() function. | |
| @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by | |
| the unformatted area. The unformatted area optionally contains text strings. | |
| @param ProducerHandle On exit, points to the ProducerHandle registered by Add(). If no ProducerHandle was passed into Add() NULL is returned. | |
| If a NULL pointer is passed in no data will be returned | |
| @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record. | |
| @retval EFI_NOT_FOUND The SMBIOS record with SmbiosHandle was the last available record. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmbiosGetNext ( | |
| IN CONST EFI_SMBIOS_PROTOCOL *This, | |
| IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle, | |
| IN EFI_SMBIOS_TYPE *Type OPTIONAL, | |
| OUT EFI_SMBIOS_TABLE_HEADER **Record, | |
| OUT EFI_HANDLE *ProducerHandle OPTIONAL | |
| ) | |
| { | |
| BOOLEAN StartPointFound; | |
| LIST_ENTRY *Link; | |
| LIST_ENTRY *Head; | |
| SMBIOS_INSTANCE *Private; | |
| EFI_SMBIOS_ENTRY *SmbiosEntry; | |
| EFI_SMBIOS_TABLE_HEADER *SmbiosTableHeader; | |
| if (SmbiosHandle == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| StartPointFound = FALSE; | |
| Private = SMBIOS_INSTANCE_FROM_THIS (This); | |
| Head = &Private->DataListHead; | |
| for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) { | |
| SmbiosEntry = SMBIOS_ENTRY_FROM_LINK (Link); | |
| SmbiosTableHeader = (EFI_SMBIOS_TABLE_HEADER *)(SmbiosEntry->RecordHeader + 1); | |
| // | |
| // If SmbiosHandle is 0xFFFE, the first matched SMBIOS record handle will be returned | |
| // | |
| if (*SmbiosHandle == SMBIOS_HANDLE_PI_RESERVED) { | |
| if ((Type != NULL) && (*Type != SmbiosTableHeader->Type)) { | |
| continue; | |
| } | |
| *SmbiosHandle = SmbiosTableHeader->Handle; | |
| *Record = SmbiosTableHeader; | |
| if (ProducerHandle != NULL) { | |
| *ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Start this round search from the next SMBIOS handle | |
| // | |
| if (!StartPointFound && (*SmbiosHandle == SmbiosTableHeader->Handle)) { | |
| StartPointFound = TRUE; | |
| continue; | |
| } | |
| if (StartPointFound) { | |
| if ((Type != NULL) && (*Type != SmbiosTableHeader->Type)) { | |
| continue; | |
| } | |
| *SmbiosHandle = SmbiosTableHeader->Handle; | |
| *Record = SmbiosTableHeader; | |
| if (ProducerHandle != NULL) { | |
| *ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| *SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; | |
| return EFI_NOT_FOUND; | |
| } | |
| /** | |
| Allow the caller to discover all of the SMBIOS records. | |
| @param This The EFI_SMBIOS_PROTOCOL instance. | |
| @param CurrentSmbiosEntry On exit, points to the SMBIOS entry on the list which includes the returned SMBIOS record information. | |
| If *CurrentSmbiosEntry is NULL on entry, then the first SMBIOS entry on the list will be returned. | |
| @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by | |
| the unformatted area. The unformatted area optionally contains text strings. | |
| @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record. | |
| *CurrentSmbiosEntry points to the SMBIOS entry which includes the returned SMBIOS record information. | |
| @retval EFI_NOT_FOUND There is no more SMBIOS entry. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| GetNextSmbiosRecord ( | |
| IN CONST EFI_SMBIOS_PROTOCOL *This, | |
| IN OUT EFI_SMBIOS_ENTRY **CurrentSmbiosEntry, | |
| OUT EFI_SMBIOS_TABLE_HEADER **Record | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| LIST_ENTRY *Head; | |
| SMBIOS_INSTANCE *Private; | |
| EFI_SMBIOS_ENTRY *SmbiosEntry; | |
| EFI_SMBIOS_TABLE_HEADER *SmbiosTableHeader; | |
| Private = SMBIOS_INSTANCE_FROM_THIS (This); | |
| if (*CurrentSmbiosEntry == NULL) { | |
| // | |
| // Get the beginning of SMBIOS entry. | |
| // | |
| Head = &Private->DataListHead; | |
| } else { | |
| // | |
| // Get previous SMBIOS entry and make it as start point. | |
| // | |
| Head = &(*CurrentSmbiosEntry)->Link; | |
| } | |
| Link = Head->ForwardLink; | |
| if (Link == &Private->DataListHead) { | |
| // | |
| // If no more SMBIOS entry in the list, return not found. | |
| // | |
| return EFI_NOT_FOUND; | |
| } | |
| SmbiosEntry = SMBIOS_ENTRY_FROM_LINK (Link); | |
| SmbiosTableHeader = (EFI_SMBIOS_TABLE_HEADER *)(SmbiosEntry->RecordHeader + 1); | |
| *Record = SmbiosTableHeader; | |
| *CurrentSmbiosEntry = SmbiosEntry; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Assembles SMBIOS table from the SMBIOS protocol. Produce Table | |
| Entry Point and return the pointer to it. | |
| @param TableEntryPointStructure On exit, points to the SMBIOS entrypoint structure. | |
| @retval EFI_SUCCESS Structure created sucessfully. | |
| @retval EFI_OUT_OF_RESOURCES No enough memory. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmbiosCreateTable ( | |
| OUT VOID **TableEntryPointStructure | |
| ) | |
| { | |
| UINT8 *BufferPointer; | |
| UINTN RecordSize; | |
| UINTN NumOfStr; | |
| EFI_STATUS Status; | |
| EFI_SMBIOS_HANDLE SmbiosHandle; | |
| EFI_SMBIOS_PROTOCOL *SmbiosProtocol; | |
| EFI_PHYSICAL_ADDRESS PhysicalAddress; | |
| EFI_SMBIOS_TABLE_HEADER *SmbiosRecord; | |
| EFI_SMBIOS_TABLE_END_STRUCTURE EndStructure; | |
| EFI_SMBIOS_ENTRY *CurrentSmbiosEntry; | |
| Status = EFI_SUCCESS; | |
| BufferPointer = NULL; | |
| if (EntryPointStructure == NULL) { | |
| // | |
| // Initialize the EntryPointStructure with initial values. | |
| // It should be done only once. | |
| // Allocate memory (below 4GB). | |
| // | |
| DEBUG ((DEBUG_INFO, "SmbiosCreateTable: Initialize 32-bit entry point structure\n")); | |
| EntryPointStructureData.MajorVersion = mPrivateData.Smbios.MajorVersion; | |
| EntryPointStructureData.MinorVersion = mPrivateData.Smbios.MinorVersion; | |
| EntryPointStructureData.SmbiosBcdRevision = 0; | |
| if ((mPrivateData.Smbios.MajorVersion <= 9) && (mPrivateData.Smbios.MinorVersion <= 9)) { | |
| EntryPointStructureData.SmbiosBcdRevision = ((mPrivateData.Smbios.MajorVersion & 0x0f) << 4) | (mPrivateData.Smbios.MinorVersion & 0x0f); | |
| } | |
| PhysicalAddress = 0xffffffff; | |
| Status = gBS->AllocatePages ( | |
| AllocateMaxAddress, | |
| EfiRuntimeServicesData, | |
| EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT)), | |
| &PhysicalAddress | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "SmbiosCreateTable () could not allocate EntryPointStructure < 4GB\n")); | |
| Status = gBS->AllocatePages ( | |
| AllocateAnyPages, | |
| EfiRuntimeServicesData, | |
| EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT)), | |
| &PhysicalAddress | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| } | |
| EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *)(UINTN)PhysicalAddress; | |
| CopyMem ( | |
| EntryPointStructure, | |
| &EntryPointStructureData, | |
| sizeof (SMBIOS_TABLE_ENTRY_POINT) | |
| ); | |
| } | |
| // | |
| // Get Smbios protocol to traverse SMBIOS records. | |
| // | |
| SmbiosProtocol = &mPrivateData.Smbios; | |
| // | |
| // Make some statistics about all the structures | |
| // | |
| EntryPointStructure->NumberOfSmbiosStructures = 0; | |
| EntryPointStructure->TableLength = 0; | |
| EntryPointStructure->MaxStructureSize = 0; | |
| // | |
| // Calculate EPS Table Length | |
| // | |
| CurrentSmbiosEntry = NULL; | |
| do { | |
| Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord); | |
| if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios32BitTable)) { | |
| GetSmbiosStructureSize (SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr); | |
| // | |
| // Record NumberOfSmbiosStructures, TableLength and MaxStructureSize | |
| // | |
| EntryPointStructure->NumberOfSmbiosStructures++; | |
| EntryPointStructure->TableLength = (UINT16)(EntryPointStructure->TableLength + RecordSize); | |
| if (RecordSize > EntryPointStructure->MaxStructureSize) { | |
| EntryPointStructure->MaxStructureSize = (UINT16)RecordSize; | |
| } | |
| } | |
| } while (!EFI_ERROR (Status)); | |
| // | |
| // Create End-Of-Table structure | |
| // | |
| GetMaxSmbiosHandle (SmbiosProtocol, &SmbiosHandle); | |
| EndStructure.Header.Type = SMBIOS_TYPE_END_OF_TABLE; | |
| EndStructure.Header.Length = (UINT8)sizeof (EFI_SMBIOS_TABLE_HEADER); | |
| EndStructure.Header.Handle = SmbiosHandle; | |
| EndStructure.Tailing[0] = 0; | |
| EndStructure.Tailing[1] = 0; | |
| EntryPointStructure->NumberOfSmbiosStructures++; | |
| EntryPointStructure->TableLength = (UINT16)(EntryPointStructure->TableLength + sizeof (EndStructure)); | |
| if (sizeof (EndStructure) > EntryPointStructure->MaxStructureSize) { | |
| EntryPointStructure->MaxStructureSize = (UINT16)sizeof (EndStructure); | |
| } | |
| if (EFI_SIZE_TO_PAGES ((UINT32)EntryPointStructure->TableLength) > mPreAllocatedPages) { | |
| // | |
| // If new SMBIOS table size exceeds the previous allocated page, | |
| // it is time to re-allocate memory (below 4GB). | |
| // | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "%a() re-allocate SMBIOS 32-bit table\n", | |
| __func__ | |
| )); | |
| if (EntryPointStructure->TableAddress != 0) { | |
| // | |
| // Free the previous allocated page | |
| // | |
| FreePages ( | |
| (VOID *)(UINTN)EntryPointStructure->TableAddress, | |
| mPreAllocatedPages | |
| ); | |
| EntryPointStructure->TableAddress = 0; | |
| mPreAllocatedPages = 0; | |
| } | |
| PhysicalAddress = 0xffffffff; | |
| Status = gBS->AllocatePages ( | |
| AllocateMaxAddress, | |
| EfiRuntimeServicesData, | |
| EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength), | |
| &PhysicalAddress | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "SmbiosCreateTable() could not allocate SMBIOS table < 4GB\n")); | |
| EntryPointStructure->TableAddress = 0; | |
| return EFI_OUT_OF_RESOURCES; | |
| } else { | |
| EntryPointStructure->TableAddress = (UINT32)PhysicalAddress; | |
| mPreAllocatedPages = EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength); | |
| } | |
| } | |
| // | |
| // Assemble the tables | |
| // | |
| ASSERT (EntryPointStructure->TableAddress != 0); | |
| BufferPointer = (UINT8 *)(UINTN)EntryPointStructure->TableAddress; | |
| CurrentSmbiosEntry = NULL; | |
| do { | |
| Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord); | |
| if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios32BitTable)) { | |
| GetSmbiosStructureSize (SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr); | |
| CopyMem (BufferPointer, SmbiosRecord, RecordSize); | |
| BufferPointer = BufferPointer + RecordSize; | |
| } | |
| } while (!EFI_ERROR (Status)); | |
| // | |
| // Assemble End-Of-Table structure | |
| // | |
| CopyMem (BufferPointer, &EndStructure, sizeof (EndStructure)); | |
| // | |
| // Fixup checksums in the Entry Point Structure | |
| // | |
| EntryPointStructure->IntermediateChecksum = 0; | |
| EntryPointStructure->EntryPointStructureChecksum = 0; | |
| EntryPointStructure->IntermediateChecksum = | |
| CalculateCheckSum8 ((UINT8 *)EntryPointStructure + 0x10, EntryPointStructure->EntryPointLength - 0x10); | |
| EntryPointStructure->EntryPointStructureChecksum = | |
| CalculateCheckSum8 ((UINT8 *)EntryPointStructure, EntryPointStructure->EntryPointLength); | |
| // | |
| // Returns the pointer | |
| // | |
| *TableEntryPointStructure = EntryPointStructure; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Assembles SMBIOS 64-bit table from the SMBIOS protocol. Produce Table | |
| Entry Point and return the pointer to it. | |
| @param TableEntryPointStructure On exit, points to the SMBIOS entrypoint structure. | |
| @retval EFI_SUCCESS Structure created sucessfully. | |
| @retval EFI_OUT_OF_RESOURCES No enough memory. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmbiosCreate64BitTable ( | |
| OUT VOID **TableEntryPointStructure | |
| ) | |
| { | |
| UINT8 *BufferPointer; | |
| UINTN RecordSize; | |
| UINTN NumOfStr; | |
| EFI_STATUS Status; | |
| EFI_SMBIOS_HANDLE SmbiosHandle; | |
| EFI_SMBIOS_PROTOCOL *SmbiosProtocol; | |
| EFI_PHYSICAL_ADDRESS PhysicalAddress; | |
| EFI_SMBIOS_TABLE_HEADER *SmbiosRecord; | |
| EFI_SMBIOS_TABLE_END_STRUCTURE EndStructure; | |
| EFI_SMBIOS_ENTRY *CurrentSmbiosEntry; | |
| Status = EFI_SUCCESS; | |
| BufferPointer = NULL; | |
| if (Smbios30EntryPointStructure == NULL) { | |
| // | |
| // Initialize the Smbios30EntryPointStructure with initial values. | |
| // It should be done only once. | |
| // Allocate memory at any address. | |
| // | |
| DEBUG ((DEBUG_INFO, "SmbiosCreateTable: Initialize 64-bit entry point structure\n")); | |
| Smbios30EntryPointStructureData.MajorVersion = mPrivateData.Smbios.MajorVersion; | |
| Smbios30EntryPointStructureData.MinorVersion = mPrivateData.Smbios.MinorVersion; | |
| Smbios30EntryPointStructureData.DocRev = PcdGet8 (PcdSmbiosDocRev); | |
| Status = gBS->AllocatePages ( | |
| AllocateAnyPages, | |
| EfiRuntimeServicesData, | |
| EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_3_0_ENTRY_POINT)), | |
| &PhysicalAddress | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "SmbiosCreate64BitTable() could not allocate Smbios30EntryPointStructure\n")); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| Smbios30EntryPointStructure = (SMBIOS_TABLE_3_0_ENTRY_POINT *)(UINTN)PhysicalAddress; | |
| CopyMem ( | |
| Smbios30EntryPointStructure, | |
| &Smbios30EntryPointStructureData, | |
| sizeof (SMBIOS_TABLE_3_0_ENTRY_POINT) | |
| ); | |
| } | |
| // | |
| // Get Smbios protocol to traverse SMBIOS records. | |
| // | |
| SmbiosProtocol = &mPrivateData.Smbios; | |
| Smbios30EntryPointStructure->TableMaximumSize = 0; | |
| // | |
| // Calculate EPS Table Length | |
| // | |
| CurrentSmbiosEntry = NULL; | |
| do { | |
| Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord); | |
| if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios64BitTable)) { | |
| GetSmbiosStructureSize (SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr); | |
| // | |
| // Record TableMaximumSize | |
| // | |
| Smbios30EntryPointStructure->TableMaximumSize = (UINT32)(Smbios30EntryPointStructure->TableMaximumSize + RecordSize); | |
| } | |
| } while (!EFI_ERROR (Status)); | |
| // | |
| // Create End-Of-Table structure | |
| // | |
| GetMaxSmbiosHandle (SmbiosProtocol, &SmbiosHandle); | |
| EndStructure.Header.Type = SMBIOS_TYPE_END_OF_TABLE; | |
| EndStructure.Header.Length = (UINT8)sizeof (EFI_SMBIOS_TABLE_HEADER); | |
| EndStructure.Header.Handle = SmbiosHandle; | |
| EndStructure.Tailing[0] = 0; | |
| EndStructure.Tailing[1] = 0; | |
| Smbios30EntryPointStructure->TableMaximumSize = (UINT32)(Smbios30EntryPointStructure->TableMaximumSize + sizeof (EndStructure)); | |
| if (EFI_SIZE_TO_PAGES (Smbios30EntryPointStructure->TableMaximumSize) > mPre64BitAllocatedPages) { | |
| // | |
| // If new SMBIOS table size exceeds the previous allocated page, | |
| // it is time to re-allocate memory at anywhere. | |
| // | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "%a() re-allocate SMBIOS 64-bit table\n", | |
| __func__ | |
| )); | |
| if (Smbios30EntryPointStructure->TableAddress != 0) { | |
| // | |
| // Free the previous allocated page | |
| // | |
| FreePages ( | |
| (VOID *)(UINTN)Smbios30EntryPointStructure->TableAddress, | |
| mPre64BitAllocatedPages | |
| ); | |
| Smbios30EntryPointStructure->TableAddress = 0; | |
| mPre64BitAllocatedPages = 0; | |
| } | |
| Status = gBS->AllocatePages ( | |
| AllocateAnyPages, | |
| EfiRuntimeServicesData, | |
| EFI_SIZE_TO_PAGES (Smbios30EntryPointStructure->TableMaximumSize), | |
| &PhysicalAddress | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "SmbiosCreateTable() could not allocate SMBIOS 64-bit table\n")); | |
| Smbios30EntryPointStructure->TableAddress = 0; | |
| return EFI_OUT_OF_RESOURCES; | |
| } else { | |
| Smbios30EntryPointStructure->TableAddress = PhysicalAddress; | |
| mPre64BitAllocatedPages = EFI_SIZE_TO_PAGES (Smbios30EntryPointStructure->TableMaximumSize); | |
| } | |
| } | |
| // | |
| // Assemble the tables | |
| // | |
| ASSERT (Smbios30EntryPointStructure->TableAddress != 0); | |
| BufferPointer = (UINT8 *)(UINTN)Smbios30EntryPointStructure->TableAddress; | |
| CurrentSmbiosEntry = NULL; | |
| do { | |
| Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord); | |
| if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios64BitTable)) { | |
| // | |
| // This record can be added to 64-bit table | |
| // | |
| GetSmbiosStructureSize (SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr); | |
| CopyMem (BufferPointer, SmbiosRecord, RecordSize); | |
| BufferPointer = BufferPointer + RecordSize; | |
| } | |
| } while (!EFI_ERROR (Status)); | |
| // | |
| // Assemble End-Of-Table structure | |
| // | |
| CopyMem (BufferPointer, &EndStructure, sizeof (EndStructure)); | |
| // | |
| // Fixup checksums in the Entry Point Structure | |
| // | |
| Smbios30EntryPointStructure->EntryPointStructureChecksum = 0; | |
| Smbios30EntryPointStructure->EntryPointStructureChecksum = | |
| CalculateCheckSum8 ((UINT8 *)Smbios30EntryPointStructure, Smbios30EntryPointStructure->EntryPointLength); | |
| // | |
| // Returns the pointer | |
| // | |
| *TableEntryPointStructure = Smbios30EntryPointStructure; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Create Smbios Table and installs the Smbios Table to the System Table. | |
| @param Smbios32BitTable The flag to update 32-bit table. | |
| @param Smbios64BitTable The flag to update 64-bit table. | |
| **/ | |
| VOID | |
| EFIAPI | |
| SmbiosTableConstruction ( | |
| BOOLEAN Smbios32BitTable, | |
| BOOLEAN Smbios64BitTable | |
| ) | |
| { | |
| UINT8 *Eps; | |
| UINT8 *Eps64Bit; | |
| EFI_STATUS Status; | |
| if (Smbios32BitTable) { | |
| Status = SmbiosCreateTable ((VOID **)&Eps); | |
| if (!EFI_ERROR (Status)) { | |
| gBS->InstallConfigurationTable (&gEfiSmbiosTableGuid, Eps); | |
| } | |
| } | |
| if (Smbios64BitTable) { | |
| Status = SmbiosCreate64BitTable ((VOID **)&Eps64Bit); | |
| if (!EFI_ERROR (Status)) { | |
| gBS->InstallConfigurationTable (&gEfiSmbios3TableGuid, Eps64Bit); | |
| } | |
| } | |
| } | |
| /** | |
| Validates a SMBIOS 2.0 table entry point. | |
| @param TableEntry The SmBios table entry to validate. | |
| @param TableAddress On exit, point to the smbios table addres. | |
| @param TableMaximumSize On exit, point to the maximum size of the table. | |
| @retval TRUE SMBIOS table entry point is valid. | |
| @retval FALSE SMBIOS table entry point is malformed. | |
| **/ | |
| STATIC | |
| BOOLEAN | |
| IsValidSmbios20Table ( | |
| IN VOID *TableEntry, | |
| OUT VOID **TableAddress, | |
| OUT UINTN *TableMaximumSize, | |
| OUT UINT8 *MajorVersion, | |
| OUT UINT8 *MinorVersion | |
| ) | |
| { | |
| UINT8 Checksum; | |
| SMBIOS_TABLE_ENTRY_POINT *SmbiosTable; | |
| SmbiosTable = (SMBIOS_TABLE_ENTRY_POINT *)TableEntry; | |
| if (CompareMem (SmbiosTable->AnchorString, "_SM_", 4) != 0) { | |
| return FALSE; | |
| } | |
| if (CompareMem (SmbiosTable->IntermediateAnchorString, "_DMI_", 5) != 0) { | |
| return FALSE; | |
| } | |
| // | |
| // The actual value of the EntryPointLength should be 1Fh. | |
| // However, it was incorrectly stated in version 2.1 of smbios specification. | |
| // Therefore, 0x1F and 0x1E are both accepted. | |
| // | |
| if ((SmbiosTable->EntryPointLength != 0x1E) && (SmbiosTable->EntryPointLength != sizeof (SMBIOS_TABLE_ENTRY_POINT))) { | |
| return FALSE; | |
| } | |
| // | |
| // MajorVersion should not be less than 2. | |
| // | |
| if (SmbiosTable->MajorVersion < 2) { | |
| return FALSE; | |
| } | |
| *MajorVersion = SmbiosTable->MajorVersion; | |
| *MinorVersion = SmbiosTable->MinorVersion; | |
| // | |
| // The whole struct check sum should be zero | |
| // | |
| Checksum = CalculateSum8 ( | |
| (UINT8 *)SmbiosTable, | |
| SmbiosTable->EntryPointLength | |
| ); | |
| if (Checksum != 0) { | |
| return FALSE; | |
| } | |
| // | |
| // The Intermediate Entry Point Structure check sum should be zero. | |
| // | |
| Checksum = CalculateSum8 ( | |
| (UINT8 *)SmbiosTable + OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString), | |
| SmbiosTable->EntryPointLength - OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString) | |
| ); | |
| if (Checksum != 0) { | |
| return FALSE; | |
| } | |
| *TableAddress = (VOID *)(UINTN)SmbiosTable->TableAddress; | |
| *TableMaximumSize = SmbiosTable->TableLength; | |
| return TRUE; | |
| } | |
| /** | |
| Validates a SMBIOS 3.0 table entry point. | |
| @param TableEntry The SmBios table entry to validate. | |
| @param TableAddress On exit, point to the smbios table addres. | |
| @param TableMaximumSize On exit, point to the maximum size of the table. | |
| @retval TRUE SMBIOS table entry point is valid. | |
| @retval FALSE SMBIOS table entry point is malformed. | |
| **/ | |
| STATIC | |
| BOOLEAN | |
| IsValidSmbios30Table ( | |
| IN VOID *TableEntry, | |
| OUT VOID **TableAddress, | |
| OUT UINTN *TableMaximumSize, | |
| OUT UINT8 *MajorVersion, | |
| OUT UINT8 *MinorVersion | |
| ) | |
| { | |
| UINT8 Checksum; | |
| SMBIOS_TABLE_3_0_ENTRY_POINT *SmbiosTable; | |
| SmbiosTable = (SMBIOS_TABLE_3_0_ENTRY_POINT *)TableEntry; | |
| if (CompareMem (SmbiosTable->AnchorString, "_SM3_", 5) != 0) { | |
| return FALSE; | |
| } | |
| if (SmbiosTable->EntryPointLength < sizeof (SMBIOS_TABLE_3_0_ENTRY_POINT)) { | |
| return FALSE; | |
| } | |
| if (SmbiosTable->MajorVersion < 3) { | |
| return FALSE; | |
| } | |
| *MajorVersion = SmbiosTable->MajorVersion; | |
| *MinorVersion = SmbiosTable->MinorVersion; | |
| // | |
| // The whole struct check sum should be zero | |
| // | |
| Checksum = CalculateSum8 ( | |
| (UINT8 *)SmbiosTable, | |
| SmbiosTable->EntryPointLength | |
| ); | |
| if (Checksum != 0) { | |
| return FALSE; | |
| } | |
| *TableAddress = (VOID *)(UINTN)SmbiosTable->TableAddress; | |
| *TableMaximumSize = SmbiosTable->TableMaximumSize; | |
| return TRUE; | |
| } | |
| /** | |
| Parse an existing SMBIOS table and insert it using SmbiosAdd. | |
| @param ImageHandle The EFI_HANDLE to this driver. | |
| @param Smbios The SMBIOS table to parse. | |
| @param Length The length of the SMBIOS table. | |
| @retval EFI_SUCCESS SMBIOS table was parsed and installed. | |
| @retval EFI_OUT_OF_RESOURCES Record was not added due to lack of system resources. | |
| @retval EFI_INVALID_PARAMETER Smbios is not a correct smbios table | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| ParseAndAddExistingSmbiosTable ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN SMBIOS_STRUCTURE_POINTER Smbios, | |
| IN UINTN Length, | |
| IN UINT8 MajorVersion, | |
| IN UINT8 MinorVersion | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| CHAR8 *String; | |
| EFI_SMBIOS_HANDLE SmbiosHandle; | |
| SMBIOS_STRUCTURE_POINTER SmbiosEnd; | |
| mPrivateData.Smbios.MajorVersion = MajorVersion; | |
| mPrivateData.Smbios.MinorVersion = MinorVersion; | |
| SmbiosEnd.Raw = Smbios.Raw + Length; | |
| if ((Smbios.Raw >= SmbiosEnd.Raw) || (Smbios.Raw == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| do { | |
| // | |
| // Make sure not to access memory beyond SmbiosEnd | |
| // | |
| if ((UINTN)(SmbiosEnd.Raw - Smbios.Raw) < sizeof (SMBIOS_STRUCTURE)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Check for end marker | |
| // | |
| if (Smbios.Hdr->Type == SMBIOS_TYPE_END_OF_TABLE) { | |
| break; | |
| } | |
| // | |
| // Make sure not to access memory beyond SmbiosEnd | |
| // Each structure shall be terminated by a double-null (0000h). | |
| // | |
| if ((UINTN)(SmbiosEnd.Raw - Smbios.Raw) < (Smbios.Hdr->Length + 2U)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Install the table | |
| // | |
| SmbiosHandle = Smbios.Hdr->Handle; | |
| Status = SmbiosAdd ( | |
| &mPrivateData.Smbios, | |
| ImageHandle, | |
| &SmbiosHandle, | |
| Smbios.Hdr | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Go to the next SMBIOS structure. Each SMBIOS structure may include 2 parts: | |
| // 1. Formatted section; 2. Unformatted string section. So, 2 steps are needed | |
| // to skip one SMBIOS structure. | |
| // | |
| // | |
| // Step 1: Skip over formatted section. | |
| // | |
| String = (CHAR8 *)(Smbios.Raw + Smbios.Hdr->Length); | |
| // | |
| // Step 2: Skip over unformatted string section. | |
| // | |
| do { | |
| // | |
| // Each string is terminated with a NULL(00h) BYTE and the sets of strings | |
| // is terminated with an additional NULL(00h) BYTE. | |
| // | |
| for ( ; *String != 0; String++) { | |
| if ((UINTN)String >= (UINTN)SmbiosEnd.Raw - sizeof (UINT8)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| } | |
| if (*(UINT8 *)++String == 0) { | |
| // | |
| // Pointer to the next SMBIOS structure. | |
| // | |
| Smbios.Raw = (UINT8 *)++String; | |
| break; | |
| } | |
| } while (TRUE); | |
| } while (Smbios.Raw < SmbiosEnd.Raw); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Retrieve SMBIOS from Hob. | |
| @param ImageHandle Module's image handle | |
| @retval EFI_SUCCESS Smbios from Hob is installed. | |
| @return EFI_NOT_FOUND Not found Smbios from Hob. | |
| @retval Other No Smbios from Hob is installed. | |
| **/ | |
| EFI_STATUS | |
| RetrieveSmbiosFromHob ( | |
| IN EFI_HANDLE ImageHandle | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN Index; | |
| SMBIOS_STRUCTURE_POINTER Smbios; | |
| EFI_HOB_GUID_TYPE *GuidHob; | |
| UNIVERSAL_PAYLOAD_SMBIOS_TABLE *SmBiosTableAdress; | |
| UNIVERSAL_PAYLOAD_GENERIC_HEADER *GenericHeader; | |
| VOID *TableAddress; | |
| UINTN TableMaximumSize; | |
| UINT8 MajorVersion; | |
| UINT8 MinorVersion; | |
| Status = EFI_NOT_FOUND; | |
| MajorVersion = 0; | |
| MinorVersion = 0; | |
| for (Index = 0; Index < ARRAY_SIZE (mIsSmbiosTableValid); Index++) { | |
| GuidHob = GetFirstGuidHob (mIsSmbiosTableValid[Index].Guid); | |
| if (GuidHob == NULL) { | |
| continue; | |
| } | |
| GenericHeader = (UNIVERSAL_PAYLOAD_GENERIC_HEADER *)GET_GUID_HOB_DATA (GuidHob); | |
| if ((sizeof (UNIVERSAL_PAYLOAD_GENERIC_HEADER) <= GET_GUID_HOB_DATA_SIZE (GuidHob)) && (GenericHeader->Length <= GET_GUID_HOB_DATA_SIZE (GuidHob))) { | |
| if (GenericHeader->Revision == UNIVERSAL_PAYLOAD_SMBIOS_TABLE_REVISION) { | |
| // | |
| // UNIVERSAL_PAYLOAD_SMBIOS_TABLE structure is used when Revision equals to UNIVERSAL_PAYLOAD_SMBIOS_TABLE_REVISION | |
| // | |
| SmBiosTableAdress = (UNIVERSAL_PAYLOAD_SMBIOS_TABLE *)GET_GUID_HOB_DATA (GuidHob); | |
| if (GenericHeader->Length >= UNIVERSAL_PAYLOAD_SIZEOF_THROUGH_FIELD (UNIVERSAL_PAYLOAD_SMBIOS_TABLE, SmBiosEntryPoint)) { | |
| if (mIsSmbiosTableValid[Index].IsValid ((VOID *)(UINTN)SmBiosTableAdress->SmBiosEntryPoint, &TableAddress, &TableMaximumSize, &MajorVersion, &MinorVersion)) { | |
| Smbios.Raw = TableAddress; | |
| Status = ParseAndAddExistingSmbiosTable (ImageHandle, Smbios, TableMaximumSize, MajorVersion, MinorVersion); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "RetrieveSmbiosFromHob: Failed to parse preinstalled tables from Guid Hob\n")); | |
| Status = EFI_UNSUPPORTED; | |
| } else { | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| Driver to produce Smbios protocol and pre-allocate 1 page for the final SMBIOS table. | |
| @param ImageHandle Module's image handle | |
| @param SystemTable Pointer of EFI_SYSTEM_TABLE | |
| @retval EFI_SUCCESS Smbios protocol installed | |
| @retval Other No protocol installed, unload driver. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmbiosDriverEntryPoint ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| mPrivateData.Signature = SMBIOS_INSTANCE_SIGNATURE; | |
| mPrivateData.Smbios.Add = SmbiosAdd; | |
| mPrivateData.Smbios.UpdateString = SmbiosUpdateString; | |
| mPrivateData.Smbios.Remove = SmbiosRemove; | |
| mPrivateData.Smbios.GetNext = SmbiosGetNext; | |
| mPrivateData.Smbios.MajorVersion = (UINT8)(PcdGet16 (PcdSmbiosVersion) >> 8); | |
| mPrivateData.Smbios.MinorVersion = (UINT8)(PcdGet16 (PcdSmbiosVersion) & 0x00ff); | |
| InitializeListHead (&mPrivateData.DataListHead); | |
| InitializeListHead (&mPrivateData.AllocatedHandleListHead); | |
| EfiInitializeLock (&mPrivateData.DataLock, TPL_NOTIFY); | |
| // | |
| // Make a new handle and install the protocol | |
| // | |
| mPrivateData.Handle = NULL; | |
| Status = gBS->InstallProtocolInterface ( | |
| &mPrivateData.Handle, | |
| &gEfiSmbiosProtocolGuid, | |
| EFI_NATIVE_INTERFACE, | |
| &mPrivateData.Smbios | |
| ); | |
| RetrieveSmbiosFromHob (ImageHandle); | |
| return Status; | |
| } |