/**
*AST2500PeiInit (0409) - Full Decompilation
*
*Module: AST2500PeiInit.efi
*PE Index: 0409
*Arch: IA32 (32-bit)
*Base Address: 0xffe51614
*Image Size: 0x1200
*MD5: 105d4b74f818219f209297607f2e1f28
*SHA256: 40afe5e3b14fb4d12a08eadfe576fefd9798fa88caeb4cc8abc08a4063b084d2
*
*This PEIM initializes AST2500 (ASPEED) Super I/O and GPIO configuration
*during the PEI phase. It detects the AST2500 SIO, programs GPIO
*configuration registers via PCI CF8/CF9 and SIO PM I/O ports (0x2E/0x2F).
*
*Source origin: edk2/MdePkg sub-libraries compiled together:
* - BaseIoLibIntrinsic (IoLibMsc.c, IoLib.c)
* - BasePciCf8Lib (PciCf8Lib.c)
* - PeiServicesTablePointerLibIdt (PeiServicesTablePointer.c)
* - BaseLib (X86ReadIdtr.c)
*
*These edk2 library functions were compiled as static-linked helper
*functions (rather than importing from other modules), which is unusual
*for PEI and suggests this module was compiled with specific build flags.
*/
/* ---------------------------------------------------------------------------
*Forward declarations
* --------------------------------------------------------------------------- */
int Ast2500PeiInitEntry(void);
char AstSioReadPmReg(int addr, int *out_value);
char AstSioWritePmReg(int addr, int value);
int AstPciCfgRead16(unsigned __int16 port);
unsigned __int16 AstPciCfgWrite16(unsigned __int16 port, unsigned __int16 value);
unsigned int __thiscall AstPciCfgRdAddr(unsigned __int16 port);
unsigned int AstPciCfgWrAddr(unsigned __int16 port, unsigned int value);
int AstPciCfgLibAssert(void);
int AstDebugAssert(int file, int line, int expr);
int AstPciCfgProgramBar(int func_addr, __int16 bar_size);
int AstGpioCfgProgram(int gpio_port, __int16 pin_mask, char flags, int function);
unsigned __int8 AstIoRmwSequence(int base, int count);
__int16 __thiscall AstPciCfgRead(unsigned int pci_addr);
__int16 AstPciCfgWrite(unsigned int pci_addr, unsigned __int16 value);
int AstPciCf8Read(unsigned int pci_addr);
int AstPciCf8Write(unsigned int pci_addr, int value);
__int16 AstIoWrite16(_WORD *addr, __int16 value);
int AstPeiServicesGetPtr(void);
void *__thiscall AstReadIdtr(void *this);
/* ---------------------------------------------------------------------------
*Data Tables (located in .data section)
*
*GPIO_CONFIG_ENTRY: 8 bytes each
*WORD gpio_num; // GPIO pin number (0-255)
*BYTE and_mask; // AND mask to clear bits
*DWORD or_value; // OR value to set bits (little-endian)
*
*IO_RMW_ENTRY: 4 bytes each
*WORD io_port; // I/O port address
*BYTE and_mask; // AND mask (0 = direct write, non-zero = RMW)
*BYTE or_value; // OR value to write
*
*PM_REG_CONFIG: 12 bytes each
*BYTE ldn_select; // LDN register to select (at offset i*4)
*DWORD and_mask; // AND mask applied to register value (at dword_FFE52668[i])
*DWORD or_value; // OR value applied to register value (at dword_FFE5266C[i])
* --------------------------------------------------------------------------- */
/*GPIO config table for non-AST2500 SIO (4 entries) at 0xFFE52646:
*GPIO2 (GPIOE0): and=0xFF, or=0x0A000000 (multi-function pin, SCU3C)
*GPIO64 (GPIOD0): and=0xFF, or=0x03E00000
*GPIO16 (GPIOA0): and=0xFF, or=0x02E00000
*GPIO32 (GPIOB0): and=0xFF, or=0x00000000
*/
static const BYTE GpioTableNonAst[] = {
0x02, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0A,
0x40, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xE0, 0x03,
0x10, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xE0, 0x02,
0x20, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
};
/*GPIO config table for AST2500 SIO ID=0x21 (5 entries) at 0xFFE52716:
*GPIO2 (GPIOE0): and=0xFF, or=0x02F80000 (multi-function pin)
*GPIO2 (GPIOE0): and=0x06, or=0x0A000000 (extra config)
*GPIO64 (GPIOD0): and=0xFF, or=0x03E00000
*GPIO16 (GPIOA0): and=0xFF, or=0x02E00000
*GPIO32 (GPIOB0): and=0xFF, or=0x00000000
*/
static const BYTE GpioTableAst[] = {
0x02, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xF8, 0x02,
0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x0A,
0x40, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xE0, 0x03,
0x10, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xE0, 0x02,
0x20, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
};
/*I/O RMW Sequence table at 0xFFE526B4 (23 entries, 4 bytes each):
*SIO unlock x2, select LDN 7, activate, set reg 0x30, clear,
*repeat for each GPIO group, SIO lock
*See full documentation in .md file.
*/
/*SIO PM Register Configuration (byte_FFE52664, dword_FFE52668, dword_FFE5266C)
* ][ byte at i*4 = LDN register select
* ][ dword at = AND mask
* ][ dword at = OR value
*
*Base address: 0x1E6E2000 (AST2500 SCU register space)
*9 groups of 3 registers each = 27 total register operations
*/
/* ---------------------------------------------------------------------------
*PEI Module Entry Point
* --------------------------------------------------------------------------- */
/**
*Module entry point - thunk to Ast2500PeiInitEntry.
*UEFI PEI entry with standard ImageHandle/SystemTable parameters.
*/
EFI_STATUS EFIAPI _ModuleEntryPoint (
EFI_HANDLE ImageHandle,
EFI_SYSTEM_TABLE *SystemTable
)
{
return Ast2500PeiInitEntry();
}
/**
*AST2500 PEI Init main routine.
*
*1. Probe AST2500 SIO via PM port 0x72/0x73 at register 0x5C
*2. If SIO ID = 0x21 (AST2500): configure 5 GPIO entries from AST table
*else: configure 4 GPIO entries from non-AST table
*3. Run 23-entry I/O RMW sequence (SIO port operations)
*4. Program 27 PM registers at base 0x1E6E2000 in 3-entry groups
* (read -> mask -> write pattern)
*
*Returns 0 (EFI_SUCCESS).
*/
int Ast2500PeiInitEntry()
{
unsigned __int8 sio_id;
char *gpio_ptr;
int num_entries;
unsigned int i;
int pm_base;
int pm_value;
int temp; // [esp-4h] [ebp-14h]
/*Probe AST2500 SIO via PM port 0x72/0x73 at register 0x5C */
__outbyte(0x72u, 0x5Cu);
sio_id = __inbyte(0x73u);
if (sio_id == 33) { /*0x21 = AST2500 */
gpio_ptr = (char *)&GpioTableAst;
num_entries = 5;
do {
/*Each entry: WORD gpio_num, BYTE and_mask, DWORD or_value */
AstGpioCfgProgram(temp, *((_WORD *)gpio_ptr - 1), *gpio_ptr, *(_DWORD *)(gpio_ptr + 2));
gpio_ptr += 8;
temp = temp; /*compiler artifact from LODWORD optimization */
--num_entries;
} while (num_entries);
/*Use IO RMW table at 0xFFE526B4 (SIO setup) */
temp = (int)&unk_FFE526B4;
} else {
gpio_ptr = (char *)&GpioTableNonAst;
num_entries = 4;
do {
AstGpioCfgProgram(temp, *((_WORD *)gpio_ptr - 1), *gpio_ptr, *(_DWORD *)(gpio_ptr + 2));
gpio_ptr += 8;
temp = temp;
--num_entries;
} while (num_entries);
temp = (int)&unk_FFE52744;
}
/*Apply 23-entry I/O RMW sequence */
AstIoRmwSequence(temp, temp);
/*Program 27 PM registers at base 0x1E6E2000 in 3-entry groups:
*byte_FFE52664[i*4] = PM sub-register select (added to base 0x1E6E2000)
*dword_FFE52668[i] = AND mask
*dword_FFE5266C[i] = OR value
*i increments by 3, so entries 0,3,6,...,24 (9 groups)
*/
for (i = 0; i < 27; i += 3) {
pm_base = (unsigned __int8)byte_FFE52664[i *4] | 0x1E6E2000;
AstSioReadPmReg(pm_base, &pm_value);
pm_value = dword_FFE5266C[i] | pm_value & dword_FFE52668[i];
AstSioWritePmReg(pm_base, pm_value);
}
return 0;
}
/* ---------------------------------------------------------------------------
*AST2500 Super I/O PM Register Access (SIO LPC PM I/O via 0x2E/0x2F)
* --------------------------------------------------------------------------- */
/**
*Read a 32-bit value from AST2500 PM register via SIO.
*
*Protocol:
*1. SIO unlock: outb(0x2E, 0xA5) x2
*2. Select LDN 0x0D (PM I/O device):
*outb(0x2E, 7); outb(0x2F, 0x0D)
*3. Enable LDN 0x0D:
*outb(0x2E, 0x30); reg = inb(0x2F); outb(0x2F, reg | 1)
*4. Write register address via SIO index registers:
*F0 = HIBYTE(addr), F1 = BYTE2(addr),
*F2 = BYTE1(addr), F3 = LOBYTE(addr)
*5. Trigger read: set F8 to mode 2, dummy read FE
*6. Read result: F4=byte0, F5=byte1, F6=byte2, F7=byte3
*7. SIO lock: outb(0x2E, 0xAA)
*
* @param addr AST2500 PM register address (SCU space)
* @param out_value Pointer to receive 32-bit register value
* @return 0xAA (unlock byte value)
*/
char AstSioReadPmReg(int addr, int *out_value)
{
unsigned __int8 b0, b1, b2, b3;
unsigned __int8 reg;
/*SIO unlock sequence */
__outbyte(0x2Eu, 0xA5u);
__outbyte(0x2Eu, 0xA5u);
/*Select logical device 0x0D (PM I/O device) */
__outbyte(0x2Eu, 7u);
__outbyte(0x2Fu, 0xDu);
/*Enable LDN */
__outbyte(0x2Eu, 0x30u);
reg = __inbyte(0x2Fu);
__outbyte(0x2Fu, reg | 1);
/*Write register address (32-bit address in 4 bytes) */
__outbyte(0x2Eu, 0xF0u);
__outbyte(0x2Fu, HIBYTE(addr));
__outbyte(0x2Eu, 0xF1u);
__outbyte(0x2Fu, BYTE2(addr));
__outbyte(0x2Eu, 0xF2u);
__outbyte(0x2Fu, BYTE1(addr));
__outbyte(0x2Eu, 0xF3u);
__outbyte(0x2Fu, addr);
/*Trigger read: set F8[1:0] = 0b10 (read mode) */
__outbyte(0x2Eu, 0xF8u);
reg = __inbyte(0x2Fu);
__outbyte(0x2Fu, reg & 0xFC | 2);
/*Flush / sync */
__outbyte(0x2Eu, 0xFEu);
__inbyte(0x2Fu); /*dummy read for synchronization */
/*Read result bytes: F4-F7 = 4 data bytes */
__outbyte(0x2Eu, 0xF4u);
b0 = __inbyte(0x2Fu);
__outbyte(0x2Eu, 0xF5u);
b1 = __inbyte(0x2Fu);
__outbyte(0x2Eu, 0xF6u);
b2 = __inbyte(0x2Fu);
__outbyte(0x2Eu, 0xF7u);
b3 = __inbyte(0x2Fu);
/*Combine into 32-bit value: b3:b2:b1:b0 (big-endian byte order) */
*out_value = b3 | ((b2 | ((b1 | (b0 << 8)) << 8)) << 8);
/*SIO lock */
__outbyte(0x2Eu, 0xAAu);
return 0xAA;
}
/**
*Write a 32-bit value to AST2500 PM register via SIO.
*
*Same protocol as read, but:
*5b. Write value bytes F4-F7
*6b. Trigger write via F8
*7b. CF9 flush register via FE
*
* @param addr AST2500 PM register address
* @param value 32-bit value to write
* @return 0xAA (unlock byte value)
*/
char AstSioWritePmReg(int addr, int value)
{
unsigned __int8 reg;
/*SIO unlock sequence */
__outbyte(0x2Eu, 0xA5u);
__outbyte(0x2Eu, 0xA5u);
/*Select logical device 0x0D (PM I/O device) */
__outbyte(0x2Eu, 7u);
__outbyte(0x2Fu, 0xDu);
/*Enable LDN */
__outbyte(0x2Eu, 0x30u);
reg = __inbyte(0x2Fu);
__outbyte(0x2Fu, reg | 1);
/*Write register address bytes */
__outbyte(0x2Eu, 0xF0u);
__outbyte(0x2Fu, HIBYTE(addr));
__outbyte(0x2Eu, 0xF1u);
__outbyte(0x2Fu, BYTE2(addr));
__outbyte(0x2Eu, 0xF2u);
__outbyte(0x2Fu, BYTE1(addr));
__outbyte(0x2Eu, 0xF3u);
__outbyte(0x2Fu, addr);
/*Write value bytes F4-F7 (big-endian: F4=MSB, F7=LSB) */
__outbyte(0x2Eu, 0xF4u);
__outbyte(0x2Fu, HIBYTE(value));
__outbyte(0x2Eu, 0xF5u);
__outbyte(0x2Fu, BYTE2(value));
__outbyte(0x2Eu, 0xF6u);
__outbyte(0x2Fu, BYTE1(value));
__outbyte(0x2Eu, 0xF7u);
__outbyte(0x2Fu, value);
/*Trigger write via F8 */
__outbyte(0x2Eu, 0xF8u);
reg = __inbyte(0x2Fu);
__outbyte(0x2Fu, reg & 0xFC | 2);
/*CF9 flush: write 0xCF to FE register */
__outbyte(0x2Eu, 0xFEu);
__outbyte(0x2Fu, 0xCFu);
/*SIO lock */
__outbyte(0x2Eu, 0xAAu);
return 0xAA;
}
/* ---------------------------------------------------------------------------
*I/O Port Primitives (edk2 IoLibMsc.c wrappers)
*These are inline I/O port access with alignment assertions.
* --------------------------------------------------------------------------- */
/**
*Read 16-bit value from I/O port.
*From BaseIoLibIntrinsic/IoLibMsc.c line 0x85.
*/
int AstPciCfgRead16(unsigned __int16 port)
{
int Device;
int result;
if ((port & 1) != 0) {
Device = AstPciCfgLibAssert();
if (Device) {
(*(void ( **)(const char *, int, const char *))(Device + 4))(
"e:\\hs\\MdePkg\\Library\\BaseIoLibIntrinsic\\IoLibMsc.c",
133,
"(Port & 1) == 0");
}
}
LOWORD(result) = __inword(port);
return (unsigned __int16)result;
}
/**
*Write 16-bit value to I/O port.
*From BaseIoLibIntrinsic/IoLibMsc.c line 0xA3.
*/
unsigned __int16 AstPciCfgWrite16(unsigned __int16 port, unsigned __int16 value)
{
int Device;
if ((port & 1) != 0) {
Device = AstPciCfgLibAssert();
if (Device) {
(*(void ( **)(const char *, int, const char *))(Device + 4))(
"e:\\hs\\MdePkg\\Library\\BaseIoLibIntrinsic\\IoLibMsc.c",
163,
"(Port & 1) == 0");
}
}
__outword(port, value);
return value;
}
/**
*Read 32-bit from I/O port (used for PCI CF8 address register).
*From BaseIoLibIntrinsic/IoLibMsc.c line 0xC1.
*/
unsigned int __thiscall AstPciCfgRdAddr(unsigned __int16 port)
{
int Device;
if ((port & 3) != 0) {
Device = AstPciCfgLibAssert();
if (Device) {
(*(void ( **)(const char *, int, const char *))(Device + 4))(
"e:\\hs\\MdePkg\\Library\\BaseIoLibIntrinsic\\IoLibMsc.c",
193,
"(Port & 3) == 0");
}
}
return __indword(port);
}
/**
*Write 32-bit to I/O port (used for PCI CF8 address register).
*From BaseIoLibIntrinsic/IoLibMsc.c line 0xDF.
*/
unsigned int AstPciCfgWrAddr(unsigned __int16 port, unsigned int value)
{
int Device;
if ((port & 3) != 0) {
Device = AstPciCfgLibAssert();
if (Device) {
(*(void ( **)(const char *, int, const char *))(Device + 4))(
"e:\\hs\\MdePkg\\Library\\BaseIoLibIntrinsic\\IoLibMsc.c",
223,
"(Port & 3) == 0");
}
}
__outdword(port, value);
return value;
}
/* ---------------------------------------------------------------------------
*PEI Assert / Debug Helpers
* --------------------------------------------------------------------------- */
/**
*Get PEI Services pointer and locate a PPI by GUID for assertion reporting.
*
*Locates PPI referenced by unk_FFE52634 (which appears to be a GUID)
*via EFI_PEI_SERVICES->LocatePpi (offset +0x20 from service table).
*Returns pointer to the found PPI instance's protocol interface.
*
*GUID at 0xFFE52634: 36 29 23 36 76 0E C8 31 A1 3A 3A F2 FC 1C 39 32
*
* @return Pointer to PPI protocol interface, or 0 on failure.
*/
int AstPciCfgLibAssert()
{
int pei_services;
int v2; // [esp+0h] [ebp-8h] PPI GUID ptr int Result; // [esp+4h] [ebp-4h] found PPI instance pei_services = AstPeiServicesGetPtr();
if ((*(int ( **)(int, void *, _DWORD, int *, int *))(*(_DWORD *)pei_services + 32))(
pei_services, &unk_FFE52634, 0, &v2, &Result) >= 0) {
return Result; /*Return PPI protocol pointer */
} else {
return 0;
}
}
/**
*Debug assertion handler - reports assertion through PEI services PPI.
*
*Calls ReportStatusCode-style function at offset +4 in the found PPI
*instance's interface.
*
* @param file Source file path string
* @param line Line number
* @param expr Failed expression string
* @return Result from status code reporter, or 0.
*/
int AstDebugAssert(int file, int line, int expr)
{
int result;
result = AstPciCfgLibAssert();
if (result) {
return (*(int ( **)(int, int, int))(result + 4))(file, line, expr);
}
return result;
}
/* ---------------------------------------------------------------------------
*GPIO / PCI BAR Programming
* --------------------------------------------------------------------------- */
/**
*Program a PCI BAR register with the given size mask.
*
*Searches 4 BAR registers at function-relative PCI config space,
*computes alignment from size, writes BAR value both to PCI CF8
*and to memory-mapped I/O at 0xFDEF0000+offset.
*
* @param func_addr PCI function address (bus/dev/func)
* @param bar_size Desired BAR size in bytes
* @return 0 on success, -2147483639 (EFI_NOT_FOUND) if no free BAR
*/
int AstPciCfgProgramBar(int func_addr, __int16 bar_size)
{
unsigned __int8 Size;
unsigned __int16 i;
__int16 bar_val;
unsigned __int8 bit_count;
unsigned __int16 n4;
int bar_cfg;
/*Search 4 BARs for a match or empty slot */
for (i = 0; i < 4u; ++i) {
bar_val = AstPciCf8Read(4 *i + 1015940); /*PCI func base + 4 (BAR0-3) */
if ((bar_val & 1) == 0) /*BAR not enabled - empty slot */
break;
if ((bar_val & 0xFFFC) == bar_size) /*BAR address match */
break;
}
if (i == 4)
return -2147483639; /*EFI_NOT_FOUND */
/*Calculate alignment bits from size */
bit_count = 0;
n4 = 4;
do {
n4 >>= 1;
++bit_count;
} while ((n4 & 1) == 0);
Size = 0;
n4 = 4;
do {
++Size;
n4 >>= 1;
} while (n4);
if (bit_count == Size - 1)
--Size;
/*Build BAR value: [31:16]=upper bits of size mask, [15:2]=aligned address */
bar_cfg = ((((1 << Size) - 1) & 0xFFFC) << 16) |
(unsigned __int16)(bar_size & ~((1 << Size) - 1)) | 1;
AstPciCf8Write(4 *i + 1015940, bar_cfg);
/*Write to MMIO copy at 0xFDEF0000 + BAR offset */
*(_DWORD *)((unsigned __int16)(4 *i + 10032) | 0xFDEF0000) = bar_cfg;
return 0;
}
/**
*Program AST2500 GPIO configuration via PCI CF8 at bus 0xF8, dev 0x80.
*
*Configures GPIO pin/pad function, direction, drive strength, pull-up/down,
*and Schmitt trigger based on function code (n5):
*
*n5=1: GPIO direction control (input/output)
* - pin_mask=0: returns error EFI_INVALID_PARAMETER (-9)
* - pin_mask >0: searches table of valid GPIO directions (1008, 1016, 888, 512...)
*
*n5=2..5: Simple GPIO config (drive type)
* - pin_mask depends on table entries
*
*n5=6: Drive strength control (2mA/4mA/8mA/12mA)
* - Searches entry table at 0xFFE5266C
* - a3=0: strength mode select, a3!=0: per-pin config
*
*n5=7: Internal pull-up/pull-down
* - Searches entry table at 0xFFE526C0
*
*n5=8: Schmitt trigger enable/disable
* - 520 = special register
*
*n5=255: Special modes
* - 46 = SCU config (4096)
* - 78 = SCU config (8192)
* - 98 = SCU config (2048)
* - others: AstPciCfgProgramBar
*
*All paths apply config via PCI at 0xF8080/0xF8082 (AST2500 SCU PCI
*config) and MMIO at 0xFDEF2770/0xFDEF2774.
*/
int AstGpioCfgProgram(
int a1,
__int16 n1008, /*GPIO pin number or special selector */
char a3, /*Sub-flag (drive strength mode, etc.) */
int n5) /*Function code: 1=dir, 6=drive, 7=pull, 8=schmitt, 255=special */
{
__int16 v4; /*Combined bit mask for or_mask */
__int16 v5; /*Combined AND mask */
__int16 n8_1; /*Data value for CF9 write (low 16 bits) */
__int16 v7; /*AND mask for CF9 data (high 16 bits) */
unsigned __int8 v9;
__int16 n888;
__int16 v11;
unsigned __int8 v12;
__int16 n1016;
unsigned __int8 v14;
__int16 n1008_1;
__int16 n8; /*Shifted OR value component */
int n57672688; /*GPIO direction table at 0xFFE526C0 */
__int16 v18; /*Reserved/padding */
_DWORD v19[2]; /*Pull-up table entries (888, ...) */
_DWORD v20[5]; /*Drive strength table (1016, 1008, 888, other, ...) */
__int16 v21; /*Reserved */
int n5a; /*PCI CF8 value for 0xF8080 */
int n5b; /*PCI CF8 value for 0xF8082 */
/*Initialize lookup tables (these are stack-local copies of const data) */
v20[0] = 49808376; /*GPIO direction-related constants */
v21 = 0;
v4 = 0;
v18 = 0;
v5 = -1;
n8_1 = 0;
v20[1] = 36176416;
v20[2] = 48759352;
v20[3] = 65536824;
v20[4] = 48235248;
v19[0] = 41419640;
v19[1] = 956;
n57672688 = 57672688;
v7 = -1;
if (n5 == 1) {
/*GPIO Direction mode */
if (!n1008) {
v7 = -9; /*EFI_INVALID_PARAMETER */
goto WRITE_CONFIG;
}
/*Search valid GPIO direction table */
v14 = 0;
n1008_1 = 1008;
do {
if (n1008_1 == n1008)
break;
n1008_1 = *((_WORD *)&n57672688 + ++v14);
} while (n1008_1);
if (!*((_WORD *)&n57672688 + v14))
return -2147483645; /*EFI_INVALID_PARAMETER */
v5 = -4097;
n8 = 8;
v11 = v14 << 12;
goto COMBINE_MASK;
}
if (n5 <= 1)
return -2147483645;
if (n5 <= 5) {
/*Simple GPIO config modes 2-5 */
v7 = n1008 == 0 ? -1025 : -1;
n8_1 = n1008 != 0 ? 0x400 : 0;
goto WRITE_CONFIG;
}
switch (n5) {
case 6: /*Drive Strength mode */
if (!n1008) {
v7 = (a3 == 0) - 3;
goto WRITE_CONFIG;
}
/*Search drive strength table */
v12 = 0;
n1016 = 1016;
do {
if (n1016 == n1008)
break;
n1016 = *((_WORD *)v20 + ++v12);
} while (n1016);
if (!*((_WORD *)v20 + v12))
return -2147483645;
if (!a3) {
v4 = v12;
n8_1 = 1;
v5 = -8;
goto WRITE_CONFIG;
}
v5 = -113;
n8 = 2;
v11 = 16 *v12;
goto COMBINE_MASK;
case 7: /*Internal Pull-up/Pull-down mode */
if (!n1008) {
v7 = -5;
goto WRITE_CONFIG;
}
v9 = 0;
n888 = 888;
do {
if (n888 == n1008)
break;
n888 = *((_WORD *)v19 + ++v9);
} while (n888);
if (!*((_WORD *)v19 + v9))
return -2147483645;
v5 = -769;
n8 = 4;
v11 = v9 << 8;
COMBINE_MASK:
n8_1 = n8;
v4 = v11;
goto WRITE_CONFIG;
case 8: /*Schmitt Trigger mode */
if (!n1008) {
v7 = -769;
goto WRITE_CONFIG;
}
n8_1 = 512;
if (n1008 == 512) {
n8_1 = 256;
goto WRITE_CONFIG;
}
if (n1008 == 520)
goto WRITE_CONFIG;
return -2147483645;
}
if (n5 != 255)
return -2147483645;
/*Special modes */
if (n1008 != 46) {
if (n1008 == 78) {
n8_1 = 0x2000;
goto WRITE_CONFIG;
}
if (n1008 == 98) {
n8_1 = 2048;
goto WRITE_CONFIG;
}
if (n1008) {
AstPciCfgProgramBar(a1, n1008);
goto WRITE_CONFIG;
}
return -2147483645;
}
n8_1 = 4096; /*GPIO46 = 0x1000 */
WRITE_CONFIG:
/*Apply configuration via PCI CF8 at 0xF8080 (AST SCU config port) */
n5a = (unsigned __int16)(v4 | v5 & AstPciCfgRead(0xF8080u));
AstPciCfgWrite(0xF8080u, n5a);
AstIoWrite16((_WORD *)0xFDEF2770, n5a);
n5b = (unsigned __int16)(n8_1 | v7 & AstPciCfgRead(0xF8082u));
AstPciCfgWrite(0xF8082u, n5b);
AstIoWrite16((_WORD *)0xFDEF2774, n5b);
return 0;
}
/* ---------------------------------------------------------------------------
*I/O Register Read-Modify-Write Sequence
* --------------------------------------------------------------------------- */
/**
*Execute a sequence of 23 I/O register operations from a table.
*
*Each table entry is a 4-byte structure:
*WORD io_port; // Target I/O port
*BYTE and_mask; // AND mask (0 = direct write, non-zero = RMW)
*BYTE or_value; // OR value to apply
*
*If and_mask == 0: direct write of or_value to io_port
*If and_mask != 0: read io_port, AND with and_mask, OR with or_value, write back
*
*The table at 0xFFE526B4 performs SIO LDN mode setup:
* - Unlocks SIO (0xA5 to port 0x2E, twice)
* - Selects various logical devices via LDN setup
* - Programs activation register (0x30) for GPIO groups
* - Locks SIO (0xAA to port 0x2E)
*
* @param base Unused (first parameter, passed through)
* @param count Used as pointer offset to table (adjusted by +3)
* @return Last written value
*/
unsigned __int8 AstIoRmwSequence(int base, int count)
{
unsigned __int8 *v2; /*Pointer into table, starting at count+3 */
int n23; /*23 entries */
unsigned __int8 Result;
unsigned __int8 v5;
unsigned __int8 result;
v2 = (unsigned __int8 *)(count + 3);
n23 = 23;
do {
/*v2[-3..-2] = port (WORD), v2[-1] = and_mask (BYTE), v2[0] = or_value (BYTE) */
if (*(v2 - 1)) {
/*RMW: read current port value, mask, then OR */
v5 = __inbyte(*(_WORD *)(v2 - 3));
Result = *v2 | v5 & *(v2 - 1);
} else {
/*Direct write */
Result = *v2;
}
result = Result;
__outbyte(*(_WORD *)(v2 - 3), Result);
v2 += 4;
--n23;
} while (n23);
return result;
}
/* ---------------------------------------------------------------------------
*PCI CF8/CF9 Access Layer (edk2 BasePciCf8Lib)
*
*Standard PCI Configuration Mechanism #1 via ports 0xCF8/0xCFC.
*CF8 (0xCF8) = PCI Configuration Address
*CFC (0xCFC) = PCI Configuration Data
*
*CF8 format (PCI Enhanced Addressing):
*bit 31 = 1 (enable)
*bits 30:24 = reserved
*bits 23:16 = bus
*bits 15:11 = device
*bits 10:8 = function
*bits 7:0 = register (with bit 0 = byte enable for 16-bit access)
*
*These functions save/restore the CF8 register and manage EFLAGS.IF.
* --------------------------------------------------------------------------- */
/**
*Read 16-bit PCI configuration register via CF8/CF9 protocol.
*From BasePciCf8Lib/PciCf8Lib.c line 613.
*
* @param pci_addr PCI config address (bus/dev/func/reg encoded)
* @return 16-bit register value
*/
__int16 __thiscall AstPciCfgRead(unsigned int pci_addr)
{
int Device;
__int16 eflags;
unsigned int saved_cfg_addr;
__int16 result;
__int16 saved_eflags;
/*Assert proper address format (bit 0 and bits 24+0 clear) */
if ((pci_addr & 0xF0000F01) != 0) {
Device = AstPciCfgLibAssert();
if (Device) {
(*(void ( **)(const char *, int, const char *))(Device + 4))(
"e:\\hs\\MdePkg\\Library\\BasePciCf8Lib\\PciCf8Lib.c",
613,
"((Address) & (~0xffff0ff | (1))) == 0");
}
}
/*Disable interrupts for atomic PCI config cycle */
eflags = __readeflags();
saved_eflags = eflags;
_disable();
/*Save CF8, then write new address */
saved_cfg_addr = AstPciCfgRdAddr(3320); /*0xCF8 */
AstPciCfgWrAddr(3320, pci_addr & 0xFC | (pci_addr >> 4) & 0xFFFF00 | 0x80000000);
/*Read from CF9 (0xCFC + byte offset = 0xCFC or 0xCFE) */
result = AstPciCfgRead16((pci_addr & 2) + 3324); /*0xCFC or 0xCFE */
/*Restore CF8 */
AstPciCfgWrAddr(3320, saved_cfg_addr);
/*Restore interrupt flag */
if ((saved_eflags & 0x200) != 0)
_enable();
else _disable();
return result;
}
/**
*Write 16-bit PCI configuration register via CF8/CF9 protocol.
*From BasePciCf8Lib/PciCf8Lib.c line 652.
*
* @param pci_addr PCI config address
* @param value 16-bit value to write
* @return Written value
*/
__int16 AstPciCfgWrite(unsigned int pci_addr, unsigned __int16 value)
{
int Device;
__int16 eflags;
unsigned int saved_cfg_addr;
__int16 result;
__int16 saved_eflags;
if ((pci_addr & 0xF0000F01) != 0) {
Device = AstPciCfgLibAssert();
if (Device) {
(*(void ( **)(const char *, int, const char *))(Device + 4))(
"e:\\hs\\MdePkg\\Library\\BasePciCf8Lib\\PciCf8Lib.c",
652,
"((Address) & (~0xffff0ff | (1))) == 0");
}
}
eflags = __readeflags();
saved_eflags = eflags;
_disable();
saved_cfg_addr = AstPciCfgRdAddr(3320);
AstPciCfgWrAddr(3320, pci_addr & 0xFC | (pci_addr >> 4) & 0xFFFF00 | 0x80000000);
result = AstPciCfgWrite16((pci_addr & 2) + 3324, value);
AstPciCfgWrAddr(3320, saved_cfg_addr);
if ((saved_eflags & 0x200) != 0)
_enable();
else _disable();
return result;
}
/**
*Read 32-bit DWORD PCI configuration via CF8/CF9.
*From BasePciCf8Lib/PciCf8Lib.c line 1114.
*
* @param pci_addr PCI config address (DWORD-aligned in low bits)
* @return 32-bit register value
*/
int AstPciCf8Read(unsigned int pci_addr)
{
int Device;
__int16 eflags;
unsigned int saved_cfg_addr;
int result;
__int16 saved_eflags;
if ((pci_addr & 0xF0000F03) != 0) {
Device = AstPciCfgLibAssert();
if (Device) {
(*(void ( **)(const char *, int, const char *))(Device + 4))(
"e:\\hs\\MdePkg\\Library\\BasePciCf8Lib\\PciCf8Lib.c",
1114,
"((Address) & (~0xffff0ff | (3))) == 0");
}
}
eflags = __readeflags();
saved_eflags = eflags;
_disable();
saved_cfg_addr = AstPciCfgRdAddr(3320);
AstPciCfgWrAddr(3320, pci_addr & 0xFC | (pci_addr >> 4) & 0xFFFF00 | 0x80000000);
result = AstPciCfgRdAddr(3324); /*0xCFC */
AstPciCfgWrAddr(3320, saved_cfg_addr);
if ((saved_eflags & 0x200) != 0)
_enable();
else _disable();
return result;
}
/**
*Write 32-bit DWORD PCI configuration via CF8/CF9.
*From BasePciCf8Lib/PciCf8Lib.c line 1153.
*
* @param pci_addr PCI config address (DWORD-aligned in low bits)
* @param value 32-bit value to write
* @return Written address value
*/
int AstPciCf8Write(unsigned int pci_addr, int value)
{
int Device;
__int16 eflags;
unsigned int saved_cfg_addr;
int result;
__int16 saved_eflags;
if ((pci_addr & 0xF0000F03) != 0) {
Device = AstPciCfgLibAssert();
if (Device) {
(*(void ( **)(const char *, int, const char *))(Device + 4))(
"e:\\hs\\MdePkg\\Library\\BasePciCf8Lib\\PciCf8Lib.c",
1153,
"((Address) & (~0xffff0ff | (3))) == 0");
}
}
eflags = __readeflags();
saved_eflags = eflags;
_disable();
saved_cfg_addr = AstPciCfgRdAddr(3320);
AstPciCfgWrAddr(3320, pci_addr & 0xFC | (pci_addr >> 4) & 0xFFFF00 | 0x80000000);
result = AstPciCfgWrAddr(3324, value); /*0xCFC */
AstPciCfgWrAddr(3320, saved_cfg_addr);
if ((saved_eflags & 0x200) != 0)
_enable();
else _disable();
return result;
}
/* ---------------------------------------------------------------------------
*16-bit Memory-Mapped I/O Write (IoLib)
* --------------------------------------------------------------------------- */
/**
*Write 16-bit value to memory-mapped I/O address with alignment check.
*From BaseIoLibIntrinsic/IoLib.c line 183.
*
* @param addr I/O address (must be 2-byte aligned)
* @param value 16-bit value to write
* @return Written value
*/
__int16 AstIoWrite16(_WORD *addr, __int16 value)
{
int Device;
if (((unsigned __int8)addr & 1) != 0) {
Device = AstPciCfgLibAssert();
if (Device) {
(*(void ( **)(const char *, int, const char *))(Device + 4))(
"e:\\hs\\MdePkg\\Library\\BaseIoLibIntrinsic\\IoLib.c",
183,
"(Address & 1) == 0");
}
}
*addr = value;
return value;
}
/* ---------------------------------------------------------------------------
*PEI Services / Interrupt Descriptor Table Access
* --------------------------------------------------------------------------- */
/**
*Get PEI Services pointer from IDT-based location.
*
*The PEI Services table pointer is stored at IDT base - 4 in memory.
*On IA32, the IDTR (interrupt descriptor table register) contains
*the base address of the IDT; the PEI services pointer is stored
*in the 4 bytes immediately preceding the IDT base.
*
*From PeiServicesTablePointerLibIdt/PeiServicesTablePointer.c.
*
* @return Pointer to EFI_PEI_SERVICES, or asserts if NULL
*/
int AstPeiServicesGetPtr()
{
int pei_services;
_BYTE idtr[8]; /*IDTR storage: 2 bytes limit + 4 bytes base */
AstReadIdtr(idtr); /*SIDT instruction */
pei_services = *(_DWORD *)(*(_DWORD *)&idtr[2] - 4); /*IDT base - 4 = PeiServices */
if (!pei_services) {
AstDebugAssert(
(int)"e:\\hs\\MdePkg\\Library\\PeiServicesTablePointerLibIdt\\PeiServicesTablePointer.c",
48,
(int)"PeiServices != ((void *) 0)");
}
return pei_services;
}
/**
*Read Interrupt Descriptor Table Register.
*
*On IA32, the SIDT instruction stores 6 bytes:
*bytes 0-1: IDT limit (size - 1)
*bytes 2-5: IDT base address (linear address)
*
*From BaseLib/X86ReadIdtr.c.
*
* @param this Pointer to 8-byte buffer for IDT register
* @return Pointer to buffer
*/
void *__thiscall AstReadIdtr(void *this)
{
if (!this) {
AstDebugAssert(
(int)"e:\\hs\\MdePkg\\Library\\BaseLib\\X86ReadIdtr.c",
37,
(int)"Idtr != ((void *) 0)");
}
__sidt(this);
return this;
}