--- /dev/null
+/** @file\r
+ 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
+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
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#include "SmbiosDxe.h"\r
+\r
+//\r
+// Module Global:\r
+// Since this driver will only ever produce one instance of the\r
+// protocol you are not required to dynamically allocate the PrivateData.\r
+//\r
+SMBIOS_INSTANCE mPrivateData;\r
+\r
+//\r
+// Chassis for SMBIOS entry point structure that is to be installed into EFI system config table.\r
+//\r
+SMBIOS_TABLE_ENTRY_POINT *EntryPointStructure = NULL;\r
+SMBIOS_TABLE_ENTRY_POINT EntryPointStructureData = {\r
+ //\r
+ // AnchorString\r
+ //\r
+ {\r
+ 0x5f,\r
+ 0x53,\r
+ 0x4d,\r
+ 0x5f\r
+ },\r
+ //\r
+ // EntryPointStructureChecksum,TO BE FILLED\r
+ //\r
+ 0,\r
+ //\r
+ // EntryPointStructure Length\r
+ //\r
+ 0x1f,\r
+ //\r
+ // MajorVersion: 2 (Version 2.4)\r
+ //\r
+ 0x02,\r
+ //\r
+ // MinorVersion: 4 (Version 2.4)\r
+ //\r
+ 0x04,\r
+ //\r
+ // MaxStructureSize, TO BE FILLED\r
+ //\r
+ 0,\r
+ //\r
+ // EntryPointRevision\r
+ //\r
+ 0,\r
+ //\r
+ // FormattedArea\r
+ //\r
+ {\r
+ 0,\r
+ 0,\r
+ 0,\r
+ 0,\r
+ 0\r
+ },\r
+ //\r
+ // IntermediateAnchorString\r
+ //\r
+ {\r
+ 0x5f,\r
+ 0x44,\r
+ 0x4d,\r
+ 0x49,\r
+ 0x5f\r
+ },\r
+ //\r
+ // IntermediateChecksum, TO BE FILLED\r
+ //\r
+ 0,\r
+ //\r
+ // StructureTableLength, TO BE FILLED\r
+ //\r
+ 0,\r
+ //\r
+ // StructureTableAddress, TO BE FILLED\r
+ //\r
+ 0,\r
+ //\r
+ // NumberOfSmbiosStructures, TO BE FILLED\r
+ //\r
+ 0,\r
+ //\r
+ // SmbiosBcdRevision\r
+ //\r
+ 0 \r
+};\r
+\r
+\r
+/**\r
+\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 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
+ \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetSmbiosStructureSize (\r
+ IN EFI_SMBIOS_TABLE_HEADER *Head,\r
+ OUT UINTN *Size,\r
+ OUT UINTN *NumberOfStrings\r
+ )\r
+{\r
+ UINTN FullSize;\r
+ UINT8 StrLen;\r
+ INT8* CharInStr;\r
+ \r
+ if (Size == NULL || NumberOfStrings == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ FullSize = Head->Length;\r
+ CharInStr = (INT8*)Head + Head->Length;\r
+ *Size = FullSize;\r
+ *NumberOfStrings = 0;\r
+ StrLen = 0;\r
+ //\r
+ // look for the two consecutive zeros, check the string limit by the way.\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 (*(CharInStr+StrLen) == 0) {\r
+ break;\r
+ } \r
+ }\r
+\r
+ if (StrLen == SMBIOS_STRING_MAX_LENGTH) {\r
+ return EFI_INVALID_PARAMETER;\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
+ // count ending two zeros.\r
+ //\r
+ *Size += 2;\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 Handle A unique handle will be assigned to the SMBIOS record.\r
+\r
+ @retval TRUE Smbios handle already in use.\r
+ @retval FALSE Smbios handle is NOT used.\r
+ \r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+CheckSmbiosHandleExistance (\r
+ IN LIST_ENTRY *Head,\r
+ IN EFI_SMBIOS_HANDLE Handle\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ SMBIOS_HANDLE_ENTRY *HandleEntry;\r
+ \r
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
+ HandleEntry = SMBIOS_HANDLE_ENTRY_FROM_LINK(Link);\r
+ if (HandleEntry->SmbiosHandle == Handle) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+\r
+ Get the max SmbiosHandle that could be use.\r
+\r
+ @param This The EFI_SMBIOS_PROTOCOL instance.\r
+ @param MaxHandle The max handle that could be assigned to the SMBIOS record.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+GetMaxSmbiosHandle (\r
+ IN CONST EFI_SMBIOS_PROTOCOL *This,\r
+ IN OUT EFI_SMBIOS_HANDLE *MaxHandle\r
+ ) \r
+{\r
+ if (This->MajorVersion == 2 && This->MinorVersion == 0) {\r
+ *MaxHandle = 0xFFFE;\r
+ } else {\r
+ *MaxHandle = 0xFEFF;\r
+ }\r
+}\r
+\r
+/**\r
+\r
+ Get an SmbiosHandle that could use.\r
+\r
+ @param This The EFI_SMBIOS_PROTOCOL instance.\r
+ @param SmbiosHandle A unique handle will be assigned to the SMBIOS record.\r
+\r
+ @retval EFI_SUCCESS Smbios handle got.\r
+ @retval EFI_OUT_OF_RESOURCES Smbios handle is NOT available.\r
+ \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetAvailableSmbiosHandle (\r
+ IN CONST EFI_SMBIOS_PROTOCOL *This,\r
+ IN OUT EFI_SMBIOS_HANDLE *Handle\r
+ )\r
+{\r
+ LIST_ENTRY *Head;\r
+ SMBIOS_INSTANCE *Private;\r
+ EFI_SMBIOS_HANDLE MaxSmbiosHandle;\r
+ EFI_SMBIOS_HANDLE AvailableHandle;\r
+\r
+ GetMaxSmbiosHandle(This, &MaxSmbiosHandle);\r
+\r
+ Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
+ Head = &Private->AllocatedHandleListHead;\r
+ for (AvailableHandle = 1; AvailableHandle < MaxSmbiosHandle; AvailableHandle++) {\r
+ if (!CheckSmbiosHandleExistance(Head, AvailableHandle)) {\r
+ *Handle = AvailableHandle;\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return EFI_OUT_OF_RESOURCES;\r
+}\r
+\r
+\r
+/**\r
+ Add an SMBIOS record.\r
+\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
+ 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
+ by EFI_SMBIOS_TABLE_HEADER.Length and either followed by a double-null (0x0000) or \r
+ a set of null terminated strings and a null.\r
+\r
+ @retval EFI_SUCCESS Record was added.\r
+ @retval EFI_OUT_OF_RESOURCES Record was not added due to lack of system resources.\r
+ @retval EFI_ALREADY_STARTED The SmbiosHandle passed in was already in use.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmbiosAdd (\r
+ IN CONST EFI_SMBIOS_PROTOCOL *This,\r
+ IN EFI_HANDLE ProducerHandle, OPTIONAL\r
+ IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle,\r
+ IN EFI_SMBIOS_TABLE_HEADER *Record\r
+ )\r
+{\r
+ VOID *Raw;\r
+ UINTN TotalSize;\r
+ UINTN RecordSize;\r
+ UINTN StructureSize;\r
+ UINTN NumberOfStrings;\r
+ EFI_STATUS Status;\r
+ LIST_ENTRY *Head;\r
+ SMBIOS_INSTANCE *Private;\r
+ EFI_SMBIOS_ENTRY *SmbiosEntry;\r
+ EFI_SMBIOS_HANDLE MaxSmbiosHandle;\r
+ SMBIOS_HANDLE_ENTRY *HandleEntry;\r
+ EFI_SMBIOS_RECORD_HEADER *InternalRecord;\r
+ \r
+ if (SmbiosHandle == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ \r
+ Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
+ //\r
+ // Check whether SmbiosHandle is already in use\r
+ //\r
+ Head = &Private->AllocatedHandleListHead;\r
+ if (*SmbiosHandle != 0 && CheckSmbiosHandleExistance(Head, *SmbiosHandle)) {\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ //\r
+ // when SmbiosHandle is zero, an available handle will be assigned\r
+ //\r
+ if (*SmbiosHandle == 0) {\r
+ Status = GetAvailableSmbiosHandle(This, SmbiosHandle);\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+ } else {\r
+ //\r
+ // Check this handle validity\r
+ //\r
+ GetMaxSmbiosHandle(This, &MaxSmbiosHandle);\r
+ if (*SmbiosHandle > MaxSmbiosHandle) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Calculate record size and string number\r
+ //\r
+ Status = GetSmbiosStructureSize(Record, &StructureSize, &NumberOfStrings);\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Enter into critical section\r
+ // \r
+ Status = EfiAcquireLockOrFail (&Private->DataLock);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ \r
+ RecordSize = sizeof (EFI_SMBIOS_RECORD_HEADER) + StructureSize;\r
+ TotalSize = sizeof (EFI_SMBIOS_ENTRY) + RecordSize;\r
+\r
+ //\r
+ // Allocate internal buffer\r
+ //\r
+ SmbiosEntry = AllocatePool (TotalSize);\r
+ if (SmbiosEntry == NULL) {\r
+ EfiReleaseLock (&Private->DataLock);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ HandleEntry = AllocatePool (sizeof(SMBIOS_HANDLE_ENTRY));\r
+ if (HandleEntry == NULL) {\r
+ EfiReleaseLock (&Private->DataLock);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\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
+ //\r
+ // Build internal record Header\r
+ //\r
+ InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION;\r
+ InternalRecord->HeaderSize = sizeof (EFI_SMBIOS_RECORD_HEADER);\r
+ InternalRecord->RecordSize = RecordSize;\r
+ InternalRecord->ProducerHandle = ProducerHandle;\r
+ InternalRecord->NumberOfStrings = NumberOfStrings;\r
+ //\r
+ // Insert record into the internal linked list\r
+ //\r
+ SmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE;\r
+ SmbiosEntry->RecordHeader = InternalRecord;\r
+ SmbiosEntry->RecordSize = TotalSize;\r
+ InsertTailList (&Private->DataListHead, &SmbiosEntry->Link);\r
+\r
+ CopyMem (Raw, Record, StructureSize);\r
+ ((EFI_SMBIOS_TABLE_HEADER*)Raw)->Handle = *SmbiosHandle;\r
+\r
+ //\r
+ // Leave critical section\r
+ //\r
+ EfiReleaseLock (&Private->DataLock);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Update the string associated with an existing SMBIOS record.\r
+\r
+ @param This The EFI_SMBIOS_PROTOCOL instance.\r
+ @param SmbiosHandle SMBIOS Handle of structure that will have its string updated.\r
+ @param StringNumber The non-zero string number of the string to update\r
+ @param String Update the StringNumber string with String.\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_NOT_FOUND The StringNumber.is not valid for this SMBIOS record.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmbiosUpdateString (\r
+ IN CONST EFI_SMBIOS_PROTOCOL *This,\r
+ IN EFI_SMBIOS_HANDLE *SmbiosHandle,\r
+ IN UINTN *StringNumber,\r
+ IN CHAR8 *String\r
+ )\r
+{\r
+ UINTN InputStrLen;\r
+ UINTN TargetStrLen;\r
+ UINTN StrIndex;\r
+ UINTN TargetStrOffset;\r
+ UINTN NewEntrySize;\r
+ CHAR8 *StrStart;\r
+ VOID *Raw;\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *Head;\r
+ EFI_STATUS Status;\r
+ SMBIOS_INSTANCE *Private;\r
+ EFI_SMBIOS_ENTRY *SmbiosEntry;\r
+ EFI_SMBIOS_ENTRY *ResizedSmbiosEntry;\r
+ EFI_SMBIOS_HANDLE MaxSmbiosHandle;\r
+ EFI_SMBIOS_TABLE_HEADER *Record;\r
+ EFI_SMBIOS_RECORD_HEADER *InternalRecord;\r
+ \r
+ //\r
+ // Check args validity\r
+ //\r
+ GetMaxSmbiosHandle(This, &MaxSmbiosHandle);\r
+\r
+ if (*SmbiosHandle > MaxSmbiosHandle) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (String == NULL) {\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ if (*StringNumber == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ InputStrLen = AsciiStrLen(String);\r
+ if (InputStrLen > SMBIOS_STRING_MAX_LENGTH) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
+ //\r
+ // Enter into critical section\r
+ // \r
+ Status = EfiAcquireLockOrFail (&Private->DataLock);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Head = &Private->DataListHead;\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
+\r
+ if ((UINTN)Record->Handle == *SmbiosHandle) {\r
+ //\r
+ // Find out the specified Smbios record\r
+ //\r
+ if (*StringNumber > SmbiosEntry->RecordHeader->NumberOfStrings) {\r
+ EfiReleaseLock (&Private->DataLock);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Point to unformed string section\r
+ //\r
+ StrStart = (CHAR8*)Record + Record->Length;\r
+ \r
+ for (StrIndex = 1, TargetStrOffset = 0; StrIndex < *StringNumber; StrStart++, TargetStrOffset++) {\r
+ //\r
+ // A string ends in 00h\r
+ //\r
+ if (*StrStart == 0) {\r
+ StrIndex++;\r
+ }\r
+ \r
+ //\r
+ // String section ends in double-null (0000h)\r
+ //\r
+ if (*StrStart == 0 && *(StrStart + 1) == 0) {\r
+ EfiReleaseLock (&Private->DataLock);\r
+ return EFI_NOT_FOUND;\r
+ } \r
+ }\r
+\r
+ //\r
+ // Now we get the string target\r
+ //\r
+ TargetStrLen = AsciiStrLen(StrStart);\r
+ if (InputStrLen == TargetStrLen) {\r
+ AsciiStrCpy(StrStart, String);\r
+ EfiReleaseLock (&Private->DataLock);\r
+ return EFI_SUCCESS;\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
+\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
+ //\r
+ // Build internal record Header\r
+ //\r
+ InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION;\r
+ InternalRecord->HeaderSize = 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
+ //\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
+\r
+ //\r
+ // Insert new record\r
+ //\r
+ ResizedSmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE;\r
+ ResizedSmbiosEntry->RecordHeader = InternalRecord;\r
+ ResizedSmbiosEntry->RecordSize = NewEntrySize;\r
+ InsertTailList (Link->ForwardLink, &ResizedSmbiosEntry->Link);\r
+\r
+ //\r
+ // Remove old record\r
+ //\r
+ RemoveEntryList(Link);\r
+ FreePool(SmbiosEntry);\r
+ EfiReleaseLock (&Private->DataLock);\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ EfiReleaseLock (&Private->DataLock);\r
+ return EFI_INVALID_PARAMETER;\r
+}\r
+\r
+/**\r
+ Remove an SMBIOS record.\r
+\r
+ @param This The EFI_SMBIOS_PROTOCOL instance.\r
+ @param SmbiosHandle The handle of the SMBIOS record to remove.\r
+\r
+ @retval EFI_SUCCESS SMBIOS record was removed.\r
+ @retval EFI_INVALID_PARAMETER SmbiosHandle does not specify a valid SMBIOS record.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmbiosRemove (\r
+ IN CONST EFI_SMBIOS_PROTOCOL *This,\r
+ IN EFI_SMBIOS_HANDLE SmbiosHandle\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *Head;\r
+ EFI_STATUS Status;\r
+ EFI_SMBIOS_HANDLE MaxSmbiosHandle;\r
+ SMBIOS_INSTANCE *Private;\r
+ EFI_SMBIOS_ENTRY *SmbiosEntry;\r
+ SMBIOS_HANDLE_ENTRY *HandleEntry;\r
+ EFI_SMBIOS_TABLE_HEADER *Record;\r
+\r
+ //\r
+ // Check args validity\r
+ //\r
+ GetMaxSmbiosHandle(This, &MaxSmbiosHandle);\r
+\r
+ if (SmbiosHandle > MaxSmbiosHandle) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
+ //\r
+ // Enter into critical section\r
+ // \r
+ Status = EfiAcquireLockOrFail (&Private->DataLock);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Head = &Private->DataListHead;\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
+ //\r
+ // Remove specified smobios record from DataList\r
+ //\r
+ RemoveEntryList(Link);\r
+ FreePool(SmbiosEntry);\r
+ // \r
+ // Remove this handle from AllocatedHandleList\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
+ RemoveEntryList(Link);\r
+ FreePool(HandleEntry);\r
+ break;\r
+ }\r
+ }\r
+ EfiReleaseLock (&Private->DataLock);\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Leave critical section\r
+ //\r
+ EfiReleaseLock (&Private->DataLock);\r
+ return EFI_INVALID_PARAMETER;\r
+ \r
+}\r
+\r
+/**\r
+ Allow the caller to discover all or some of the SMBIOS records.\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
+ @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
+ the unformatted area. The unformatted area optionally contains text strings.\r
+ @param ProducerHandle On exit, points to the ProducerHandle registered by Add(). If no ProducerHandle was passed into Add() NULL is returned. \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
+EFI_STATUS\r
+EFIAPI\r
+SmbiosGetNext (\r
+ IN CONST EFI_SMBIOS_PROTOCOL *This,\r
+ IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle,\r
+ IN EFI_SMBIOS_TYPE *Type, OPTIONAL\r
+ OUT EFI_SMBIOS_TABLE_HEADER **Record,\r
+ OUT EFI_HANDLE *ProducerHandle OPTIONAL\r
+ )\r
+{\r
+ BOOLEAN StartPointFound;\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
+ if (SmbiosHandle == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ StartPointFound = FALSE;\r
+ Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
+ Head = &Private->DataListHead;\r
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
+ SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);\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
+ //\r
+ if (*SmbiosHandle == 0) {\r
+ if ((Type != NULL) && (*Type != SmbiosTableHeader->Type)) {\r
+ continue; \r
+ }\r
+\r
+ *SmbiosHandle = SmbiosTableHeader->Handle;\r
+ *Record =SmbiosTableHeader;\r
+ if (ProducerHandle != NULL) {\r
+ *ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;\r
+ }\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Start this round search from the next Smbios handle\r
+ //\r
+ if (!StartPointFound && (*SmbiosHandle == SmbiosTableHeader->Handle)) {\r
+ StartPointFound = TRUE;\r
+ continue;\r
+ }\r
+\r
+ if (StartPointFound) {\r
+ if ((Type != NULL) && (*Type != SmbiosTableHeader->Type)) {\r
+ continue; \r
+ }\r
+ \r
+ *SmbiosHandle = SmbiosTableHeader->Handle;\r
+ *Record = SmbiosTableHeader; \r
+ if (ProducerHandle != NULL) {\r
+ *ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;\r
+ }\r
+\r
+ return EFI_SUCCESS; \r
+ }\r
+ }\r
+\r
+ *SmbiosHandle = 0;\r
+ return EFI_NOT_FOUND;\r
+ \r
+}\r
+\r
+\r
+/**\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
+ \r
+ @retval EFI_SUCCESS Structure created sucessfully.\r
+ @retval EFI_NOT_READY Some of The SMBIOS records was not available yet.\r
+ @retval EFI_OUT_OF_RESOURCES No enough memory.\r
+ \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmbiosCreateTable (\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_SMBIOS_HANDLE SmbiosHandle;\r
+ EFI_SMBIOS_PROTOCOL *SmbiosProtocol;\r
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
+ EFI_SMBIOS_TABLE_HEADER *SmbiosRecord;\r
+ EFI_SMBIOS_TABLE_END_STRUCTURE EndStructure;\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
+ //\r
+ gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **) &SmbiosProtocol);\r
+ \r
+ ASSERT (SmbiosProtocol != NULL);\r
+\r
+ //\r
+ // Make some statistics about all the structures\r
+ //\r
+ EntryPointStructure->NumberOfSmbiosStructures = 0;\r
+ EntryPointStructure->TableLength = 0;\r
+ EntryPointStructure->MaxStructureSize = 0;\r
+ SmbiosHandle = 0;\r
+\r
+ //\r
+ // Calculate EPS Table Length\r
+ //\r
+ do {\r
+ Status = SmbiosProtocol->GetNext (\r
+ SmbiosProtocol,\r
+ &SmbiosHandle,\r
+ NULL,\r
+ &SmbiosRecord,\r
+ NULL\r
+ );\r
+ \r
+ if (Status == EFI_SUCCESS) {\r
+ GetSmbiosStructureSize(SmbiosRecord, &RecordSize, &NumOfStr);\r
+ //\r
+ // Record NumberOfSmbiosStructures, TableLength and MaxStructureSize\r
+ //\r
+ EntryPointStructure->NumberOfSmbiosStructures++;\r
+ EntryPointStructure->TableLength = (UINT16) (EntryPointStructure->TableLength + RecordSize);\r
+ if (RecordSize > EntryPointStructure->MaxStructureSize) {\r
+ EntryPointStructure->MaxStructureSize = (UINT16) RecordSize;\r
+ }\r
+ }\r
+ } while (!EFI_ERROR(Status));\r
+ \r
+ //\r
+ // Create End-Of-Table structure\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.Handle = SmbiosHandle;\r
+ EndStructure.Tailing[0] = 0;\r
+ EndStructure.Tailing[1] = 0;\r
+ EntryPointStructure->NumberOfSmbiosStructures++;\r
+ EntryPointStructure->TableLength = (UINT16) (EntryPointStructure->TableLength + sizeof (EndStructure));\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
+ \r
+ //\r
+ // Assemble the tables\r
+ //\r
+ BufferPointer = (UINT8 *) (UINTN) PhysicalAddress;\r
+ SmbiosHandle = 0;\r
+ do {\r
+ Status = SmbiosProtocol->GetNext (\r
+ SmbiosProtocol,\r
+ &SmbiosHandle,\r
+ NULL,\r
+ &SmbiosRecord,\r
+ NULL\r
+ );\r
+ if (Status == EFI_SUCCESS) {\r
+ GetSmbiosStructureSize(SmbiosRecord, &RecordSize, &NumOfStr);\r
+ CopyMem (BufferPointer, SmbiosRecord, RecordSize);\r
+ BufferPointer = BufferPointer + RecordSize;\r
+ }\r
+ } while (!EFI_ERROR(Status));\r
+ \r
+ //\r
+ // Assemble End-Of-Table structure\r
+ //\r
+ CopyMem (BufferPointer, &EndStructure, sizeof (EndStructure));\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
+\r
+ //\r
+ // Returns the pointer\r
+ //\r
+ *TableEntryPointStructure = EntryPointStructure;\r
+\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
+**/\r
+VOID\r
+EFIAPI\r
+SmbiosTableConstruction (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ UINT8 *Eps;\r
+ EFI_STATUS Status;\r
+\r
+ Status = SmbiosCreateTable ((VOID **) &Eps);\r
+ if (!EFI_ERROR (Status)) {\r
+ gBS->InstallConfigurationTable (&gEfiSmbiosTableGuid, Eps);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+\r
+ Driver to produce Smbios protocol and register event for constructing SMBIOS table. \r
+\r
+ @param ImageHandle Module's image handle\r
+ @param SystemTable Pointer of EFI_SYSTEM_TABLE\r
+\r
+ @retval EFI_SUCCESS Smbios protocol installed\r
+ @retval Other No protocol installed, unload driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmbiosDriverEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_EVENT ReadyToBootEvent;\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
+\r
+ InitializeListHead (&mPrivateData.DataListHead);\r
+ InitializeListHead (&mPrivateData.AllocatedHandleListHead);\r
+ EfiInitializeLock (&mPrivateData.DataLock, TPL_NOTIFY);\r
+ \r
+ //\r
+ // Make a new handle and install the protocol\r
+ //\r
+ mPrivateData.Handle = NULL;\r
+ Status = gBS->InstallProtocolInterface (\r
+ &mPrivateData.Handle,\r
+ &gEfiSmbiosProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\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