git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			519 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			519 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++
 | |
| 
 | |
| 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
 | |
|           );
 | |
|   }
 | |
| }
 | |
| 
 |