/** @file
LnvDxeStatusCode - Lenovo DXE Status Code Driver
This DXE driver initializes status code reporting for the Lenovo HR650X
BIOS. It registers ExitBootServices and VirtualAddressChange callbacks,
locates the custom Lenovo Status Code Protocol (DXE boot-time) and the
EFI Runtime Status Code Protocol, and provides a filtered reporting path
controlled by a CMOS debug-level register at index 0x4B.
Build paths referenced by debug strings in the original binary:
e:\hs\MdePkg\Library\UefiBootServicesTableLib\UefiBootServicesTableLib.c
e:\hs\MdePkg\Library\UefiRuntimeServicesTableLib\UefiRuntimeServicesTableLib.c
e:\hs\MdePkg\Library\UefiRuntimeLib\RuntimeLib.c
e:\hs\MdeModulePkg\Library\RuntimeDxeReportStatusCodeLib\ReportStatusCodeLib.c
e:\hs\Build\HR6N0XMLK\DEBUG_VS2015\X64\LenovoServerPkg\POSTStatus\LnvDxeStatusCode\DEBUG\AutoGen.c
e:\hs\MdePkg\Library\DxeHobLib\HobLib.c
e:\hs\MdePkg\Library\BaseLib\Unaligned.c
Copyright (c) Lenovo. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Guid/HobList.h>
//
// -- GUID constants (data section at 0x3000..0x3040) -----------------------
//
//
// Custom Lenovo Status Code Protocol (0x3000):
// +0x00: ReportStatusCode(ErrorLevel, Format, va_list)
// +0x08: DebugAssert(FileName, LineNumber, Expression)
//
#define LENOVO_STATUS_CODE_PROTOCOL_GUID \
{ 0x36232936, 0x0e76, 0x31c8, { 0xa1, 0x3a, 0x3a, 0xf2, 0xfc, 0x1c, 0x39, 0x32 } }
//
// gEfiStatusCodeRuntimeProtocolGuid (0x3010) from MdeModulePkg.
//
#define EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID \
{ 0xd2b2b828, 0x0826, 0x48a7, { 0xb3, 0xdf, 0x98, 0x3c, 0x00, 0x60, 0x24, 0xf0 } }
//
// gEfiHobListGuid (0x3020) from MdePkg.
//
#define EFI_HOB_LIST_GUID \
{ 0x7739f24c, 0x93d7, 0x11d4, { 0x9a, 0x3a, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } }
//
// gEfiEventExitBootServicesGuid (0x3030).
//
#define EFI_EVENT_EXIT_BOOT_SERVICES_GUID \
{ 0x27abf055, 0xb1b8, 0x4c26, { 0x80, 0x48, 0x74, 0x8f, 0x37, 0xba, 0xa2, 0xdf } }
//
// gEfiEventVirtualAddressChangeGuid (0x3040).
//
#define EFI_EVENT_VIRTUAL_ADDRESS_CHANGE_GUID \
{ 0x13fa7698, 0xc831, 0x49c7, { 0x87, 0xea, 0x8f, 0x43, 0xfc, 0xc2, 0x51, 0x96 } }
// ---------------------------------------------------------------------------
// Lenovo custom protocol vtable layout
// ---------------------------------------------------------------------------
typedef struct {
UINT64 ReportStatusCodeFn; // offset +0x00
UINT64 DebugAssertFn; // offset +0x08
} LENOVO_STATUS_CODE_PROTOCOL;
// ---------------------------------------------------------------------------
// Global variables
// ---------------------------------------------------------------------------
EFI_HANDLE gImageHandle_ = 0; // 0x3060
EFI_SYSTEM_TABLE *gSystemTable_ = NULL; // 0x3050
EFI_BOOT_SERVICES *gBootServices_ = NULL; // 0x3058
EFI_RUNTIME_SERVICES *gRuntimeServices_ = NULL; // 0x3068
EFI_RUNTIME_SERVICES *gRuntimeServicesRt_ = NULL; // 0x3070
VOID *gRegClearBs_ = NULL; // 0x3080
EFI_BOOT_SERVICES *gBootServicesBs_ = NULL; // 0x3088
VOID *gLenovoProtocol_ = NULL; // 0x3090
VOID *gHobList_ = NULL; // 0x3098
BOOLEAN gRuntimeInitDone_ = FALSE; // 0x30A0
VOID *gRuntimeProtocol_ = NULL; // 0x30A8
VOID *gRegVirtAddrChange_ = NULL; // 0x30B8
VOID *gRegExitBsStatus_ = NULL; // 0x30C0
VOID *gRuntimeServicesReg_ = NULL; // 0x30D0
VOID *gRegExitBs_ = NULL; // 0x30D8
//
// GUID constants in .data section
//
STATIC CONST GUID mStatusCodeProtocolGuid = LENOVO_STATUS_CODE_PROTOCOL_GUID;
STATIC CONST GUID mStatusCodeRuntimeProtocolGuid = EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID;
STATIC CONST GUID mHobListGuid = EFI_HOB_LIST_GUID;
STATIC CONST GUID mExitBootServicesGroupGuid = EFI_EVENT_EXIT_BOOT_SERVICES_GUID;
STATIC CONST GUID mVirtualAddressChangeGuid = EFI_EVENT_VIRTUAL_ADDRESS_CHANGE_GUID;
//
// CMOS debug register definitions
//
#define CMOS_PORT_INDEX 0x70
#define CMOS_PORT_DATA 0x71
#define CMOS_DEBUG_REG 0x4B
#define CMOS_NMI_MASK 0x80
//
// Status code severity masks
//
#define REPORT_SEVERITY_ERROR 0xC0000000
#define REPORT_SEVERITY_WARNING 0x80000000
// ---------------------------------------------------------------------------
// Forward declarations
// ---------------------------------------------------------------------------
VOID
EFIAPI
ReportStatusCodeFiltered (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
);
VOID
EFIAPI
DebugAssertViaProtocol (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Expression
);
// ===========================================================================
// ReadUnaligned64 (0x179C) -- read a UINT64 from memory
// ===========================================================================
UINT64
ReadUnaligned64 (
IN CONST VOID *Buffer
)
{
if (Buffer == NULL) {
DebugAssertViaProtocol (
"e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
192,
"Buffer != ((void *) 0)"
);
}
return *(volatile UINT64 *)Buffer;
}
// ===========================================================================
// IsHobListGuid (0x172C) -- compare a HOB UUID to gEfiHobListGuid
// ===========================================================================
BOOLEAN
IsHobListGuid (
IN CONST EFI_GUID *HobGuid
)
{
UINT64 GuidLo;
UINT64 GuidHi;
GuidLo = ReadUnaligned64 (&mHobListGuid);
GuidHi = ReadUnaligned64 (((UINT8 *)&mHobListGuid) + 8);
return (GuidLo == ReadUnaligned64 (&HobGuid->Data1)) &&
(GuidHi == ReadUnaligned64 (((UINT8 *)&HobGuid->Data1) + 8));
}
// ===========================================================================
// GetHobListFromConfigTable (0x159C) -- find the HOB list in the
// SystemTable configuration table
// ===========================================================================
VOID *
GetHobListFromConfigTable (
VOID
)
{
UINTN EntryCount;
VOID *ConfigTable;
UINTN Index;
UINT64 *EntryPtr;
if (gHobList_ != NULL) {
return gHobList_;
}
gHobList_ = NULL;
EntryCount = *(UINTN *)((UINT8 *)gSystemTable_ + 0x68);
ConfigTable = *(VOID **)((UINT8 *)gSystemTable_ + 0x70);
if (EntryCount == 0) {
ReportStatusCodeFiltered (
0x80000000,
"\nASSERT_EFI_ERROR (Status = %r)\n",
0x800000000000000EULL
);
DebugAssertViaProtocol (
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
54,
"!EFI_ERROR (Status)"
);
if (gHobList_ == NULL) {
DebugAssertViaProtocol (
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
55,
"mHobList != ((void *) 0)"
);
}
return gHobList_;
}
EntryPtr = (UINT64 *)ConfigTable;
for (Index = 0; Index < EntryCount; Index++) {
//
// Config table entry: GUID (16 bytes) + VendorTable (8 bytes) = 24 bytes.
//
if (IsHobListGuid ((EFI_GUID *)(&EntryPtr[Index * 3]))) {
gHobList_ = (VOID *)EntryPtr[Index * 3 + 2];
return gHobList_;
}
}
//
// Fall-through: HOB list GUID not found.
//
ReportStatusCodeFiltered (
0x80000000,
"\nASSERT_EFI_ERROR (Status = %r)\n",
0x800000000000000EULL
);
DebugAssertViaProtocol (
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
54,
"!EFI_ERROR (Status)"
);
if (gHobList_ == NULL) {
DebugAssertViaProtocol (
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
55,
"mHobList != ((void *) 0)"
);
}
return gHobList_;
}
// ===========================================================================
// GetLenovoStatusCodeProtocol (0x1420) -- locate the custom Lenovo protocol
// ===========================================================================
VOID *
GetLenovoStatusCodeProtocol (
VOID
)
{
VOID *Protocol;
EFI_STATUS Status;
VOID *Pool;
Protocol = gLenovoProtocol_;
if (Protocol != NULL) {
return Protocol;
}
if (gBootServicesBs_ != NULL) {
//
// AllocatePool/FreePool as a boot-services-liveness check.
//
Status = gBootServicesBs_->AllocatePool (EfiBootServicesData, 31, &Pool);
gBootServicesBs_->FreePool (Pool);
if (Pool != NULL) {
Status = gBootServicesBs_->LocateProtocol (
(EFI_GUID *)&mStatusCodeProtocolGuid,
NULL,
&Protocol
);
if (EFI_ERROR (Status)) {
Protocol = NULL;
}
gLenovoProtocol_ = Protocol;
return Protocol;
}
}
return NULL;
}
// ===========================================================================
// ReportStatusCodeFiltered (0x14A8) -- CMOS-gated status code report
// ===========================================================================
VOID
EFIAPI
ReportStatusCodeFiltered (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
LENOVO_STATUS_CODE_PROTOCOL *Protocol;
UINT8 DebugLevel;
UINT8 CmosIdx;
UINTN SeverityFilter;
VA_LIST Args;
Protocol = GetLenovoStatusCodeProtocol ();
if (Protocol == NULL) {
return;
}
//
// Read debug level from CMOS register 0x4B.
// Preserve NMI bit (0x80) in the index byte.
//
CmosIdx = (UINT8)(IoRead8 (CMOS_PORT_INDEX) & CMOS_NMI_MASK) | CMOS_DEBUG_REG;
IoWrite8 (CMOS_PORT_INDEX, CmosIdx);
DebugLevel = IoRead8 (CMOS_PORT_DATA);
if (DebugLevel > 3) {
DebugLevel = 3;
}
//
// Build severity filter mask from the debug level.
// Level 0 -> silent (all filtered)
// Level 1 -> errors only (0xC0000000)
// Level 2 -> + warnings (0x80000000)
// Level 3 -> all severities
//
SeverityFilter = REPORT_SEVERITY_ERROR;
if (DebugLevel >= 2) {
SeverityFilter |= REPORT_SEVERITY_WARNING;
}
if ((SeverityFilter & ErrorLevel) == 0 || DebugLevel == 0) {
return;
}
VA_START (Args, Format);
((EFI_STATUS (EFIAPI *)(UINTN, CONST CHAR8 *, VA_LIST))
Protocol->ReportStatusCodeFn)(ErrorLevel, Format, Args);
VA_END (Args);
}
// ===========================================================================
// DebugAssertViaProtocol (0x1528) -- forward ASSERT via the Lenovo protocol
// ===========================================================================
VOID
EFIAPI
DebugAssertViaProtocol (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Expression
)
{
LENOVO_STATUS_CODE_PROTOCOL *Protocol;
Protocol = GetLenovoStatusCodeProtocol ();
if (Protocol != NULL) {
((EFI_STATUS (EFIAPI *)(CONST CHAR8 *, UINTN, CONST CHAR8 *))
Protocol->DebugAssertFn)(FileName, LineNumber, Expression);
}
}
// ===========================================================================
// LocateRuntimeStatusCodeProtocol (0x168C)
// ===========================================================================
VOID
LocateRuntimeStatusCodeProtocol (
VOID
)
{
EFI_STATUS Status;
if (gRuntimeProtocol_ != NULL || gRuntimeInitDone_) {
return;
}
if (gBootServices_ != NULL) {
Status = gBootServices_->LocateProtocol (
(EFI_GUID *)&mStatusCodeRuntimeProtocolGuid,
NULL,
&gRuntimeProtocol_
);
if (EFI_ERROR (Status)) {
gRuntimeProtocol_ = NULL;
}
}
}
// ===========================================================================
// Event callbacks
// ===========================================================================
//
// ExitBootServices callback that clears the boot-services pointer.
//
VOID
EFIAPI
OnExitBootServicesClearBs (
IN EFI_EVENT Event,
IN VOID *Context
)
{
gBootServicesBs_ = NULL;
}
//
// ExitBootServices callback that converts the Lenovo protocol pointer.
//
EFI_STATUS
EFIAPI
OnExitBootServicesConvertLenovo (
IN EFI_EVENT Event,
IN VOID *Context
)
{
if (gLenovoProtocol_ != NULL) {
return gRuntimeServicesRt_->ConvertPointer (0, &gLenovoProtocol_);
}
return EFI_SUCCESS;
}
//
// Runtime protocol notify callback used as a no-op placeholder.
//
VOID
EFIAPI
RuntimeProtocolNotifyNop (
IN EFI_EVENT Event,
IN VOID *Context
)
{
}
//
// Event callback that converts the runtime-services registration pointer.
//
EFI_STATUS
EFIAPI
OnExitBootServicesConvertReg (
IN EFI_EVENT Event,
IN VOID *Context
)
{
return gRuntimeServices_->ConvertPointer (0, &gRuntimeServicesReg_);
}
//
// ExitBootServices/virtual-address-change callback to convert runtime protocol pointer.
//
EFI_STATUS
EFIAPI
OnExitBootServicesConvertRuntime (
IN EFI_EVENT Event,
IN VOID *Context
)
{
if (gRuntimeProtocol_ != NULL) {
return gRuntimeServices_->ConvertPointer (0, &gRuntimeProtocol_);
}
return EFI_SUCCESS;
}
//
// Virtual-address-change callback to re-locate runtime protocol and mark init done.
//
VOID
EFIAPI
OnVirtualAddressChange (
IN EFI_EVENT Event,
IN VOID *Context
)
{
LocateRuntimeStatusCodeProtocol ();
gRuntimeInitDone_ = TRUE;
}
// ===========================================================================
// DriverSetupInit (0x10F4) -- main initialisation
// ===========================================================================
EFI_STATUS
EFIAPI
DriverSetupInit (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// 1. Cache UEFI table pointers (inlined boot-services-table-lib init).
//
gImageHandle_ = ImageHandle;
DebugAssertViaProtocol (NULL, 0, "gImageHandle != ((void *) 0)");
gSystemTable_ = SystemTable;
DebugAssertViaProtocol (NULL, 0, "gST != ((void *) 0)");
gBootServices_ = SystemTable->BootServices;
DebugAssertViaProtocol (NULL, 0, "gBS != ((void *) 0)");
gRuntimeServices_ = SystemTable->RuntimeServices;
DebugAssertViaProtocol (NULL, 0, "gRT != ((void *) 0)");
gBootServicesBs_ = SystemTable->BootServices;
gRuntimeServicesRt_ = SystemTable->RuntimeServices;
//
// 2. CreateEvent(EVT_NOTIFY_SIGNAL, TPL_NOTIFY, ClearBs, NULL, NULL).
//
gBootServicesBs_->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
OnExitBootServicesClearBs,
NULL,
NULL
);
//
// 3. CreateEventEx(EVT_RUNTIME | EVT_NOTIFY_SIGNAL, TPL_NOTIFY,
// ConvertLenovo, NULL, &gRegClearBs_).
// (Uses CreateEventEx with no event-group GUID -- registration only.)
//
gBootServicesBs_->CreateEventEx (
EVT_RUNTIME | EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
OnExitBootServicesConvertLenovo,
NULL,
&gRegClearBs_
);
//
// 4. Get the HOB list pointer.
//
GetHobListFromConfigTable ();
//
// 5. Locate the Lenovo Status Code Protocol.
//
GetLenovoStatusCodeProtocol ();
//
// 6. Locate the Runtime Status Code Protocol.
//
LocateRuntimeStatusCodeProtocol ();
//
// 7. RegisterProtocolNotify(gEfiStatusCodeRuntimeProtocolGuid, NOP).
//
Status = gBootServicesBs_->RegisterProtocolNotify (
(EFI_GUID *)&mStatusCodeRuntimeProtocolGuid,
RuntimeProtocolNotifyNop,
&gRuntimeProtocol_
);
if (EFI_ERROR (Status)) {
ReportStatusCodeFiltered (0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
DebugAssertViaProtocol (
"e:\\hs\\Build\\HR6N0XMLK\\DEBUG_VS2015\\X64"
"\\LenovoServerPkg\\POSTStatus\\LnvDxeStatusCode\\DEBUG\\AutoGen.c",
288,
"!EFI_ERROR (Status)"
);
}
//
// 8. RegisterProtocolNotify(gEfiEventVirtualAddressChangeGuid,
// OnVirtualAddressChange).
//
Status = gBootServicesBs_->RegisterProtocolNotify (
(EFI_GUID *)&mVirtualAddressChangeGuid,
OnVirtualAddressChange,
&gRegVirtAddrChange_
);
if (EFI_ERROR (Status)) {
ReportStatusCodeFiltered (0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
DebugAssertViaProtocol (
"e:\\hs\\MdeModulePkg\\Library\\RuntimeDxeReportStatusCodeLib\\ReportStatusCodeLib.c",
152,
"!EFI_ERROR (Status)"
);
}
//
// 9. RegisterProtocolNotify(gEfiEventExitBootServicesGuid,
// OnExitBootServicesConvertRuntime).
//
Status = gBootServicesBs_->RegisterProtocolNotify (
(EFI_GUID *)&mExitBootServicesGroupGuid,
OnExitBootServicesConvertRuntime,
&gRegExitBs_
);
if (EFI_ERROR (Status)) {
ReportStatusCodeFiltered (0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
DebugAssertViaProtocol (
"e:\\hs\\MdeModulePkg\\Library\\RuntimeDxeReportStatusCodeLib\\ReportStatusCodeLib.c",
165,
"!EFI_ERROR (Status)"
);
}
return EFI_SUCCESS;
}
// ===========================================================================
// _ModuleEntryPoint (0x10D0)
// ===========================================================================
EFI_STATUS
EFIAPI
LnvDxeStatusCodeEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
DriverSetupInit (ImageHandle, SystemTable);
ReportStatusCodeFiltered (
0x40,
"'FFDC_CHECKPOINT_PROGRESS_LOG' Disabled. No send DXE progress to BMC for FFDC \n"
);
return EFI_SUCCESS;
}