449 lines
13 KiB
C
449 lines
13 KiB
C
/** @file
|
|
Runtime DXE driver for Cmos Report Status Code
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2012, Insyde Software Corp. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
#include "CmosStatusCodeRuntimeDxe.h"
|
|
|
|
//
|
|
// module variables
|
|
//
|
|
UINTN mKernelDebugCodeTblSize = 0;
|
|
UINTN mChipsetDebugCodeTblSize = 0;
|
|
DEBUG_CODE_DATA *mSortKernelTblPtr = NULL;
|
|
DEBUG_CODE_DATA *mSortChipSetTblPtr = NULL;
|
|
EFI_EVENT mExitBootServicesEvent = NULL;
|
|
EFI_RSC_HANDLER_PROTOCOL *mRscHandlerProtocol = NULL;
|
|
|
|
|
|
/**
|
|
Entry point of Cmos Status Code Driver.
|
|
|
|
This function is the entry point of this DXE Status Code Driver.
|
|
It registers notify event for EFI_RSC_HANDLER_PROTOCOL installed.
|
|
|
|
@param ImageHandle The firmware allocated handle for the EFI image.
|
|
@param SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The entry point is executed successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CmosStatusCodeRuntimeDxeEntry (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
VOID *Registration;
|
|
DEBUG_CODE_DATA *KernelDebugCodeTbl = NULL; //retrieved from Pcd
|
|
DEBUG_CODE_DATA *ChipsetDebugCodeTbl = NULL; //retrieved from Pcd
|
|
DEBUG_CODE_DATA EndEntry;
|
|
UINTN NumOfEntries;
|
|
UINTN TotalTblSize;
|
|
|
|
ZeroMem (&EndEntry, sizeof (DEBUG_CODE_DATA));
|
|
|
|
KernelDebugCodeTbl = (DEBUG_CODE_DATA *)PcdGetPtr (PcdDxeKernelDebugCodeTable);
|
|
ChipsetDebugCodeTbl = (DEBUG_CODE_DATA *)PcdGetPtr (PcdDxeChipsetDebugCodeTable);
|
|
|
|
//
|
|
// Calculate the number of non-zero entries in the debug code table
|
|
//
|
|
NumOfEntries = 0;
|
|
while (CompareMem (&EndEntry, &KernelDebugCodeTbl[NumOfEntries], sizeof (DEBUG_CODE_DATA)) != 0) {
|
|
NumOfEntries++;
|
|
}
|
|
mKernelDebugCodeTblSize = NumOfEntries; //excluding EndEntry
|
|
TotalTblSize = mKernelDebugCodeTblSize * sizeof (DEBUG_CODE_DATA);
|
|
|
|
//
|
|
// initialize module variables:
|
|
// array of kernel modules with debug codes and file guids
|
|
//
|
|
if (mKernelDebugCodeTblSize > 0) {
|
|
mSortKernelTblPtr = (DEBUG_CODE_DATA *)AllocatePool (TotalTblSize);
|
|
CopyMem (mSortKernelTblPtr, KernelDebugCodeTbl, TotalTblSize);
|
|
SortDebugCodeTbl (mSortKernelTblPtr, mKernelDebugCodeTblSize);
|
|
} else {
|
|
mSortKernelTblPtr = NULL;
|
|
}
|
|
|
|
//
|
|
// Calculate the number of non-zero entries in the debug code table
|
|
//
|
|
NumOfEntries = 0;
|
|
while (CompareMem (&EndEntry, &ChipsetDebugCodeTbl[NumOfEntries], sizeof (DEBUG_CODE_DATA)) != 0) {
|
|
NumOfEntries++;
|
|
}
|
|
mChipsetDebugCodeTblSize = NumOfEntries; //excluding EndEntry
|
|
TotalTblSize = mChipsetDebugCodeTblSize * sizeof (DEBUG_CODE_DATA);
|
|
|
|
//
|
|
// initialize module variables:
|
|
// array of chipset modules with debug codes and file guids
|
|
//
|
|
if (mChipsetDebugCodeTblSize > 0) {
|
|
mSortChipSetTblPtr = (DEBUG_CODE_DATA *)AllocatePool (TotalTblSize);
|
|
CopyMem (mSortChipSetTblPtr, ChipsetDebugCodeTbl, TotalTblSize);
|
|
SortDebugCodeTbl (mSortChipSetTblPtr, mChipsetDebugCodeTblSize);
|
|
} else {
|
|
mSortChipSetTblPtr = NULL;
|
|
}
|
|
|
|
EfiCreateProtocolNotifyEvent (
|
|
&gEfiRscHandlerProtocolGuid,
|
|
TPL_CALLBACK,
|
|
RscHandlerCallBack,
|
|
NULL,
|
|
&Registration
|
|
);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Decode status code value, and write to Cmos.
|
|
|
|
@param CodeType Indicates the type of status code being reported.
|
|
@param Value Describes the current status of a hardware or software entity.
|
|
This included information about the class and subclass that is used to
|
|
classify the entity as well as an operation.
|
|
@param Instance The enumeration of a hardware or software entity within
|
|
the system. Valid instance numbers start with 1.
|
|
@param CallerId This optional parameter may be used to identify the caller.
|
|
This parameter allows the status code driver to apply different rules to
|
|
different callers.
|
|
@param Data This optional parameter may be used to pass additional data.
|
|
|
|
@retval EFI_SUCCESS Status code is written to Cmos successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CmosStatusCodeReportWorker (
|
|
IN EFI_STATUS_CODE_TYPE CodeType,
|
|
IN EFI_STATUS_CODE_VALUE Value,
|
|
IN UINT32 Instance,
|
|
IN EFI_GUID *CallerId,
|
|
IN EFI_STATUS_CODE_DATA *Data OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 CodeValue;
|
|
UINT8 GroupValue;
|
|
|
|
if (Data == NULL) {
|
|
//
|
|
// The DebugInfo was not sent by DxeCore Dispatcher.
|
|
//
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Progress or error code, Output to CMOS Offset 0x38 and 0x39
|
|
//
|
|
if (Value == (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_BEGIN)) {
|
|
//
|
|
// Search in KernelDebugCodeTbl and ChipsetDebugCodeTbl
|
|
//
|
|
Status = SearchDebugCodeValue (Data, &CodeValue, &GroupValue);
|
|
if (!EFI_ERROR (Status)) {
|
|
WriteCmos8 (CurrentDebugGroup, GroupValue);
|
|
WriteCmos8 (CurrentDebugCode, CodeValue);
|
|
} else {
|
|
//
|
|
// Driver GUID is not found.
|
|
//
|
|
WriteCmos8 (CurrentDebugGroup, 0xFF);
|
|
WriteCmos8 (CurrentDebugCode, 0xFF);
|
|
}
|
|
|
|
} else if (Value == (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_END)) {
|
|
//
|
|
// Reserve for expand.
|
|
//
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Notification function for ReportStatusCode handler Protocol
|
|
|
|
This routine is the notification function for EFI_RSC_HANDLER_PROTOCOL
|
|
|
|
@param EFI_EVENT Event of the notification
|
|
@param Context not used in this function
|
|
|
|
@retval none
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
RscHandlerCallBack (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiRscHandlerProtocolGuid,
|
|
NULL,
|
|
(VOID **) &mRscHandlerProtocol
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Register the worker function to ReportStatusCodeRouter
|
|
//
|
|
mRscHandlerProtocol->Register (CmosStatusCodeReportWorker, TPL_HIGH_LEVEL);
|
|
Status = gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_NOTIFY,
|
|
UnregisterBootTimeHandlers,
|
|
NULL,
|
|
&gEfiEventExitBootServicesGuid,
|
|
&mExitBootServicesEvent
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
gBS->CloseEvent(Event);
|
|
}
|
|
|
|
|
|
/**
|
|
Unregister status code callback functions only available at boot time from
|
|
report status code router when exiting boot services.
|
|
|
|
@param Event Event whose notification function is being invoked.
|
|
@param Context Pointer to the notification function's context, which is
|
|
always zero in current implementation.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
UnregisterBootTimeHandlers (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
mRscHandlerProtocol->Unregister (CmosStatusCodeReportWorker);
|
|
|
|
if (mSortKernelTblPtr != NULL) {
|
|
FreePool (mSortKernelTblPtr);
|
|
}
|
|
if (mSortChipSetTblPtr != NULL) {
|
|
FreePool (mSortChipSetTblPtr);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Helper function to sort modules with debug code by Guids.
|
|
|
|
@param *Array array of modules with debug code and guids to be sorted.
|
|
@param DataCount number of items in the array.
|
|
|
|
@retval None
|
|
|
|
**/
|
|
VOID
|
|
SortDebugCodeTbl (
|
|
IN DEBUG_CODE_DATA *Array,
|
|
IN UINTN DataCount
|
|
)
|
|
{
|
|
DEBUG_CODE_DATA TempData;
|
|
DEBUG_CODE_DATA *TempPtr;
|
|
UINTN DataSize;
|
|
UINTN DataIndex;
|
|
UINTN DataIndex2;
|
|
INT32 CmpValue;
|
|
BOOLEAN NoChange;
|
|
|
|
DataSize = DataCount;
|
|
TempPtr = Array;
|
|
NoChange = FALSE;
|
|
|
|
//
|
|
// bubble sort
|
|
//
|
|
for (DataIndex = 1; (DataIndex < DataSize) && (!NoChange); DataIndex++) {
|
|
NoChange = TRUE;
|
|
for (DataIndex2 = 0; DataIndex2 < (DataSize - DataIndex); DataIndex2++) {
|
|
CmpValue = HelperCompareGuid ( (EFI_GUID*)(TempPtr + DataIndex2), (EFI_GUID*)(TempPtr + (DataIndex2 + 1)));
|
|
if (CmpValue == 1) {
|
|
TempData = *(TempPtr + DataIndex2);
|
|
*(TempPtr + DataIndex2) = *(TempPtr + (DataIndex2 + 1));
|
|
*(TempPtr + (DataIndex2 + 1)) = TempData;
|
|
NoChange = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Helper function to search the module guid in KernelDebugCodeTable and ChipsetDebugCodeTable.
|
|
The FileGuid of module is embedded in Data.
|
|
|
|
@param Data The ExtendedData sent by REPORT_STATUS_CODE_WITH_EXTENDED_DATA.
|
|
@param DebugCodeValue The pointer to the value of the DebugCode found.
|
|
@param DebugGroupValue The pointer to the value of the DebugGroup found.
|
|
|
|
@retval EFI_INVALID_PARAMETER Invalid file guid value.
|
|
@retval EFI_NOT_FOUND The module is not in the DebugCode tables.
|
|
@retval EFI_SUCCESS The module is found in the DebugCode table,
|
|
the DebugCode/DebugGroup values outputed successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
SearchDebugCodeValue (
|
|
IN CONST EFI_STATUS_CODE_DATA *Data,
|
|
OUT UINT8 *DebugCodeValue,
|
|
OUT UINT8 *DebugGroupValue
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_STATUS_CODE_DATA *DataPtr;
|
|
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
|
|
EFI_GUID *NameGuid;
|
|
UINTN IndexLow;
|
|
UINTN IndexMid;
|
|
UINTN IndexHigh;
|
|
INT32 CmpValue;
|
|
EFI_HANDLE Handle;
|
|
|
|
NameGuid = NULL;
|
|
*DebugCodeValue = 0;
|
|
*DebugGroupValue = 0;
|
|
|
|
//
|
|
// The ExtendedData was sent by Dispatcher of DxeCore
|
|
//
|
|
DataPtr = (EFI_STATUS_CODE_DATA *)Data;
|
|
Handle = *(EFI_HANDLE *)(UINTN)(DataPtr + 1);
|
|
|
|
//
|
|
// Retrieve the FileGuid on LoadedImageProtocol
|
|
//
|
|
Status = gBS->HandleProtocol (
|
|
Handle,
|
|
&gEfiLoadedImageProtocolGuid,
|
|
(VOID **)&LoadedImage
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
if (LoadedImage->FilePath == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)LoadedImage->FilePath);
|
|
if (NameGuid == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Search the FileGuid in KernelDebugCodeTable and ChipsetDebugCodeTable
|
|
//
|
|
Status = EFI_NOT_FOUND;
|
|
IndexLow = 1;
|
|
IndexHigh = mKernelDebugCodeTblSize;
|
|
//
|
|
// binary search
|
|
//
|
|
if (mSortKernelTblPtr != NULL) {
|
|
while (IndexLow <= IndexHigh) {
|
|
IndexMid = (IndexLow + IndexHigh) / 2;
|
|
CmpValue = HelperCompareGuid ((EFI_GUID *)&mSortKernelTblPtr[IndexMid - 1].NameGuid, NameGuid);
|
|
if (CmpValue == 1) {
|
|
IndexHigh = IndexMid - 1;
|
|
} else if (CmpValue == -1) {
|
|
IndexLow = IndexMid + 1;
|
|
} else {
|
|
*DebugCodeValue = mSortKernelTblPtr[IndexMid - 1].DebugCode;
|
|
*DebugGroupValue = mSortKernelTblPtr[IndexMid - 1].DebugGroup;
|
|
Status = EFI_SUCCESS;
|
|
return Status;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// binary search
|
|
//
|
|
if (mSortChipSetTblPtr != NULL) {
|
|
IndexLow = 1;
|
|
IndexHigh = mChipsetDebugCodeTblSize;
|
|
while (IndexLow <= IndexHigh) {
|
|
IndexMid = (IndexLow + IndexHigh) / 2;
|
|
CmpValue = HelperCompareGuid ((EFI_GUID *)&mSortChipSetTblPtr[IndexMid - 1].NameGuid, NameGuid);
|
|
if (CmpValue == 1) {
|
|
IndexHigh = IndexMid - 1;
|
|
} else if (CmpValue == -1) {
|
|
IndexLow = IndexMid + 1;
|
|
} else {
|
|
*DebugCodeValue = mSortChipSetTblPtr[IndexMid - 1].DebugCode;
|
|
*DebugGroupValue = mSortChipSetTblPtr[IndexMid - 1].DebugGroup;
|
|
Status = EFI_SUCCESS;
|
|
return Status;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Helper function to compare two guids.
|
|
|
|
@param *Guid1 guid to be compared.
|
|
@param *Guid2 guid to be compared.
|
|
|
|
@retval 0 if Guid1 == Guid2
|
|
1 if Guid1 > Guid2
|
|
-1 if Guid1 < Guid2
|
|
**/
|
|
INT32
|
|
HelperCompareGuid (
|
|
IN EFI_GUID *Guid1,
|
|
IN EFI_GUID *Guid2
|
|
)
|
|
{
|
|
UINTN Index;
|
|
|
|
//
|
|
// compare byte by byte
|
|
//
|
|
for (Index = 0; Index < 16; ++Index) {
|
|
if (*(((UINT8*) Guid1) + Index) > *(((UINT8*) Guid2) + Index)) {
|
|
|
|
return 1;
|
|
} else if (*(((UINT8*) Guid1) + Index) < *(((UINT8*) Guid2) + Index)) {
|
|
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|