This code produces the Smbios protocol. It also responsible for constructing \r
SMBIOS table into system table.\r
\r
-Copyright (c) 2009, Intel Corporation \r
-All rights reserved. This program and the accompanying materials \r
+Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
are licensed and made available under the terms and conditions of the BSD License \r
which accompanies this distribution. The full text of the license may be found at \r
http://opensource.org/licenses/bsd-license.php \r
//\r
SMBIOS_INSTANCE mPrivateData;\r
\r
+UINTN mPreAllocatedPages = 0;\r
+\r
//\r
// Chassis for SMBIOS entry point structure that is to be installed into EFI system config table.\r
//\r
//\r
0x1f,\r
//\r
- // MajorVersion: 2 (Version 2.4)\r
+ // MajorVersion\r
//\r
- 0x02,\r
+ 0,\r
//\r
- // MinorVersion: 4 (Version 2.4)\r
+ // MinorVersion\r
//\r
- 0x04,\r
+ 0,\r
//\r
// MaxStructureSize, TO BE FILLED\r
//\r
//\r
0,\r
//\r
- // StructureTableLength, TO BE FILLED\r
+ // TableLength, TO BE FILLED\r
//\r
0,\r
//\r
- // StructureTableAddress, TO BE FILLED\r
+ // TableAddress, TO BE FILLED\r
//\r
0,\r
//\r
//\r
// SmbiosBcdRevision\r
//\r
- 0 \r
+ 0\r
};\r
\r
\r
+\r
/**\r
\r
- Get the full size of smbios structure including optional strings that follow the formatted structure.\r
+ Get the full size of SMBIOS structure including optional strings that follow the formatted structure.\r
\r
- @param Head Pointer to the beginning of smbios structure.\r
+ @param This The EFI_SMBIOS_PROTOCOL instance.\r
+ @param Head Pointer to the beginning of SMBIOS structure.\r
@param Size The returned size.\r
@param NumberOfStrings The returned number of optional strings that follow the formatted structure.\r
\r
@retval EFI_SUCCESS Size retured in Size.\r
- @retval EFI_INVALID_PARAMETER Input smbios structure mal-formed or Size is NULL.\r
+ @retval EFI_INVALID_PARAMETER Input SMBIOS structure mal-formed or Size is NULL.\r
\r
**/\r
EFI_STATUS\r
EFIAPI\r
GetSmbiosStructureSize (\r
+ IN CONST EFI_SMBIOS_PROTOCOL *This,\r
IN EFI_SMBIOS_TABLE_HEADER *Head,\r
OUT UINTN *Size,\r
OUT UINTN *NumberOfStrings\r
)\r
{\r
UINTN FullSize;\r
- UINT8 StrLen;\r
+ UINTN StrLen;\r
+ UINTN MaxLen;\r
INT8* CharInStr;\r
\r
if (Size == NULL || NumberOfStrings == NULL) {\r
//\r
while (*CharInStr != 0 || *(CharInStr+1) != 0) { \r
if (*CharInStr == 0) {\r
- *NumberOfStrings += 1;\r
*Size += 1;\r
CharInStr++;\r
}\r
\r
- for (StrLen = 0 ; StrLen < SMBIOS_STRING_MAX_LENGTH; StrLen++) {\r
+ if (This->MajorVersion < 2 || (This->MajorVersion == 2 && This->MinorVersion < 7)){\r
+ MaxLen = SMBIOS_STRING_MAX_LENGTH;\r
+ } else {\r
+ //\r
+ // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string.\r
+ // However, the length of the entire structure table (including all strings) must be reported\r
+ // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,\r
+ // which is a WORD field limited to 65,535 bytes.\r
+ //\r
+ MaxLen = SMBIOS_TABLE_MAX_LENGTH;\r
+ }\r
+\r
+ for (StrLen = 0 ; StrLen < MaxLen; StrLen++) {\r
if (*(CharInStr+StrLen) == 0) {\r
break;\r
- } \r
+ }\r
}\r
\r
- if (StrLen == SMBIOS_STRING_MAX_LENGTH) {\r
+ if (StrLen == MaxLen) {\r
return EFI_INVALID_PARAMETER;\r
}\r
+\r
//\r
// forward the pointer\r
//\r
CharInStr += StrLen;\r
*Size += StrLen;\r
- \r
- }\r
-\r
- if (*NumberOfStrings > 0) {\r
*NumberOfStrings += 1;\r
}\r
+\r
//\r
// count ending two zeros.\r
//\r
*Size += 2;\r
- return EFI_SUCCESS; \r
+ return EFI_SUCCESS;\r
}\r
\r
/**\r
\r
Determin whether an SmbiosHandle has already in use.\r
\r
- @param Head Pointer to the beginning of smbios structure.\r
+ @param Head Pointer to the beginning of SMBIOS structure.\r
@param Handle A unique handle will be assigned to the SMBIOS record.\r
\r
@retval TRUE Smbios handle already in use.\r
\r
Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
Head = &Private->AllocatedHandleListHead;\r
- for (AvailableHandle = 1; AvailableHandle < MaxSmbiosHandle; AvailableHandle++) {\r
+ for (AvailableHandle = 0; AvailableHandle < MaxSmbiosHandle; AvailableHandle++) {\r
if (!CheckSmbiosHandleExistance(Head, AvailableHandle)) {\r
*Handle = AvailableHandle;\r
return EFI_SUCCESS;\r
@param This The EFI_SMBIOS_PROTOCOL instance.\r
@param ProducerHandle The handle of the controller or driver associated with the SMBIOS information. NULL\r
means no handle.\r
- @param SmbiosHandle On entry, if non-zero, the handle of the SMBIOS record. If zero, then a unique handle\r
- will be assigned to the SMBIOS record. If the SMBIOS handle is already in use\r
+ @param SmbiosHandle On entry, the handle of the SMBIOS record to add. If FFFEh, then a unique handle\r
+ will be assigned to the SMBIOS record. If the SMBIOS handle is already in use,\r
EFI_ALREADY_STARTED is returned and the SMBIOS record is not updated.\r
@param Record The data for the fixed portion of the SMBIOS record. The format of the record is\r
determined by EFI_SMBIOS_TABLE_HEADER.Type. The size of the formatted area is defined \r
// Check whether SmbiosHandle is already in use\r
//\r
Head = &Private->AllocatedHandleListHead;\r
- if (*SmbiosHandle != 0 && CheckSmbiosHandleExistance(Head, *SmbiosHandle)) {\r
+ if (*SmbiosHandle != SMBIOS_HANDLE_PI_RESERVED && CheckSmbiosHandleExistance(Head, *SmbiosHandle)) {\r
return EFI_ALREADY_STARTED;\r
}\r
\r
//\r
- // when SmbiosHandle is zero, an available handle will be assigned\r
+ // when SmbiosHandle is 0xFFFE, an available handle will be assigned\r
//\r
- if (*SmbiosHandle == 0) {\r
+ if (*SmbiosHandle == SMBIOS_HANDLE_PI_RESERVED) {\r
Status = GetAvailableSmbiosHandle(This, SmbiosHandle);\r
if (EFI_ERROR(Status)) {\r
return Status;\r
//\r
// Calculate record size and string number\r
//\r
- Status = GetSmbiosStructureSize(Record, &StructureSize, &NumberOfStrings);\r
+ Status = GetSmbiosStructureSize(This, Record, &StructureSize, &NumberOfStrings);\r
if (EFI_ERROR(Status)) {\r
return Status;\r
}\r
\r
+ if (EntryPointStructure->TableLength + StructureSize > SMBIOS_TABLE_MAX_LENGTH) {\r
+ //\r
+ // The length of the entire structure table (including all strings) must be reported\r
+ // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,\r
+ // which is a WORD field limited to 65,535 bytes.\r
+ //\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
//\r
// Enter into critical section\r
// \r
//\r
// Allocate internal buffer\r
//\r
- SmbiosEntry = AllocatePool (TotalSize);\r
+ SmbiosEntry = AllocateZeroPool (TotalSize);\r
if (SmbiosEntry == NULL) {\r
EfiReleaseLock (&Private->DataLock);\r
return EFI_OUT_OF_RESOURCES;\r
}\r
- HandleEntry = AllocatePool (sizeof(SMBIOS_HANDLE_ENTRY));\r
+ HandleEntry = AllocateZeroPool (sizeof(SMBIOS_HANDLE_ENTRY));\r
if (HandleEntry == NULL) {\r
EfiReleaseLock (&Private->DataLock);\r
return EFI_OUT_OF_RESOURCES;\r
//\r
// Build Handle Entry and insert into linked list\r
//\r
- ZeroMem(HandleEntry, sizeof(SMBIOS_HANDLE_ENTRY));\r
HandleEntry->Signature = SMBIOS_HANDLE_ENTRY_SIGNATURE;\r
HandleEntry->SmbiosHandle = *SmbiosHandle;\r
InsertTailList(&Private->AllocatedHandleListHead, &HandleEntry->Link);\r
\r
- ZeroMem (SmbiosEntry, TotalSize);\r
InternalRecord = (EFI_SMBIOS_RECORD_HEADER *) (SmbiosEntry + 1);\r
Raw = (VOID *) (InternalRecord + 1);\r
\r
// Build internal record Header\r
//\r
InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION;\r
- InternalRecord->HeaderSize = sizeof (EFI_SMBIOS_RECORD_HEADER);\r
+ InternalRecord->HeaderSize = (UINT16) sizeof (EFI_SMBIOS_RECORD_HEADER);\r
InternalRecord->RecordSize = RecordSize;\r
InternalRecord->ProducerHandle = ProducerHandle;\r
InternalRecord->NumberOfStrings = NumberOfStrings;\r
CopyMem (Raw, Record, StructureSize);\r
((EFI_SMBIOS_TABLE_HEADER*)Raw)->Handle = *SmbiosHandle;\r
\r
+ //\r
+ // Some UEFI drivers (such as network) need some information in SMBIOS table.\r
+ // Here we create SMBIOS table and publish it in\r
+ // configuration table, so other UEFI drivers can get SMBIOS table from\r
+ // configuration table without depending on PI SMBIOS protocol.\r
+ //\r
+ SmbiosTableConstruction ();\r
+ \r
//\r
// Leave critical section\r
//\r
\r
@retval EFI_SUCCESS SmbiosHandle had its StringNumber String updated.\r
@retval EFI_INVALID_PARAMETER SmbiosHandle does not exist.\r
- @retval EFI_UNSUPPORTED String was not added since it's longer than 64 significant characters.\r
+ @retval EFI_UNSUPPORTED String was not added because it is longer than the SMBIOS Table supports.\r
@retval EFI_NOT_FOUND The StringNumber.is not valid for this SMBIOS record.\r
\r
**/\r
}\r
\r
InputStrLen = AsciiStrLen(String);\r
- if (InputStrLen > SMBIOS_STRING_MAX_LENGTH) {\r
- return EFI_UNSUPPORTED;\r
+\r
+ if (This->MajorVersion < 2 || (This->MajorVersion == 2 && This->MinorVersion < 7)) {\r
+ if (InputStrLen > SMBIOS_STRING_MAX_LENGTH) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ } else {\r
+ //\r
+ // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string.\r
+ // However, the length of the entire structure table (including all strings) must be reported \r
+ // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,\r
+ // which is a WORD field limited to 65,535 bytes.\r
+ //\r
+ if (InputStrLen > SMBIOS_TABLE_MAX_LENGTH) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
}\r
\r
Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);\r
Record = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);\r
\r
- if ((UINTN)Record->Handle == *SmbiosHandle) {\r
+ if (Record->Handle == *SmbiosHandle) {\r
//\r
- // Find out the specified Smbios record\r
+ // Find out the specified SMBIOS record\r
//\r
if (*StringNumber > SmbiosEntry->RecordHeader->NumberOfStrings) {\r
EfiReleaseLock (&Private->DataLock);\r
//\r
// Point to unformed string section\r
//\r
- StrStart = (CHAR8*)Record + Record->Length;\r
+ StrStart = (CHAR8 *) Record + Record->Length;\r
\r
for (StrIndex = 1, TargetStrOffset = 0; StrIndex < *StringNumber; StrStart++, TargetStrOffset++) {\r
//\r
} \r
}\r
\r
+ if (*StrStart == 0) {\r
+ StrStart++;\r
+ TargetStrOffset++;\r
+ }\r
+ \r
//\r
// Now we get the string target\r
//\r
TargetStrLen = AsciiStrLen(StrStart);\r
if (InputStrLen == TargetStrLen) {\r
AsciiStrCpy(StrStart, String);\r
+ //\r
+ // Some UEFI drivers (such as network) need some information in SMBIOS table.\r
+ // Here we create SMBIOS table and publish it in\r
+ // configuration table, so other UEFI drivers can get SMBIOS table from\r
+ // configuration table without depending on PI SMBIOS protocol.\r
+ //\r
+ SmbiosTableConstruction ();\r
EfiReleaseLock (&Private->DataLock);\r
return EFI_SUCCESS;\r
}\r
\r
+ if (EntryPointStructure->TableLength + InputStrLen - TargetStrLen > SMBIOS_TABLE_MAX_LENGTH) {\r
+ //\r
+ // The length of the entire structure table (including all strings) must be reported\r
+ // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,\r
+ // which is a WORD field limited to 65,535 bytes.\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
//\r
// Original string buffer size is not exactly match input string length.\r
// Re-allocate buffer is needed.\r
//\r
NewEntrySize = SmbiosEntry->RecordSize + InputStrLen - TargetStrLen;\r
- ResizedSmbiosEntry = AllocatePool (NewEntrySize);\r
+ ResizedSmbiosEntry = AllocateZeroPool (NewEntrySize);\r
\r
if (ResizedSmbiosEntry == NULL) {\r
EfiReleaseLock (&Private->DataLock);\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
- ZeroMem (ResizedSmbiosEntry, NewEntrySize);\r
InternalRecord = (EFI_SMBIOS_RECORD_HEADER *) (ResizedSmbiosEntry + 1);\r
Raw = (VOID *) (InternalRecord + 1);\r
\r
// Build internal record Header\r
//\r
InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION;\r
- InternalRecord->HeaderSize = sizeof (EFI_SMBIOS_RECORD_HEADER);\r
+ InternalRecord->HeaderSize = (UINT16) sizeof (EFI_SMBIOS_RECORD_HEADER);\r
InternalRecord->RecordSize = SmbiosEntry->RecordHeader->RecordSize + InputStrLen - TargetStrLen;\r
InternalRecord->ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;\r
InternalRecord->NumberOfStrings = SmbiosEntry->RecordHeader->NumberOfStrings;\r
\r
//\r
- // Copy smbios structure and optional strings.\r
+ // Copy SMBIOS structure and optional strings.\r
//\r
- CopyMem (Raw, SmbiosEntry->RecordHeader + 1, sizeof(EFI_SMBIOS_TABLE_HEADER) + TargetStrOffset);\r
- CopyMem ((VOID*)((UINTN)Raw + sizeof(EFI_SMBIOS_TABLE_HEADER) + TargetStrOffset), String, InputStrLen + 1);\r
- AsciiStrCpy((CHAR8*)((UINTN)Raw + sizeof(EFI_SMBIOS_TABLE_HEADER) + TargetStrOffset + InputStrLen + 1), (CHAR8*)Record + Record->Length + TargetStrOffset + TargetStrLen + 1);\r
+ CopyMem (Raw, SmbiosEntry->RecordHeader + 1, Record->Length + TargetStrOffset);\r
+ CopyMem ((VOID*)((UINTN)Raw + Record->Length + TargetStrOffset), String, InputStrLen + 1);\r
+ CopyMem ((CHAR8*)((UINTN)Raw + Record->Length + TargetStrOffset + InputStrLen + 1),\r
+ (CHAR8*)Record + Record->Length + TargetStrOffset + TargetStrLen + 1,\r
+ SmbiosEntry->RecordHeader->RecordSize - sizeof (EFI_SMBIOS_RECORD_HEADER) - Record->Length - TargetStrOffset - TargetStrLen - 1);\r
\r
//\r
// Insert new record\r
//\r
RemoveEntryList(Link);\r
FreePool(SmbiosEntry);\r
+ //\r
+ // Some UEFI drivers (such as network) need some information in SMBIOS table.\r
+ // Here we create SMBIOS table and publish it in\r
+ // configuration table, so other UEFI drivers can get SMBIOS table from\r
+ // configuration table without depending on PI SMBIOS protocol.\r
+ //\r
+ SmbiosTableConstruction ();\r
EfiReleaseLock (&Private->DataLock);\r
return EFI_SUCCESS;\r
}\r
for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);\r
Record = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);\r
- if ((UINTN)Record->Handle == SmbiosHandle) {\r
+ if (Record->Handle == SmbiosHandle) {\r
//\r
// Remove specified smobios record from DataList\r
//\r
Head = &Private->AllocatedHandleListHead;\r
for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
HandleEntry = SMBIOS_HANDLE_ENTRY_FROM_LINK(Link);\r
- if ((UINTN)HandleEntry->SmbiosHandle == SmbiosHandle) {\r
+ if (HandleEntry->SmbiosHandle == SmbiosHandle) {\r
RemoveEntryList(Link);\r
FreePool(HandleEntry);\r
break;\r
}\r
}\r
+ //\r
+ // Some UEFI drivers (such as network) need some information in SMBIOS table.\r
+ // Here we create SMBIOS table and publish it in\r
+ // configuration table, so other UEFI drivers can get SMBIOS table from\r
+ // configuration table without depending on PI SMBIOS protocol.\r
+ //\r
+ SmbiosTableConstruction ();\r
EfiReleaseLock (&Private->DataLock);\r
return EFI_SUCCESS;\r
}\r
\r
@param This The EFI_SMBIOS_PROTOCOL instance.\r
@param SmbiosHandle On entry, points to the previous handle of the SMBIOS record. On exit, points to the\r
- next SMBIOS record handle. If it is zero on entry, then the first SMBIOS record\r
- handle will be returned. If it returns zero on exit, then there are no more SMBIOS records.\r
+ next SMBIOS record handle. If it is FFFEh on entry, then the first SMBIOS record\r
+ handle will be returned. If it returns FFFEh on exit, then there are no more SMBIOS records.\r
@param Type On entry it means return the next SMBIOS record of type Type. If a NULL is passed in \r
this functionally it ignored. Type is not modified by the GetNext() function.\r
@param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by\r
If a NULL pointer is passed in no data will be returned \r
\r
@retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.\r
- SmbiosHandle is the handle of the current SMBIOS record\r
@retval EFI_NOT_FOUND The SMBIOS record with SmbiosHandle was the last available record.\r
\r
**/\r
SmbiosTableHeader = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1); \r
\r
//\r
- // If SmbiosHandle is zero, the first matched SMBIOS record handle will be returned\r
+ // If SmbiosHandle is 0xFFFE, the first matched SMBIOS record handle will be returned\r
//\r
- if (*SmbiosHandle == 0) {\r
+ if (*SmbiosHandle == SMBIOS_HANDLE_PI_RESERVED) {\r
if ((Type != NULL) && (*Type != SmbiosTableHeader->Type)) {\r
continue; \r
}\r
}\r
\r
//\r
- // Start this round search from the next Smbios handle\r
+ // Start this round search from the next SMBIOS handle\r
//\r
if (!StartPointFound && (*SmbiosHandle == SmbiosTableHeader->Handle)) {\r
StartPointFound = TRUE;\r
}\r
}\r
\r
- *SmbiosHandle = 0;\r
+ *SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;\r
return EFI_NOT_FOUND;\r
\r
}\r
\r
+/**\r
+ Allow the caller to discover all of the SMBIOS records.\r
+\r
+ @param This The EFI_SMBIOS_PROTOCOL instance.\r
+ @param CurrentSmbiosEntry On exit, points to the SMBIOS entry on the list which includes the returned SMBIOS record information. \r
+ If *CurrentSmbiosEntry is NULL on entry, then the first SMBIOS entry on the list will be returned. \r
+ @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by\r
+ the unformatted area. The unformatted area optionally contains text strings.\r
+ \r
+ @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.\r
+ *CurrentSmbiosEntry points to the SMBIOS entry which includes the returned SMBIOS record information.\r
+ @retval EFI_NOT_FOUND There is no more SMBIOS entry.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetNextSmbiosRecord (\r
+ IN CONST EFI_SMBIOS_PROTOCOL *This,\r
+ IN OUT EFI_SMBIOS_ENTRY **CurrentSmbiosEntry,\r
+ OUT EFI_SMBIOS_TABLE_HEADER **Record\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *Head;\r
+ SMBIOS_INSTANCE *Private;\r
+ EFI_SMBIOS_ENTRY *SmbiosEntry;\r
+ EFI_SMBIOS_TABLE_HEADER *SmbiosTableHeader;\r
+\r
+ Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
+ if (*CurrentSmbiosEntry == NULL) {\r
+ //\r
+ // Get the beginning of SMBIOS entry.\r
+ //\r
+ Head = &Private->DataListHead;\r
+ } else {\r
+ //\r
+ // Get previous SMBIOS entry and make it as start point.\r
+ //\r
+ Head = &(*CurrentSmbiosEntry)->Link;\r
+ }\r
+ \r
+ Link = Head->ForwardLink;\r
+ \r
+ if (Link == &Private->DataListHead) {\r
+ //\r
+ // If no more SMBIOS entry in the list, return not found.\r
+ //\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ \r
+ SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);\r
+ SmbiosTableHeader = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);\r
+ *Record = SmbiosTableHeader; \r
+ *CurrentSmbiosEntry = SmbiosEntry;\r
+ return EFI_SUCCESS; \r
+}\r
\r
/**\r
- Assembles Smbios table from the SMBIOS protocol. Produce Table\r
+ Assembles SMBIOS table from the SMBIOS protocol. Produce Table\r
Entry Point and return the pointer to it.\r
\r
@param TableEntryPointStructure On exit, points to the SMBIOS entrypoint structure.\r
OUT VOID **TableEntryPointStructure\r
)\r
{\r
- UINT8 CheckSum;\r
UINT8 *BufferPointer;\r
- UINTN Index;\r
UINTN RecordSize;\r
UINTN NumOfStr;\r
EFI_STATUS Status;\r
EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
EFI_SMBIOS_TABLE_HEADER *SmbiosRecord;\r
EFI_SMBIOS_TABLE_END_STRUCTURE EndStructure;\r
+ EFI_SMBIOS_ENTRY *CurrentSmbiosEntry;\r
\r
Status = EFI_SUCCESS;\r
BufferPointer = NULL;\r
- CheckSum = 0;\r
-\r
- //\r
- // Initialize the EntryPointStructure with initial values.\r
- //\r
- if (EntryPointStructure == NULL) {\r
- //\r
- // Allocate memory (below 4GB)\r
- //\r
- PhysicalAddress = 0xffffffff;\r
- Status = gBS->AllocatePages (\r
- AllocateMaxAddress,\r
- EfiReservedMemoryType,\r
- EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT)),\r
- &PhysicalAddress\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) (UINTN) PhysicalAddress;\r
- \r
- CopyMem (\r
- EntryPointStructure,\r
- &EntryPointStructureData,\r
- sizeof (SMBIOS_TABLE_ENTRY_POINT)\r
- );\r
- }\r
\r
//\r
- // Free the original image\r
- //\r
- if (EntryPointStructure->TableAddress) {\r
- FreePages (\r
- (VOID*)(UINTN)EntryPointStructure->TableAddress,\r
- EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength)\r
- );\r
- EntryPointStructure->TableAddress = 0;\r
- }\r
- \r
- //\r
- // Locate smbios protocol to traverse smbios records.\r
+ // Get Smbios protocol to traverse SMBIOS records.\r
//\r
- gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **) &SmbiosProtocol);\r
- \r
- ASSERT (SmbiosProtocol != NULL);\r
+ SmbiosProtocol = &mPrivateData.Smbios;\r
\r
//\r
// Make some statistics about all the structures\r
EntryPointStructure->NumberOfSmbiosStructures = 0;\r
EntryPointStructure->TableLength = 0;\r
EntryPointStructure->MaxStructureSize = 0;\r
- SmbiosHandle = 0;\r
\r
//\r
// Calculate EPS Table Length\r
//\r
+ CurrentSmbiosEntry = NULL;\r
do {\r
- Status = SmbiosProtocol->GetNext (\r
- SmbiosProtocol,\r
- &SmbiosHandle,\r
- NULL,\r
- &SmbiosRecord,\r
- NULL\r
- );\r
+ Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);\r
\r
if (Status == EFI_SUCCESS) {\r
- GetSmbiosStructureSize(SmbiosRecord, &RecordSize, &NumOfStr);\r
+ GetSmbiosStructureSize(SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);\r
//\r
// Record NumberOfSmbiosStructures, TableLength and MaxStructureSize\r
//\r
//\r
GetMaxSmbiosHandle(SmbiosProtocol, &SmbiosHandle);\r
EndStructure.Header.Type = EFI_SMBIOS_TYPE_END_OF_TABLE;\r
- EndStructure.Header.Length = sizeof(EFI_SMBIOS_TABLE_HEADER);\r
+ EndStructure.Header.Length = (UINT8) sizeof (EFI_SMBIOS_TABLE_HEADER);\r
EndStructure.Header.Handle = SmbiosHandle;\r
EndStructure.Tailing[0] = 0;\r
EndStructure.Tailing[1] = 0;\r
if (sizeof (EndStructure) > EntryPointStructure->MaxStructureSize) {\r
EntryPointStructure->MaxStructureSize = (UINT16) sizeof (EndStructure);\r
}\r
- \r
- //\r
- // Allocate memory (below 4GB)\r
- //\r
- PhysicalAddress = 0xffffffff;\r
- Status = gBS->AllocatePages (\r
- AllocateMaxAddress,\r
- EfiReservedMemoryType,\r
- EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength),\r
- &PhysicalAddress\r
- );\r
- if (EFI_ERROR (Status)) {\r
- FreePages ((VOID*)(UINTN)EntryPointStructure, EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength));\r
- EntryPointStructure = NULL;\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
\r
- EntryPointStructure->TableAddress = (UINT32) PhysicalAddress;\r
+ if ((UINTN) EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength) > mPreAllocatedPages) {\r
+ //\r
+ // If new SMBIOS talbe size exceeds the original pre-allocated page, \r
+ // it is time to re-allocate memory (below 4GB).\r
+ // \r
+ if (EntryPointStructure->TableAddress != 0) {\r
+ //\r
+ // Free the original pre-allocated page\r
+ // \r
+ FreePages (\r
+ (VOID*)(UINTN)EntryPointStructure->TableAddress,\r
+ mPreAllocatedPages\r
+ );\r
+ EntryPointStructure->TableAddress = 0;\r
+ mPreAllocatedPages = 0;\r
+ }\r
+ \r
+ PhysicalAddress = 0xffffffff;\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiRuntimeServicesData,\r
+ EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength),\r
+ &PhysicalAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SmbiosCreateTable() could not allocate SMBIOS table < 4GB\n"));\r
+ EntryPointStructure->TableAddress = 0;\r
+ return EFI_OUT_OF_RESOURCES;\r
+ } else {\r
+ EntryPointStructure->TableAddress = (UINT32) PhysicalAddress;\r
+ mPreAllocatedPages = EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength);\r
+ }\r
+ }\r
\r
//\r
// Assemble the tables\r
//\r
- BufferPointer = (UINT8 *) (UINTN) PhysicalAddress;\r
- SmbiosHandle = 0;\r
+ ASSERT (EntryPointStructure->TableAddress != 0);\r
+ BufferPointer = (UINT8 *) (UINTN) EntryPointStructure->TableAddress;\r
+ CurrentSmbiosEntry = NULL;\r
do {\r
- Status = SmbiosProtocol->GetNext (\r
- SmbiosProtocol,\r
- &SmbiosHandle,\r
- NULL,\r
- &SmbiosRecord,\r
- NULL\r
- );\r
+ Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);\r
+\r
if (Status == EFI_SUCCESS) {\r
- GetSmbiosStructureSize(SmbiosRecord, &RecordSize, &NumOfStr);\r
+ GetSmbiosStructureSize(SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);\r
CopyMem (BufferPointer, SmbiosRecord, RecordSize);\r
BufferPointer = BufferPointer + RecordSize;\r
}\r
//\r
// Fixup checksums in the Entry Point Structure\r
//\r
- CheckSum = 0;\r
EntryPointStructure->IntermediateChecksum = 0;\r
- for (Index = 0x10; Index < EntryPointStructure->EntryPointLength; Index++) {\r
- CheckSum = (UINT8) (CheckSum + ((UINT8 *) (EntryPointStructure))[Index]);\r
- }\r
-\r
- EntryPointStructure->IntermediateChecksum = (UINT8) (0 - CheckSum);\r
-\r
- CheckSum = 0;\r
EntryPointStructure->EntryPointStructureChecksum = 0;\r
- for (Index = 0x0; Index < EntryPointStructure->EntryPointLength; Index++) {\r
- CheckSum = (UINT8) (CheckSum + ((UINT8 *) (EntryPointStructure))[Index]);\r
- }\r
\r
- EntryPointStructure->EntryPointStructureChecksum = (UINT8) (0 - CheckSum);\r
+ EntryPointStructure->IntermediateChecksum =\r
+ CalculateCheckSum8 ((UINT8 *) EntryPointStructure + 0x10, EntryPointStructure->EntryPointLength - 0x10);\r
+ EntryPointStructure->EntryPointStructureChecksum =\r
+ CalculateCheckSum8 ((UINT8 *) EntryPointStructure, EntryPointStructure->EntryPointLength);\r
\r
//\r
// Returns the pointer\r
return EFI_SUCCESS;\r
}\r
\r
-\r
-\r
/**\r
- Installs the Smbios Table to the System Table. This function gets called\r
- when the EFI_EVENT_SIGNAL_READY_TO_BOOT gets signaled\r
- \r
- @param Event The event to signal\r
- @param Context Event contex\r
-\r
+ Create SMBIOS Table and install it to the System Table.\r
**/\r
VOID\r
EFIAPI\r
SmbiosTableConstruction (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
+ VOID\r
)\r
{\r
UINT8 *Eps;\r
}\r
}\r
\r
-\r
/**\r
\r
- Driver to produce Smbios protocol and register event for constructing SMBIOS table. \r
+ Driver to produce Smbios protocol and pre-allocate 1 page for the final SMBIOS table. \r
\r
@param ImageHandle Module's image handle\r
@param SystemTable Pointer of EFI_SYSTEM_TABLE\r
)\r
{\r
EFI_STATUS Status;\r
- EFI_EVENT ReadyToBootEvent;\r
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
\r
mPrivateData.Signature = SMBIOS_INSTANCE_SIGNATURE;\r
mPrivateData.Smbios.Add = SmbiosAdd;\r
mPrivateData.Smbios.UpdateString = SmbiosUpdateString;\r
mPrivateData.Smbios.Remove = SmbiosRemove;\r
mPrivateData.Smbios.GetNext = SmbiosGetNext;\r
- mPrivateData.Smbios.MajorVersion = SMBIOS_MAJOR_VERSION;\r
- mPrivateData.Smbios.MinorVersion = SMBIOS_MINOR_VERSION;\r
+ mPrivateData.Smbios.MajorVersion = (UINT8) (PcdGet16 (PcdSmbiosVersion) >> 8);\r
+ mPrivateData.Smbios.MinorVersion = (UINT8) (PcdGet16 (PcdSmbiosVersion) & 0x00ff);\r
+ EntryPointStructureData.MajorVersion = mPrivateData.Smbios.MajorVersion;\r
+ EntryPointStructureData.MinorVersion = mPrivateData.Smbios.MinorVersion;\r
+ EntryPointStructureData.SmbiosBcdRevision = (UINT8) ((PcdGet16 (PcdSmbiosVersion) >> 4) & 0xf0) | (UINT8) (PcdGet16 (PcdSmbiosVersion) & 0x0f);\r
\r
InitializeListHead (&mPrivateData.DataListHead);\r
InitializeListHead (&mPrivateData.AllocatedHandleListHead);\r
EfiInitializeLock (&mPrivateData.DataLock, TPL_NOTIFY);\r
+\r
+ //\r
+ // Initialize the EntryPointStructure with initial values.\r
+ // Allocate memory (below 4GB).\r
+ //\r
+ PhysicalAddress = 0xffffffff;\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiRuntimeServicesData,\r
+ EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT)),\r
+ &PhysicalAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SmbiosDriverEntryPoint() could not allocate EntryPointStructure < 4GB\n"));\r
+ Status = gBS->AllocatePages (\r
+ AllocateAnyPages,\r
+ EfiRuntimeServicesData,\r
+ EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT)),\r
+ &PhysicalAddress\r
+ );\r
+ if (EFI_ERROR (Status)) { \r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ }\r
+\r
+ EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) (UINTN) PhysicalAddress;\r
+ \r
+ CopyMem (\r
+ EntryPointStructure,\r
+ &EntryPointStructureData,\r
+ sizeof (SMBIOS_TABLE_ENTRY_POINT)\r
+ );\r
+\r
+ //\r
+ // Pre-allocate 1 page for SMBIOS table below 4GB.\r
+ // SMBIOS table will be updated when new SMBIOS type is added or \r
+ // existing SMBIOS type is updated. If the total size of SMBIOS table exceeds 1 page,\r
+ // we will re-allocate new memory when creating whole SMBIOS table.\r
+ //\r
+ PhysicalAddress = 0xffffffff;\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiRuntimeServicesData,\r
+ 1,\r
+ &PhysicalAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SmbiosDriverEntryPoint() could not allocate SMBIOS table < 4GB\n"));\r
+ EntryPointStructure->TableAddress = 0;\r
+ } else {\r
+ EntryPointStructure->TableAddress = (UINT32) PhysicalAddress;\r
+ mPreAllocatedPages = 1;\r
+ }\r
+\r
+ //\r
+ // Init TableLength to the length of End-Of-Table structure for SmbiosAdd() called at the first time\r
+ // to check the TableLength limitation.\r
+ //\r
+ EntryPointStructure->TableLength = sizeof (EFI_SMBIOS_TABLE_END_STRUCTURE);\r
\r
//\r
// Make a new handle and install the protocol\r
&mPrivateData.Smbios\r
);\r
\r
- if (EFI_ERROR(Status)) {\r
- return Status;\r
- }\r
- //\r
- // Register the event to install SMBIOS Table into EFI System Table\r
- //\r
- Status = gBS->CreateEventEx (\r
- EVT_NOTIFY_SIGNAL,\r
- TPL_NOTIFY,\r
- SmbiosTableConstruction,\r
- NULL,\r
- &gEfiEventReadyToBootGuid,\r
- &ReadyToBootEvent\r
- );\r
- \r
return Status;\r
}\r