Newer
Older
AMI-Aptio-BIOS-Reversed / CRBPei / CRBPei.c
@Ajax Dong Ajax Dong 2 days ago 18 KB Init
/** @file CRBPei - Crash Record Buffer PEI Driver This PEI module initializes PCI Express base address detection via configuration cycles, updates the PcdPciExpressBaseAddress PCD,
 locates the IIO UDS (Unified Data Structure) HOB to populate the PCIe segment/bus table, and publishes microcode patch address/size information.

 Source: AmiCRBPkg/CRB/CRBPEI.c Processor: IA-32 Module: CRBPei.efi (0398)
**/

#include <PiPei.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/HobLib.h>
#include <Library/PeiServicesLib.h>
#include <Library/PeiServicesTablePointerLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/IoLib.h>

//
// Forward declarations
//
VOID *EFIAPI Memset (
 VOID *Buf,
 UINTN Count,
 CHAR8 Value
 );

INT32 EFIAPI MemsetDwordPairArray (
 INT32 ArrayBase,
 INT32 Index,
 INT32 Value1,
 INT32 Value2
 );

VOID *EFIAPI Memset32 (
 VOID *Buf,
 UINTN Count,
 INT32 Value
 );

VOID *EFIAPI Memmove (
 VOID *Destination,
 const VOID *Source,
 UINTN Count
 );

INT32 EFIAPI GetDebugPrintInterface (
 VOID
 );

INT32 EFIAPI DebugPrint (
 INT32 ErrorLevel,
 const CHAR8 *Format,
 ...
 );

INT32 EFIAPI DebugAssert (
 INT32 FileName,
 INT32 LineNumber,
 INT32 Description
 );

INT32 EFIAPI GetPcdServiceInterface (
 VOID
 );

INT32 EFIAPI SetPcdMicrocodePatchData (
 VOID *PcdService,
 UINT32 *BufferSize,
 INT32 Buffer
 );

INT32 EFIAPI GetHobList (
 VOID
 );

UINT16 *EFIAPI GetNextHobByType (
 UINT16 *HobStart
 );

INT32 EFIAPI GetNextGuidHob (
 EFI_GUID *Guid
 );

INT32 EFIAPI AmiUpdatePcieSegmentBusTable (
 VOID *SegBusTable
 );

INT32 EFIAPI DebugPrintAssert (
 INT32 ReturnAddress,
 EFI_SYSTEM_TABLE *SystemTable,
 CHAR8 *Format,
 ...
 );

INT32 EFIAPI GetPlatformDebugLevel (
 VOID
 );

UINT64 EFIAPI ReadUnaligned64 (
 const VOID *Buffer
 );

BOOLEAN EFIAPI CompareGuid (
 const EFI_GUID *Guid1,
 const EFI_GUID *Guid2
 );

INT32 EFIAPI GetPeiServicesTablePointer (
 VOID
 );

VOID *EFIAPI ReadIdtr (
 VOID *Idtr
 );

//
// GUID definitions for the HOBs this module consumes
//
EFI_GUID gEfiIioUdsHobGuid = { 0x4A43824B, 0x307F, 0x45BA, { 0x9D, 0xC3, 0xFE, 0x9F, 0xC6, 0xB3, 0x81, 0x48 } };
EFI_GUID gEfiPcdServiceHobGuid = { 0x5CB51B44, 0xE4D1, 0x4EBC, { 0x85, 0xAF, 0x5D, 0x3E, 0x83, 0xC9, 0x19, 0x11 } };
EFI_GUID gEfiPeiDebugPrintHobGuid = { 0x3B25E79E, 0xE44E, 0x4062, { 0x97, 0x6C, 0x1F, 0x24, 0xB4, 0x11, 0x6A, 0x1B } };

/**====================================================================
 Library support functions
====================================================================**/

/**Fills a buffer with a specified byte value.
**/
VOID *EFIAPI Memset (
 VOID *Buf,
 UINTN Count,
 CHAR8 Value
 )
{
 return memset (Buf, Value, Count);
}

/**Fills an array of DWORD pairs with specified values.
**/
INT32 EFIAPI MemsetDwordPairArray (
 INT32 ArrayBase,
 INT32 Index,
 INT32 Value1,
 INT32 Value2
 )
{
 do {
 *(UINT32 *)(ArrayBase + 8 *Index - 8) = Value1;
 *(UINT32 *)(ArrayBase + 8 *Index-- - 4) = Value2;
 } while (Index);

 return ArrayBase;
}

