/** @file
OemPlatformDxePhase.c - Lenovo HR650X OEM Platform DXE Phase Driver
This module implements platform-specific initialization during the DXE
phase. It handles:
1. UEFI Boot/Runtime services pointer caching (library init pattern)
2. DXE Services Table registration for GCD management
3. MM PCI Base Protocol setup for PCIe segment bus access
4. PCD Protocol for PCIe segment bus table sizing
5. Memory topology enumeration via HOB traversal
6. IPMI SEL logging for disabled DIMMs
Build info from embedded strings:
Module: OemPlatformDxePhase.efi
Package: LenovoServerPkg\OemPlatformDxePhase\OemPlatformDxePhase
Build Path: e:\hs\Build\HR6N0XMLK\DEBUG_VS2015\X64\
Toolchain: VS2015, DEBUG
Source: AutoGen.c (at line 364 for ASSERT)
**/
#include "OemPlatformDxePhase.h"
//
// ============================================================================
// Global Data
// ============================================================================
//
// NOTE: These globals are initialized by OemPlatformDxePhaseInitialize().
// They follow the UEFI standard library pattern for boot services table libs.
// Addresses in comments reference the .data section in the original PE image.
//
// @ 0x14B8: EFI System Table pointer (gST)
// @ 0x14C0: EFI Boot Services pointer (gBS)
// @ 0x14C8: Image Handle
// @ 0x14D0: EFI Runtime Services pointer (gRT)
void *gMmPciUsra; // @ 0x14E8: MM PCI Usra Protocol
void *gIpmiTransport; // @ 0x14B0: IPMI Transport Protocol
void *gDebugProtocol; // @ 0x14D8: Debug Output Protocol
void *gDxeServicesTable; // @ 0x14E0: DXE Services Table
void *gHobList; // @ 0x14F0: HOB List
void *gPcdProtocol; // @ 0x1548: PCD Protocol
//
// Static buffers used by CopyMem (internal)
//
static char DstBuffer[0x48]; // @ 0x1500: destination buffer (72 bytes)
static UINT8 N3; // @ 0x1550: temp for CMOS debug level
//
// ============================================================================
// Helper Functions
// ============================================================================
/**
Reads a 64-bit value from memory without alignment requirements.
@param[in] Buffer Address to read from (may be unaligned)
@return The 64-bit value at Buffer
Used by CompareGuid() to compare GUIDs as two 64-bit integers.
**/
UINT64
ReadUnaligned64 (
const void *Buffer
)
{
if (Buffer == NULL) {
DebugAssert (
"e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
192,
"Buffer != ((void *) 0)"
);
}
return *(const UINT64 *)Buffer;
}
/**
Compares two GUIDs by splitting each into two 64-bit halves.
The GUID is compared as two 64-bit words:
- Qword[0] = bytes 0..7
- Qword[1] = bytes 8..15
@param[in] Guid1 First GUID to compare
@param[in] Guid2 Second GUID to compare
@retval TRUE GUIDs are identical
@retval FALSE GUIDs differ
**/
BOOLEAN
CompareGuid (
const GUID *Guid1,
const GUID *Guid2
)
{
UINT64 Qw1Lo;
UINT64 Qw1Hi;
UINT64 Qw2Lo;
UINT64 Qw2Hi;
Qw1Lo = ReadUnaligned64 (Guid1);
Qw1Hi = ReadUnaligned64 ((const void *)((const UINT8 *)Guid1 + 8));
Qw2Lo = ReadUnaligned64 (Guid2);
Qw2Hi = ReadUnaligned64 ((const void *)((const UINT8 *)Guid2 + 8));
return (BOOLEAN)(Qw1Lo == Qw2Lo && Qw1Hi == Qw2Hi);
}
/**
Overlapping memory copy, handling forward/backward move.
If destination is after source and the buffers overlap, copies from
end-to-start to avoid corruption. Otherwise copies from start-to-end
in aligned 8-byte chunks followed by remaining bytes.
@param[out] Dst Destination buffer
@param[in] Src Source buffer
@param[in] Count Number of bytes to copy
@return Pointer to destination buffer (matches Dst parameter)
**/
char *
InternalMemCopyMem (
char *Dst,
const char *Src,
UINT64 Count
)
{
UINT64 CountAligned;
UINT64 Remainder;
if ((Src < Dst) && (&Src[Count - 1] >= Dst)) {
//
// Overlapping with Dst after Src: copy backwards
//
CopyMemBackwards (Dst, Src, Count);
} else {
//
// Non-overlapping or Src after Dst: copy forwards in 8-byte chunks
//
CountAligned = Count >> 3;
Remainder = Count & 7;
qmemcpy (Dst, Src, CountAligned * 8);
qmemcpy (&Dst[CountAligned * 8], &Src[CountAligned * 8], Remainder);
}
return Dst;
}
/**
Copies memory with overlap-safe handling.
Validates buffer bounds and delegates to InternalMemCopyMem.
@param[out] Dst Destination buffer
@param[in] Src Source buffer
@param[in] Count Number of bytes to copy
@return Pointer to destination buffer
**/
char *
CopyMem (
void *Dst,
const void *Src,
UINT64 Count
)
{
if (Count == 0) {
return (char *)Dst;
}
//
// Validate that (Count - 1) does not overflow the address space
// for either destination or source.
//
if ((Count - 1) > (UINT64)(-1) - (UINT64)Dst) {
DebugAssert (
"e:\\hs\\MdePkg\\Library\\BaseMemoryLibRepStr\\CopyMemWrapper.c",
56,
"(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)DestinationBuffer)"
);
}
if ((Count - 1) > (UINT64)(-1) - (UINT64)Src) {
DebugAssert (
"e:\\hs\\MdePkg\\Library\\BaseMemoryLibRepStr\\CopyMemWrapper.c",
57,
"(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)SourceBuffer)"
);
}
if (Dst == Src) {
return (char *)Dst;
}
return InternalMemCopyMem ((char *)Dst, (const char *)Src, Count);
}
//
// ============================================================================
// Debug Output Functions
// ============================================================================
/**
Locates and caches the Debug Output Protocol.
Uses EFI Boot Services LocateProtocol to find the debug output interface.
The protocol interface provides 3 service functions:
+0: DebugPrint
+8: DebugAssert
+16: DebugAssertDead (unused)
@return Pointer to the debug protocol interface, or NULL
**/
void *
GetDebugOutputProtocol (
VOID
)
{
void *Protocol;
if (gDebugProtocol != NULL) {
return gDebugProtocol;
}
Protocol = AllocatePool (31);
if ((UINT64)Protocol <= 0x10) {
//
// Allocation too small or failed - skip protocol lookup
//
return NULL;
}
gBS->LocateProtocol (&gDebugOutputProtocolGuid, NULL, &gDebugProtocol);
if (gDebugProtocol == NULL) {
return NULL;
}
return gDebugProtocol;
}
/**
Debug print function with CMOS log-level filtering.
Reads the current debug level from CMOS index 0x4B and only prints
if the message ErrorLevel matches the configured filter.
CMOS port 0x70/0x71 protocol for debug level register 0x4B:
- Level 0: disabled (no debug output)
- Level 1: EFI_D_ERROR only
- Level 2: EFI_D_ERROR and EFI_D_WARN
- Level 3+: All messages
@param[in] ErrorLevel Debug message error level mask
@param[in] Format Format string
@param[in] ... Variable arguments (passed via va_list)
**/
UINT8
DebugPrint (
INT64 ErrorLevel,
const CHAR8 *Format,
...
)
{
void *DebugProtocol;
UINT64 FilterMask;
UINT8 DebugLevel;
UINT8 CmosValue;
UINT8 CmosDebugLevel;
va_list VaList;
va_start (VaList, Format);
DebugProtocol = GetDebugOutputProtocol ();
FilterMask = 0;
DebugLevel = 3;
if (DebugProtocol != NULL) {
//
// Read the debug level from CMOS register 0x4B
//
CmosValue = __inbyte (CMOS_INDEX_PORT);
__outbyte (CMOS_INDEX_PORT, CmosValue & 0x80 | CMOS_DEBUG_INDEX);
CmosDebugLevel = __inbyte (CMOS_DATA_PORT);
//
// Decode CMOS debug level
//
if (CmosDebugLevel > 3) {
if (CmosDebugLevel == 0) {
CmosDebugLevel = (MEMORY[0xFDAF0490] & 2) | 1;
}
} else {
DebugLevel = CmosDebugLevel - 1;
}
if (DebugLevel <= 0xFD) {
DebugLevel = 4;
if (CmosDebugLevel == 1) {
FilterMask = 0x80000000; // EFI_D_ERROR
} else {
FilterMask = 0x80000004; // EFI_D_WARN
}
}
//
// If the message ErrorLevel matches the filter, forward to protocol
//
if ((FilterMask & ErrorLevel) != 0) {
((DEBUG_PRINT_PROTOCOL *)DebugProtocol)->DebugPrint (
ErrorLevel,
Format,
VaList
);
}
}
va_end (VaList);
return DebugLevel;
}
/**
Debug assertion handler.
Called when a runtime assertion fails. Delegates to the Debug Output
Protocol's AssertBreak function (offset +8 from protocol base).
@param[in] FileName Source file name of the assertion
@param[in] LineNumber Line number of the assertion
@param[in] Description Description of the failed assertion
**/
VOID
DebugAssert (
const CHAR8 *FileName,
UINT64 LineNumber,
const CHAR8 *Description
)
{
void *DebugProtocol;
DebugProtocol = GetDebugOutputProtocol ();
if (DebugProtocol != NULL) {
((DEBUG_ASSERT_PROTOCOL *)DebugProtocol)->AssertBreak (
FileName,
LineNumber,
Description
);
}
}
//
// ============================================================================
// Configuration Table and HOB Services
// ============================================================================
/**
Retrieves a DXE configuration table by its GUID.
Iterates the System Table's configuration table array comparing
each entry's GUID with the requested GUID.
@param[in] TableGuid GUID of the configuration table to find
@param[out] Table Receives the pointer to the table
@retval EFI_SUCCESS Table found, Table is valid
@retval EFI_UNSUPPORTED No configuration table exists in system table
@retval EFI_NOT_FOUND No table with the matching GUID found
**/
EFI_STATUS
InternalGetDxeServicesTable (
const GUID *TableGuid,
void **Table
)
{
UINT64 NumberOfEntries;
UINT64 Index;
GUID *ConfigTable;
if (TableGuid == NULL) {
DebugAssert (
"e:\\hs\\MdePkg\\Library\\UefiLib\\UefiLib.c",
97,
"TableGuid != ((void *) 0)"
);
}
if (Table == NULL) {
DebugAssert (
"e:\\hs\\MdePkg\\Library\\UefiLib\\UefiLib.c",
98,
"Table != ((void *) 0)"
);
}
*Table = NULL;
NumberOfEntries = *(UINT64 *)((UINT8 *)gST + 104);
if (NumberOfEntries == 0) {
return EFI_UNSUPPORTED;
}
ConfigTable = *(GUID **)((UINT8 *)gST + 112);
Index = 0;
while (!CompareGuid (TableGuid, &ConfigTable[Index])) {
Index++;
if (Index >= NumberOfEntries) {
return EFI_NOT_FOUND;
}
}
//
// Each configuration table entry is 24 bytes:
// +0: GUID (16 bytes)
// +16: Table pointer (8 bytes)
//
*Table = *(void **)((UINT8 *)ConfigTable + (24 * Index) + 16);
return EFI_SUCCESS;
}
/**
Gets the HOB (Hand-Off Block) list pointer.
Retrieves the HOB list by looking up the DXE services configuration
table containing the HOB list GUID.
@return Pointer to the start of the HOB list. Asserts if not found.
**/
VOID *
GetHobList (
VOID
)
{
EFI_STATUS Status;
if (gHobList != NULL) {
return gHobList;
}
Status = InternalGetDxeServicesTable (&gEfiHobListGuid, &gHobList);
if (EFI_ERROR (Status)) {
DebugPrint (
0x80000000,
"\nASSERT_EFI_ERROR (Status = %r)\n",
Status
);
DebugAssert (
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
54,
"!EFI_ERROR (Status)"
);
}
if (gHobList == NULL) {
DebugAssert (
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
55,
"mHobList != ((void *) 0)"
);
}
return gHobList;
}
/**
Walks the HOB list to find a HOB of type GUID Extension (type 4).
Starting from the given HOB header, advances through the HOB list
until finding a HOB with type 4 (EFI_HOB_TYPE_GUID_EXTENSION).
HOB header structure:
+0: UINT16 Type
+2: UINT16 Length (in bytes, includes 8-byte header)
@param[in] HobStart Pointer to the first HOB to examine
@return Pointer to the matching HOB (type 4), or NULL if end of list
**/
UINT16 *
GetNextHobByType (
UINT16 *HobStart
)
{
UINT16 HobType;
UINT16 HobLength;
if (HobStart == NULL) {
DebugAssert (
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
108,
"HobStart != ((void *) 0)"
);
}
while (TRUE) {
HobType = *HobStart;
HobLength = HobStart[1];
if (HobType == EFI_HOB_TYPE_END_OF_HOB_LIST) {
return NULL;
}
if (HobType == EFI_HOB_TYPE_GUID_EXTENSION) {
return HobStart;
}
//
// Advance to next HOB using the length field
//
HobStart = (UINT16 *)((UINT8 *)HobStart + HobLength);
}
}
//
// ============================================================================
// PCD Protocol Services
// ============================================================================
/**
Locates and caches the PCD (Platform Configuration Database) Protocol.
Uses EFI Boot Services LocateProtocol to find the PCD protocol interface.
The protocol provides access to platform configuration values including
PCIe segment bus table size.
@return Pointer to the PCD protocol interface
**/
void *
GetPcdProtocol (
VOID
)
{
EFI_STATUS Status;
if (gPcdProtocol != NULL) {
return gPcdProtocol;
}
Status = gBS->LocateProtocol (&gEfiPcdProtocolGuid, NULL, &gPcdProtocol);
if (EFI_ERROR (Status)) {
DebugPrint (
0x80000000,
"\nASSERT_EFI_ERROR (Status = %r)\n",
Status
);
DebugAssert (
"e:\\hs\\MdePkg\\Library\\DxePcdLib\\DxePcdLib.c",
78,
"!EFI_ERROR (Status)"
);
}
if (gPcdProtocol == NULL) {
DebugAssert (
"e:\\hs\\MdePkg\\Library\\DxePcdLib\\DxePcdLib.c",
79,
"mPcd != ((void *) 0)"
);
}
return gPcdProtocol;
}
//
// ============================================================================
// IPMI SEL Logging for Disabled DIMMs
// ============================================================================
/**
Probes the memory topology from the system HOB and logs all disabled
DIMMs via IPMI SEL (System Event Log).
Algorithm:
1. Walk HOB list to find the memory resource HOB (type GUID Ext)
by matching the memory topology GUID
2. Offsets into HOB data at +5346 bytes to reach memory topology
3. Iterates over sockets [0..9], channels [0..5], DIMMs [0..1]
4. For each DIMM: check presence byte and enable byte
5. If DIMM is present but disabled, constructs a SEL record and
sends it via IPMI "Add SEL Entry" command
Memory topology layout within the system HOB:
Per DIMM: 168 bytes
Per channel: 527 bytes
Per socket: 5337 bytes
Data offset: 5346 from HOB base
@retval EFI_SUCCESS All DIMMs checked, disabled ones logged
@retval EFI_NOT_FOUND Required HOB not found
**/
EFI_STATUS
OemPlatformCheckAndLogDimms (
VOID
)
{
UINT8 DimmIndex;
EFI_STATUS Status;
UINT16 *MemHob;
UINT16 *CurrentHob;
UINT8 *SocketTopology;
UINT8 Socket;
UINT8 Channel;
UINT8 Dimm;
UINT8 *DimmEntry;
UINT8 *ChannelBase;
EFI_SEL_RECORD SelRecord;
UINT8 SelRecordSize;
UINT16 SelRecordReserved;
DimmIndex = 0;
SelRecordReserved = 0;
//
// Build the SEL record command frame
//
SelRecord.EvtDirType = 0;
SelRecord.EventData1 = 2;
SelRecord.EventData2 = 0;
SelRecord.EventData3 = 0;
//
// Locate the memory topology HOB
//
CurrentHob = (UINT16 *)GetHobList ();
Status = EFI_STATUS_NOT_FOUND;
while (CurrentHob != NULL) {
if (CompareGuid (&gMemoryTopologyGuid, (GUID *)(CurrentHob + 4))) {
break;
}
CurrentHob = GetNextHobByType (CurrentHob);
}
if (CurrentHob == NULL) {
DebugPrint (
0x80000000,
"locate DXE ipmi Status: %r\n",
EFI_STATUS_NOT_FOUND
);
return EFI_STATUS_NOT_FOUND;
}
//
// Memory topology data starts at offset +5346 from the HOB structure
//
SocketTopology = (UINT8 *)CurrentHob + MEM_HOB_BASE_OFFSET;
//
// Iterate over 10 sockets
//
for (Socket = 0; Socket < MAX_SOCKETS; Socket++) {
ChannelBase = SocketTopology;
//
// 6 channels per socket
//
for (Channel = 0; Channel < MAX_CHANNELS; Channel++) {
DimmEntry = ChannelBase;
//
// 2 DIMMs per channel
//
for (Dimm = 0; Dimm < MAX_DIMMS; Dimm++) {
DebugPrint (
64,
"Check Socket %d, Channel %d, DIMM %d,present: %x \n",
Socket,
Channel,
Dimm,
*DimmEntry
);
if (*DimmEntry != 0) {
//
// DIMM is present - check if enabled
//
if (DimmEntry[1] == 0) {
//
// DIMM is disabled - log via IPMI SEL
//
DebugPrint (
64,
"Socket %d, Channel %d, DIMM %d is disabled \n",
Socket,
Channel,
Dimm
);
//
// Build SEL record for the disabled DIMM
//
SelRecord.RecordType = 0xA4; // OEM System Event Record
SelRecord.EventData3 = (UINT8)Socket;
SelRecord.EventData1 = Dimm + 2 * (Channel + (Socket << 3));
SelRecordSize = MEM_RECORD_SIZE;
//
// Encode channel position:
// Top nibble = Channel, bottom nibble = DimmIndex
//
*(UINT16 *)&SelRecord.EvtDirType =
(UINT16)((Channel << 4) | (DimmIndex & 0x0F));
//
// Clear remaining event data
//
SelRecord.EventData2 = 0;
SelRecord.EventData3 &= 0x0F;
//
// Send IPMI Add SEL Entry
//
if (gIpmiTransport != NULL ||
(gBS->LocateProtocol (
&gIpmiTransportProtocolGuid,
NULL,
&gIpmiTransport
) >= 0))
{
DebugPrint (
0x80000000,
"Size of EFI_SEL_RECORD_DATA : 0x%X\n",
MEM_RECORD_SIZE
);
//
// IPMI Add SEL command via transport protocol
//
Status = ((IPMI_TRANSPORT_PROTOCOL *)gIpmiTransport)->AddSel (
gIpmiTransport,
TRUE, // SEL entry type
0, // Reserved
IPMI_NETFN_STORAGE,
&SelRecordReserved,
MEM_RECORD_SIZE,
(UINT8 *)&SelRecord,
&SelRecordSize
);
DebugPrint (
0x80000000,
"Add SEL Status: %r, ResponseData %x,%x,\n",
Status,
SelRecordSize,
SelRecord.EventData1
);
}
}
}
DimmIndex++;
DimmEntry += DIMM_STRIDE;
}
ChannelBase += CHANNEL_STRIDE;
DimmIndex = 0;
}
SocketTopology += SOCKET_STRIDE;
}
return EFI_SUCCESS;
}
//
// ============================================================================
// Main Entry Point - Module Initialization
// ============================================================================
/**
UEFI Driver Entry Point for OemPlatformDxePhase.
Initialization sequence:
1. Cache global Boot Services / Runtime Services / System Table pointers
2. Register DXE Services Table for GCD configuration
3. Locate and cache MM PCI Base Protocol (mPciUsra) for PCIe segment bus
4. Initialize HOB list for memory topology access
5. Get PCD protocol and size the PCIe segment bus table
6. Call OemPlatformCheckAndLogDimms() to log disabled DIMMs via IPMI
7. Write CMOS checkpoint (0x72=0x71, 0x73=0xBB) marking completion
@param[in] ImageHandle The firmware allocated handle for the EFI image
@param[in] SystemTable A pointer to the EFI System Table
@retval EFI_SUCCESS The entry point executed successfully
**/
EFI_STATUS
EFIAPI
OemPlatformDxePhaseInitialize (
EFI_HANDLE ImageHandle,
EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
VOID *PcieSegBusTable;
UINT64 PcieSegBusTableSize;
// ========================================================================
// Phase 1: Cache UEFI Boot Services pointers
//
gImageHandle = ImageHandle;
if (ImageHandle == NULL) {
DebugAssert (
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
51,
"gImageHandle != ((void *) 0)"
);
}
gST = SystemTable;
if (SystemTable == NULL) {
DebugAssert (
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
57,
"gST != ((void *) 0)"
);
}
gBS = SystemTable->BootServices;
if (gBS == NULL) {
DebugAssert (
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
63,
"gBS != ((void *) 0)"
);
}
gRT = SystemTable->RuntimeServices;
if (gRT == NULL) {
DebugAssert (
"e:\\hs\\MdePkg\\Library\\UefiRuntimeServicesTableLib\\UefiRuntimeServicesTableLib.c",
47,
"gRT != ((void *) 0)"
);
}
// ========================================================================
// Phase 2: Initialize DXE Services Table (for GCD access)
//
Status = InternalGetDxeServicesTable (&gEfiDxeServicesTableGuid, &gDxeServicesTable);
if (EFI_ERROR (Status)) {
DebugPrint (0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
DebugAssert (
"e:\\hs\\MdePkg\\Library\\DxeServicesTableLib\\DxeServicesTableLib.c",
64,
"!EFI_ERROR (Status)"
);
}
if (gDxeServicesTable == NULL) {
DebugAssert (
"e:\\hs\\MdePkg\\Library\\DxeServicesTableLib\\DxeServicesTableLib.c",
65,
"gDS != ((void *) 0)"
);
}
if (EFI_ERROR (Status)) {
DebugPrint (0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
DebugAssert (
"e:\\hs\\Build\\HR6N0XMLK\\DEBUG_VS2015\\X64\\LenovoServerPkg\\OemPlatformDxePhase\\OemPlatformDxePhase\\DEBUG\\AutoGen.c",
364,
"!EFI_ERROR (Status)"
);
}
// ========================================================================
// Phase 3: Locate and cache MM PCI Base Protocol
//
if (gMmPciUsra == NULL) {
Status = gBS->LocateProtocol (&gEfiMmPciBaseProtocolGuid, NULL, &gMmPciUsra);
if (EFI_ERROR (Status)) {
DebugPrint (0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
DebugAssert (
"e:\\hs\\CpRcPkg\\Library\\DxeMmPciBaseLib\\DxeMmPciBaseLib.c",
52,
"!EFI_ERROR (Status)"
);
}
if (gMmPciUsra == NULL) {
DebugAssert (
"e:\\hs\\CpRcPkg\\Library\\DxeMmPciBaseLib\\DxeMmPciBaseLib.c",
53,
"mPciUsra != ((void *) 0)"
);
}
}
// ========================================================================
// Phase 4: Initialize HOB list for memory topology
//
GetHobList ();
// ========================================================================
// Phase 5: Get PCD protocol and configure PCIe segment bus table size
//
PcdProtocol = GetPcdProtocol ();
//
// PCD protocol vtable interface:
// +0: Reserved
// +8: Reserved
// +16: Reserved
// +24: Reserved
// +32: SetValue (PCD token number)
// +40: GetSize (PCD token number)
// +48: GetSizes? (skip)
// +56: GetValue (PCD token number)
//
PcdProtocol->SetValue (5);
PcieSegBusTableSize = PcdProtocol->GetSize (7);
PcdProtocol->GetSizes (7);
if (PcieSegBusTableSize > 0x48) {
DebugAssert (
"e:\\hs\\AmiCRBPkg\\Library\\AmiPcieSegBusLib\\AmiPcieSegBusDxeSmm.c",
60,
"sizeof (PCIE_SEG_BUS_TABLE) >= LibPcdGetSize(7U)"
);
}
PcieSegBusTableSize = PcdProtocol->GetValue (7);
// ========================================================================
// Phase 6: Initialize PCIe segment bus table (CopyMem)
//
CopyMem (&DstBuffer, (void *)PcieSegBusTableSize, PcieSegBusTableSize);
// ========================================================================
// Phase 7: Check memory topology and log disabled DIMMs
//
OemPlatformCheckAndLogDimms ();
return EFI_SUCCESS;
}
//
// ============================================================================
// Module Entry Point (AutoGen)
// ============================================================================
/**
UEFI module entry point (AutoGen).
Calls the main initialization function, then checks memory topology
for disabled DIMMs. Finally writes a completion marker to CMOS.
@param[in] ImageHandle The firmware allocated handle for the EFI image
@param[in] SystemTable A pointer to the EFI System Table
@retval EFI_SUCCESS Always returns success
**/
EFI_STATUS
EFIAPI
ModuleEntryPoint (
EFI_HANDLE ImageHandle,
EFI_SYSTEM_TABLE *SystemTable
)
{
//
// Initialize platform (boot services, DXE table, PCIe, PCD, etc.)
//
OemPlatformDxePhaseInitialize (ImageHandle, SystemTable);
//
// Log disabled DIMMs to IPMI SEL
//
OemPlatformCheckAndLogDimms ();
//
// Write completion checkpoint to CMOS
// 0x72 = 0x71 (CMOS index register for extended RAM)
// 0x73 = 0xBB (CMOS data register - platform init complete)
//
__outbyte (0x72, 0x71);
__outbyte (0x73, 0xBB);
return EFI_SUCCESS;
}