/**
*PciTableInit.c
*Module: PciTableInit (0397) - AmiCspLib: PciTableInit library
*Source: e:\hs\Build\HR6N0XMLK\DEBUG_VS2015\IA32\AmiChipsetModulePkg\Library\AmiCspLib\PciTableInit\DEBUG\PciTableInit.pdb
*SHA256: 423d394c79dc70b99dafa9db7af46c2cdc8ad3cef5679eb7bbf02f28b11063d1
*
*This module provides PCI table initialization support during the PEI phase.
*It registers PPI notification and installation dispatch callbacks via
*CspLibPei_Init to manage PCI table data structures.
*
*Reconstructed from IDA Pro 32-bit x86 decompilation.
*/
#include <Uefi.h>
#include <Pi/PiPeiCis.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/PeiServicesLib.h>
#include <Library/PeiServicesTablePointerLib.h>
#include <Library/IoLib.h>
#include "PciTableInit.h"
//
// GUID for EFI_DEBUG_SUPPORT_PPI
// {36232936-0E76-31C8-A13A-3AF2FC1C3932}
//
EFI_GUID gEfiDebugSupportPpiGuid = {
0x36232936, 0x0E76, 0x31C8, {0xA1, 0x3A, 0x3A, 0xF2, 0xFC, 0x1C, 0x39, 0x32}
};
//
// GUID for PciTableInit PPI (produced by this module)
// {97F91E78-EA12-4EA6-B7B3-7B0678C28673}
//
EFI_GUID gPciTableInitPpiGuid = {
0x97F91E78, 0xEA12, 0x4EA6, {0xB7, 0xB3, 0x7B, 0x06, 0x78, 0xC2, 0x86, 0x73}
};
//
// PPI descriptor for this module
// Flags: 0x80000010 (notification + not install-on-demand)
// GUID: gPciTableInitPpiGuid
// Ppi: gPciTableInitNotify
//
EFI_PEI_PPI_DESCRIPTOR gPciTableInitPpiDescriptor = {
EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES,
&gPciTableInitPpiGuid,
&gPciTableInitNotify
};
//
// Dispatch function pointers
// gPciTableInitNotify = PpiNotifyDispatch (0xffe30e78)
// gPciTableInitInstall = PpiInstallDispatch (0xffe30ecf)
//
// These are referenced by the PPI descriptor and called by CspLibPei_Init
// to process the notification and installation dispatch tables.
//
//----------------------------------------------------------------------
// Internal helper functions (library-level)
//----------------------------------------------------------------------
/**
*Fills a buffer with a byte value.
*
*Simple wrapper around memset.
*
* @param[in] buf Pointer to buffer to fill
* @param[in] count Number of bytes to fill
* @param[in] value Byte value to fill with
* @return Pointer to the filled buffer
*/
void *SetMem (
void *buf,
unsigned int count,
char value
)
{
return memset (buf, value, count);
}
/**
*Fills a buffer with a dword value.
*
*Simple wrapper around memset32.
*
* @param[in] buf Pointer to buffer to fill
* @param[in] count Number of dwords to fill
* @param[in] value Dword value to fill with
* @return Pointer to the filled buffer
*/
void *SetMem32 (
void *buf,
unsigned int count,
int value
)
{
return memset32 (buf, value, count);
}
/**
*Copies memory with overlap-safe handling.
*
*If the source overlaps the destination (backward copy needed),
*copies byte-by-byte from the end. Otherwise copies 4-byte aligned
*chunks first, then residual bytes.
*
* @param[out] dst Destination buffer
* @param[in] src Source buffer
* @param[in] count_1 Number of bytes to copy
* @return Pointer to destination buffer
*/
char *CopyMem (
char *dst,
char *src,
unsigned int count_1
)
{
unsigned int count;
char *dst_1;
char *src_1;
count = count_1;
if (src < dst && &src[count_1 - 1] >= dst) {
//
// Backward copy to handle overlapping regions
//
src_1 = &src[count_1 - 1];
dst_1 = &dst[count_1 - 1];
} else {
//
// Forward copy: copy aligned dwords first, then residual bytes
//
count = count_1 & 3;
qmemcpy (dst, src, 4 * (count_1 >> 2));
src_1 = &src[4 * (count_1 >> 2)];
dst_1 = &dst[4 * (count_1 >> 2)];
}
qmemcpy (dst_1, src_1, count);
return dst;
}
/**
*Initializes an array of (key, value) dword pairs.
*
*Iterates backward through the array, writing each element as
*a pair of dwords.
*
* @param[in] a1 Pointer to array base
* @param[in] a2 Number of elements
* @param[in] a3 Key value for each element
* @param[in] a4 Value for each element
* @return a1 (array base)
*/
int TableInitLoop (
int a1,
int a2,
int a3,
int a4
)
{
do {
*(_DWORD *)(a1 + 8 *a2 - 8) = a3;
*(_DWORD *)(a1 + 8 *a2-- - 4) = a4;
} while (a2);
return a1;
}
//----------------------------------------------------------------------
// PPI dispatch functions
//----------------------------------------------------------------------
/**
*Dispatches PPI notifications from a table.
*
*Each table entry is 3 bytes:
* [0] offset from base address (1 byte)
* [1] flags (1 byte, bitwise inverted control value)
* [2] callback parameter (1 byte)
*
*For each entry, calls PpiInterfaceCall with:
* - addr = base + offset
* - callback_param = entry[1]
* - control = ~entry[0]
*
* @param[in] a1 Context parameter (unused)
* @param[in] a2 Context parameter (unused)
* @param[in] a3 Context parameter (unused)
* @param[in] a4 Base address (64-bit) for offset calculations
* @param[in] a5 Pointer to notification table
* @param[in] a6 Number of entries in the table
* @return Always 0
*/
int PpiNotifyDispatch (
int a1,
int a2,
int a3,
__int64 a4,
int a5,
unsigned __int16 a6
)
{
int v6;
char *v7;
if (a6 && a5) {
v6 = a6;
v7 = (char *)(a5 + 2);
do {
PpiInterfaceCall (
a4 + (unsigned __int8)*(v7 - 2),
(a4 + (unsigned __int64)(unsigned __int8)*(v7 - 2)) >> 32,
*v7,
~*(v7 - 1)
);
v7 += 3;
--v6;
} while (v6);
}
return 0;
}
/**
*Dispatches PPI installations from a table.
*
*Each table entry is 12 bytes:
* [0] offset from base address (1 byte)
* [4] flags/attribute (4 bytes)
* [8] callback function pointer or parameter (4 bytes)
*
*Calls PpiInterfaceCall for each entry with:
* - addr = base + offset
* - callback param from entry[4..7]
* - attribute from entry[8..11]
*
*Stops processing if PpiInterfaceCall returns negative.
*
* @param[in] a1 Context parameter (unused)
* @param[in] a2 Context parameter (unused)
* @param[in] a3 Context parameter (unused)
* @param[in] a4 Base address (64-bit) for offset calculations
* @param[in] a5 Pointer to installation table
* @param[in] a6 Number of entries in the table
* @return Always 0
*/
int PpiInstallDispatch (
int a1,
int a2,
int a3,
__int64 a4,
int a5,
unsigned __int16 a6
)
{
int v6;
unsigned int v7;
_DWORD *v8;
int v9;
v6 = 0;
if (a6 && a5) {
v7 = 0;
v8 = (_DWORD *)(a5 + 8);
do {
if (v6 < 0) {
break;
}
v9 = PpiInterfaceCall (
a4 + *((unsigned __int8 *)v8 - 8),
(a4 + (unsigned __int64)*((unsigned __int8 *)v8 - 8)) >> 32,
*v8,
*(v8 - 1)
);
v8 += 3;
++v7;
v6 = v9;
} while (v7 < a6);
}
return 0;
}
//----------------------------------------------------------------------
// Debug output support
//----------------------------------------------------------------------
/**
*Gets the debug output interface via PeiServices.
*
*Locates the EFI_DEBUG_SUPPORT_PPI using PeiServices->LocatePpi
*and returns the debug interface instance.
*
* @return Pointer to debug output interface, or NULL if not found
*/
int GetDebugOutputInterface (
void
)
{
int v0;
EFI_GUID *Interface;
EFI_STATUS Status;
v0 = GetPeiServices ();
Status = ((EFI_PEI_SERVICES **)v0)->LocatePpi (
v0,
&gEfiDebugSupportPpiGuid,
0,
NULL,
&Interface
);
if (Status >= 0) {
return (int)Interface;
}
return 0;
}
/**
*Conditionally prints a debug message.
*
*Checks if debug output is enabled for the given error level.
*If enabled, calls the debug output interface's print function.
*
* @param[in] ErrorLevel Debug error level mask
* @param[in] Format Format string
* @param[in] ... Variable arguments
* @return Result of the debug print call, or EFI error
*/
int DebugPrint (
int ErrorLevel,
const char *Format,
...
)
{
int result;
EFI_DEBUG_SUPPORT_PPI *DebugInterface;
VA_LIST Va;
VA_START (Va, Format);
result = GetDebugOutputInterface ();
DebugInterface = (EFI_DEBUG_SUPPORT_PPI *)result;
if (result != 0) {
result = IsDebugPrintEnabled ();
if ((result & (UINTN)ErrorLevel) != 0) {
return DebugInterface->DebugPrint (ErrorLevel, Format, Va);
}
}
VA_END (Va);
return result;
}
/**
*Reports an assertion failure.
*
*Called when an ASSERT() expression evaluates to FALSE.
*Forwards the assertion info to the debug output interface.
*
* @param[in] FileName Source file name (string pointer as int)
* @param[in] LineNumber Line number of the assertion
* @param[in] Expression Failed assertion expression (string pointer as int)
* @return Result of the assertion report
*/
int ReportAssertion (
int FileName,
int LineNumber,
int Expression
)
{
int result;
result = GetDebugOutputInterface ();
if (result != 0) {
return (*(int ( **)(int, int, int))(result + 4))(
FileName,
LineNumber,
Expression
);
}
return result;
}
/**
*Invokes a PPI interface method.
*
*Looks up the PPI interface from the context and calls the
*method at vtable offset +8.
*
* @param[in] a1 Parameter passed via edx (typically address)
* @param[in] a2 Context/interface pointer passed via ecx
* @param[in] a3 Parameter (typically callback value)
* @param[in] a4 Parameter (typically control flags)
* @param[in] ... Additional variable arguments
* @return Result from the PPI interface call, or EFI_UNSUPPORTED
*/
int __usercall PpiInterfaceCall (
int a1,
int a2,
int a3,
int a4,
...
)
{
int v4;
int v6;
va_list va;
VA_START (va, a4);
v6 = VA_ARG (va, int);
v4 = *(_DWORD *)(*(_DWORD *)a2 + 100);
if (v4 != 0) {
return (*(int ( **)(int, int, int, int, int, int *, void **))(
v4 + 8
))(
a2,
v4,
a1,
a3,
a4,
(int *)va,
(void **)va
);
}
return EFI_UNSUPPORTED;
}
//----------------------------------------------------------------------
// Platform debug status
//----------------------------------------------------------------------
/**
*Checks if debug printing is enabled via CMOS/NVRAM.
*
*Reads CMOS register 0x4A through the RTC index/data ports (0x70/0x71).
*Preserves the NMI mask bit (bit 7) on the index port.
*
*Interpretation:
* - 0: disabled
* - 1: enabled (debug mode)
* - other: platform-specific mode
*
*If the CMOS value is 0 (but was >3), falls back to checking the
*ICH/GPIO register at 0xFDAF0490 bit 1 to determine the platform setting.
*
* @return EFI status code or raw debug level
*0 if disabled
*EFI_INVALID_PARAMETER (0x80000002) if enabled in non-debug
*EFI_UNSUPPORTED (0x80000001) if enabled in debug
* -1 if disabled (magic value)
*/
int IsDebugPrintEnabled (
void
)
{
UINT8 CmosIndex;
UINT8 DebugValue;
UINT8 DebugValue2;
//
// Read current CMOS index, set to 0x4A while preserving NMI mask
//
CmosIndex = IoRead8 (0x70);
IoWrite8 (0x70, CmosIndex & 0x80 | 0x4A);
DebugValue = IoRead8 (0x71);
DebugValue2 = DebugValue;
if ((UINT8)DebugValue <= 3) {
goto CheckValue;
}
DebugValue2 = DebugValue;
if (DebugValue == 0) {
//
// Platform override: check GPIO register bit 1
//
DebugValue2 = (MmioRead8 (0xFDAF0490) & 2) | 1;
goto CheckValue;
}
CheckValue:
if (DebugValue2 == 0) {
return 0;
}
if (DebugValue2 == (UINT8)-1) {
return 0;
}
return (DebugValue2 == 1) ? EFI_UNSUPPORTED : EFI_INVALID_PARAMETER;
}
//----------------------------------------------------------------------
// PEI Services access
//----------------------------------------------------------------------
/**
*Gets the PEI Services Table Pointer via IDT.
*
*Reads the IDTR and extracts the PEI services pointer from the
*IDT entry at a fixed offset relative to the IDT base.
*
* @return Pointer to EFI_PEI_SERVICES, or 0 if not found
*/
int GetPeiServices (
void
)
{
int v0;
IA32_IDTR Idtr;
int V3;
ReadIdtr (&Idtr);
v0 = *(_DWORD *)(V3 - 4);
if (v0 == 0) {
ReportAssertion (
(int)"e:\\hs\\MdePkg\\Library\\PeiServicesTablePointerLibIdt\\PeiServicesTablePointer.c",
48,
(int)"PeiServices != ((void *) 0)"
);
}
return v0;
}
/**
*Reads the IDTR register.
*
*Executes the sidt instruction to capture the current IDTR value.
*Asserts if the output buffer is NULL.
*
* @param[out] Idtr Pointer to receive the IDTR value
* @return Pointer to the IDTR buffer
*/
void *__thiscall ReadIdtr (
void *Idtr
)
{
if (Idtr == NULL) {
ReportAssertion (
(int)"e:\\hs\\MdePkg\\Library\\BaseLib\\X86ReadIdtr.c",
37,
(int)"Idtr != ((void *) 0)"
);
}
__sidt (Idtr);
return Idtr;
}
//----------------------------------------------------------------------
// Module entry point
//----------------------------------------------------------------------
/**
*Module entry point.
*
*Called by the PEI core when the PciTableInit module is loaded.
*Calls CspLibPei_Init (via SystemTable->Signature+24 interface)
*to register PPI notification and installation dispatch callbacks
*from the dispatch tables.
*
*The dispatch table entries reference:
* - gPciTableInitNotify = PpiNotifyDispatch
* - gPciTableInitInstall = PpiInstallDispatch
*
* @param[in] ImageHandle Handle for this PEI module
* @param[in] SystemTable Pointer to EFI system table
* @return EFI_STATUS
*EFI_SUCCESS if initialization succeeded
*Error code if CspLibPei_Init failed
*/
EFI_STATUS ModuleEntryPoint (
EFI_HANDLE ImageHandle,
EFI_SYSTEM_TABLE *SystemTable
)
{
int v2;
EFI_STATUS v3;
//
// Initialize global SystemTable pointer
//
if (SystemTable == NULL) {
//
// SystemTable->Hdr.Signature is used as a scratch register via LODWORD trick.
// The actual initialization is:
// ::SystemTable = (int)SystemTable;
// dword_FFDAB284 = SystemTable->Hdr.Signature field at offset 100;
// Then call CspLibPei_Init with the PPI descriptor.
//
v2 = CspLibPei_Init (SystemTable, &gPciTableInitPpiDescriptor);
} else {
v2 = CspLibPei_Init (SystemTable, &gPciTableInitPpiDescriptor);
}
v3 = v2;
if (v2 != 0) {
DebugPrint (EFI_D_ERROR, "CspLibPei_Init Return Code : %r\n", v2);
}
return v3;
}