/**Fills a buffer with a specified DWORD value.
**/
VOID *EFIAPI Memset32 (
 VOID *Buf,
 UINTN Count,
 INT32 Value
 )
{
 return memset32 (Buf, Value, Count);
}

/**Copies a buffer, handling overlapping regions.
**/
VOID *EFIAPI Memmove (
 VOID *Destination,
 const VOID *Source,
 UINTN Count
 )
{
 UINTN CountAligned;
 CHAR8 *Dst;
 CHAR8 *Src;

 if ((Source < Destination) && (&((const CHAR8 *)Source)[Count - 1] >= (const CHAR8 *)Destination)) {
 //
 // Overlapping: copy from end
 //
 Src = &((CHAR8 *)Source)[Count - 1];
 Dst = &((CHAR8 *)Destination)[Count - 1];
 } else {
 //
 // Non-overlapping: copy aligned portion first
 //
 CountAligned = Count & 3;
 qmemcpy (Destination, Source, 4 * (Count >> 2));
 Src = &((CHAR8 *)Source)[4 * (Count >> 2)];
 Dst = &((CHAR8 *)Destination)[4 * (Count >> 2)];
 }

 qmemcpy (Dst, Src, CountAligned);

 return Destination;
}

/**====================================================================
 Debug services
====================================================================**/

/**Locates the EFI_PEI_DEBUG_PRINT_INTERFACE HOB and returns its pointer.
**/
INT32 EFIAPI GetDebugPrintInterface (
 VOID
 )
{
 INT32 PeiServices;
 VOID *Interface;
 INT32 InterfaceSize;

 PeiServices = GetPeiServicesTablePointer ();
 if ((*(INT32 ( **)(INT32, VOID *, UINT32, VOID **, INT32 *))(*(UINT32 *)PeiServices + 32))(
 PeiServices,
 &gEfiPeiDebugPrintHobGuid,
 0,
 &Interface,
 &InterfaceSize) >= 0) {
 return InterfaceSize;
 }

 return 0;
}

/**Emits a debug message if the error level matches the platform-configured mask.
**/
INT32 EFIAPI DebugPrint (
 INT32 ErrorLevel,
 const CHAR8 *Format,
 ...
 )
{
 INT32 Result;
 INT32 ( **PrintInterface)(INT32, const CHAR8 *, CHAR8 *);
 VA_LIST Va;

 VA_START (Va, Format);

 Result = GetDebugPrintInterface ();
 PrintInterface = (INT32 ( **)(INT32, const CHAR8 *, CHAR8 *))Result;
 if (Result != 0) {
 Result = GetPlatformDebugLevel ();
 if ((Result & ErrorLevel) != 0) {
 return (*PrintInterface)(ErrorLevel, Format, (CHAR8 *)Va);
 }
 }

 return Result;
}

/**Invokes the debug assertion handler via the print HOB.
**/
INT32 EFIAPI DebugAssert (
 INT32 FileName,
 INT32 LineNumber,
 INT32 Description
 )
{
 INT32 Result;

 Result = GetDebugPrintInterface ();
 if (Result != 0) {
 return (*(INT32 ( **)(INT32, INT32, INT32))(Result + 4))(
 FileName,
 LineNumber,
 Description);
 }

 return Result;
}

/**Reads the platform debug level from CMOS register 0x4A and determines the debug print mask.
**/
INT32 EFIAPI GetPlatformDebugLevel (
 VOID
 )
{
 UINT8 SavedIndex;
 UINT8 DebugLevel;

 SavedIndex = IoRead8 (0x70);
 IoWrite8 (0x70, SavedIndex & 0x80 | 0x4A);
 DebugLevel = IoRead8 (0x71);

 if (DebugLevel <= 3) {
 if (DebugLevel == 0) {
 return 0; // Debug disabled
 }
 } else {
 //
 // DebugLevel > 3
 //
 if (DebugLevel == 0) {
 DebugLevel = (*(UINT8 *)0xFDAF0490 & 2) | 1;
 }
 if (DebugLevel == 0) {
 return 0;
 }
 }

 if (DebugLevel == (UINT8)-1) {
 return 0;
 }

 if (DebugLevel == 1) {
 return (INT32)0xC0000004; // EFI_D_ERROR
 }

 return (INT32)0xC0000046; // EFI_D_WARN
}

