+/*++\r
+\r
+Copyright (c) 2006 - 2007, 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
+Module Name:\r
+\r
+ MiscSubclassDriverEntryPoint.c\r
+\r
+Abstract:\r
+\r
+ This driver parses the mMiscSubclassDataTable structure and reports\r
+ any generated data to the DataHub.\r
+\r
+--*/\r
+\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "CommonHeader.h"\r
+\r
+#include "MiscSubclassDriver.h"\r
+\r
+\r
+extern UINT8 MiscSubclassStrings[];\r
+\r
+VOID\r
+EFIAPI\r
+WinNtIoProtocolNotifyFunction (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ );\r
+\r
+//\r
+//\r
+//\r
+EFI_STATUS\r
+LogRecordDataToDataHub (\r
+ EFI_DATA_HUB_PROTOCOL *DataHub,\r
+ UINT32 RecordType,\r
+ UINT32 RecordLen,\r
+ VOID *RecordData\r
+ )\r
+/*++\r
+Description:\r
+\r
+Parameters:\r
+\r
+ DataHub\r
+ %%TBD\r
+\r
+ RecordType\r
+ %%TBD\r
+\r
+ RecordLen\r
+ %%TBD\r
+\r
+ RecordData\r
+ %%TBD\r
+\r
+Returns:\r
+\r
+ EFI_INVALID_PARAMETER\r
+\r
+ EFI_SUCCESS\r
+\r
+ Other Data Hub errors\r
+\r
+--*/\r
+{\r
+ EFI_MISC_SUBCLASS_DRIVER_DATA MiscSubclass;\r
+ EFI_STATUS EfiStatus;\r
+\r
+ //\r
+ // Do nothing if data parameters are not valid.\r
+ //\r
+ if (RecordLen == 0 || RecordData == NULL) {\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "RecordLen == %d RecordData == %xh\n",\r
+ RecordLen,\r
+ RecordData)\r
+ );\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Assemble Data Hub record.\r
+ //\r
+ MiscSubclass.Header.Version = EFI_MISC_SUBCLASS_VERSION;\r
+ MiscSubclass.Header.HeaderSize = sizeof (EFI_SUBCLASS_TYPE1_HEADER);\r
+ MiscSubclass.Header.Instance = 1;\r
+ MiscSubclass.Header.SubInstance = 1;\r
+ MiscSubclass.Header.RecordType = RecordType;\r
+\r
+ CopyMem (\r
+ &MiscSubclass.Record,\r
+ RecordData,\r
+ RecordLen\r
+ );\r
+\r
+ //\r
+ // Log Data Hub record.\r
+ //\r
+ EfiStatus = DataHub->LogData (\r
+ DataHub,\r
+ &gEfiMiscSubClassGuid,\r
+ &gEfiMiscSubClassGuid,\r
+ EFI_DATA_RECORD_CLASS_DATA,\r
+ &MiscSubclass,\r
+ sizeof (EFI_SUBCLASS_TYPE1_HEADER) + RecordLen\r
+ );\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "LogData(%d bytes) == %r\n",\r
+ sizeof (EFI_SUBCLASS_TYPE1_HEADER) + RecordLen,\r
+ EfiStatus)\r
+ );\r
+ }\r
+\r
+ return EfiStatus;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+MiscSubclassDriverEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+/*++\r
+Description:\r
+\r
+ Standard EFI driver point. This driver parses the mMiscSubclassDataTable\r
+ structure and reports any generated data to the DataHub.\r
+\r
+Arguments:\r
+\r
+ ImageHandle\r
+ Handle for the image of this driver\r
+\r
+ SystemTable\r
+ Pointer to the EFI System Table\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS\r
+ The data was successfully reported to the Data Hub.\r
+\r
+--*/\r
+{\r
+ EFI_MISC_SUBCLASS_DRIVER_DATA RecordData;\r
+ EFI_DATA_HUB_PROTOCOL *DataHub;\r
+ EFI_HII_PROTOCOL *Hii;\r
+ EFI_HII_PACKAGES *PackageList;\r
+ EFI_HII_HANDLE HiiHandle;\r
+ EFI_STATUS EfiStatus;\r
+ UINTN Index;\r
+ BOOLEAN LogRecordData;\r
+ EFI_EVENT Event;\r
+ VOID *Registration;\r
+\r
+\r
+ //\r
+ // Initialize constant portion of subclass header.\r
+ //\r
+ RecordData.Header.Version = EFI_MISC_SUBCLASS_VERSION;\r
+ RecordData.Header.HeaderSize = sizeof (EFI_SUBCLASS_TYPE1_HEADER);\r
+ RecordData.Header.Instance = 1;\r
+ RecordData.Header.SubInstance = 1;\r
+\r
+ //\r
+ // Locate data hub protocol.\r
+ //\r
+ EfiStatus = gBS->LocateProtocol (&gEfiDataHubProtocolGuid, NULL, &DataHub);\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ DEBUG ((EFI_D_ERROR, "Could not locate DataHub protocol. %r\n", EfiStatus));\r
+ return EfiStatus;\r
+ } else if (DataHub == NULL) {\r
+ DEBUG ((EFI_D_ERROR, "LocateProtocol(DataHub) returned NULL pointer!\n"));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Locate hii protocol.\r
+ //\r
+ EfiStatus = gBS->LocateProtocol (&gEfiHiiProtocolGuid, NULL, &Hii);\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ DEBUG ((EFI_D_ERROR, "Could not locate Hii protocol. %r\n", EfiStatus));\r
+ return EfiStatus;\r
+ } else if (Hii == NULL) {\r
+ DEBUG ((EFI_D_ERROR, "LocateProtocol(Hii) returned NULL pointer!\n"));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Add our default strings to the HII database. They will be modified later.\r
+ //\r
+ PackageList = PreparePackages (1, &gEfiMiscSubClassGuid, MiscSubclassStrings);\r
+ EfiStatus = Hii->NewPack (Hii, PackageList, &HiiHandle);\r
+ FreePool (PackageList);\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ DEBUG ((EFI_D_ERROR, "Could not log default strings to Hii. %r\n", EfiStatus));\r
+ return EfiStatus;\r
+ }\r
+ //\r
+ //\r
+ //\r
+ for (Index = 0; Index < mMiscSubclassDataTableEntries; ++Index) {\r
+ //\r
+ // Stupidity check! Do nothing if RecordLen is zero.\r
+ // %%TBD - Should this be an error or a mechanism for ignoring\r
+ // records in the Data Table?\r
+ //\r
+ if (mMiscSubclassDataTable[Index].RecordLen == 0) {\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "mMiscSubclassDataTable[%d].RecordLen == 0\n",\r
+ Index)\r
+ );\r
+\r
+ continue;\r
+ }\r
+ //\r
+ // Initialize per-record portion of subclass header and\r
+ // copy static data into data portion of subclass record.\r
+ //\r
+ RecordData.Header.RecordType = mMiscSubclassDataTable[Index].RecordType;\r
+\r
+ if (mMiscSubclassDataTable[Index].RecordData == NULL) {\r
+ ZeroMem (\r
+ &RecordData.Record,\r
+ mMiscSubclassDataTable[Index].RecordLen\r
+ );\r
+ } else {\r
+ CopyMem (\r
+ &RecordData.Record,\r
+ mMiscSubclassDataTable[Index].RecordData,\r
+ mMiscSubclassDataTable[Index].RecordLen\r
+ );\r
+ }\r
+ //\r
+ // If the entry does not have a function pointer, just log the data.\r
+ //\r
+ if (mMiscSubclassDataTable[Index].Function == NULL) {\r
+ //\r
+ // Log RecordData to Data Hub.\r
+ //\r
+ EfiStatus = DataHub->LogData (\r
+ DataHub,\r
+ &gEfiMiscSubClassGuid,\r
+ &gEfiMiscSubClassGuid,\r
+ EFI_DATA_RECORD_CLASS_DATA,\r
+ &RecordData,\r
+ sizeof (EFI_SUBCLASS_TYPE1_HEADER) + mMiscSubclassDataTable[Index].RecordLen\r
+ );\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "LogData(%d bytes) == %r\n",\r
+ sizeof (EFI_SUBCLASS_TYPE1_HEADER) + mMiscSubclassDataTable[Index].RecordLen,\r
+ EfiStatus)\r
+ );\r
+ }\r
+\r
+ continue;\r
+ }\r
+ //\r
+ // The entry has a valid function pointer.\r
+ // Keep calling the function and logging data until there\r
+ // is no more data to log.\r
+ //\r
+ for (;;) {\r
+ //\r
+ //\r
+ //\r
+ EfiStatus = (*mMiscSubclassDataTable[Index].Function)\r
+ (\r
+ mMiscSubclassDataTable[Index].RecordType, &mMiscSubclassDataTable[Index].RecordLen, &RecordData.Record, &\r
+ LogRecordData\r
+ );\r
+\r
+ //\r
+ //\r
+ //\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ break;\r
+ }\r
+\r
+ if (!LogRecordData) {\r
+ break;\r
+ }\r
+ //\r
+ //\r
+ //\r
+ EfiStatus = DataHub->LogData (\r
+ DataHub,\r
+ &gEfiMiscSubClassGuid,\r
+ &gEfiMiscSubClassGuid,\r
+ EFI_DATA_RECORD_CLASS_DATA,\r
+ &RecordData,\r
+ sizeof (EFI_SUBCLASS_TYPE1_HEADER) + mMiscSubclassDataTable[Index].RecordLen\r
+ );\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "LogData(%d bytes) == %r\n",\r
+ sizeof (EFI_SUBCLASS_TYPE1_HEADER) + mMiscSubclassDataTable[Index].RecordLen,\r
+ EfiStatus)\r
+ );\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Install notify function to fetch memory data through WinNtIo protocol and store to data hub.\r
+ //\r
+ EfiStatus = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ WinNtIoProtocolNotifyFunction,\r
+ ImageHandle,\r
+ &Event\r
+ );\r
+ ASSERT (!EFI_ERROR (EfiStatus));\r
+\r
+ EfiStatus = gBS->RegisterProtocolNotify (\r
+ &gEfiWinNtIoProtocolGuid,\r
+ Event,\r
+ &Registration\r
+ );\r
+ ASSERT (!EFI_ERROR (EfiStatus));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+UINTN\r
+Atoi (\r
+ CHAR16 *String\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Convert a unicode string to a UINTN\r
+\r
+Arguments:\r
+ String - Unicode string.\r
+\r
+Returns:\r
+ UINTN of the number represented by String.\r
+\r
+--*/\r
+{\r
+ UINTN Number;\r
+ CHAR16 *Str;\r
+\r
+ //\r
+ // skip preceeding white space\r
+ //\r
+ Str = String;\r
+ while ((*Str) && (*Str == ' ' || *Str == '"')) {\r
+ Str++;\r
+ }\r
+ //\r
+ // Convert ot a Number\r
+ //\r
+ Number = 0;\r
+ while (*Str != '\0') {\r
+ if ((*Str >= '0') && (*Str <= '9')) {\r
+ Number = (Number * 10) +*Str - '0';\r
+ } else {\r
+ break;\r
+ }\r
+\r
+ Str++;\r
+ }\r
+\r
+ return Number;\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+WinNtIoProtocolNotifyFunction (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This function will log memory size data to data hub.\r
+\r
+Arguments:\r
+Event - Event whose notification function is being invoked.\r
+Context - Pointer to the notification function's context.\r
+\r
+Returns:\r
+ EFI_STATUS.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_MEMORY_SUBCLASS_DRIVER_DATA MemorySubClassData;\r
+ EFI_DATA_RECORD_HEADER *Record;\r
+ EFI_SUBCLASS_TYPE1_HEADER *DataHeader;\r
+ UINTN HandleCount;\r
+ UINTN HandleIndex;\r
+ UINT64 MonotonicCount;\r
+ BOOLEAN RecordFound;\r
+ EFI_HANDLE *HandleBuffer;\r
+ EFI_WIN_NT_IO_PROTOCOL *WinNtIo;\r
+ EFI_DATA_HUB_PROTOCOL *DataHub;\r
+ UINT64 TotalMemorySize;\r
+\r
+ DataHub = NULL;\r
+ MonotonicCount = 0;\r
+ RecordFound = FALSE;\r
+\r
+ //\r
+ // Retrieve the list of all handles from the handle database.\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ AllHandles,\r
+ &gEfiWinNtIoProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return ;\r
+ }\r
+ //\r
+ // Locate DataHub protocol.\r
+ //\r
+ Status = gBS->LocateProtocol (&gEfiDataHubProtocolGuid, NULL, &DataHub);\r
+ if (EFI_ERROR (Status)) {\r
+ return ;\r
+ }\r
+ //\r
+ // Search the Handle array to find the meory size information.\r
+ //\r
+ for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {\r
+ Status = gBS->OpenProtocol (\r
+ HandleBuffer[HandleIndex],\r
+ &gEfiWinNtIoProtocolGuid,\r
+ &WinNtIo,\r
+ Context,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ if ((WinNtIo->WinNtThunk->Signature == EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) &&\r
+ CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtMemoryGuid)\r
+ ) {\r
+ //\r
+ // Check if this record has been stored in data hub.\r
+ //\r
+ do {\r
+ Status = DataHub->GetNextRecord (DataHub, &MonotonicCount, NULL, &Record);\r
+ if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA) {\r
+ DataHeader = (EFI_SUBCLASS_TYPE1_HEADER *) (Record + 1);\r
+ if (CompareGuid (&Record->DataRecordGuid, &gEfiProcessorSubClassGuid) &&\r
+ (DataHeader->RecordType == EFI_MEMORY_ARRAY_START_ADDRESS_RECORD_NUMBER)\r
+ ) {\r
+ RecordFound = TRUE;\r
+ }\r
+ }\r
+ } while (MonotonicCount != 0);\r
+\r
+ if (RecordFound) {\r
+ RecordFound = FALSE;\r
+ continue;\r
+ }\r
+ //\r
+ // Initialize data record.\r
+ //\r
+ MemorySubClassData.Header.Instance = 1;\r
+ MemorySubClassData.Header.SubInstance = EFI_SUBCLASS_INSTANCE_NON_APPLICABLE;\r
+ MemorySubClassData.Header.RecordType = EFI_MEMORY_ARRAY_START_ADDRESS_RECORD_NUMBER;\r
+\r
+ TotalMemorySize = (UINT64) Atoi (WinNtIo->EnvString);\r
+\r
+ MemorySubClassData.Record.ArrayStartAddress.MemoryArrayStartAddress = 0;\r
+ MemorySubClassData.Record.ArrayStartAddress.MemoryArrayEndAddress = LShiftU64 (TotalMemorySize, 20) - 1;\r
+ MemorySubClassData.Record.ArrayStartAddress.PhysicalMemoryArrayLink.ProducerName = gEfiMemoryProducerGuid;\r
+ MemorySubClassData.Record.ArrayStartAddress.PhysicalMemoryArrayLink.Instance = 1;\r
+ MemorySubClassData.Record.ArrayStartAddress.PhysicalMemoryArrayLink.SubInstance = EFI_SUBCLASS_INSTANCE_NON_APPLICABLE;\r
+ MemorySubClassData.Record.ArrayStartAddress.MemoryArrayPartitionWidth = 0;\r
+\r
+ //\r
+ // Store memory size data record to data hub.\r
+ //\r
+ Status = DataHub->LogData (\r
+ DataHub,\r
+ &gEfiMemorySubClassGuid,\r
+ &gEfiMemoryProducerGuid,\r
+ EFI_DATA_RECORD_CLASS_DATA,\r
+ &MemorySubClassData,\r
+ sizeof (EFI_SUBCLASS_TYPE1_HEADER) + sizeof (EFI_MEMORY_ARRAY_START_ADDRESS_DATA)\r
+ );\r
+ }\r
+\r
+ gBS->CloseProtocol (\r
+ HandleBuffer[HandleIndex],\r
+ &gEfiWinNtIoProtocolGuid,\r
+ Context,\r
+ NULL\r
+ );\r
+ }\r
+}\r
+\r