Newer
Older
AMI-Aptio-BIOS-Reversed / LenovoServerPkg / POSTStatus / LnvDxeStatusCode / LnvDxeStatusCode.c
/** @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;
}