/**Prints an ASSERT message, converting %s and %G format specifiers to ASCII-safe replacements before calling into the system table output.
**/
INT32 EFIAPI DebugPrintAssert (
 INT32 ReturnAddress,
 EFI_SYSTEM_TABLE *SystemTable,
 CHAR8 *Format,
 ...
 )
{
 INT32 Result;
 CHAR8 *Fmt;
 VA_LIST Va;

 VA_START (Va, Format);

 Result = (*(INT32 (__stdcall **)(INT32))(*(UINT32 *)SystemTable + 32))(SystemTable);
 if (Result >= 0) {
 if (SystemTable != NULL) {
 Result = GetPlatformDebugLevel ();
 if ((Result & ReturnAddress) != 0) {
 Fmt = Format;
 if (*Fmt != 0) {
 do {
 if (*Fmt == '%') {
 if (*(++Fmt) == 's') {
 *Fmt = 'a'; // %s -> %a (ANSI string)
 } else if (*Fmt == 'G') {
 *Fmt = 'g'; // %G -> %g (GUID format)
 }
 }
 ++Fmt;
 } while (*Fmt != 0);
 Fmt = Format;
 }
 return (*(INT32 ( **)(INT32, CHAR8 *, CHAR8 *))SystemTable)(
 ReturnAddress,
 Fmt,
 (CHAR8 *)Va);
 }
 }
 }

 return Result;
}

/**====================================================================
 PCD services
====================================================================**/

/**Locates the PCD service HOB and returns a token space interface.
**/
INT32 EFIAPI GetPcdServiceInterface (
 VOID
 )
{
 INT32 PeiServices;
 INT32 Status;
 INT32 TokenSpace;

 PeiServices = GetPeiServicesTablePointer ();
 TokenSpace = (INT32)&TokenSpace;
 Status = (*(INT32 ( **)(INT32, VOID *, UINT32, UINT32))(*(UINT32 *)PeiServices + 32))(
 PeiServices,
 &gEfiPcdServiceHobGuid,
 0,
 0);
 if (Status < 0) {
 DebugPrint (0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);

 {
 INT32 AssertIf;
 AssertIf = GetDebugPrintInterface ();
 if (AssertIf != 0) {
 (*(VOID ( **)(const CHAR8 *, INT32, const CHAR8 *))(AssertIf + 4))(
 "e:\\hs\\MdePkg\\Library\\PeiPcdLib\\PeiPcdLib.c",
 49,
 "!EFI_ERROR (Status)");
 }
 }
 }

 return TokenSpace;
}

/**Sets a microcode patch PCD value (token 115), with size validation.
**/
INT32 EFIAPI SetPcdMicrocodePatchData (
 VOID *PcdService,
 UINT32 *BufferSize,
 INT32 Buffer
 )
{
 UINT32 OriginalSize;

 if (BufferSize == NULL) {
 GetDebugPrintInterface ();
 }

 if (*BufferSize != 0) {
 if (Buffer == 0) {
 GetDebugPrintInterface ();
 }
 }

 OriginalSize = *BufferSize;
 PcdService = GetPcdServiceInterface (PcdService);

 if ((*(INT32 ( **)(INT32, UINT32 *, INT32))(*(UINT32 *)PcdService + 76))(
 115, BufferSize, Buffer) >= 0 || *BufferSize >= OriginalSize) {
 return Buffer;
 }

 return 0;
}

/**====================================================================
 HOB (Hand-Off Block) navigation
====================================================================**/

/**Returns the start of the HOB list.
**/
INT32 EFIAPI GetHobList (
 VOID
 )
{
 INT32 PeiServices;
 INT32 Status;
 INT32 HobList;

 PeiServices = GetPeiServicesTablePointer ();
 Status = (*(INT32 ( **)(INT32, INT32 *))(*(UINT32 *)PeiServices + 48))(
 PeiServices,
 &HobList);
 if (Status < 0) {
 DebugPrint (0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);

 {
 INT32 AssertIf;
 AssertIf = GetDebugPrintInterface ();
 if (AssertIf != 0) {
 (*(VOID ( **)(const CHAR8 *, INT32, const CHAR8 *))(AssertIf + 4))(
 "e:\\hs\\MdePkg\\Library\\PeiHobLib\\HobLib.c",
 50,
 "!EFI_ERROR (Status)");
 }
 }
 }

 if (HobList == 0) {
 INT32 AssertIf;
 AssertIf = GetDebugPrintInterface ();
 if (AssertIf != 0) {
 (*(VOID ( **)(const CHAR8 *, INT32, const CHAR8 *))(AssertIf + 4))(
 "e:\\hs\\MdePkg\\Library\\PeiHobLib\\HobLib.c",
 51,
 "HobList != ((void *) 0)");
 }
 }

 return HobList;
}

