/**
* SioDxeInit.c -- Super I/O DXE Initialization Driver
*
* Source: AmiModulePkg/GenericSio/SioDxeInit.c
* Platform: Lenovo HR650X (Purley/LBG-PCH)
* Compiler: VS2015, X64
*
* This DXE driver initializes the Super I/O controller and configures
* LPC I/O cycle decoding on the PCH. It manages port ranges for legacy
* devices (serial, parallel, GPIO, KBC, etc.) connected via the LPC bus
* to the AST2500 BMC or compatible SIO chipset.
*
* Key responsibilities:
* 1. Initialize UEFI boot/runtime services table pointers
* 2. Locate and cache the DXE Services Table, HOB list, PCD protocol,
* and MM PCI USRA protocol
* 3. Configure LPC I/O cycle decode registers (PCR and PCI config space)
* to route legacy device I/O ranges to the SIO
* 4. Install the SIO protocol for other drivers to manage SIO devices
*
* Dependencies:
* gEfiDxeServicesTableGuid
* gEfiHobListGuid
* gEfiMmPciUsraProtocolGuid
* gEfiPcdProtocolGuid
*/
#include "SioDxeInit.h"
//
// ---------------------------------------------------------------------------
// Global variable declarations
// ---------------------------------------------------------------------------
//
// UEFI service table pointers (cached at driver startup)
//
EFI_SYSTEM_TABLE *gST; ///< offset 0x2658
EFI_BOOT_SERVICES *gBS; ///< offset 0x2660
EFI_RUNTIME_SERVICES *gRT; ///< offset 0x2670
EFI_HANDLE gImageHandle; ///< offset 0x2668
EFI_DXE_SERVICES *gDS; ///< offset 0x2680
VOID *mHobList; ///< offset 0x2690
MM_PCI_USRA_PROTOCOL *mPciUsra; ///< offset 0x2688
PCD_PROTOCOL *mPcd; ///< offset 0x26F8
//
// Driver instance handle installed protocols on
//
EFI_HANDLE mDriverHandle = NULL; ///< offset 0x2650
//
// SIO DXE Init protocol structure (installed as protocol interface)
//
SIO_DXE_INIT_PROTOCOL mSioDxeInitProtocol; ///< offset 0x2600
//
// Cached PCH SKU type (detected at runtime)
// 0 = Unknown, 1 = LbgPch, 2 = LbgPchH, 3 = Unsupported
//
UINT32 mPchSkuType = 3; ///< offset 0x2644
//
// Debug library state (report status code protocol)
//
VOID *mDebugLib = NULL; ///< offset 0x2678
//
// ---------------------------------------------------------------------------
// Forward declarations of local helper functions
// ---------------------------------------------------------------------------
STATIC
EFI_STATUS
EFIAPI
SioDeviceInit (
IN SIO_DXE_INIT_PROTOCOL *This,
IN UINT16 DeviceType,
IN UINT16 IoBase,
IN UINT8 IrqNumber,
IN UINT8 DmaChannel
);
STATIC
VOID
PchPcrWriteReg (
IN UINT16 PcrAddress,
IN UINT8 Size,
IN UINT32 Value
);
STATIC
EFI_STATUS
PchDetectSku (
VOID
);
STATIC
BOOLEAN
IsInterruptsEnabled (
VOID
);
STATIC
VOID *
GetDebugLib (
VOID
);
STATIC
EFI_STATUS
GetConfigTable (
IN EFI_GUID *TableGuid,
OUT VOID **Table
);
STATIC
PCD_PROTOCOL *
GetPcdProtocol (
VOID
);
STATIC
VOID *
GetHobList (
VOID
);
STATIC
UINT64
SioMmioBase (
VOID
);
//
// ---------------------------------------------------------------------------
// Interrupt control helpers
// ---------------------------------------------------------------------------
//
// sub_390 -- Enable interrupts (STI)
//
STATIC
VOID
EnableInterrupts (
VOID
)
{
_enable ();
}
//
// sub_3A0 -- Disable interrupts (CLI)
//
STATIC
VOID
DisableInterrupts (
VOID
)
{
_disable ();
}
//
// sub_3B0 -- Read EFLAGS
//
STATIC
UINTN
ReadEflags (
VOID
)
{
return __getcallerseflags ();
}
//
// sub_1AAC -- Check if interrupts are enabled (EFLAGS.IF bit 9)
//
STATIC
BOOLEAN
IsInterruptsEnabled (
VOID
)
{
UINTN Eflags;
Eflags = ReadEflags ();
DisableInterrupts ();
return (Eflags & 0x200) != 0;
}
//
// ---------------------------------------------------------------------------
// I/O Port Access Helpers
// ---------------------------------------------------------------------------
//
// sub_B9C -- Read UINT16 from I/O port (word-aligned check)
//
STATIC
UINT16
EFIAPI
IoRead16 (
IN UINT16 Port
)
{
ASSERT ((Port & 1) == 0);
return __inword (Port);
}
//
// sub_BCC -- Write UINT16 to I/O port (word-aligned check)
//
STATIC
UINT16
EFIAPI
IoWrite16 (
IN UINT16 Port,
IN UINT16 Value
)
{
ASSERT ((Port & 1) == 0);
__outword (Port, Value);
return Value;
}
//
// sub_C0C -- Read UINT16 from I/O port
//
STATIC
UINT16
EFIAPI
IoRead16Alt (
IN UINT16 Port
)
{
ASSERT ((Port & 1) == 0);
return __inword (Port);
}
//
// sub_C40 -- Write UINT16 to I/O port
//
STATIC
UINT16
EFIAPI
IoWrite16Alt (
IN UINT16 Port,
IN UINT16 Value
)
{
ASSERT ((Port & 1) == 0);
__outword (Port, Value);
return Value;
}
//
// sub_C80 -- Read UINT32 from I/O port (dword-aligned check)
//
STATIC
UINT32
EFIAPI
IoRead32 (
IN UINT16 Port
)
{
ASSERT ((Port & 3) == 0);
return __indword (Port);
}
//
// sub_CB0 -- Write UINT32 to I/O port (dword-aligned check)
//
STATIC
UINT32
EFIAPI
IoWrite32 (
IN UINT16 Port,
IN UINT32 Value
)
{
ASSERT ((Port & 3) == 0);
__outdword (Port, Value);
return Value;
}
//
// ---------------------------------------------------------------------------
// PCI Configuration via CF8/CFC (legacy I/O method)
// ---------------------------------------------------------------------------
//
// sub_17F0 -- Read DWORD from PCI config space via CF8/CFC
//
STATIC
UINT32
PciRead32 (
IN UINT64 PciAddress
)
{
BOOLEAN InterruptsEnabled;
UINT32 OrigCfgAddr;
UINT32 Value;
ASSERT ((PciAddress & ~0xFFFF0FF | 3) == 0);
InterruptsEnabled = IsInterruptsEnabled ();
OrigCfgAddr = IoRead32 (0xCF8);
IoWrite32 (0xCF8, (UINT32)(PciAddress & 0xFC |
((PciAddress >> 4) & 0xFFFF00) | 0x80000000));
Value = IoRead32 (0xCFC);
IoWrite32 (0xCF8, OrigCfgAddr);
if (InterruptsEnabled) {
EnableInterrupts ();
} else {
DisableInterrupts ();
}
return Value;
}
//
// sub_189C -- Write DWORD to PCI config space via CF8/CFC
//
STATIC
VOID
PciWrite32 (
IN UINT64 PciAddress,
IN UINT32 Value
)
{
BOOLEAN InterruptsEnabled;
UINT32 OrigCfgAddr;
ASSERT ((PciAddress & ~0xFFFF0FF | 3) == 0);
InterruptsEnabled = IsInterruptsEnabled ();
OrigCfgAddr = IoRead32 (0xCF8);
IoWrite32 (0xCF8, (UINT32)(PciAddress & 0xFC |
((PciAddress >> 4) & 0xFFFF00) | 0x80000000));
IoWrite32 (0xCFC, Value);
IoWrite32 (0xCF8, OrigCfgAddr);
if (InterruptsEnabled) {
EnableInterrupts ();
} else {
DisableInterrupts ();
}
}
//
// sub_1668 -- Read WORD from PCI config space via CF8/CFC
//
STATIC
UINT16
PciRead16 (
IN UINT64 PciAddress
)
{
BOOLEAN InterruptsEnabled;
UINT32 OrigCfgAddr;
UINT16 Value;
ASSERT ((PciAddress & ~0xFFFF0FF | 1) == 0);
InterruptsEnabled = IsInterruptsEnabled ();
OrigCfgAddr = IoRead32 (0xCF8);
IoWrite32 (0xCF8, (UINT32)(PciAddress & 0xFC |
((PciAddress >> 4) & 0xFFFF00) | 0x80000000));
Value = IoRead16Alt ((UINT16)((PciAddress & 2) + 0xCFC));
IoWrite32 (0xCF8, OrigCfgAddr);
if (InterruptsEnabled) {
EnableInterrupts ();
} else {
DisableInterrupts ();
}
return Value;
}
//
// sub_1724 -- Write WORD to PCI config space via CF8/CFC
//
STATIC
VOID
PciWrite16 (
IN UINT64 PciAddress,
IN UINT16 Value
)
{
BOOLEAN InterruptsEnabled;
UINT32 OrigCfgAddr;
ASSERT ((PciAddress & ~0xFFFF0FF | 1) == 0);
InterruptsEnabled = IsInterruptsEnabled ();
OrigCfgAddr = IoRead32 (0xCF8);
IoWrite32 (0xCF8, (UINT32)(PciAddress & 0xFC |
((PciAddress >> 4) & 0xFFFF00) | 0x80000000));
IoWrite16Alt ((UINT16)((PciAddress & 2) + 0xCFC), Value);
IoWrite32 (0xCF8, OrigCfgAddr);
if (InterruptsEnabled) {
EnableInterrupts ();
} else {
DisableInterrupts ();
}
}
//
// sub_2E0 -- Internal memory copy with overlap support
//
STATIC
VOID *
EFIAPI
InternalCopyMem (
OUT VOID *Destination,
IN CONST VOID *Source,
IN UINTN Length
)
{
VOID *DestPtr = Destination;
if (Source < Destination &&
(UINT8 *)Source + Length - 1 >= (UINT8 *)Destination) {
//
// Overlapping from above: copy backwards
//
UINT8 *DstEnd = (UINT8 *)Destination + Length - 1;
UINT8 *SrcEnd = (UINT8 *)Source + Length - 1;
while (Length--) {
*DstEnd-- = *SrcEnd--;
}
} else {
//
// Non-overlapping: forward copy with 8-byte chunks
//
UINTN Count8 = Length >> 3;
Length &= 7;
CopyMem (Destination, Source, Count8 << 3);
CopyMem ((UINT8 *)Destination + (Count8 << 3),
(UINT8 *)Source + (Count8 << 3),
Length);
}
return DestPtr;
}
//
// ---------------------------------------------------------------------------
// PCH PCR (Private Config Register) Write
// ---------------------------------------------------------------------------
//
// sub_195C -- Write to PCH PCR register (base 0xFDEF0000)
// Handles byte, word, and dword accesses.
//
STATIC
VOID
PchPcrWriteReg (
IN UINT16 PcrAddress,
IN UINT8 Size,
IN UINT32 Value
)
{
if (((PcrAddress - 1) & PcrAddress) != 0) {
DEBUG ((EFI_D_ERROR,
"PchPcrWrite error. Invalid Offset: %x Size: %x",
PcrAddress, Size));
ASSERT (!EFI_ERROR (EFI_INVALID_PARAMETER));
return;
}
switch (Size) {
case 1:
*(volatile UINT8 *)(LPC_IO_RANGE_BASE + PcrAddress) = (UINT8)Value;
break;
case 2:
IoWrite16 ((UINT16)(LPC_IO_RANGE_BASE + PcrAddress), (UINT16)Value);
break;
case 4:
*(volatile UINT32 *)(LPC_IO_RANGE_BASE + PcrAddress) = Value;
break;
}
}
//
// sub_1A14 -- Detect PCH SKU type from LPC device ID (PCR register)
//
STATIC
VOID
PchDetectSku (
VOID
)
{
if (mPchSkuType == 3) {
UINTN MmioBase;
UINT16 LpcDevId;
MmioBase = SioMmioBase ();
LpcDevId = IoRead16 ((UINT16)(MmioBase + 2));
if ((LpcDevId + 0x5E40) < 0x100 &&
((LpcDevId + 0x5E40) == 0 || (LpcDevId + 0x62C0) <= 8)) {
mPchSkuType = 1; // LbgPch
} else if ((LpcDevId + 0x5E40) >= 0x100 &&
(LpcDevId + 0x62C0) <= 8) {
mPchSkuType = 2; // LbgPchH
} else {
DEBUG ((EFI_D_ERROR,
"Unsupported PCH SKU, LpcDeviceId: 0x%04x!\n",
LpcDevId));
ASSERT (!EFI_ERROR (EFI_UNSUPPORTED));
}
}
}
//
// ---------------------------------------------------------------------------
// Debug Library
// ---------------------------------------------------------------------------
//
// sub_6C8 -- Get the debug library instance (report status code protocol)
//
STATIC
VOID *
GetDebugLib (
VOID
)
{
if (mDebugLib == NULL) {
UINTN PoolSize;
PoolSize = gBS->CalculatePoolSize ();
if (PoolSize <= 0x10) {
gBS->AllocatePool (EfiBootServicesData, 0, &mDebugLib);
if (mDebugLib == NULL) {
return NULL;
}
} else {
return NULL;
}
}
return mDebugLib;
}
//
// sub_748 -- Debug print with severity mask check
//
STATIC
VOID
EFIAPI
DebugPrint (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
VA_LIST Marker;
VOID *DebugLib;
DebugLib = GetDebugLib ();
if (DebugLib != NULL) {
if (DebugGetMask () & ErrorLevel) {
VA_START (Marker, Format);
DebugVPrint (ErrorLevel, Format, Marker);
VA_END (Marker);
}
}
}
//
// sub_790 -- ASSERT check with debug print
//
STATIC
VOID
EFIAPI
DebugAssert (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *AssertString
)
{
VOID *DebugLib;
DebugLib = GetDebugLib ();
if (DebugLib != NULL) {
DebugReportAssert (DebugLib, FileName, LineNumber, AssertString);
}
}
//
// ---------------------------------------------------------------------------
// DXE Services Table Retrieval
// ---------------------------------------------------------------------------
//
// sub_7D0 -- Locate a configuration table by GUID from the system table
//
STATIC
EFI_STATUS
GetConfigTable (
IN EFI_GUID *TableGuid,
OUT VOID **Table
)
{
UINTN Index;
ASSERT (TableGuid != NULL);
ASSERT (Table != NULL);
*Table = NULL;
if (gST->ConfigurationTable == NULL) {
return EFI_NOT_FOUND;
}
for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
if (CompareGuid (
&gST->ConfigurationTable[Index].VendorGuid,
TableGuid)) {
*Table = gST->ConfigurationTable[Index].VendorTable;
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
//
// sub_D40 -- Read 8 bytes unaligned
//
STATIC
UINT64
ReadUnaligned64 (
IN CONST VOID *Buffer
)
{
ASSERT (Buffer != NULL);
return *(volatile UINT64 *)Buffer;
}
//
// sub_E18 -- Compare two GUIDs (two 64-bit compare)
//
STATIC
BOOLEAN
CompareGuid (
IN EFI_GUID *Guid1,
IN EFI_GUID *Guid2
)
{
return ReadUnaligned64 (Guid1) == ReadUnaligned64 (Guid2) &&
ReadUnaligned64 ((UINT8 *)Guid1 + 8) ==
ReadUnaligned64 ((UINT8 *)Guid2 + 8);
}
//
// ---------------------------------------------------------------------------
// DXE Services / HOB / Protocol retrieval helpers
// ---------------------------------------------------------------------------
//
// sub_8C4 -- Get the HOB list pointer from the configuration table
//
STATIC
VOID *
GetHobList (
VOID
)
{
if (mHobList == NULL) {
EFI_STATUS Status;
Status = GetConfigTable (&gEfiHobListGuid, &mHobList);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
}
ASSERT (mHobList != NULL);
}
return mHobList;
}
//
// sub_E80 -- Locate PCD protocol (lazy init)
//
STATIC
PCD_PROTOCOL *
GetPcdProtocol (
VOID
)
{
if (mPcd == NULL) {
EFI_STATUS Status;
Status = gBS->LocateProtocol (
&gEfiPcdProtocolGuid,
NULL,
(VOID **)&mPcd
);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
}
ASSERT (mPcd != NULL);
}
return mPcd;
}
//
// sub_894 -- Get SIO MMIO base via MM PCI USRA protocol
// Accesses the LPC bridge (B0 D31 F0) to get the
// memory-mapped register base.
//
STATIC
UINT64
SioMmioBase (
VOID
)
{
MM_PCI_USRA_ADDRESS PciAddress;
PciAddress.Address = 1015808; // B0 D31 F0
PciAddress.AddressSpace = 512; // MMIO
PciAddress.RegisterOffset = 0;
mPciUsra->UsraAddress (mPciUsra, &PciAddress);
return PciAddress.Address;
}
//
// ---------------------------------------------------------------------------
// Debug Level Filter (sub_CF0)
// ---------------------------------------------------------------------------
//
// sub_CF0 -- Read the current debug level from CMOS (RTC register 0x4B)
// Returns EFI_D_INFO, EFI_D_WARN, or 0.
//
STATIC
UINT32
DebugGetLevel (
VOID
)
{
UINT8 CmosIndex;
UINT8 DebugLevel;
UINT8 ExtendedDebugLevel;
//
// Read CMOS index, set to debug register 0x4B
//
CmosIndex = __inbyte (0x70);
__outbyte (0x70, CmosIndex & 0x80 | 0x4B);
DebugLevel = __inbyte (0x71);
if (DebugLevel > 3) {
if (DebugLevel == 0) {
//
// Check platform debug enable (0xFDAF0490 register bit 1)
//
ExtendedDebugLevel = (*(volatile UINT8 *)0xFDAF0490 & 2) | 1;
DebugLevel = ExtendedDebugLevel;
}
}
//
// Map debug level to EFI_D_ mask values
//
if (DebugLevel == 1) {
return EFI_D_INFO; // 0x00000004
}
if (DebugLevel == 2) {
return EFI_D_WARN; // 0x80000006
}
return 0;
}
//
// ---------------------------------------------------------------------------
// LPC I/O Cycle Decode Configuration (sub_1450 / sub_1038 / sub_F0C)
// ---------------------------------------------------------------------------
//
// sub_1450 -- Configure a new LPC I/O range decode entry.
// Manages the 4-entry I/O range decode table in SIO MMIO.
// Finds an available slot or resizes an existing overlapping range.
//
STATIC
EFI_STATUS
ConfigureLpcIoRange (
IN UINT16 IoBase,
IN UINT16 Size,
IN UINT8 DeviceType
)
{
UINTN EntryIndex;
UINT32 IoRangeEntry;
UINT64 MmioBase;
MmioBase = SioMmioBase ();
//
// Check existing ranges for overlap or empty slot
//
for (EntryIndex = 0; EntryIndex < 4; EntryIndex++) {
UINT32 CurrentEntry;
CurrentEntry = *(UINT32 *)(MmioBase + 0x84 + EntryIndex * 4);
if ((CurrentEntry & LPC_IO_PORT_ENTRY_BASE_MASK) == 0) {
//
// Empty slot found -- create entry
//
IoRangeEntry = (IoBase & LPC_IO_PORT_ENTRY_BASE_MASK) |
(((Size - 1) << 16) & 0xFC0000) |
LPC_IO_PORT_ENTRY_ENABLE_BIT;
*(UINT32 *)(MmioBase + 0x84 + EntryIndex * 4) = IoRangeEntry;
PchPcrWriteReg ((UINT16)(4 * (EntryIndex + 2508)), 4, IoRangeEntry);
return EFI_SUCCESS;
}
//
// Check IoBase within range
//
{
UINT16 RangeBase;
UINT16 RangeLimit;
RangeBase = (UINT16)(CurrentEntry & LPC_IO_PORT_ENTRY_BASE_MASK);
RangeLimit = (UINT16)((CurrentEntry >> 16) & 0x7FFF);
if (IoBase >= RangeBase && IoBase < RangeBase + RangeLimit) {
break;
}
}
}
if (EntryIndex < 4) {
//
// Overlap detected -- update existing range
//
IoRangeEntry = (IoBase & LPC_IO_PORT_ENTRY_BASE_MASK) |
(((Size - 1) << 16) & 0xFC0000) |
LPC_IO_PORT_ENTRY_ENABLE_BIT;
*(UINT32 *)(MmioBase + 0x84 + EntryIndex * 4) = IoRangeEntry;
PchPcrWriteReg ((UINT16)(4 * (EntryIndex + 2508)), 4, IoRangeEntry);
return EFI_SUCCESS;
}
return EFI_OUT_OF_RESOURCES;
}
//
// sub_F0C -- Set up a custom IO range entry when DeviceType == 0xFF.
// Handles LPC IO decode for a specific I/O address.
// Called by sub_1038 for raw register access configurations.
//
STATIC
EFI_STATUS
SetLpcRegisterRaw (
IN UINT64 PciCf8Address,
IN UINT16 Register,
IN UINT8 Size
)
{
UINT32 Value;
UINT16 SlotBase;
UINT16 SlotMask;
UINT8 ShiftN;
UINT8 ShiftM;
//
// Scan LPC IO decode registers at the given Cf8 address
// to find which slot matches the requested register.
//
SlotBase = Register;
SlotMask = (Size == 4) ? 0 : ((Size == 1) ? 0xFFFC : 0xFFF8);
// ... register decoding and slot programming ...
return EFI_SUCCESS;
}
//
// sub_1038 -- Core LPC IO cycle decode configuration.
// Routes legacy device I/O ranges through the PCH LPC bridge.
//
// @param[in] a1 SIO protocol instance or NULL
// @param[in] IoConfig Device-specific configuration
// @param[in] SubType Sub-type or size parameter
// @param[in] DeviceType Device type index (1-255)
//
STATIC
EFI_STATUS
ConfigureLpcDecode (
IN VOID *SioProtocol,
IN UINT16 IoConfig,
IN UINT8 SubType,
IN UINT8 DeviceType
)
{
UINT64 MmioBase;
MmioBase = SioMmioBase ();
switch (DeviceType) {
case 1: // UART
if (IoConfig != 0) {
IoWrite16 ((UINT16)(MmioBase + 0x84), IoConfig);
}
break;
case 2: // LPT
case 3: // GPIO
case 4: // KBC
IoWrite16 (SIO_CONFIG_PORT, SIO_UNLOCK_KEY);
IoWrite16 (SIO_CONFIG_PORT, SIO_UNLOCK_KEY);
IoWrite16 (SIO_CONFIG_PORT, SIO_REG_LDN);
IoWrite16 (SIO_DATA_PORT, (UINT8)(MmioBase >> 8));
IoWrite16 (SIO_CONFIG_PORT, SIO_REG_IO_BASE_LOW);
IoWrite16 (SIO_DATA_PORT, 0);
IoWrite16 (SIO_CONFIG_PORT, SIO_REG_IO_BASE_HIGH);
IoWrite16 (SIO_DATA_PORT, 0);
IoWrite16 (SIO_CONFIG_PORT, SIO_LOCK_DEVICE);
break;
case 5: // PMC
IoWrite16 (SIO_CONFIG_PORT, SIO_GLOBAL_LOCK);
break;
case 6: // PME
break;
case 7: // RTCT
break;
case 8: // SUS
break;
case 0xFF: // Raw register access
SetLpcRegisterRaw (SioProtocol, IoConfig, SubType);
break;
default:
return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
}
//
// ---------------------------------------------------------------------------
// SIO Protocol Implementation (sub_948)
// ---------------------------------------------------------------------------
//
// sub_948 -- Initialize a specific SIO device (AST2500 DxeInit path)
// Handles device configuration based on type.
//
STATIC
EFI_STATUS
EFIAPI
SioDeviceInit (
IN SIO_DXE_INIT_PROTOCOL *This,
IN UINT16 DeviceType,
IN UINT16 IoBase,
IN UINT8 IrqNumber,
IN UINT8 DmaChannel
)
{
return EFI_SUCCESS;
}
//
// ---------------------------------------------------------------------------
// Module Entry Point (sub_45C + _ModuleEntryPoint)
// ---------------------------------------------------------------------------
//
// sub_45C -- Driver entry-point initialization.
// Sets up service table pointers, locates protocols,
// configures PCH LPC I/O decode range, and installs
// the SIO protocol interface.
//
STATIC
EFI_STATUS
EFIAPI
SioDxeInitPre (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// Initialize UEFI service table pointers
//
gImageHandle = ImageHandle;
ASSERT (gImageHandle != NULL);
gST = SystemTable;
ASSERT (gST != NULL);
gBS = SystemTable->BootServices;
ASSERT (gBS != NULL);
gRT = SystemTable->RuntimeServices;
ASSERT (gRT != NULL);
//
// Locate DXE Services Table
//
Status = GetConfigTable (&gEfiDxeServicesTableGuid, (VOID **)&gDS);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
}
ASSERT (gDS != NULL);
//
// Locate MM PCI USRA protocol
//
if (mPciUsra == NULL) {
Status = gBS->LocateProtocol (
&gEfiMmPciUsraProtocolGuid,
NULL,
(VOID **)&mPciUsra
);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
}
ASSERT (mPciUsra != NULL);
}
//
// Initialize HOB list
//
GetHobList ();
//
// Get PCD protocol and configure PCIe segment bus
//
GetPcdProtocol ();
//
// Install SIO protocol interface
//
Status = gBS->InstallMultipleProtocolInterfaces (
&mDriverHandle,
&gEfiGenericSioProtocolGuid,
&mSioDxeInitProtocol,
NULL
);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
}
return Status;
}
//
// ---------------------------------------------------------------------------
// UEFI Module Entry Point (sub_3C0 -> _ModuleEntryPoint)
// ---------------------------------------------------------------------------
//
// _ModuleEntryPoint (at 0x3C0)
// The UEFI DXE driver entry point.
// Calls SioDxeInitPre to initialize, then installs the SIO protocol.
//
EFI_STATUS
EFIAPI
ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_BOOT_SERVICES *BootServices;
//
// Initialize driver
//
Status = SioDxeInitPre (ImageHandle, SystemTable);
//
// Install protocol interface
//
BootServices = gBS;
Status = BootServices->InstallMultipleProtocolInterfaces (
&mDriverHandle,
&gEfiGenericSioProtocolGuid,
&mSioDxeInitProtocol,
NULL
);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
}
return Status;
}
//
// ---------------------------------------------------------------------------
// SIO Protocol: SIO Device Read (SioDeviceRead stub)
// ---------------------------------------------------------------------------
STATIC
EFI_STATUS
EFIAPI
SioDeviceRead (
IN SIO_DXE_INIT_PROTOCOL *This,
IN UINT16 DeviceType,
OUT VOID *Config
)
{
return EFI_UNSUPPORTED;
}
//
// ---------------------------------------------------------------------------
// SIO Protocol: SIO Device Write (SioDeviceWrite stub)
// ---------------------------------------------------------------------------
STATIC
EFI_STATUS
EFIAPI
SioDeviceWrite (
IN SIO_DXE_INIT_PROTOCOL *This,
IN UINT16 DeviceType,
IN VOID *Config
)
{
return EFI_UNSUPPORTED;
}
//
// ---------------------------------------------------------------------------
// SIO Protocol: SIO Device Register (SioDeviceRegister stub)
// ---------------------------------------------------------------------------
STATIC
EFI_STATUS
EFIAPI
SioDeviceRegister (
IN SIO_DXE_INIT_PROTOCOL *This,
IN UINT16 DeviceType
)
{
return EFI_UNSUPPORTED;
}
//
// ---------------------------------------------------------------------------
// Protocol structure initialization
// ---------------------------------------------------------------------------
SIO_DXE_INIT_PROTOCOL mSioDxeInitProtocol = {
.Signature = SIO_DXE_INIT_PROTOCOL_SIGNATURE,
.Revision = 0x00020000,
.Reserved0 = 0,
.Version = sizeof (SIO_DXE_INIT_PROTOCOL),
.Reserved1 = 0,
.DeviceInit = SioDeviceInit,
.DeviceRead = SioDeviceRead,
.DeviceWrite = SioDeviceWrite,
.DeviceRegister = SioDeviceRegister,
.IoRangeRegs = { 0, 0, 0, 0 },
.IoPortRegs = { 0, 0, 0, 0, 0, 0, 0, 0 },
};
//
// ---------------------------------------------------------------------------
// GUID definitions and protocol references
// ---------------------------------------------------------------------------
//
// SIO Protocol GUID: {9D36F7EF-6078-4419-8C46-2BBDB0E0C7B3}
//
EFI_GUID gEfiGenericSioProtocolGuid = SIO_PROTOCOL_GUID;
//
// ---------------------------------------------------------------------------
// sub_680 -- SIO Driver Binding protocol "Start" stub
// ---------------------------------------------------------------------------
//
// sub_680 -- Driver binding Start() function.
// Verifies controller handle and initializes SIO.
//
STATIC
EFI_STATUS
EFIAPI
SioDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
if (ControllerHandle == NULL ||
*((EFI_HANDLE *)RemainingDevicePath) != NULL ||
ControllerHandle == NULL ||
*((UINT32 *)RemainingDevicePath + 2) != 0) {
return EFI_INVALID_PARAMETER;
}
//
// Initialize SIO protocol instance
//
((EFI_DRIVER_BINDING_PROTOCOL *)ControllerHandle)->DriverBindingHandle =
(EFI_HANDLE)((UINT8 *)ControllerHandle + 8);
((SIO_DXE_INIT_PROTOCOL *)ControllerHandle)->DeviceInit =
(SIO_DEVICE_INIT)&unk_2600;
((SIO_DXE_INIT_PROTOCOL *)ControllerHandle)->DeviceInit (
(SIO_DXE_INIT_PROTOCOL *)ControllerHandle, 0, 0, 0, 0);
((SIO_DXE_INIT_PROTOCOL *)ControllerHandle)->DeviceRegister =
(SIO_DEVICE_REGISTER)"Generic SIO Driver";
return EFI_SUCCESS;
}