Newer
Older
AMI-Aptio-BIOS-Reversed / OemPlatformDxePhase / OemPlatformDxePhase.c
@Ajax Dong Ajax Dong 2 days ago 25 KB Init
/** @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;
}