/**Walks the HOB list until a HOB of type 4 (EFI_HOB_TYPE_GUID_EXTENSION)
 is found, or returns NULL if the end marker is hit.
**/
UINT16 *EFIAPI GetNextHobByType (
 UINT16 *HobStart
 )
{
 if (HobStart == NULL) {
 GetDebugPrintInterface ();
 }

 while (TRUE) {
 if (*HobStart == 0xFFFF) {
 return NULL; // End of HOB list
 }
 if (*HobStart == 4) { // EFI_HOB_TYPE_GUID_EXTENSION break;
 }
 HobStart = (UINT16 *)((CHAR8 *)HobStart + HobStart[1]);
 }

 return HobStart;
}

/**Locates a GUID-extension HOB matching the specified GUID.
**/
INT32 EFIAPI GetNextGuidHob (
 EFI_GUID *Guid
 )
{
 INT32 HobList;
 UINT16 *Hob;

 HobList = GetHobList ();

 do {
 Hob = GetNextHobByType ((UINT16 *)HobList);
 } while (Hob != NULL && !CompareGuid (Guid, (EFI_GUID *)(Hob + 8)));

 return (INT32)Hob;
}

/**Compares two EFI_GUID structures by reading them as unaligned 64-bit values.
**/
BOOLEAN EFIAPI CompareGuid (
 const EFI_GUID *Guid1,
 const EFI_GUID *Guid2
 )
{
 UINT64 Data1_A;
 UINT64 Data1_B;
 UINT64 Data2_A;
 UINT64 Data2_B;

 Data1_A = ReadUnaligned64 (Guid1);
 Data1_B = ReadUnaligned64 (Guid2);
 Data2_A = ReadUnaligned64 ((UINT8 *)Guid1 + 8);
 Data2_B = ReadUnaligned64 ((UINT8 *)Guid2 + 8);

 return (Data1_A == Data1_B) && (Data2_A == Data2_B);
}

/**Reads an unaligned 64-bit value from memory.
**/
UINT64 EFIAPI ReadUnaligned64 (
 const VOID *Buffer
 )
{
 if (Buffer == NULL) {
 GetDebugPrintInterface ();
 }

 return *(volatile UINT64 *)Buffer;
}

/**====================================================================
 PEI Services Table Pointer
====================================================================**/

/**Retrieves the PEI Services Table pointer from IDT register storage.
**/
INT32 EFIAPI GetPeiServicesTablePointer (
 VOID
 )
{
 IA32_IDTR_GATE_DESCRIPTOR Idtr;
 INT32 PeiServices;

 ReadIdtr (&Idtr);
 PeiServices = *(UINT32 *)(*(UINT32 *)((UINT32)&Idtr + 6) - 4);

 if (PeiServices == 0) {
 DebugAssert (
 (INT32)"e:\\hs\\MdePkg\\Library\\PeiServicesTablePointerLibIdt\\PeiServicesTablePointer.c",
 48,
 (INT32)"PeiServices != ((void *) 0)");
 }

 return PeiServices;
}

/**Reads the IDTR (Interrupt Descriptor Table Register) via SIDT instruction.
**/
VOID *EFIAPI ReadIdtr (
 VOID *Idtr
 )
{
 if (Idtr == NULL) {
 DebugAssert (
 (INT32)"e:\\hs\\MdePkg\\Library\\BaseLib\\X86ReadIdtr.c",
 37,
 (INT32)"Idtr != ((void *) 0)");
 }

 __sidt (Idtr);

 return Idtr;
}

/**====================================================================
 PCIe Segment/Bus table update
====================================================================**/

