Newer
Older
AMI-Aptio-BIOS-Reversed / AmiChipsetModulePkg / Library / AmiCspLib / PciTableInit / PciTableInit.c
@Ajax Dong Ajax Dong 2 days ago 13 KB Restructure the repo
/**
 *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;
}