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