//-------------------------------------------------------------------------
// WheaSupport.c - WHEA Support DXE Driver for Lenovo HR650X BIOS
// Module: CpPlatPkg/Whea/WheaSupport/WheaSupport.c
// PE file: 0309_WheaSupport_95b18380d0d5 (from HR650X_3647_AJAX_BIOS)
//
// Build info:
// Source: e:\hs\CpPlatPkg\Whea\WheaSupport\WheaSupport.c
// Build: DEBUG_VS2015 X64
// Image: HR6N0XMLK
// GUID: {36232936-0E76-31C8-A13A-3AF2FC1C3932}
//
// This DXE driver implements Windows Hardware Error Architecture (WHEA)
// support. It constructs ACPI WHEA tables in memory and installs them
// via SMM communication at ReadyToBoot:
// - HEST (Hardware Error Source Table) - 0x8000 bytes
// - ERST (Error Record Serialization) - 0x2000 bytes
// - BERT (Boot Error Record Table) - 0x8000 bytes
// - EINJ (Error Injection Table) - 0x2000 bytes
//
// The driver also allocates a shared communication buffer (0xE000 bytes)
// at 0x4000 offset for HEST+ERST data, 0x6000 offset for BERT.
//-------------------------------------------------------------------------
#include "WheaSupport.h"
//-------------------------------------------------------------------------
// Global Variables (from IDA - .data section, imagebase 0x0)
//-------------------------------------------------------------------------
// Module globals (set during WheaSupportEntry)
EFI_HANDLE gImageHandle = NULL; // 0x1FF0
EFI_SYSTEM_TABLE *gSystemTable = NULL; // 0x1FE0
EFI_BOOT_SERVICES *gBootServices = NULL; // 0x1FE8
EFI_RUNTIME_SERVICES *gRuntimeServices = NULL; // 0x1FF8
// WHEA instance allocations (from WheaDriverInit)
VOID *gHest = NULL; // 0x1F38: 0x8000
VOID *gErst = NULL; // 0x1F40: 0x2000
VOID *gEinj = NULL; // 0x1F50: 0x2000
VOID *gBert = NULL; // 0x1F48: 0x8000
// Shared SMM communication buffer
VOID *gCommBuffer = NULL; // 0x1F68: 0xE000
// Pointers into comm buffer
VOID *gSharedData = NULL; // 0x1F58
VOID *gHestErstData = NULL; // 0x1F78: at +0x4000
VOID *gBertData = NULL; // 0x1F88: at +0x6000
UINT8 gEinjEntryCount = 8; // 0x1FD8: 8 or 9 entries
UINT32 gSize0x4000 = 0x4000; // 0x1F60
UINT32 gSize0x2000 = 0x2000; // 0x1F70
UINT32 gSize0x8000 = 0x8000; // 0x1F80
CHAR8 gWheaStr[] = "WHEA"; // 0x1F30
// Protocol handles
VOID *gSmmCommProtocol = NULL; // 0x1FD0
VOID *gDebugPort = NULL; // 0x2000
VOID *gPcdProtocol = NULL; // 0x2020
VOID *gDS = NULL; // 0x2008
VOID *gPciUsra = NULL; // 0x2010
VOID *gHobList = NULL; // 0x2018
// Function table for WHEA protocol
VOID *gFnCreateHest = NULL; // 0x1FA0
VOID *gFnGetErst = NULL; // 0x1FA8
VOID *gFnSetEinj = NULL; // 0x1FB0
VOID *gFnGetEinjCtx = NULL; // 0x1FB8
VOID *gFnGetBert = NULL; // 0x1FC0
VOID *gFnSetErst = NULL; // 0x1FC8
//-------------------------------------------------------------------------
// CR (CONTAINING_RECORD) macros
//
// The WHEA instance uses signature 0x41424344 ("ABCD") at offset -112 bytes
// from the checked field pointer.
//-------------------------------------------------------------------------
#define WHEA_INSTANCE_SIG 0x41424344ULL
#define WHEA_CR_OFFSET 0x70
#define WHEA_CR_FROM_FIELD(Ptr, Field) \
((Ptr) != NULL && \
*((UINT64 *)(Ptr) - (WHEA_CR_OFFSET / sizeof(UINT64))) == \
WHEA_INSTANCE_SIG \
? ((VOID *)((UINT64 *)(Ptr) - (WHEA_CR_OFFSET / sizeof(UINT64)))) \
: NULL)
//-------------------------------------------------------------------------
// InternalCopyMem (0x2A0)
//
// memmove with overlap handling.
//-------------------------------------------------------------------------
char *
InternalCopyMem (char *dst, char *src, UINT64 count)
{
char *orig_dst = dst;
if (src < dst && &src[count - 1] >= dst) {
// Backward copy for overlapping regions
src = &src[count - 1];
dst = &dst[count - 1];
goto DO_COPY;
}
// Forward copy in 8-byte chunks
{
UINT64 count_8 = count >> 3;
count &= 7;
qmemcpy(dst, src, 8 * count_8);
src += 8 * count_8;
dst += 8 * count_8;
}
DO_COPY:
qmemcpy(dst, src, count);
return orig_dst;
}
//-------------------------------------------------------------------------
// InternalZeroMem (0x2F0)
//
//-------------------------------------------------------------------------
char *
InternalZeroMem (char *buf, UINT64 size)
{
memset(buf, 0, 8 * (size >> 3));
memset(&buf[8 * (size >> 3)], 0, size & 7);
return buf;
}
//-------------------------------------------------------------------------
// _ModuleEntryPoint / WheaSupportEntry / WheaDriverInit
//
// Entry: standard UEFI DXE entry, chains into driver init.
//-------------------------------------------------------------------------
EFI_STATUS
EFIAPI
_ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
WheaSupportEntry(ImageHandle, SystemTable);
return WheaDriverInit();
}
//-------------------------------------------------------------------------
// WheaSupportEntry (0x358)
//
// Initializes UEFI boot services / runtime services globals,
// locates DxeServicesTable, PCI USRA protocol, HOB list, PCD protocol.
//-------------------------------------------------------------------------
__int64
WheaSupportEntry (__int64 ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
__int64 Status;
// Save globals
gImageHandle = (EFI_HANDLE)ImageHandle;
if (!ImageHandle)
DebugAssert("e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
51, "gImageHandle != ((void *) 0)");
gSystemTable = SystemTable;
if (!SystemTable)
DebugAssert("e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
57, "gST != ((void *) 0)");
gBootServices = SystemTable->BootServices;
if (!gBootServices)
DebugAssert("e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
63, "gBS != ((void *) 0)");
gRuntimeServices = SystemTable->RuntimeServices;
if (!gRuntimeServices)
DebugAssert(
"e:\\hs\\MdePkg\\Library\\UefiRuntimeServicesTableLib\\UefiRuntimeServicesTableLib.c",
47, "gRT != ((void *) 0)");
// Locate DxeServicesTable
Status = EfiGetSystemConfigurationTable(&gEfiDxeServicesTableGuid, &gDS);
if (Status < 0) {
DebugPrint(0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
DebugAssert("e:\\hs\\MdePkg\\Library\\DxeServicesTableLib\\DxeServicesTableLib.c",
64, "!EFI_ERROR (Status)");
}
if (!gDS)
DebugAssert("e:\\hs\\MdePkg\\Library\\DxeServicesTableLib\\DxeServicesTableLib.c",
65, "gDS != ((void *) 0)");
if (Status < 0) {
DebugPrint(0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
DebugAssert(
"e:\\hs\\Build\\HR6N0XMLK\\DEBUG_VS2015\\X64\\CpPlatPkg\\Whea\\WheaSupport\\WheaSupport\\DEBUG\\AutoGen.c",
300, "!EFI_ERROR (Status)");
}
// Locate PCI USRA protocol (for MM PCI config access)
if (!gPciUsra) {
Status = gBootServices->LocateProtocol(&gEfiMmPciBaseProtocolGuid, NULL, &gPciUsra);
if (Status < 0) {
DebugPrint(0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
DebugAssert("e:\\hs\\CpRcPkg\\Library\\DxeMmPciBaseLib\\DxeMmPciBaseLib.c",
52, "!EFI_ERROR (Status)");
}
if (!gPciUsra)
DebugAssert("e:\\hs\\CpRcPkg\\Library\\DxeMmPciBaseLib\\DxeMmPciBaseLib.c",
53, "mPciUsra != ((void *) 0)");
}
GetHobList();
return ((__int64 (*)(UINTN))(((UINT8 *)GetPcdProtocol()) + 32))(5);
}
//-------------------------------------------------------------------------
// WheaCreateHestErrorSrcDescriptor (0x524)
//
// Creates a HEST error source descriptor in the HEST table area.
//
// Types:
// 0 = IA-32 Machine Check (standard) -- 656 bytes
// 1 = IPMI -- 664 bytes
// 6 = PCIe Root Port AER -- 48 bytes (16+32)
// 7 = PCIe Device AER -- 44 bytes (16+28)
// 8 = PCIe Bridge AER -- 56 bytes (16+40)
// 9 = Generic Hardware Error Source -- variable
//-------------------------------------------------------------------------
UINT64
WheaCreateHestErrorSrcDescriptor (
_QWORD *a1, INT32 n6, CHAR8 a3, CHAR8 a4,
UINT16 *a5, INT32 a6, INT32 a7, __int64 a8
)
{
_QWORD *Instance;
__int64 HestBase;
__int64 Dst;
INT32 DescSize;
INT32 DataSize;
Instance = a1;
if (!a1)
return EFI_INVALID_PARAMETER;
// CR: find containing struct (-14 qwords = -112 bytes)
if (*(a1 - 14) == WHEA_INSTANCE_SIG)
Instance = a1 - 14;
else
DebugAssert("e:\\hs\\CpPlatPkg\\Whea\\WheaSupport\\WheaSupport.c",
86, "CR has Bad Signature");
HestBase = Instance[1]; // HEST table ptr
Dst = HestBase + *(UINT32 *)(HestBase + 4); // current end offset
if (n6 == 0) {
*(UINT16 *)Dst = 0;
DescSize = 656;
DataSize = 640;
goto COMMON;
}
if (n6 == 1) {
*(UINT16 *)Dst = 1;
DescSize = 664;
DataSize = 648;
goto COMMON;
}
if (n6 < 6 || n6 > 9)
return EFI_UNSUPPORTED;
if (n6 == 9) {
// Type 9: Generic Hardware Error Source
UINT64 maxLen;
DescSize = 64;
maxLen = MAX(*(UINT32 *)(a8 + 2), *(UINT32 *)(a8 + 46));
if (Instance[5] + maxLen + 8 > 0x4000)
return EFI_OUT_OF_RESOURCES;
*(UINT64 *)(a8 + 10) = Instance[7];
*(UINT64 *)Instance[7] = Instance[7] + 8;
*(UINT8 *)(a8 + 6) = 0;
*(UINT16 *)(a8 + 7) = 64;
*(UINT8 *)(a8 + 9) = 4;
Instance[7] += maxLen + 8;
Instance[5] += maxLen + 8;
*(UINT16 *)Dst = 9;
*a5 = *(UINT16 *)(HestBase + 36);
*(UINT16 *)(Dst + 2) = *(UINT16 *)(HestBase + 36);
*(UINT16 *)(Dst + 4) = *(UINT16 *)a8;
*(UINT8 *)(Dst + 7) = (a4 == 1);
*(UINT32 *)(Dst + 8) = a6;
*(UINT32 *)(Dst + 12) = a7;
*(UINT8 *)(Dst + 6) = a3;
*(UINT32 *)(Dst + 16) = *(UINT32 *)(a8 + 2);
gBootServices->CopyMem((VOID *)(Dst + 20), (VOID *)(a8 + 6), 12);
gBootServices->CopyMem((VOID *)(Dst + 32), (VOID *)(a8 + 18), 28);
*(UINT32 *)(Dst + 60) = *(UINT32 *)(a8 + 46);
goto DONE;
}
// Types 6, 7, 8 (PCIe AER)
*(UINT16 *)Dst = n6;
*a5 = *(UINT16 *)(HestBase + 36);
*(UINT16 *)(Dst + 2) = *(UINT16 *)(HestBase + 36);
*(UINT8 *)(Dst + 7) = (a4 == 1);
*(UINT32 *)(Dst + 8) = a6;
*(UINT32 *)(Dst + 12) = a7;
*(UINT16 *)(Dst + 4) = 0;
*(UINT8 *)(Dst + 6) = a3;
switch (n6 - 6) {
case 0: DataSize = 32; break;
case 1: DataSize = 28; break;
default:DataSize = 40; break;
}
gBootServices->CopyMem((VOID *)(Dst + 16), (VOID *)a8, DataSize);
DescSize = DataSize + 16;
goto DONE;
COMMON:
*a5 = *(UINT16 *)(HestBase + 36);
*(UINT16 *)(Dst + 2) = *(UINT16 *)(HestBase + 36);
*(UINT8 *)(Dst + 7) = (a4 == 1);
*(UINT32 *)(Dst + 8) = a6;
*(UINT32 *)(Dst + 12) = a7;
*(UINT16 *)(Dst + 4) = 0;
*(UINT8 *)(Dst + 6) = a3;
gBootServices->CopyMem((VOID *)(Dst + 16), (VOID *)a8, DataSize);
DONE:
*(UINT32 *)(HestBase + 4) += DescSize;
++*(UINT32 *)(HestBase + 36);
return 0;
}
//-------------------------------------------------------------------------
// WheaGetErstRecordCount (0x7DC)
//
// Dummy: returns 0 (no ERST records).
//-------------------------------------------------------------------------
UINT64 WheaGetErstRecordCount (VOID) { return 0; }
//-------------------------------------------------------------------------
// WheaSetEinjConfig (0x7E0)
//
// Configure EINJ table error injection entries.
// CR offset: -0x70 (112 bytes)
//-------------------------------------------------------------------------
UINT64
WheaSetEinjConfig (__int64 a1, __int64 Context, __int64 a3, __int64 EntryData)
{
__int64 Instance;
Instance = a1;
if (!a1) return EFI_INVALID_PARAMETER;
if (*(UINT64 *)(a1 - 112) == WHEA_INSTANCE_SIG)
Instance = a1 - 112;
else
DebugAssert(SOURCE_FILE, 250, "CR has Bad Signature");
if (gEinjEntryCount > 10)
DebugAssert(SOURCE_FILE, 252, "mEinjEntries <= 10");
// Set EinjContext at Instance+0x68, EinjEntryCount in table
*(UINT64 *)(Instance + 0x68) = Context;
*(UINT32 *)(*(UINT64 *)(Instance + 0x20) + 0x2C) = gEinjEntryCount;
gBootServices->CopyMem(
(VOID *)(*(UINT64 *)(Instance + 0x20) + 0x30),
(VOID *)EntryData,
32 * gEinjEntryCount);
// EINJ table length based on entries
if (gEinjEntryCount == 9)
*(UINT32 *)(*(UINT64 *)(Instance + 0x20) + 4) = 336;
else
*(UINT32 *)(*(UINT64 *)(Instance + 0x20) + 4) = 304;
return 0;
}
//-------------------------------------------------------------------------
// WheaGetEinjContext (0x8BC)
//-------------------------------------------------------------------------
UINT64
WheaGetEinjContext (__int64 a1, UINT64 *Context)
{
__int64 Instance;
Instance = a1;
if (!a1) return EFI_INVALID_PARAMETER;
if (*(UINT64 *)(a1 - 112) == WHEA_INSTANCE_SIG)
Instance = a1 - 112;
else
DebugAssert(SOURCE_FILE, 283, "CR has Bad Signature");
*Context = *(UINT64 *)(Instance + 0x68);
return 0;
}
//-------------------------------------------------------------------------
// WheaGetBertContext (0x91C)
//-------------------------------------------------------------------------
UINT64
WheaGetBertContext (__int64 a1, UINT64 *BertRegion, UINT64 *BertRegionSize)
{
__int64 Instance;
Instance = a1;
if (!a1) return EFI_INVALID_PARAMETER;
if (*(UINT64 *)(a1 - 112) == WHEA_INSTANCE_SIG)
Instance = a1 - 112;
else
DebugAssert(SOURCE_FILE, 309, "CR has Bad Signature");
*BertRegion = *(UINT64 *)(Instance + 0x40);
*BertRegionSize = *(UINT64 *)(Instance + 0x48);
return (*BertRegion && *BertRegionSize) ? 0 : EFI_NOT_FOUND;
}
//-------------------------------------------------------------------------
// WheaSetErstConfig (0x9A8)
//-------------------------------------------------------------------------
UINT64
WheaSetErstConfig (__int64 a1, UINT64 EntryCount, __int64 EntryData)
{
__int64 Instance;
Instance = a1;
if (!a1) return EFI_INVALID_PARAMETER;
if (*(UINT64 *)(a1 - 112) == WHEA_INSTANCE_SIG)
Instance = a1 - 112;
else
DebugAssert(SOURCE_FILE, 341, "CR has Bad Signature");
if (EntryCount > 16)
DebugAssert(SOURCE_FILE, 343, "InstCount <= 16");
*(UINT32 *)(*(UINT64 *)(Instance + 0x10) + 0x2C) = (UINT32)EntryCount;
gBootServices->CopyMem(
(VOID *)(*(UINT64 *)(Instance + 0x10) + 0x30),
(VOID *)EntryData,
32 * EntryCount);
*(UINT32 *)(*(UINT64 *)(Instance + 0x10) + 4) = 560;
return 0;
}
//-------------------------------------------------------------------------
// WheaInstallTables (0xA5C)
//
// Installs HEST, ERST, BERT, EINJ tables via SMM communication protocol.
// Calls ->Communicate() for each table, then frees buffers.
//-------------------------------------------------------------------------
UINT64
WheaInstallTables (__int64 Instance)
{
UINT64 Status;
UINT64 v15;
if (!Instance) return EFI_INVALID_PARAMETER;
if (*(UINT8 *)(Instance + 0x60)) // already installed
return EFI_ALREADY_STARTED;
if (gSmmCommProtocol) {
DebugPrint(0x80000000, "WheaSupport. Install Whea Tables \n");
// HEST
v15 = 0;
Status = ((UINT64 (*)(UINT64, UINT64, UINT32, UINT64 *))gSmmCommProtocol)(
(UINT64)gSmmCommProtocol,
*(UINT64 *)(Instance + 0x08),
*(UINT32 *)(*(UINT64 *)(Instance + 0x08) + 4),
&v15);
// ERST
v15 = 0;
Status |= ((UINT64 (*)(UINT64, UINT64, UINT32, UINT64 *))gSmmCommProtocol)(
(UINT64)gSmmCommProtocol,
*(UINT64 *)(Instance + 0x18),
*(UINT32 *)(*(UINT64 *)(Instance + 0x18) + 4),
&v15);
// BERT
v15 = 0;
Status |= ((UINT64 (*)(UINT64, UINT64, UINT32, UINT64 *))gSmmCommProtocol)(
(UINT64)gSmmCommProtocol,
*(UINT64 *)(Instance + 0x10),
*(UINT32 *)(*(UINT64 *)(Instance + 0x10) + 4),
&v15);
// EINJ
v15 = 0;
Status |= ((UINT64 (*)(UINT64, UINT64, UINT32, UINT64 *))gSmmCommProtocol)(
(UINT64)gSmmCommProtocol,
*(UINT64 *)(Instance + 0x20),
*(UINT32 *)(*(UINT64 *)(Instance + 0x20) + 4),
&v15);
if (Status < 0) {
DebugPrint(0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
DebugAssert(SOURCE_FILE, 378, "!EFI_ERROR (Status)");
}
// Mark installed and free tables
*(UINT8 *)(Instance + 0x60) = 1;
gBootServices->FreePool((VOID *)*(UINT64 *)(Instance + 0x08));
gBootServices->FreePool((VOID *)*(UINT64 *)(Instance + 0x18));
gBootServices->FreePool((VOID *)*(UINT64 *)(Instance + 0x10));
gBootServices->FreePool((VOID *)*(UINT64 *)(Instance + 0x20));
}
return 0;
}
//-------------------------------------------------------------------------
// WheaReadyToBootNotify (0xBBC)
//
// ReadyToBoot callback: calls WheaInstallTables.
// Tolerates EFI_ALREADY_STARTED (0x8000000000000014).
//-------------------------------------------------------------------------
EFI_STATUS
EFIAPI
WheaReadyToBootNotify (IN EFI_EVENT Event, IN VOID *Context)
{
EFI_STATUS Status;
Status = WheaInstallTables((__int64)Context);
if (Status < 0 && Status != EFI_ALREADY_STARTED) {
DebugPrint(0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
return DebugAssert(SOURCE_FILE, 402, "!EFI_ERROR (Status)");
}
return Status;
}
//-------------------------------------------------------------------------
// WheaDriverInit (0xC10) - Main init function
//
// 1. Locate WHEA protocol (skip if already)
// 2. Allocate HEST (0x8000), ERST (0x2000), EINJ (0x2000), BERT (0x8000)
// 3. Fill ACPI table headers with sig/revision/OEM data
// HEST: 0x54534548, ERST: 0x54535245, EINJ: 0x4A4E4945, BERT: 0x54524542
// 4. Allocate comm buffer (0xE000) and partition it
// 5. Register WHEA protocol interface
// 6. Locate SMM Communication protocol
// 7. Register ReadyToBoot callback
//-------------------------------------------------------------------------
EFI_STATUS
WheaDriverInit (VOID)
{
UINT8 n9;
UINT64 v4, v5, v8, v9;
UINT64 v10;
__int64 v11;
__int64 v15;
v10 = (__int64)&v15; // ImageHandle capture
v11 = 0;
// Locate WHEA protocol - if found, skip init (already registered)
if (gBootServices->LocateProtocol(&gWheaProtocolGuid, NULL, &v11) < 0
|| !((UINT8 (*)(__int64))(v11 + 8))(v11))
return EFI_UNSUPPORTED;
// Allocate tables
gHest = AllocateZeroPool(0x8000);
if (!gHest) DebugAssert(SOURCE_FILE, 476, "mWheaInst.Hest != NULL");
gErst = AllocateZeroPool(0x2000);
if (!gErst) DebugAssert(SOURCE_FILE, 478, "mWheaInst.Erst != NULL");
gEinj = AllocateZeroPool(0x2000);
if (!gEinj) DebugAssert(SOURCE_FILE, 480, "mWheaInst.Einj != NULL");
gBert = AllocateZeroPool(0x8000);
if (!gBert) DebugAssert(SOURCE_FILE, 482, "mWheaInst.Bert != NULL");
// HEST header
if (gHest) {
*(UINT32 *)gHest = 0x54534548; // "HEST"
*(UINT32 *)((UINT8 *)gHest + 4) = 40;
*(UINT32 *)((UINT8 *)gHest + 36) = 0;
*(UINT8 *)((UINT8 *)gHest + 8) = 1;
*(UINT8 *)((UINT8 *)gHest + 9) = 0;
InitAcpiTableHeader((__int64)gHest);
}
// ERST header
if (gErst) {
*(UINT32 *)gErst = 0x54535245; // "ERST"
*(UINT32 *)((UINT8 *)gErst + 4) = 560;
*(UINT32 *)((UINT8 *)gErst + 36) = 48;
*(UINT32 *)((UINT8 *)gErst + 44) = 0;
*(UINT8 *)((UINT8 *)gErst + 8) = 1;
*(UINT8 *)((UINT8 *)gErst + 9) = 0;
InitAcpiTableHeader((__int64)gErst);
}
// BERT header
if (gBert) {
*(UINT32 *)gBert = 0x54524542; // "BERT"
*(UINT32 *)((UINT8 *)gBert + 4) = 48;
*(UINT8 *)((UINT8 *)gBert + 8) = 1;
*(UINT8 *)((UINT8 *)gBert + 9) = 0;
InitAcpiTableHeader((__int64)gBert);
}
// EINJ header (determine entries from HW-reduced flag)
if (gEinj) {
*(UINT32 *)gEinj = 0x4A4E4945; // "EINJ"
if (*(UINT8 *)(v11 + 4) == 1) { // HW-reduced ACPI?
*(UINT32 *)((UINT8 *)gEinj + 4) = 336;
n9 = 9;
} else {
*(UINT32 *)((UINT8 *)gEinj + 4) = 304;
n9 = 8;
}
gEinjEntryCount = n9;
*(UINT32 *)((UINT8 *)gEinj + 36) = 12;
*(UINT32 *)((UINT8 *)gEinj + 44) = n9;
*(UINT8 *)((UINT8 *)gEinj + 8) = 1;
*(UINT8 *)((UINT8 *)gEinj + 9) = 0;
InitAcpiTableHeader((__int64)gEinj);
}
// Allocate SMM communication buffer (0xE000)
v4 = gBootServices->AllocatePool(EfiBootServicesData, 57344, &gCommBuffer);
if (v4 < 0) {
DebugPrint(0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", v4);
DebugAssert(SOURCE_FILE, 535, "!EFI_ERROR (Status)");
}
gBootServices->SetMem(gCommBuffer, 57344, 0);
// Partition: [0x0000-reserved][0x4000-HEST/ERST data][0x6000-BERT region]
gSharedData = NULL; // placeholder
gHestErstData = (UINT8 *)gCommBuffer + 0x4000;
gBertData = (UINT8 *)gCommBuffer + 0x6000;
// BERT error region
*(UINT32 *)((UINT8 *)gBert + 36) = 0x8000;
*(UINT64 *)((UINT8 *)gBert + 40) = (UINT64)gBertData;
// Function table for protocol
v10 = 0;
gFnCreateHest = (VOID *)WheaCreateHestErrorSrcDescriptor;
gFnGetErst = (VOID *)WheaGetErstRecordCount;
gFnSetEinj = (VOID *)WheaSetEinjConfig;
gFnGetEinjCtx = (VOID *)WheaGetEinjContext;
gFnGetBert = (VOID *)WheaGetBertContext;
gFnSetErst = (VOID *)WheaSetErstConfig;
v5 = gBootServices->InstallProtocolInterface(
&v10, &gWheaProtocolGuid,
EFI_NATIVE_INTERFACE,
&gFnCreateHest);
if (v5 < 0) {
DebugPrint(0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", v5);
DebugAssert(SOURCE_FILE, 567, "!EFI_ERROR (Status)");
}
// Locate SMM Communication protocol
gSmmCommProtocol = NULL;
gBootServices->LocateProtocol(&gSmmCommunicationProtocolGuid, NULL, &gSmmCommProtocol);
// Register ReadyToBoot event
v8 = RegisterWheaReadyToBoot();
v9 = v8;
if (v8 < 0) {
DebugPrint(0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", v8);
DebugAssert(SOURCE_FILE, 584, "!EFI_ERROR (Status)");
}
return v9;
}
//-------------------------------------------------------------------------
// DebugLibConstructor (0x1068)
// DebugPrint (0x10E8)
// DebugAssert (0x1170)
//
// Standard UEFI debug library functions used by MDE modules.
// See edk2/MdePkg/Library/UefiDebugLibStdErr/
//-------------------------------------------------------------------------
__int64 DebugLibConstructor (VOID)
{
UINT64 result = (UINT64)gDebugPort;
if (!gDebugPort) {
UINT64 tsc;
tsc = gBootServices->GetTimerValue(31);
gBootServices->RestoreTimerValue(tsc);
if (tsc <= 0x10) {
if (gBootServices->LocateProtocol(&gEfiDebugPortProtocolGuid, NULL, &gDebugPort) >= 0)
return (__int64)gDebugPort;
gDebugPort = NULL;
}
return 0;
}
return result;
}
CHAR8 DebugPrint(__int64 ErrorLevel, const CHAR8 *Format, ...)
{
va_list va;
UINT64 DebugPort;
UINT64 FilterMask;
UINT8 n3;
va_start(va, Format);
DebugPort = DebugLibConstructor();
FilterMask = 0;
if (DebugPort) {
// Read debug level from CMOS reg 0x4B
__outbyte(0x70, __inbyte(0x70) & 0x80 | 0x4B);
n3 = __inbyte(0x71);
if ((UINT8)n3 > 3)
if (!n3)
n3 = (UINT8)(MEMORY[0xFDAF0490] & 2) | 1;
if ((UINT8)(n3 - 1) <= 0xFD)
FilterMask = (n3 == 1) ? 0x80000004 : 0x80000006;
if ((FilterMask & ErrorLevel) != 0)
((__int64 (*)(__int64, const CHAR8 *, va_list))DebugPort)(ErrorLevel, Format, va);
}
return 0;
}
__int64 DebugAssert(__int64 FileName, __int64 LineNumber, __int64 Description)
{
__int64 result = DebugLibConstructor();
if (result)
return (*(__int64 (__fastcall **)(__int64, __int64, __int64))(result + 8))(
FileName, LineNumber, Description);
return result;
}
//-------------------------------------------------------------------------
// Memory allocation helpers
//-------------------------------------------------------------------------
VOID *AllocatePool(UINTN PoolType, UINTN AllocationSize)
{
VOID *Buf = NULL;
if (gBootServices->AllocatePool(PoolType, AllocationSize, &Buf) < 0)
return NULL;
return Buf;
}
VOID *AllocateZeroPool(UINTN Size)
{
VOID *Buf = AllocatePool(EfiBootServicesData, Size);
if (Buf) Buf = ZeroMem(Buf, Size);
return Buf;
}
//-------------------------------------------------------------------------
// EfiGetSystemConfigurationTable (0x1208)
//-------------------------------------------------------------------------
EFI_STATUS
EfiGetSystemConfigurationTable (IN EFI_GUID *TableGuid, OUT VOID **Table)
{
UINT64 i, count;
if (!TableGuid) DebugAssert(STR_LIB_UEFI_C, 97, "TableGuid != NULL");
if (!Table) DebugAssert(STR_LIB_UEFI_C, 98, "Table != NULL");
*Table = NULL;
count = *(UINT64 *)((UINT8 *)gSystemTable + 0x68);
if (!count) return EFI_NOT_FOUND;
for (i = 0; ; i += 24) {
if (CompareGuid(TableGuid,
*(EFI_GUID **)((UINT8 *)gSystemTable + 0x70) + i / sizeof(EFI_GUID)))
break;
if (i / 24 + 1 >= count)
return EFI_NOT_FOUND;
}
*Table = *(VOID **)(*(UINT64 *)((UINT8 *)gSystemTable + 0x70) + i + 16);
return 0;
}
//-------------------------------------------------------------------------
// RegisterWheaReadyToBoot (0x12CC)
//-------------------------------------------------------------------------
EFI_STATUS RegisterWheaReadyToBoot (VOID)
{
if (*(UINT32 *)((UINT8 *)gSystemTable + 8) >= 0x20000) {
return gBootServices->CreateEventEx(
EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
WheaReadyToBootNotify, (VOID *)"WHEA",
&gEfiEventReadyToBootGuid,
(EFI_EVENT *)&gEventBuffer);
}
DebugPrint(0x80000000, "EFI1.1 can't support ReadyToBootEvent!");
DebugAssert("e:\\hs\\MdePkg\\Library\\UefiLib\\UefiNotTiano.c", 185, "((BOOLEAN)(0==1))");
return EFI_UNSUPPORTED;
}
//-------------------------------------------------------------------------
// GetHobList (0x1354)
// GetPcdProtocol (0x15D0)
// InitAcpiTableHeader (0x13D8)
// CopyMem (0x1458)
// ZeroMem (0x14F8)
// CompareGuid (0x1568)
// ReadUnaligned64 (0x165C)
//-------------------------------------------------------------------------
VOID *GetHobList (VOID)
{
if (!gHobList) {
if (EfiGetSystemConfigurationTable(&gEfiHobListGuid, &gHobList) < 0) {
DebugPrint(0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", 0);
DebugAssert("e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c", 54, "!EFI_ERROR (Status)");
}
if (!gHobList)
DebugAssert("e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c", 55, "mHobList != NULL");
}
return gHobList;
}
VOID *GetPcdProtocol (VOID)
{
if (!gPcdProtocol) {
if (gBootServices->LocateProtocol(&gEfiPcdProtocolGuid, NULL, &gPcdProtocol) < 0) {
DebugPrint(0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", 0);
DebugAssert("e:\\hs\\MdePkg\\Library\\DxePcdLib\\DxePcdLib.c", 78, "!EFI_ERROR (Status)");
}
if (!gPcdProtocol)
DebugAssert("e:\\hs\\MdePkg\\Library\\DxePcdLib\\DxePcdLib.c", 79, "mPcd != NULL");
}
return gPcdProtocol;
}
UINT64 InitAcpiTableHeader (__int64 Table)
{
__int64 Pcd1, Pcd2;
CHAR8 OemId[6];
CHAR8 OemTableId[8];
// Set initial OEM placeholder
*(UINT32 *)(Table + 10) = 0x454D4F49; // "OEM "
*(UINT16 *)(Table + 14) = 0x2020; // " "
Pcd1 = GetPcdProtocol();
Pcd2 = GetPcdProtocol();
// Get OEM values from PCD protocol
// PcdGet32(32) = OEM ID, PcdGet32(31) = OEM Table ID
*(UINT64 *)&OemTableId = ((UINT64 (*)(UINT32))(((UINT8 *)Pcd1) + 32))(32);
CopyMem((VOID *)OemId, (VOID *)((UINT8 *)Pcd2 + 40), 6);
CopyMem((VOID *)(Table + 10), OemId, 6);
CopyMem((VOID *)(Table + 16), &OemTableId, 8);
*(UINT32 *)(Table + 24) = 1; // Creator ID
*(UINT32 *)(Table + 28) = 1280593481; // Creator Rev
*(UINT32 *)(Table + 32) = 1; // OEM Revision
return 1;
}
VOID *CopyMem (VOID *Dest, CONST VOID *Src, UINTN Len)
{
if (!Len) return Dest;
if ((UINTN)(Len - 1) > ~(UINTN)Dest)
DebugAssert(STR_COPYMEM_C, 56, STR_OFFSET_CHECK);
if ((UINTN)(Len - 1) > ~(UINTN)Src)
DebugAssert(STR_COPYMEM_C, 57, STR_OFFSET_CHECK2);
if (Dest != Src)
return InternalCopyMem((char *)Dest, (char *)Src, Len);
return Dest;
}
VOID *ZeroMem (VOID *Buf, UINTN Len)
{
if (!Len) return Buf;
if (!Buf) DebugAssert(STR_ZEROMEM_C, 53, "Buffer != NULL");
if (Len > ~(UINTN)Buf)
DebugAssert(STR_ZEROMEM_C, 54, STR_LENGTH_CHECK);
return InternalZeroMem((char *)Buf, Len);
}
BOOLEAN CompareGuid (CONST EFI_GUID *g1, CONST EFI_GUID *g2)
{
return ReadUnaligned64(g1) == ReadUnaligned64(g2)
&& ReadUnaligned64((UINT8 *)g1 + 8) == ReadUnaligned64((UINT8 *)g2 + 8);
}
UINT64 ReadUnaligned64 (CONST VOID *Buf)
{
if (!Buf) DebugAssert("e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c", 192, "Buffer != NULL");
return *(UINT64 *)Buf;
}