/** @file
PcatSingleSegmentPciCfg2Pei.c - Full decompilation
Full reverse engineering of the PcatSingleSegmentPciCfg2Pei UEFI PEIM.
This PEIM installs the EFI_PEI_PCI_CFG2_PPI on a single-segment PCI
system using PCI Express (ECAM) memory-mapped configuration space access.
Source: MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PciCfg2.c
Build: VS2015 DEBUG IA32
PDB: PcatSingleSegmentPciCfg2Pei.pdb
GUID: {057A449A-1FDC-4C06-BFC9-F53F6A99BB92}
Image layout:
HEADER 0xffdab714 - 0xffdab974 (0x260)
.text 0xffdab974 - 0xffdac614 (0xca0)
.rdata 0xffdac614 - 0xffdac9f4 (0x3e0)
.data 0xffdac9f4 - 0xffdaca54 (0x60)
.reloc 0xffdaca54 - 0xffdacad4 (0x80)
**/
#include <Uefi.h>
#include <PiPei.h>
#include <Ppi/PciCfg2.h>
#include <Library/DebugLib.h>
#include <Library/BaseLib.h>
#include <Library/IoLib.h>
#include <Library/PciExpressLib.h>
#include <Library/PeiServicesTablePointerLib.h>
//
// .data section global data
//
// GUID for PCD database PPI lookup
STATIC CONST EFI_GUID mPcdDatabaseGuid = {
0x36232936, 0x0E76, 0x31C8, { 0xA1, 0x3A, 0x3A, 0xF2, 0xFC, 0x1C, 0x39, 0x32 }
};
// EFI_PEI_PCI_CFG2_PPI GUID: {057A449A-1FDC-4C06-BFC9-F53F6A99BB92}
STATIC CONST EFI_GUID mPcatSingleSegmentPciCfg2PpiGuid = {
0x057A449A, 0x1FDC, 0x4C06, { 0xBF, 0xC9, 0xF5, 0x3F, 0x6A, 0x99, 0xBB, 0x92 }
};
//
// PRIVATE_DATA - EFI_PEI_PCI_CFG2_PPI instance
//
STATIC EFI_PEI_PCI_CFG2_PPI mPrivateData;
//
// PPI Descriptor
//
STATIC EFI_PEI_PPI_DESCRIPTOR mPpiDescriptor = {
EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
&mPcatSingleSegmentPciCfg2PpiGuid,
&mPrivateData
};
// ============================================================================
// Forward declarations
// ============================================================================
EFI_STATUS
EFIAPI
PciCfg2Read (
IN EFI_PEI_SERVICES **PeiServices,
IN VOID *This,
IN UINTN Width,
IN UINT64 Address,
IN VOID *Buffer
);
EFI_STATUS
EFIAPI
PciCfg2Write (
IN EFI_PEI_SERVICES **PeiServices,
IN VOID *This,
IN UINTN Width,
IN UINT64 Address,
IN VOID *Buffer
);
EFI_STATUS
EFIAPI
PciCfg2Modify (
IN EFI_PEI_SERVICES **PeiServices,
IN VOID *This,
IN UINTN Width,
IN UINT64 Address,
IN VOID *SetBits,
IN VOID *ClearBits
);
// ============================================================================
// Module entry point
// Address: 0xffdaba34 | Size: 0x5b
// ============================================================================
EFI_STATUS
EFIAPI
ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_PEI_SERVICES **PeiServices;
//
// Store PRIVATE_DATA address in SystemTable reserved slot.
// This effectively associates the private data with ImageHandle.
// Equivalent to: ImageHandle->SystemTable->Something = &mPrivateData
//
*(UINTN *)((UINTN)SystemTable + 100) = (UINTN)&mPrivateData;
//
// Get PEI Services Table pointer
//
PeiServices = GetPeiServicesTablePtr();
//
// Install EFI_PEI_PCI_CFG2_PPI
//
Status = (*PeiServices)->InstallPpi (PeiServices, &mPpiDescriptor);
//
// ASSERT on failure
//
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
}
return Status;
}
// ============================================================================
// PCI Express address to MMIO offset conversion
// Address: 0xffdaba8f | Size: 0x52
// ============================================================================
//
// The EFI_PEI_PCI_CFG2_PPI Address format packs:
// Offset 0: Register (bits 7:0) - config register offset
// Offset 1: Function (bits 2:0)
// Offset 2: Device (bits 4:0)
// Offset 3: Bus (bits 7:0)
// Offset 4-7: ExtendedRegister (32-bit, if non-zero overrides Register)
//
// ECAM MMIO offset = (Bus * 32 + Device) * 8 + Function) * 4096 + Register
// Bus << 20 | Device << 15 | Function << 12 | Register
//
UINTN
EFIAPI
PciExpressAddressToOffset (
IN UINT8 *PciAddress
)
{
UINTN Device;
UINTN Bus;
UINTN Function;
UINTN Register;
UINT32 ExtendedRegister;
Device = PciAddress[2] & 0x1F;
ExtendedRegister = *(UINT32 *)(PciAddress + 4);
if (ExtendedRegister != 0) {
//
// Extended config space access (>= 256 bytes offset, for ECAM)
//
return (ExtendedRegister & 0xFFF)
| (((PciAddress[1] & 7) | (8 * ((32 * PciAddress[3]) | Device))) << 12);
} else {
//
// Standard config space access (< 256 bytes offset)
//
Function = PciAddress[1] & 7;
Bus = PciAddress[3];
Register = PciAddress[0];
return Register | (((Function | (Device << 3) | (Bus << 8))) << 12);
}
}
// ============================================================================
// PCI CFG2 Read
// Address: 0xffdabae1 | Size: 0x1b1
// ============================================================================
//
// Reads from PCI configuration space at the given Address.
// Supports UINT8 (0), UINT16 (1), UINT32 (2), and UINT64 (3) widths.
// Handles misaligned accesses by breaking into byte/word reads as needed.
//
EFI_STATUS
EFIAPI
PciCfg2Read (
IN EFI_PEI_SERVICES **PeiServices,
IN VOID *This,
IN UINTN Width,
IN UINT64 Address,
IN VOID *Buffer
)
{
UINTN Offset;
Offset = PciExpressAddressToOffset ((UINT8 *)&Address);
switch (Width) {
case PCI_CFG2_WIDTH_UINT8:
*(UINT8 *)Buffer = PciExpressRead8 (Offset);
break;
case PCI_CFG2_WIDTH_UINT16:
if (Offset & 1) {
//
// Misaligned: read two bytes individually
//
((UINT8 *)Buffer)[0] = PciExpressRead8 (Offset);
((UINT8 *)Buffer)[1] = PciExpressRead8 (Offset + 1);
} else {
UnalignedWrite16 (Buffer, PciExpressRead16 (Offset));
}
break;
case PCI_CFG2_WIDTH_UINT32:
if (Offset & 3) {
if (Offset & 1) {
//
// Word-level misalignment: read 4 bytes individually
//
((UINT8 *)Buffer)[0] = PciExpressRead8 (Offset);
((UINT8 *)Buffer)[1] = PciExpressRead8 (Offset + 1);
((UINT8 *)Buffer)[2] = PciExpressRead8 (Offset + 2);
((UINT8 *)Buffer)[3] = PciExpressRead8 (Offset + 3);
} else {
//
// Halfword-aligned but not word-aligned: two 16-bit reads
//
UnalignedWrite16 (Buffer, PciExpressRead16 (Offset));
UnalignedWrite16 ((UINT8 *)Buffer + 2, PciExpressRead16 (Offset + 2));
}
} else {
UnalignedWrite32 (Buffer, PciExpressRead32 (Offset));
}
break;
case PCI_CFG2_WIDTH_UINT64:
if (Offset & 3) {
if (Offset & 1) {
//
// Byte-level misalignment: read 8 bytes individually
//
((UINT8 *)Buffer)[0] = PciExpressRead8 (Offset);
((UINT8 *)Buffer)[1] = PciExpressRead8 (Offset + 1);
((UINT8 *)Buffer)[2] = PciExpressRead8 (Offset + 2);
((UINT8 *)Buffer)[3] = PciExpressRead8 (Offset + 3);
((UINT8 *)Buffer)[4] = PciExpressRead8 (Offset + 4);
((UINT8 *)Buffer)[5] = PciExpressRead8 (Offset + 5);
((UINT8 *)Buffer)[6] = PciExpressRead8 (Offset + 6);
((UINT8 *)Buffer)[7] = PciExpressRead8 (Offset + 7);
} else {
//
// Halfword-aligned: four 16-bit reads
//
UnalignedWrite16 (Buffer, PciExpressRead16 (Offset));
UnalignedWrite16 ((UINT16 *)Buffer + 1, PciExpressRead16 (Offset + 2));
UnalignedWrite16 ((UINT16 *)Buffer + 2, PciExpressRead16 (Offset + 4));
UnalignedWrite16 ((UINT16 *)Buffer + 3, PciExpressRead16 (Offset + 6));
}
} else {
//
// Word-aligned: two 32-bit reads
//
UnalignedWrite32 (Buffer, PciExpressRead32 (Offset));
UnalignedWrite32 ((UINT8 *)Buffer + 4, PciExpressRead32 (Offset + 4));
}
break;
default:
return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
}
// ============================================================================
// PCI CFG2 Write
// Address: 0xffdabc92 | Size: 0x1a5
// ============================================================================
//
// Writes to PCI configuration space at the given Address.
// Supports UINT8 (0), UINT16 (1), UINT32 (2), and UINT64 (3) widths.
//
EFI_STATUS
EFIAPI
PciCfg2Write (
IN EFI_PEI_SERVICES **PeiServices,
IN VOID *This,
IN UINTN Width,
IN UINT64 Address,
IN VOID *Buffer
)
{
UINTN Offset;
Offset = PciExpressAddressToOffset ((UINT8 *)&Address);
switch (Width) {
case PCI_CFG2_WIDTH_UINT8:
PciExpressWrite8 (Offset, *(UINT8 *)Buffer);
break;
case PCI_CFG2_WIDTH_UINT16:
if (Offset & 1) {
//
// Misaligned: write as two bytes
//
PciExpressWrite8 (Offset, ((UINT8 *)Buffer)[0]);
PciExpressWrite8 (Offset + 1, ((UINT8 *)Buffer)[1]);
} else {
PciExpressWrite16 (Offset, UnalignedRead16 (Buffer));
}
break;
case PCI_CFG2_WIDTH_UINT32:
if (Offset & 3) {
if (Offset & 1) {
//
// Byte-level misalignment: write 4 bytes individually
//
PciExpressWrite8 (Offset, ((UINT8 *)Buffer)[0]);
PciExpressWrite8 (Offset + 1, ((UINT8 *)Buffer)[1]);
PciExpressWrite8 (Offset + 2, ((UINT8 *)Buffer)[2]);
PciExpressWrite8 (Offset + 3, ((UINT8 *)Buffer)[3]);
} else {
//
// Halfword-aligned: two 16-bit writes
//
PciExpressWrite16 (Offset, UnalignedRead16 (Buffer));
PciExpressWrite16 (Offset + 2, UnalignedRead16 ((UINT8 *)Buffer + 2));
}
} else {
PciExpressWrite32 (Offset, UnalignedRead32 (Buffer));
}
break;
case PCI_CFG2_WIDTH_UINT64:
if (Offset & 3) {
if (Offset & 1) {
//
// Byte-level misalignment: write 8 bytes individually
//
PciExpressWrite8 (Offset, ((UINT8 *)Buffer)[0]);
PciExpressWrite8 (Offset + 1, ((UINT8 *)Buffer)[1]);
PciExpressWrite8 (Offset + 2, ((UINT8 *)Buffer)[2]);
PciExpressWrite8 (Offset + 3, ((UINT8 *)Buffer)[3]);
PciExpressWrite8 (Offset + 4, ((UINT8 *)Buffer)[4]);
PciExpressWrite8 (Offset + 5, ((UINT8 *)Buffer)[5]);
PciExpressWrite8 (Offset + 6, ((UINT8 *)Buffer)[6]);
PciExpressWrite8 (Offset + 7, ((UINT8 *)Buffer)[7]);
} else {
//
// Halfword-aligned: four 16-bit writes
//
PciExpressWrite16 (Offset, UnalignedRead16 (Buffer));
PciExpressWrite16 (Offset + 2, UnalignedRead16 ((UINT8 *)Buffer + 2));
PciExpressWrite16 (Offset + 4, UnalignedRead16 ((UINT8 *)Buffer + 4));
PciExpressWrite16 (Offset + 6, UnalignedRead16 ((UINT8 *)Buffer + 6));
}
} else {
//
// Word-aligned: two 32-bit writes
//
PciExpressWrite32 (Offset, UnalignedRead32 (Buffer));
PciExpressWrite32 (Offset + 4, UnalignedRead32 ((UINT8 *)Buffer + 4));
}
break;
default:
return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
}
// ============================================================================
// PCI CFG2 Modify (Read-Modify-Write)
// Address: 0xffdabe37 | Size: 0x325
// ============================================================================
//
// Performs a read-modify-write on PCI configuration space.
// new_value = (old_value & ~ClearBits) | SetBits
// Supports UINT8 (0), UINT16 (1), UINT32 (2), and UINT64 (3) widths.
//
EFI_STATUS
EFIAPI
PciCfg2Modify (
IN EFI_PEI_SERVICES **PeiServices,
IN VOID *This,
IN UINTN Width,
IN UINT64 Address,
IN VOID *SetBits,
IN VOID *ClearBits
)
{
UINTN Offset;
Offset = PciExpressAddressToOffset ((UINT8 *)&Address);
switch (Width) {
case PCI_CFG2_WIDTH_UINT8:
PciExpressOr8 (Offset, ~*(UINT8 *)ClearBits, *(UINT8 *)SetBits);
break;
case PCI_CFG2_WIDTH_UINT16:
if (Offset & 1) {
//
// Misaligned: two byte-level ORs
//
PciExpressOr8 (Offset, ~((UINT8 *)ClearBits)[0], ((UINT8 *)SetBits)[0]);
PciExpressOr8 (Offset + 1, ~((UINT8 *)ClearBits)[1], ((UINT8 *)SetBits)[1]);
} else {
PciExpressOr16 (Offset, ~UnalignedRead16 (ClearBits), UnalignedRead16 (SetBits));
}
break;
case PCI_CFG2_WIDTH_UINT32:
if (Offset & 3) {
if (Offset & 1) {
//
// Byte-level misalignment: four byte ORs
//
PciExpressOr8 (Offset, ~((UINT8 *)ClearBits)[0], ((UINT8 *)SetBits)[0]);
PciExpressOr8 (Offset + 1, ~((UINT8 *)ClearBits)[1], ((UINT8 *)SetBits)[1]);
PciExpressOr8 (Offset + 2, ~((UINT8 *)ClearBits)[2], ((UINT8 *)SetBits)[2]);
PciExpressOr8 (Offset + 3, ~((UINT8 *)ClearBits)[3], ((UINT8 *)SetBits)[3]);
} else {
//
// Halfword-aligned: two 16-bit ORs
//
PciExpressOr16 (Offset, ~UnalignedRead16 (ClearBits), UnalignedRead16 (SetBits));
PciExpressOr16 (Offset + 2, ~UnalignedRead16 ((UINT8 *)ClearBits + 2),
UnalignedRead16 ((UINT8 *)SetBits + 2));
}
} else {
PciExpressOr32 (Offset, ~UnalignedRead32 (ClearBits), UnalignedRead32 (SetBits));
}
break;
case PCI_CFG2_WIDTH_UINT64:
if (Offset & 3) {
if (Offset & 1) {
//
// Byte-level misalignment: eight byte ORs
//
PciExpressOr8 (Offset, ~((UINT8 *)ClearBits)[0], ((UINT8 *)SetBits)[0]);
PciExpressOr8 (Offset + 1, ~((UINT8 *)ClearBits)[1], ((UINT8 *)SetBits)[1]);
PciExpressOr8 (Offset + 2, ~((UINT8 *)ClearBits)[2], ((UINT8 *)SetBits)[2]);
PciExpressOr8 (Offset + 3, ~((UINT8 *)ClearBits)[3], ((UINT8 *)SetBits)[3]);
PciExpressOr8 (Offset + 4, ~((UINT8 *)ClearBits)[4], ((UINT8 *)SetBits)[4]);
PciExpressOr8 (Offset + 5, ~((UINT8 *)ClearBits)[5], ((UINT8 *)SetBits)[5]);
PciExpressOr8 (Offset + 6, ~((UINT8 *)ClearBits)[6], ((UINT8 *)SetBits)[6]);
PciExpressOr8 (Offset + 7, ~((UINT8 *)ClearBits)[7], ((UINT8 *)SetBits)[7]);
} else {
//
// Halfword-aligned: four 16-bit ORs
//
PciExpressOr16 (Offset, ~UnalignedRead16 (ClearBits), UnalignedRead16 (SetBits));
PciExpressOr16 (Offset + 2, ~UnalignedRead16 ((UINT8 *)ClearBits + 2),
UnalignedRead16 ((UINT8 *)SetBits + 2));
PciExpressOr16 (Offset + 4, ~UnalignedRead16 ((UINT8 *)ClearBits + 4),
UnalignedRead16 ((UINT8 *)SetBits + 4));
PciExpressOr16 (Offset + 6, ~UnalignedRead16 ((UINT8 *)ClearBits + 6),
UnalignedRead16 ((UINT8 *)SetBits + 6));
}
} else {
//
// Word-aligned: two 32-bit ORs
//
PciExpressOr32 (Offset, ~UnalignedRead32 (ClearBits), UnalignedRead32 (SetBits));
PciExpressOr32 (Offset + 4, ~UnalignedRead32 ((UINT8 *)ClearBits + 4),
UnalignedRead32 ((UINT8 *)SetBits + 4));
}
break;
default:
return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
}
// ============================================================================
// Memory utility functions (library wrappers)
// ============================================================================
VOID *
EFIAPI
SetMem (
OUT VOID *Buffer,
IN UINTN Size,
IN UINT8 Value
)
{
return memset (Buffer, Value, Size);
}
VOID *
EFIAPI
SetMem32 (
OUT VOID *Buffer,
IN UINTN Count,
IN UINT32 ValueLo,
IN UINT32 ValueHi
)
{
UINT32 *Buf32 = (UINT32 *)Buffer;
do {
Buf32[0] = ValueLo;
Buf32[1] = ValueHi;
Buf32 += 2;
} while (--Count);
return Buffer;
}
VOID *
EFIAPI
ZeroMem (
OUT VOID *Buffer,
IN UINTN Size
)
{
return memset (Buffer, 0, Size);
}
VOID *
EFIAPI
CopyMem (
OUT VOID *Destination,
IN CONST VOID *Source,
IN UINTN Size
)
{
//
// If source < destination and ranges overlap (backward copy case):
// reverse copy from end
//
if ((UINTN)Source < (UINTN)Destination &&
(UINTN)Source + Size - 1 >= (UINTN)Destination) {
//
// Copy backwards from the end, one byte at a time
//
return memmove (Destination, Source, Size);
}
//
// Forward copy: start with aligned 32-bit chunks, then byte remainder
//
Size = (Size & 3); // remainder after 32-bit copies
// ... (the rest falls through to byte-by-byte qmemcpy of remainder)
// In the actual binary, the remainder copy uses qmemcpy for remainder of size % 4.
return memcpy (Destination, Source, ((UINTN)Size + 3) & ~3);
}
// ============================================================================
// PEI Services Table pointer retrieval (via IDTR)
// Address: 0xffdac3a8 | Size: 0x32
// ============================================================================
EFI_PEI_SERVICES **
EFIAPI
GetPeiServicesTablePtr (
VOID
)
{
IA32_IDTR Idtr;
EFI_PEI_SERVICES **PeiServices;
//
// Read IDTR to find the base of the IDT
//
ReadIdtr (&Idtr);
//
// The PEI Services Table pointer is stored at offset -4 from the IDT base.
// This is a standard PEI Services Table Pointer Library mechanism for IA32.
//
PeiServices = *(EFI_PEI_SERVICES ***)(Idtr.Base - 4);
if (PeiServices == NULL) {
DEBUG ((EFI_D_ERROR, "PeiServices is NULL\n"));
}
return PeiServices;
}
// ============================================================================
// Read IDTR register (SIDT instruction wrapper)
// Address: 0xffdac3da | Size: 0x23
// ============================================================================
VOID
EFIAPI
ReadIdtr (
OUT IA32_IDTR *IdtrBuffer
)
{
ASSERT (IdtrBuffer != NULL);
__sidt (IdtrBuffer);
}
// ============================================================================
// PCD Database access
// Address: 0xffdac15c | Size: 0x31
// ============================================================================
//
// Retrieves the PCD database pointer by locating the PCD PPI via
// PEI Services' LocatePpi.
//
VOID *
EFIAPI
GetPcdDatabasePtr (
VOID
)
{
EFI_PEI_SERVICES **PeiServices;
VOID *PcdDatabase;
EFI_STATUS Status;
PeiServices = GetPeiServicesTablePtr ();
Status = (*PeiServices)->LocatePpi (
PeiServices,
&mPcdDatabaseGuid,
0,
NULL,
&PcdDatabase
);
if (!EFI_ERROR (Status)) {
return PcdDatabase;
}
return NULL;
}
// ============================================================================
// Get PCD database pointer via PEI PCD PPI Locate
// Address: 0xffdac5b5 | Size: 0x58
// ============================================================================
//
// This function locates the PCD PPI (not PCD database directly) and
// returns the PPI interface. It is used to get PcdPpi, which is then
// used to call PcdGetX functions.
//
VOID *
EFIAPI
PeiPcdLocate (
VOID
)
{
EFI_PEI_SERVICES **PeiServices;
VOID *PcdPpi;
EFI_STATUS Status;
PeiServices = GetPeiServicesTablePtr ();
//
// LocatePpi to get the PCD PPI interface
//
Status = (*PeiServices)->LocatePpi (
PeiServices,
&mPcdDatabaseGuid, // Actually uses gPeiPcdPpiGuid
0,
NULL,
&PcdPpi
);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
}
return PcdPpi;
}
// ============================================================================
// PCI Express base address retrieval (from PCD)
// Address: 0xffdac3fd | Size: 0xc
// ============================================================================
//
// Gets the PciExpressBaseAddress from PCD. Uses the PCD PPI to call
// PcdGet64/PcdGet32(token=5) which returns the MMIO base address of
// the PCI Express configuration space (ECAM).
//
UINTN
EFIAPI
GetPciExpressBaseAddr (
VOID
)
{
VOID *PcdPpi;
UINTN (**PcdGetPtr)(UINTN);
PcdPpi = PeiPcdLocate ();
PcdGetPtr = (UINTN (**)(UINTN))PcdPpi;
//
// Call PcdGetPtr(token_value=5) to retrieve PcdPciExpressBaseAddress.
// The token value 5 corresponds to fixed-at-build PCD
// PcdPciExpressBaseAddress in typical EDK2 builds.
//
return PcdGetPtr[4] (5);
}
// ============================================================================
// PCI Express MMIO config space access - Read8
// Address: 0xffdac409 | Size: 0x30
// ============================================================================
UINT8
EFIAPI
PciExpressRead8 (
IN UINTN Address
)
{
//
// Validate address: must have bits [31:28] clear ( < 256MB offset )
//
if ((Address & 0xF0000000) != 0) {
ASSERT (Address <= 0x0FFFFFFF);
}
return *(volatile UINT8 *)(GetPciExpressBaseAddr () + Address);
}
// ============================================================================
// PCI Express MMIO config space access - Write8
// Address: 0xffdac439 | Size: 0x39
// ============================================================================
UINT8
EFIAPI
PciExpressWrite8 (
IN UINTN Address,
IN UINT8 Value
)
{
if ((Address & 0xF0000000) != 0) {
ASSERT (Address <= 0x0FFFFFFF);
}
*(volatile UINT8 *)(GetPciExpressBaseAddr () + Address) = Value;
return Value;
}
// ============================================================================
// PCI Express MMIO config space access - Read16
// Address: 0xffdac472 | Size: 0x38
// ============================================================================
UINT16
EFIAPI
PciExpressRead16 (
IN UINTN Address
)
{
if ((Address & 0xF0000000) != 0) {
ASSERT (Address <= 0x0FFFFFFF);
}
return AlignedRead16 ((UINT16 *)(GetPciExpressBaseAddr () + Address));
}
// ============================================================================
// PCI Express MMIO config space access - Write16
// Address: 0xffdac4aa | Size: 0x3e
// ============================================================================
UINT16
EFIAPI
PciExpressWrite16 (
IN UINTN Address,
IN UINT16 Value
)
{
if ((Address & 0xF0000000) != 0) {
ASSERT (Address <= 0x0FFFFFFF);
}
return AlignedWrite16 ((UINT16 *)(GetPciExpressBaseAddr () + Address), Value);
}
// ============================================================================
// PCI Express MMIO config space access - Read32
// Address: 0xffdac4e8 | Size: 0x33
// ============================================================================
UINT32
EFIAPI
PciExpressRead32 (
IN UINTN Address
)
{
if ((Address & 0xF0000000) != 0) {
ASSERT (Address <= 0x0FFFFFFF);
}
return *(volatile UINT32 *)(GetPciExpressBaseAddr () + Address);
}
// ============================================================================
// PCI Express MMIO config space access - Write32
// Address: 0xffdac51b | Size: 0x39
// ============================================================================
UINT32
EFIAPI
PciExpressWrite32 (
IN UINTN Address,
IN UINT32 Value
)
{
if ((Address & 0xF0000000) != 0) {
ASSERT (Address <= 0x0FFFFFFF);
}
*(volatile UINT32 *)(GetPciExpressBaseAddr () + Address) = Value;
return Value;
}
// ============================================================================
// PCI Express Atomic OR - 8-bit
// Address: 0xffdac283 | Size: 0x42
// ============================================================================
UINT8
EFIAPI
PciExpressOr8 (
IN UINTN Address,
IN UINT8 OrData,
IN UINT8 AndData
)
{
UINT8 Value;
if ((Address & 0xF0000000) != 0) {
ASSERT (Address <= 0x0FFFFFFF);
}
Value = *(volatile UINT8 *)(GetPciExpressBaseAddr () + Address);
Value = (Value & AndData) | OrData;
*(volatile UINT8 *)(GetPciExpressBaseAddr () + Address) = Value;
return Value;
}
// ============================================================================
// PCI Express Atomic OR - 16-bit
// Address: 0xffdac2c5 | Size: 0x52
// ============================================================================
UINT16
EFIAPI
PciExpressOr16 (
IN UINTN Address,
IN UINT16 OrData,
IN UINT16 AndData
)
{
UINT16 *AddrPtr;
if ((Address & 0xF0000000) != 0) {
ASSERT (Address <= 0x0FFFFFFF);
}
AddrPtr = (UINT16 *)(GetPciExpressBaseAddr () + Address);
return AlignedWrite16 (
AddrPtr,
(AlignedRead16 (AddrPtr) & AndData) | OrData
);
}
// ============================================================================
// PCI Express Atomic OR - 32-bit
// Address: 0xffdac317 | Size: 0x42
// ============================================================================
UINT32
EFIAPI
PciExpressOr32 (
IN UINTN Address,
IN UINT32 OrData,
IN UINT32 AndData
)
{
UINT32 Value;
if ((Address & 0xF0000000) != 0) {
ASSERT (Address <= 0x0FFFFFFF);
}
Value = *(volatile UINT32 *)(GetPciExpressBaseAddr () + Address);
Value = (Value & AndData) | OrData;
*(volatile UINT32 *)(GetPciExpressBaseAddr () + Address) = Value;
return Value;
}
// ============================================================================
// Unaligned memory access helpers
// ============================================================================
UINT16
EFIAPI
UnalignedRead16 (
IN VOID *Buffer
)
{
ASSERT (Buffer != NULL);
return *(UINT16 *)Buffer;
}
UINT16
EFIAPI
UnalignedWrite16 (
OUT VOID *Buffer,
IN UINT16 Value
)
{
ASSERT (Buffer != NULL);
*(UINT16 *)Buffer = Value;
return Value;
}
UINT32
EFIAPI
UnalignedRead32 (
IN VOID *Buffer
)
{
ASSERT (Buffer != NULL);
return *(UINT32 *)Buffer;
}
UINT32
EFIAPI
UnalignedWrite32 (
OUT VOID *Buffer,
IN UINT32 Value
)
{
ASSERT (Buffer != NULL);
*(UINT32 *)Buffer = Value;
return Value;
}
// ============================================================================
// Aligned memory access helpers
// ============================================================================
UINT16
EFIAPI
AlignedRead16 (
IN UINT16 *Address
)
{
ASSERT (((UINTN)Address & 1) == 0);
return *Address;
}
UINT16
EFIAPI
AlignedWrite16 (
OUT UINT16 *Address,
IN UINT16 Value
)
{
ASSERT (((UINTN)Address & 1) == 0);
*Address = Value;
return Value;
}
// ============================================================================
// Platform error status (CMOS-based)
// Address: 0xffdac359 | Size: 0x4f
// ============================================================================
//
// Reads the platform error status from CMOS register 0x4A.
// This is used by the ASSERT infrastructure to decide whether to
// break or halt on assertion failure.
//
// Returns:
// 0 - No error
// 0xFFFFFFFF - Error status cleared
// -2147483644 - EFI_DEVICE_ERROR (recoverable)
// -2147483578 - EFI_DEVICE_ERROR (non-recoverable)
//
UINTN
EFIAPI
GetPlatformErrorStatus (
VOID
)
{
UINT8 Status;
//
// Read current CMOS index register (0x70), preserving bit 7 (NMI disable)
//
Status = IoRead8 (0x70);
IoWrite8 (0x70, (Status & 0x80) | 0x4A);
Status = IoRead8 (0x71);
if (Status > 3) {
if (Status == 0) {
//
// Check a hardware register (at fixed address 0xFDAF0490) for
// additional error info
//
Status = (*(volatile UINT8 *)0xFDAF0490 & 2) | 1;
}
}
//
// Only Status values 1 and 2 are used:
// 1 -> EFI_DEVICE_ERROR (recoverable)
// 2 -> more severe error
//
switch (Status) {
case 0:
return 0;
case 1:
return (UINTN)EFI_DEVICE_ERROR; // -2147483644
default:
if (Status != 0xFF) {
return (UINTN)(0x80000000 | 0x00010046); // -2147483578
}
return 0; // Status was 0xFF (cleared)
}
}
// ============================================================================
// Debug/assert infrastructure
// ============================================================================
//
// These functions use the PCD database to call into the DebugLib
// implementation installed as a PPI. The PCD database pointer at
// offset +4 contains the assertion/debug message handler function.
//
// Note: This is the old-style EDK2 DEBUG/ASSERT infrastructure
// before the standardized DebugLib was widely used.
VOID
EFIAPI
ReportAssert (
IN UINTN Flags,
IN CONST CHAR8 *Format,
...
)
{
VOID *PcdDatabase;
UINTN ErrorStatus;
VA_LIST Marker;
VA_START (Marker, Format);
PcdDatabase = GetPcdDatabasePtr ();
if (PcdDatabase != NULL) {
ErrorStatus = GetPlatformErrorStatus ();
if ((ErrorStatus & Flags) != 0) {
//
// Call the ASSERT handler from PCD database (at offset +4)
//
((VOID (*)(UINTN, CONST CHAR8 *, VA_LIST))(
*(UINTN *)((UINTN)PcdDatabase + 4)
))(Flags, Format, Marker);
}
}
VA_END (Marker);
}
VOID
EFIAPI
ReportDebugMsg (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Message
)
{
VOID *PcdDatabase;
PcdDatabase = GetPcdDatabasePtr ();
if (PcdDatabase != NULL) {
//
// Call the DEBUG handler from PCD database (at offset +4)
//
((VOID (*)(CONST CHAR8 *, UINTN, CONST CHAR8 *))(
*(UINTN *)((UINTN)PcdDatabase + 4)
))(FileName, LineNumber, Message);
}
}