/**Locates the IIO UDS HOB and copies the PCIe segment/bus table data into the provided output structure.

 The IIO UDS HOB (identified by gEfiIioUdsHobGuid) contains a table of up to 4 IIO stacks, each with 43 bytes of routing data. This routine extracts the base bus information and segment configuration.
**/
INT32 EFIAPI AmiUpdatePcieSegmentBusTable (
 VOID *SegBusTable
 )
{
 INT32 PcdService;
 INT32 Hob;
 UINT8 *Dst;
 UINT8 *Src;
 INT32 StackCount;
 INT32 ByteCount;

 PcdService = GetPcdServiceInterface (SegBusTable);
 if ((UINT32)(*(INT32 ( **)(INT32))(PcdService + 28))(7) > 0x48) {
 //
 // sizeof(PCIE_SEG_BUS_TABLE) exceeds the configured PCD size
 //
 GetDebugPrintInterface ();
 }

 Hob = GetNextGuidHob (&gEfiIioUdsHobGuid);
 if (Hob != 0) {
 //
 // Found the IIO UDS HOB -- copy the routing data
 //
 *(UINT8 *)SegBusTable = 1;
 Dst = (UINT8 *)SegBusTable + 9;
 Src = (UINT8 *)(Hob + 65);

 *(UINT32 *)((UINT8 *)SegBusTable + 4) = *(UINT32 *)(Hob + 2091);

 StackCount = 4;
 do {
 Dst[-1] = *(Src - 10); // bus0: Dst[ 0..7] ?
 *Dst = *Src; //
 //
 // Copy 6 bytes per stack entry
 //
 {
 INT32 N6;
 N6 = 6;
 do {
 *Dst++ = *Src++;
 --N6;
 } while (N6);
 }
 //
 // Advance to next entry:
 // Destination stride = 8 bytes
 // Source stride = 43 bytes per IIO stack
 //
 Dst = (UINT8 *)(SegBusTable + 9 + (UINT64)UINT32);
 Src += 43;
 --StackCount;
 } while (StackCount);

 DebugPrint (64, "AmiUpdatePcieSegmentBusTable Updated SEG BUS table PCD with IIO UDS HOB\n");
 return 0;
 } else {
 DebugPrint (0x80000000, "AmiUpdatePcieSegmentBusTable Can't locate the IIO UDS HOB\n");
 return (INT32)0xC000000E; // EFI_NOT_FOUND
 }
}

/**====================================================================
 PCIe Base Address detection
====================================================================**/

/**Reads the PCI Express base address via PCI config cycle.
 Uses the standard CF8/CFC mechanism with bus 0, device 1,
 function 0, register 0x24.
**/
UINT32 EFIAPI GetPciExpressBaseAddress (
 VOID
 )
{
 //
 // PCI config: CF8 = 0x80002890 => Bus 0, Dev 5, Func 0, Reg 0x24
 //
 __outdword (0xCF8, 0x80002890);
 return IoRead32 (0xCFC) & 0xFFFFFFF0;
}

/**====================================================================
 Entry points
====================================================================**/

/**Updates PcdPciExpressBaseAddress and PcdPcieSegmentBusTable.

 Reads PCIE base address from HW, stores to PCD, then updates the PCIe segment/bus table via IIO UDS HOB.
**/
INT32 EFIAPI AmiUpdateSegBusPcd (
 VOID
 )
{
 INT32 PcdService;
 UINT8 *SegBusTable;

 PcdService = GetPcdServiceInterface ();
 SegBusTable = (UINT8 *)(*(INT32 ( **)(INT32))(PcdService + 20))(7);

 if (*SegBusTable != 0 || AmiUpdatePcieSegmentBusTable (SegBusTable) >= 0) {
 DebugPrint (64, "AmiUpdateSegBusPcd\n");
 return 0;
 }

 return (INT32)0xC000000E; // EFI_NOT_FOUND
}

/**The main entry point for CRB PEI module execution.

 This is called from the PEI dispatcher callback after GetFirmwareVolumeHobAndFixPcieMemSpace completes the PCIe memory space fixup. It then retrieves microcode patch address/size PCDs and publishes them.
**/
INT32 EFIAPI CrbPeiMainEntry (
 VOID
 )
{
 INT32 Result;
 UINT64 MicrocodePatchAddress;
 UINT64 MicrocodePatchRegionSize;
 INT32 N16;

 Result = GetFirmwareVolumeHobAndFixPcieMemSpace (NULL);
 N16 = 16;

 //
 // Token 113: PcdMicrocodePatchAddress
 // Token 114: PcdMicrocodePatchRegionSize
 //
 {
 INT32 PcdService;
 PcdService = GetPcdServiceInterface ();
 MicrocodePatchAddress = ((UINT64 ( *)(INT32))*(UINT32 *)(PcdService + 16))(113);
 PcdService = GetPcdServiceInterface ();
 MicrocodePatchRegionSize = ((UINT64 ( *)(INT32))*(UINT32 *)(PcdService + 16))(114);
 }

 DebugPrint (64,
 "MicrocodePatchAddress: %lX, MicrocodePatchRegionSize:%lX\n",
 (UINT32)MicrocodePatchAddress,
 (UINT32)(MicrocodePatchAddress >> 32));

 if (MicrocodePatchAddress != 0 && MicrocodePatchRegionSize != 0) {
 SetPcdMicrocodePatchData (&MicrocodePatchAddress, &((UINT32 *)&MicrocodePatchRegionSize)[1], 0);
 }

 return Result;
}

