alder_lake_bios/Insyde/InsydeModulePkg/Universal/StatusCode/CmosStatusCodeRuntimeDxe/CmosStatusCodeRuntimeDxe.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;
}