2100 lines
66 KiB
C
2100 lines
66 KiB
C
/** @file
|
|
SMBIOS driver.
|
|
|
|
;******************************************************************************
|
|
;* 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 "SmbiosDxe.h"
|
|
|
|
EFI_SMBIOS_HANDLE *mMappingTable = NULL;
|
|
UINT16 mNumberOfStructure;
|
|
|
|
//
|
|
// 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;
|
|
|
|
BOOLEAN AlreadyExist[256] = {FALSE};
|
|
BOOLEAN EndOfSmbiosScm = FALSE;
|
|
//
|
|
// 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
|
|
//
|
|
(UINT8) (FixedPcdGet16 (PcdSmbiosVersion) >> 8),
|
|
//
|
|
// MinorVersion
|
|
//
|
|
(UINT8) (FixedPcdGet16 (PcdSmbiosVersion) & 0x00ff),
|
|
//
|
|
// MaxStructureSize, TO BE FILLED
|
|
//
|
|
0,
|
|
//
|
|
// EntryPointRevision
|
|
//
|
|
0,
|
|
//
|
|
// FormattedArea
|
|
//
|
|
{
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0
|
|
},
|
|
//
|
|
// IntermediateAnchorString
|
|
//
|
|
{
|
|
0x5f,
|
|
0x44,
|
|
0x4d,
|
|
0x49,
|
|
0x5f
|
|
},
|
|
//
|
|
// IntermediateChecksum, TO BE FILLED
|
|
//
|
|
0,
|
|
//
|
|
// StructureTableLength, TO BE FILLED
|
|
//
|
|
0,
|
|
//
|
|
// StructureTableAddress, TO BE FILLED
|
|
//
|
|
0,
|
|
//
|
|
// NumberOfSmbiosStructures, TO BE FILLED
|
|
//
|
|
0,
|
|
//
|
|
// SmbiosBcdRevision
|
|
//
|
|
(UINT8) ((FixedPcdGet16 (PcdSmbiosVersion) >> 4) & 0xf0)
|
|
| (UINT8) (FixedPcdGet16 (PcdSmbiosVersion) & 0x0f)
|
|
};
|
|
|
|
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
|
|
};
|
|
|
|
VOID
|
|
RecordSmbios(
|
|
VOID
|
|
);
|
|
|
|
/**
|
|
|
|
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 returned 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;
|
|
}
|
|
|
|
/**
|
|
|
|
Determine 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 in a sorted list.
|
|
|
|
@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.
|
|
|
|
**/
|
|
VOID
|
|
SmbiosInsertSortedList (
|
|
IN OUT LIST_ENTRY *ListHead,
|
|
IN OUT LIST_ENTRY *Entry,
|
|
IN EFI_SMBIOS_TYPE Type
|
|
)
|
|
{
|
|
LIST_ENTRY *TempList;
|
|
EFI_SMBIOS_ENTRY *TempEntry;
|
|
EFI_SMBIOS_TABLE_HEADER *CurrentSmbiosHeader, *NextSmbiosHeadr;
|
|
|
|
if (IsListEmpty (ListHead)) {
|
|
InsertHeadList (ListHead, Entry);
|
|
return;
|
|
}
|
|
|
|
TempList = ListHead;
|
|
for (TempList = ListHead->ForwardLink; TempList != ListHead; TempList = TempList->ForwardLink) {
|
|
TempEntry = SMBIOS_ENTRY_FROM_LINK (TempList);
|
|
CurrentSmbiosHeader = (EFI_SMBIOS_TABLE_HEADER*)(TempEntry->RecordHeader + 1);
|
|
if (Type < CurrentSmbiosHeader->Type) {
|
|
InsertTailList (TempList, Entry);
|
|
return;
|
|
}
|
|
|
|
if (IsNodeAtEnd (ListHead, TempList)) {
|
|
InsertHeadList (TempList, Entry);
|
|
return;
|
|
}
|
|
|
|
TempEntry = SMBIOS_ENTRY_FROM_LINK (TempList->ForwardLink);
|
|
NextSmbiosHeadr = (EFI_SMBIOS_TABLE_HEADER*)(TempEntry->RecordHeader + 1);
|
|
if (Type < NextSmbiosHeadr->Type) {
|
|
InsertHeadList (TempList, Entry);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
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;
|
|
}
|
|
|
|
DEBUG_CODE_BEGIN();
|
|
if (EndOfSmbiosScm && AlreadyExist[Record->Type]) {
|
|
DEBUG((EFI_D_INFO, "The SMBIOS type %d already exist when install SMBIOS protocol.\n", Record->Type));
|
|
}
|
|
DEBUG_CODE_END();
|
|
|
|
//
|
|
// 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 ((EFI_D_INFO, "SmbiosAdd: Total length exceeds max 32-bit table length with type = %d size = 0x%x\n", Record->Type, StructureSize));
|
|
} else {
|
|
Smbios32BitTable = TRUE;
|
|
DEBUG ((EFI_D_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 ((EFI_D_INFO, "SmbiosAdd: Total length exceeds max 64-bit table length with type = %d size = 0x%x\n", Record->Type, StructureSize));
|
|
} else {
|
|
DEBUG ((EFI_D_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;
|
|
SmbiosInsertSortedList (&Private->DataListHead, &SmbiosEntry->Link, Record->Type);
|
|
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, AsciiStrSize(StrStart), 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 ((EFI_D_INFO, "SmbiosUpdateString: Total length exceeds max 32-bit table length\n"));
|
|
} else {
|
|
DEBUG ((EFI_D_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 ((EFI_D_INFO, "SmbiosUpdateString: Total length exceeds max 64-bit table length\n"));
|
|
} else {
|
|
DEBUG ((EFI_D_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 SMBIOS 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);
|
|
HandleEntry = NULL;
|
|
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 ((EFI_D_INFO, "SmbiosRemove: remove from 32-bit table\n"));
|
|
}
|
|
if (SmbiosEntry->Smbios64BitTable) {
|
|
DEBUG ((EFI_D_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 entry point structure.
|
|
|
|
@retval EFI_SUCCESS Structure created successfully.
|
|
@retval EFI_NOT_READY Some of The SMBIOS records was not available yet.
|
|
@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 ((EFI_D_INFO, "SmbiosCreateTable: Initialize 32-bit entry point structure\n"));
|
|
EntryPointStructureData.MajorVersion = mPrivateData.Smbios.MajorVersion;
|
|
EntryPointStructureData.MinorVersion = mPrivateData.Smbios.MinorVersion;
|
|
EntryPointStructureData.SmbiosBcdRevision = (UINT8) ((PcdGet16 (PcdSmbiosVersion) >> 4) & 0xf0) | (UINT8) (PcdGet16 (PcdSmbiosVersion) & 0x0f);
|
|
PhysicalAddress = 0xffffffff;
|
|
Status = gBS->AllocatePages (
|
|
AllocateMaxAddress,
|
|
EfiRuntimeServicesData,
|
|
EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT)),
|
|
&PhysicalAddress
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_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 = EFI_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 ((UINTN) EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength + PcdGet32(PcdH2OSmbiosTableExtraMemorySize)) > mPreAllocatedPages) {
|
|
//
|
|
// If new SMBIOS talbe size exceeds the original pre-allocated page,
|
|
// it is time to re-allocate memory (below 4GB).
|
|
//
|
|
DEBUG ((EFI_D_INFO, "SmbiosCreateTable() re-allocate SMBIOS 32-bit table\n"));
|
|
if (EntryPointStructure->TableAddress != 0) {
|
|
//
|
|
// Free the original pre-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 + PcdGet32(PcdH2OSmbiosTableExtraMemorySize)),
|
|
&PhysicalAddress
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_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 + PcdGet32(PcdH2OSmbiosTableExtraMemorySize));
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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 ((EFI_D_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 ((EFI_D_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 = EFI_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 ((UINTN) EFI_SIZE_TO_PAGES (Smbios30EntryPointStructure->TableMaximumSize + PcdGet32(PcdH2OSmbiosTableExtraMemorySize)) > mPre64BitAllocatedPages) {
|
|
//
|
|
// If new SMBIOS table size exceeds the previous allocated page,
|
|
// it is time to re-allocate memory at anywhere.
|
|
//
|
|
DEBUG ((EFI_D_INFO, "SmbiosCreate64BitTable() re-allocate SMBIOS 64-bit table\n"));
|
|
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 + PcdGet32(PcdH2OSmbiosTableExtraMemorySize)),
|
|
&PhysicalAddress
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_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 + PcdGet32(PcdH2OSmbiosTableExtraMemorySize));
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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 install it to the System Table.
|
|
|
|
SmbiosEntry->Smbios32BitTable = Smbios32BitTable;
|
|
SmbiosEntry->Smbios64BitTable = Smbios64BitTable;
|
|
|
|
**/
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Search the handle number from the mapping table.
|
|
If the handle number is not found, return 0xFFFF.
|
|
|
|
@param Handle The old handle number.
|
|
|
|
@return The new handle number.
|
|
|
|
**/
|
|
EFI_SMBIOS_HANDLE
|
|
SearchMappingHandle (
|
|
IN EFI_SMBIOS_HANDLE Handle
|
|
)
|
|
{
|
|
EFI_SMBIOS_HANDLE Index;
|
|
|
|
for (Index = 0; Index < mNumberOfStructure; Index++) {
|
|
if (mMappingTable[Index] == Handle) {
|
|
return Index;
|
|
}
|
|
}
|
|
|
|
return 0xFFFF;
|
|
}
|
|
|
|
/**
|
|
Fixup the Link Data. Search the correct handle number and update to the record.
|
|
|
|
@param HandlePtr The pointer to the handle value.
|
|
|
|
**/
|
|
VOID
|
|
FixupLinkData (
|
|
IN EFI_SMBIOS_HANDLE *HandlePtr
|
|
)
|
|
{
|
|
EFI_SMBIOS_HANDLE TempHandle;
|
|
|
|
TempHandle = SearchMappingHandle (*HandlePtr);
|
|
if ((TempHandle == 0xFFFF) && (*HandlePtr >= SMBIOS_HANDLE_RESERVED_BEGIN)) {
|
|
return;
|
|
}
|
|
|
|
CopyMem (HandlePtr, &TempHandle, sizeof (EFI_SMBIOS_HANDLE));
|
|
}
|
|
|
|
/**
|
|
Search the handle number for SMBIOS type.
|
|
If the handle number is not found, return 0xFFFF.
|
|
|
|
@param Head Link list head for SMBIOS records.
|
|
@param Type SMBIOS type number.
|
|
|
|
**/
|
|
EFI_SMBIOS_HANDLE
|
|
SearchHandle (
|
|
IN LIST_ENTRY *Head,
|
|
IN EFI_SMBIOS_TYPE Type
|
|
)
|
|
{
|
|
EFI_SMBIOS_HANDLE ReturnHandle;
|
|
EFI_SMBIOS_ENTRY *SmbiosEntry;
|
|
LIST_ENTRY *Link;
|
|
EFI_SMBIOS_TABLE_HEADER *SmbiosHeader;
|
|
|
|
ReturnHandle = 0xFFFF;
|
|
for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
|
|
SmbiosEntry = SMBIOS_ENTRY_FROM_LINK (Link);
|
|
SmbiosHeader = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);
|
|
|
|
if (SmbiosHeader->Type == Type) {
|
|
ReturnHandle = SmbiosHeader->Handle;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ReturnHandle;
|
|
}
|
|
|
|
/**
|
|
Transfer Asscii lowercase letter (a~z) to uppercase letter
|
|
|
|
@param Letter One Ascill letter.
|
|
|
|
@return the uppercase Ascill character.
|
|
|
|
**/
|
|
STATIC
|
|
CHAR8
|
|
EFIAPI
|
|
TransfertoUP (
|
|
IN CHAR8 Letter
|
|
)
|
|
{
|
|
if ((Letter >= 'a') && (Letter <= 'z')) {
|
|
Letter -= 0x20;
|
|
}
|
|
return Letter;
|
|
}
|
|
|
|
|
|
/**
|
|
Case insensitive comparsion for the two Ascii NULL Strings by specify length.
|
|
|
|
@param Str1 First NULL string.
|
|
@param Str2 Second NULL string.
|
|
@param CompareLength Specify the length to compare.
|
|
|
|
@retval 0 Comparative result are same when in case insensitive comparsion.
|
|
@return Others Comparative result are different when in case insensitive comparsion.
|
|
**/
|
|
STATIC
|
|
INTN
|
|
EFIAPI
|
|
AsciiStrinCmp (
|
|
IN CONST CHAR8 *Str1,
|
|
IN CONST CHAR8 *Str2,
|
|
IN UINTN CompareLength
|
|
)
|
|
{
|
|
CHAR8 Letter1;
|
|
CHAR8 Letter2;
|
|
INTN ReturnValue;
|
|
|
|
ReturnValue = 0;
|
|
|
|
if (CompareLength == 0) {
|
|
return ReturnValue;
|
|
}
|
|
|
|
for (; (*Str1 != '\0') && (CompareLength >= 1); CompareLength--) {
|
|
Letter1 = TransfertoUP(*Str1);
|
|
Letter2 = TransfertoUP(*Str2);
|
|
if (Letter1 != Letter2) {
|
|
ReturnValue = (INTN) Letter1 - Letter2;
|
|
break;
|
|
}
|
|
Str1++;
|
|
Str2++;
|
|
}
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SmbiosUpdateValue (
|
|
VOID
|
|
)
|
|
{
|
|
SMBIOS_INSTANCE *Private;
|
|
LIST_ENTRY *Head;
|
|
LIST_ENTRY *Link;
|
|
EFI_SMBIOS_ENTRY *SmbiosEntry;
|
|
EFI_SMBIOS_TABLE_HEADER *CurrentSmbiosHeader;
|
|
SMBIOS_TABLE_TYPE13 *Type13Record;
|
|
CHAR8 *LanguageTable;
|
|
CHAR8 *SCULanguage;
|
|
CHAR8 *Type13Lang;
|
|
CHAR8 *TempSCULanguage;
|
|
UINTN CompareLength;
|
|
UINT8 LanguageIndex;
|
|
EFI_SMBIOS_HANDLE Index;
|
|
|
|
Private = SMBIOS_INSTANCE_FROM_THIS (&mPrivateData.Smbios);
|
|
Head = &Private->DataListHead;
|
|
|
|
//
|
|
// Update SMBIOS value before boot.
|
|
//
|
|
for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
|
|
SmbiosEntry = SMBIOS_ENTRY_FROM_LINK (Link);
|
|
CurrentSmbiosHeader = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);
|
|
switch (CurrentSmbiosHeader->Type) {
|
|
|
|
//
|
|
// Type13 current language setting need to dependent on SCU language setting.
|
|
//
|
|
case EFI_SMBIOS_TYPE_BIOS_LANGUAGE_INFORMATION:
|
|
Type13Record = (SMBIOS_TABLE_TYPE13 *) CurrentSmbiosHeader;
|
|
//
|
|
// Default Language
|
|
//
|
|
Type13Record->CurrentLanguages = 1;
|
|
//
|
|
// Get SCU language.
|
|
//
|
|
GetEfiGlobalVariable2 (L"PlatformLang", (VOID **)&SCULanguage, NULL);
|
|
if (SCULanguage == NULL) {
|
|
SCULanguage = AllocatePool (AsciiStrSize("en-US"));
|
|
if (SCULanguage == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
AsciiStrCpyS (SCULanguage, AsciiStrSize("en-US"), (CHAR8 *) "en-US");
|
|
}
|
|
|
|
//
|
|
// Convert SCU language format and set the CompareLength follow abbreviated flag
|
|
// eg. en-US to en|US or enUS
|
|
//
|
|
TempSCULanguage = SCULanguage;
|
|
for (Index = 0; *(SCULanguage + Index) != '\0'; Index++) {
|
|
if (*(SCULanguage + Index) == '-') {
|
|
*(SCULanguage + Index) = '|';
|
|
} else if ((Type13Record->Flags & 0x01) == 0x01) {
|
|
*(TempSCULanguage) = *(SCULanguage + Index);
|
|
TempSCULanguage++;
|
|
}
|
|
}
|
|
CompareLength = 5;
|
|
if ((Type13Record->Flags & 0x01) == 0x01) {
|
|
CompareLength = 4;
|
|
}
|
|
|
|
//
|
|
// Get Type 13 Language Table and search the match language
|
|
//
|
|
LanguageTable = (CHAR8 *)((UINTN)CurrentSmbiosHeader + sizeof(SMBIOS_TABLE_TYPE13));
|
|
Type13Lang = AllocatePool (CompareLength + 1);
|
|
|
|
if (Type13Lang == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
for (LanguageIndex = 1; *LanguageTable != '\0'; LanguageIndex++, LanguageTable++) {
|
|
for (Index = 0; *LanguageTable != '\0'; LanguageTable++, Index++) {
|
|
if(Index < CompareLength) {
|
|
*(Type13Lang + Index) = *LanguageTable;
|
|
}
|
|
}
|
|
if (AsciiStrinCmp(SCULanguage, Type13Lang, CompareLength) == 0) {
|
|
Type13Record->CurrentLanguages = LanguageIndex;
|
|
break;
|
|
}
|
|
}
|
|
|
|
FreePool(SCULanguage);
|
|
FreePool(Type13Lang);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Update the specific handle numbers from handle number of SMBIOS types.
|
|
|
|
**/
|
|
VOID
|
|
UpdateHandleBySearchType (
|
|
VOID
|
|
)
|
|
{
|
|
SMBIOS_INSTANCE *Private;
|
|
LIST_ENTRY *Head;
|
|
EFI_SMBIOS_ENTRY *SmbiosEntry;
|
|
EFI_SMBIOS_TABLE_HEADER *CurrentSmbiosHeader;
|
|
LIST_ENTRY *Link;
|
|
|
|
Private = SMBIOS_INSTANCE_FROM_THIS (&mPrivateData.Smbios);
|
|
Head = &Private->DataListHead;
|
|
|
|
//
|
|
// Adjust LinkData handle values.
|
|
//
|
|
for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
|
|
SmbiosEntry = SMBIOS_ENTRY_FROM_LINK (Link);
|
|
CurrentSmbiosHeader = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);
|
|
|
|
switch (CurrentSmbiosHeader->Type) {
|
|
|
|
case EFI_SMBIOS_TYPE_BASEBOARD_INFORMATION:
|
|
((SMBIOS_TABLE_TYPE2 *)CurrentSmbiosHeader)->ChassisHandle = SearchHandle (Head, EFI_SMBIOS_TYPE_SYSTEM_ENCLOSURE);
|
|
break;
|
|
|
|
case EFI_SMBIOS_TYPE_GROUP_ASSOCIATIONS:
|
|
((SMBIOS_TABLE_TYPE14 *)CurrentSmbiosHeader)->Group->ItemHandle = SearchHandle (Head, ((SMBIOS_TABLE_TYPE14 *)CurrentSmbiosHeader)->Group->ItemType);
|
|
break;
|
|
|
|
case EFI_SMBIOS_TYPE_COOLING_DEVICE:
|
|
((SMBIOS_TABLE_TYPE27 *)CurrentSmbiosHeader)->TemperatureProbeHandle = SearchHandle (Head, EFI_SMBIOS_TYPE_TEMPERATURE_PROBE);
|
|
break;
|
|
|
|
case EFI_SMBIOS_TYPE_MANAGEMENT_DEVICE_COMPONENT:
|
|
((SMBIOS_TABLE_TYPE35 *)CurrentSmbiosHeader)->ManagementDeviceHandle = SearchHandle (Head, EFI_SMBIOS_TYPE_MANAGEMENT_DEVICE);
|
|
if (((SMBIOS_TABLE_TYPE35 *)CurrentSmbiosHeader)->ThresholdHandle != 0xFFFF) {
|
|
((SMBIOS_TABLE_TYPE35 *)CurrentSmbiosHeader)->ThresholdHandle = SearchHandle (Head, EFI_SMBIOS_TYPE_MANAGEMENT_DEVICE_THRESHOLD_DATA);
|
|
}
|
|
break;
|
|
|
|
case EFI_SMBIOS_TYPE_SYSTEM_POWER_SUPPLY:
|
|
if (((SMBIOS_TABLE_TYPE39 *)CurrentSmbiosHeader)->InputVoltageProbeHandle != 0xFFFF) {
|
|
((SMBIOS_TABLE_TYPE39 *)CurrentSmbiosHeader)->InputVoltageProbeHandle = SearchHandle (Head, EFI_SMBIOS_TYPE_VOLTAGE_PROBE);
|
|
}
|
|
if (((SMBIOS_TABLE_TYPE39 *)CurrentSmbiosHeader)->CoolingDeviceHandle != 0xFFFF) {
|
|
((SMBIOS_TABLE_TYPE39 *)CurrentSmbiosHeader)->CoolingDeviceHandle = SearchHandle (Head, EFI_SMBIOS_TYPE_COOLING_DEVICE);
|
|
}
|
|
if (((SMBIOS_TABLE_TYPE39 *)CurrentSmbiosHeader)->InputCurrentProbeHandle != 0xFFFF) {
|
|
((SMBIOS_TABLE_TYPE39 *)CurrentSmbiosHeader)->InputCurrentProbeHandle = SearchHandle (Head, EFI_SMBIOS_TYPE_ELECTRICAL_CURRENT_PROBE);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
Update the specific handle numbers from mMappingTable.
|
|
|
|
@param Head Link list head for SMBIOS records.
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_NOT_FOUND mMappingTable is NULL.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UpdateHandleByMappingTable (
|
|
IN LIST_ENTRY *Head
|
|
)
|
|
{
|
|
EFI_SMBIOS_HANDLE Index;
|
|
EFI_SMBIOS_ENTRY *SmbiosEntry;
|
|
EFI_SMBIOS_TABLE_HEADER *CurrentSmbiosHeader;
|
|
ADDITIONAL_INFORMATION_ENTRY *AdditionalInfo;
|
|
LIST_ENTRY *Link;
|
|
UINT8 *TempPtr;
|
|
SMBIOS_TABLE_TYPE5 *SmbiosType5;
|
|
SMBIOS_TABLE_TYPE37 *SmbiosType37;
|
|
SMBIOS_TABLE_TYPE40 *SmbiosType40;
|
|
|
|
if (mMappingTable == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
//
|
|
// Adjust LinkData handle values.
|
|
//
|
|
for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
|
|
SmbiosEntry = SMBIOS_ENTRY_FROM_LINK (Link);
|
|
CurrentSmbiosHeader = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);
|
|
|
|
switch (CurrentSmbiosHeader->Type) {
|
|
|
|
case EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION:
|
|
FixupLinkData ((EFI_SMBIOS_HANDLE *)(UINTN)&(((SMBIOS_TABLE_TYPE4 *)CurrentSmbiosHeader)->L1CacheHandle));
|
|
FixupLinkData ((EFI_SMBIOS_HANDLE *)(UINTN)&(((SMBIOS_TABLE_TYPE4 *)CurrentSmbiosHeader)->L2CacheHandle));
|
|
FixupLinkData ((EFI_SMBIOS_HANDLE *)(UINTN)&(((SMBIOS_TABLE_TYPE4 *)CurrentSmbiosHeader)->L3CacheHandle));
|
|
break;
|
|
|
|
case EFI_SMBIOS_TYPE_MEMORY_CONTROLLER_INFORMATION:
|
|
SmbiosType5 = (SMBIOS_TABLE_TYPE5 *)CurrentSmbiosHeader;
|
|
for (Index = 0; Index < SmbiosType5->AssociatedMemorySlotNum; Index++) {
|
|
TempPtr = (UINT8 *)(((SMBIOS_TABLE_TYPE5 *)CurrentSmbiosHeader)->MemoryModuleConfigHandles) +
|
|
Index * sizeof (EFI_SMBIOS_HANDLE);
|
|
FixupLinkData ((EFI_SMBIOS_HANDLE *)(UINTN)TempPtr);
|
|
}
|
|
break;
|
|
|
|
case EFI_SMBIOS_TYPE_PHYSICAL_MEMORY_ARRAY:
|
|
FixupLinkData ((EFI_SMBIOS_HANDLE *)(UINTN)&(((SMBIOS_TABLE_TYPE16 *)CurrentSmbiosHeader)->MemoryErrorInformationHandle));
|
|
break;
|
|
|
|
case EFI_SMBIOS_TYPE_MEMORY_DEVICE:
|
|
FixupLinkData ((EFI_SMBIOS_HANDLE *)(UINTN)&(((SMBIOS_TABLE_TYPE17 *)CurrentSmbiosHeader)->MemoryArrayHandle));
|
|
FixupLinkData ((EFI_SMBIOS_HANDLE *)(UINTN)&(((SMBIOS_TABLE_TYPE17 *)CurrentSmbiosHeader)->MemoryErrorInformationHandle));
|
|
break;
|
|
|
|
case EFI_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS:
|
|
FixupLinkData ((EFI_SMBIOS_HANDLE *)(UINTN)&(((SMBIOS_TABLE_TYPE19 *)CurrentSmbiosHeader)->MemoryArrayHandle));
|
|
break;
|
|
|
|
case EFI_SMBIOS_TYPE_MEMORY_DEVICE_MAPPED_ADDRESS:
|
|
FixupLinkData ((EFI_SMBIOS_HANDLE *)(UINTN)&(((SMBIOS_TABLE_TYPE20 *)CurrentSmbiosHeader)->MemoryDeviceHandle));
|
|
FixupLinkData ((EFI_SMBIOS_HANDLE *)(UINTN)&(((SMBIOS_TABLE_TYPE20 *)CurrentSmbiosHeader)->MemoryArrayMappedAddressHandle));
|
|
break;
|
|
|
|
case EFI_SMBIOS_TYPE_MANAGEMENT_DEVICE_COMPONENT:
|
|
FixupLinkData ((EFI_SMBIOS_HANDLE *)(UINTN)&(((SMBIOS_TABLE_TYPE35 *)CurrentSmbiosHeader)->ComponentHandle));
|
|
break;
|
|
|
|
case EFI_SMBIOS_TYPE_MEMORY_CHANNEL:
|
|
SmbiosType37 = (SMBIOS_TABLE_TYPE37 *)CurrentSmbiosHeader;
|
|
for (Index = 0; Index < SmbiosType37->MemoryDeviceCount; Index++) {
|
|
TempPtr = (UINT8 *)(UINTN)&(((SMBIOS_TABLE_TYPE37 *)CurrentSmbiosHeader)->MemoryDevice->DeviceHandle) +
|
|
Index * sizeof (MEMORY_DEVICE);
|
|
FixupLinkData ((EFI_SMBIOS_HANDLE *)(UINTN)TempPtr);
|
|
}
|
|
break;
|
|
|
|
case EFI_SMBIOS_TYPE_ADDITIONAL_INFORMATION:
|
|
SmbiosType40 = (SMBIOS_TABLE_TYPE40 *)CurrentSmbiosHeader;
|
|
AdditionalInfo = ((SMBIOS_TABLE_TYPE40 *)CurrentSmbiosHeader)->AdditionalInfoEntries;
|
|
for (Index = 0; Index < SmbiosType40->NumberOfAdditionalInformationEntries; Index++) {
|
|
FixupLinkData ((EFI_SMBIOS_HANDLE *)(UINTN)&AdditionalInfo->ReferencedHandle);
|
|
AdditionalInfo = (ADDITIONAL_INFORMATION_ENTRY *)(((UINT8 *)AdditionalInfo) + AdditionalInfo->EntryLength);
|
|
}
|
|
break;
|
|
|
|
case SMBIOS_TYPE_PROCESSOR_ADDITIONAL_INFORMATION:
|
|
FixupLinkData ((EFI_SMBIOS_HANDLE *)(UINTN)&(((SMBIOS_TABLE_TYPE44 *)CurrentSmbiosHeader)->RefHandle));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This callback function will sort the handle numbers of SMBIOS table.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
SmbiosSortHandleNumber (
|
|
BOOLEAN IsSmbios32BitTable
|
|
)
|
|
{
|
|
EFI_SMBIOS_HANDLE Index;
|
|
SMBIOS_INSTANCE *Private;
|
|
LIST_ENTRY *Link;
|
|
LIST_ENTRY *Head;
|
|
EFI_SMBIOS_ENTRY *SmbiosEntry;
|
|
EFI_SMBIOS_TABLE_HEADER *CurrentSmbiosHeader;
|
|
SMBIOS_TABLE_ENTRY_POINT *SmbiosTableEntryAddress;
|
|
|
|
//
|
|
// Initialize the data we need.
|
|
//
|
|
SmbiosTableEntryAddress = NULL;
|
|
Private = SMBIOS_INSTANCE_FROM_THIS (&mPrivateData.Smbios);
|
|
Head = &Private->DataListHead;
|
|
|
|
if (IsSmbios32BitTable) {
|
|
EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid, (VOID **)&SmbiosTableEntryAddress);
|
|
} else {
|
|
EfiGetSystemConfigurationTable (&gEfiSmbios3TableGuid, (VOID **)&SmbiosTableEntryAddress);
|
|
}
|
|
|
|
if (SmbiosTableEntryAddress == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (IsSmbios32BitTable){
|
|
mNumberOfStructure = SmbiosTableEntryAddress->NumberOfSmbiosStructures;
|
|
} else {
|
|
|
|
EFI_STATUS Status;
|
|
UINT16 NumberOfSmbiosStructures;
|
|
EFI_SMBIOS_TABLE_HEADER *SmbiosRecord;
|
|
EFI_SMBIOS_HANDLE SmbiosHandle;
|
|
|
|
//
|
|
// Calculate EPS Table Length
|
|
//
|
|
NumberOfSmbiosStructures = 0;
|
|
SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
|
|
|
|
do {
|
|
Status = SmbiosGetNext (&mPrivateData.Smbios, &SmbiosHandle, NULL, &SmbiosRecord, NULL);
|
|
if (Status == EFI_SUCCESS) {
|
|
NumberOfSmbiosStructures++;
|
|
}
|
|
} while (!EFI_ERROR(Status));
|
|
mNumberOfStructure = NumberOfSmbiosStructures;
|
|
}
|
|
|
|
mMappingTable = AllocateZeroPool (mNumberOfStructure * sizeof (EFI_SMBIOS_HANDLE));
|
|
if (mMappingTable == NULL) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Sort the handle numbers and make a mapping table.
|
|
//
|
|
for (Link = Head->ForwardLink, Index = 0; Link != Head; Link = Link->ForwardLink, Index++) {
|
|
SmbiosEntry = SMBIOS_ENTRY_FROM_LINK (Link);
|
|
CurrentSmbiosHeader = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);
|
|
mMappingTable[Index] = CurrentSmbiosHeader->Handle;
|
|
CurrentSmbiosHeader->Handle = Index;
|
|
}
|
|
|
|
UpdateHandleByMappingTable(Head);
|
|
|
|
FreePool (mMappingTable);
|
|
}
|
|
|
|
/**
|
|
Before boot, some data need to be fixed.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
SmbiosReadyToBootCallback (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Cotext
|
|
)
|
|
{
|
|
UINT8 MajorVersion;
|
|
BOOLEAN Smbios32BitTable;
|
|
BOOLEAN Smbios64BitTable;
|
|
|
|
Smbios32BitTable = FALSE;
|
|
Smbios64BitTable = FALSE;
|
|
|
|
MajorVersion =(UINT8) (PcdGet16 (PcdSmbiosVersion) >> 8);
|
|
|
|
gBS->CloseEvent (Event);
|
|
//
|
|
// Make this event late enough.
|
|
//
|
|
gBS->RestoreTPL (TPL_APPLICATION);
|
|
|
|
SmbiosUpdateValue ();
|
|
|
|
if ((MajorVersion < 0x3) ||
|
|
((MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT0) == BIT0))) {
|
|
Smbios32BitTable = TRUE;
|
|
}
|
|
|
|
if ((MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT1) == BIT1)) {
|
|
Smbios64BitTable = TRUE;
|
|
}
|
|
|
|
if (FeaturePcdGet(PcdH2OSmbiosHandleSortEnable)) {
|
|
if (Smbios32BitTable){
|
|
SmbiosSortHandleNumber (TRUE);
|
|
}
|
|
|
|
if (Smbios64BitTable){
|
|
SmbiosSortHandleNumber (FALSE);
|
|
}
|
|
}
|
|
|
|
UpdateHandleBySearchType();
|
|
|
|
SmbiosTableConstruction (Smbios32BitTable, Smbios64BitTable);
|
|
|
|
gBS->RaiseTPL (TPL_CALLBACK);
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
|
|
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;
|
|
EFI_EVENT SmbiosSortEvent;
|
|
|
|
|
|
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);
|
|
|
|
//
|
|
// Depend on PCD create SMBIOS structures
|
|
//
|
|
RecordSmbios();
|
|
|
|
//
|
|
// Make a new handle and install the protocol
|
|
//
|
|
mPrivateData.Handle = NULL;
|
|
Status = gBS->InstallProtocolInterface (
|
|
&mPrivateData.Handle,
|
|
&gEfiSmbiosProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
&mPrivateData.Smbios
|
|
);
|
|
|
|
Status = EfiCreateEventReadyToBootEx (
|
|
TPL_CALLBACK,
|
|
SmbiosReadyToBootCallback,
|
|
NULL,
|
|
&SmbiosSortEvent
|
|
);
|
|
|
|
return Status;
|
|
}
|