/**Locates the firmware volume HOB and fixes up PCIe memory space.
 If the PcdPciExpressMemorySize indicates 18 or 32, it clears the PCIC
 (PCIe Controller Configuration) bit for the IIO UDS region.
**/
INT32 EFIAPI GetFirmwareVolumeHobAndFixPcieMemSpace (
 VOID *PeiServices
 )
{
 INT32 Status;
 INT32 Hob;
 INT32 PciExpressMemorySize;

 PeiServices = GetPeiServicesTablePointer (PeiServices);
 PciExpressMemorySize = (INT32)&PciExpressMemorySize;

 Status = (*(INT32 ( **)(INT32))(*(UINT32 *)PeiServices + 40))(PeiServices);
 if (Status < 0) {
 DebugPrint (0x80000000, \"\\nASSERT_EFI_ERROR (Status = %r)\\n\", Status);
 GetDebugPrintInterface ();
 }

 Hob = GetNextGuidHob (&gEfiIioUdsHobGuid);

 if (Hob != 0) {
 if (PciExpressMemorySize == 18 || PciExpressMemorySize == 32) {
 *(UINT32 *)(Hob + 2923) &= ~8u; // Clear PCIC bit in IIO UDS
 }
 return 0;
 } else {
 GetDebugPrintInterface ();
 return (INT32)0xC000000E; // EFI_NOT_FOUND
 }
}

/**====================================================================
 Module Entry Point (PEIM)
====================================================================**/

/**CRB PEI initialization entry point.

 - Reads PCI Express base address via CF8/CFC (Bus0 Dev5 Fn0 Reg24)
 - Sets PcdPciExpressBaseAddress PCD (token 5) via PCD protocol
 - Verifies the PCD by reading it back
 - Installs the FV file GUID HOB for subsequent PEI dispatching

 @param[in] ImageHandle PEI image handle
 @param[in] SystemTable PEI system table

 @retval EFI_SUCCESS Entry point completed successfully
**/
EFI_STATUS EFIAPI CrbPeiEntryPoint (
 IN EFI_HANDLE ImageHandle,
 IN EFI_SYSTEM_TABLE *SystemTable
 )
{
 UINT32 PciExpressBaseAddress;
 INT32 PcdService;
 INT32 Status;

 //
 // Step 1: Read PCIE base address from hardware
 //
 PciExpressBaseAddress = GetPciExpressBaseAddress ();
 DebugPrint (64, \"SecpciExbase:%x\\n\", PciExpressBaseAddress);

 //
 // Step 2: Store into PCD via PCD service (PcdPciExpressBaseAddress, token 5)
 //
 PcdService = GetPcdServiceInterface ();
 (*(VOID ( **)(INT32, UINT32, UINT32))(PcdService + 72))(5, PciExpressBaseAddress, 0);

 //
 // Step 3: Read back the PCD to verify
 //
 PcdService = GetPcdServiceInterface ();
 Status = ((INT32 ( *)(INT32))*(UINT32 *)(PcdService + 16))(5);
 DebugPrint (64, \"PcdPciExpressBaseAddress:%x\\n\", Status);

 //
 // Step 4: Install FV file HOB so the PEI dispatcher picks up the callback
 // PPIs registered by CrbPeiMainEntry()
 //
 if ((*(INT32 ( **)(EFI_SYSTEM_TABLE *, VOID *))(LODWORD(SystemTable->Hdr.Signature) + 36))(
 SystemTable,
 &gEfiPcdServiceHobGuid) < 0) {
 DebugPrintAssert (-1, (INT32)SystemTable, (INT32)\"ASSERT in %s on %i: %s\\n\", \"e:\\\\hs\\\\AmiCRBPkg\\\\CRB\\\\CRBPEI.c\");
 while (TRUE);
 }

 return EFI_SUCCESS;
}