/** @file
*AmiBoardInfo2.c - AMI Board Info DXE Driver
*
*UEFI DXE driver that collects platform board configuration data
* (DSDT ACPI tables, SIO data, IOAPIC data) from HOBs created during
*PEI phase and installs them via a UEFI protocol for consumption
*by other DXE drivers.
*
*Source: e:\hs\AmiModulePkg\BoardInfo\AmiBoardInfo2.c
*Module: AmiBoardInfo2.efi
*Arch: x86_64
*Size: 0x18a0 (6304 bytes)
*MD5: bc8960b98848df805337c991a63a7ac3
*SHA256: 2e0d2b3091d5abc6bd7a02b495380cf534aec2e56326ad9e267dbfef864375f5
*/
/*=============================================================================
*HEADERS
*============================================================================*/
#include <Uefi.h>
#include <Library/DebugLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/HobLib.h>
#include <Protocol/BoardInfo.h> /*AMI-specific board info protocol */
#include "AmiBoardInfo2.h"
/*=============================================================================
*GLOBAL VARIABLES
*============================================================================*/
//
// Standard UEFI globals (set by _ModuleEntryPoint)
//
EFI_HANDLE gImageHandle = NULL;
EFI_SYSTEM_TABLE *gSystemTable = NULL;
EFI_BOOT_SERVICES *gBootServices = NULL;
EFI_RUNTIME_SERVICES *gRuntimeServices = NULL;
//
// Persistent copies for AmiBoardInfo2Entry
//
EFI_SYSTEM_TABLE *gSavedSystemTable = NULL; /*0x1760 */
EFI_BOOT_SERVICES *gSavedBootServices = NULL; /*0x1740 */
EFI_RUNTIME_SERVICES *gSavedRuntimeServices = NULL; /*0x1748 */
//
// Debug library globals
//
VOID *gDebugOutputProtocol = NULL; /*0x1720 (serial debug) */
VOID *gDebugOutputProtocol2 = NULL; /*0x1758 (console debug) */
UINT8 gDebugInitialized = 0; /*0x1730 - 0=serial, 1=console */
UINT8 gDebugMode = 0; /*0x1731 */
//
// HOB list pointer (lazily initialized by GetHobList)
//
VOID *gHobList = NULL; /*0x1728 */
/*=============================================================================
*DEBUG OUTPUT FUNCTIONS (linked from DebugLib)
*============================================================================*/
/**
*Get the debug output protocol pointer.
*
*Lazily locates the debug output protocol (serial I/O protocol)
*via gBS->LocateProtocol(&gEfiSerialIoProtocolGuid, ...).
*
* @return Pointer to the debug output protocol, or NULL if not found.
*/
VOID *DebugLibGetDebugOutput (
VOID
)
{
UINTN Pages;
VOID *Protocol;
Protocol = gDebugOutputProtocol;
if (Protocol != NULL) {
return Protocol;
}
//
// Allocate one page for the serial I/O interface
//
Pages = gBootServices->AllocatePages (AllocateAnyPages, EfiBootServicesData, 1);
gBootServices->FreePages (Pages, 1);
if (Pages > 0x10) {
return NULL;
}
//
// Locate the Serial I/O protocol
//
gBootServices->LocateProtocol (&gEfiSerialIoProtocolGuid, NULL, &gDebugOutputProtocol);
Protocol = gDebugOutputProtocol;
if (Protocol == NULL) {
Protocol = NULL;
}
gDebugOutputProtocol = Protocol;
return Protocol;
}
/**
*Get the current platform debug print level.
*
*Reads CMOS register 0x4B (diagnostic status register DSR) to
*determine the enabled debug mask. Also checks a known memory-mapped
*register at 0xFDAF0490 for additional platform-specific debug flags.
*
* @return Debug level bitmask:
*0x80000004 (EFI_D_INFO | EFI_D_ERROR) if debug enabled at level 3+
*0x80000006 (EFI_D_WARN | EFI_D_INFO | EFI_D_ERROR) if debug level 1
*0 if debug level 0 (none)
*/
UINTN DebugGetPlatformDebugLevel (
VOID
)
{
UINT8 CmosDebugLevel;
UINT8 DebugLevel;
UINT8 PlatformFlags;
//
// Read CMOS diagnostic status register (0x70/0x71, index 0x4B)
//
CmosDebugLevel = IoRead8 (0x70);
IoWrite8 (0x70, CmosDebugLevel & 0x80 | 0x4B);
DebugLevel = IoRead8 (0x71);
if (DebugLevel > 3) {
//
// Check platform-specific memory-mapped register
//
PlatformFlags = *(volatile UINT8 *)(UINTN)0xFDAF0490;
if (DebugLevel == 0) {
DebugLevel = (PlatformFlags & 2) | 1;
}
}
if (DebugLevel - 1 > 0xFD) {
//
// DebugLevel is 0: debug disabled
//
return 0;
}
if (DebugLevel == 1) {
return EFI_D_WARN | EFI_D_INFO | EFI_D_ERROR; /*0x80000006 */
}
return EFI_D_INFO | EFI_D_ERROR; /*0x80000004 */
}
/**
*Initialize the debug library.
*
*Sets up the debug output protocol based on the configuration.
*If console debug is requested (byte_1730 != 0), attempts to
*locate the StdErr protocol; otherwise, uses the serial I/O
*protocol obtained via AllocatePages + LocateProtocol.
*
* @return EFI_SUCCESS Debug output initialized.
*EFI_NOT_READY Could not allocate or locate protocol.
*/
EFI_STATUS DebugLibInitialize (
VOID
)
{
EFI_STATUS Status;
UINTN Pages;
VOID *Protocol;
if (gDebugInitialized) {
//
// Console debug mode: locate StdErr protocol
//
if (gDebugOutputProtocol2 != NULL) {
return EFI_SUCCESS;
}
if (gDebugMode == 1) {
return EFI_NOT_READY;
}
//
// This path not taken in console mode since gDebugInitialized=0
//
return EFI_NOT_READY;
} else {
//
// Serial debug mode (default)
//
if (gDebugOutputProtocol2 != NULL) {
return EFI_SUCCESS;
}
if (gDebugMode == 1) {
return EFI_NOT_READY;
}
//
// Allocate/free memory to probe available pages
//
Pages = gSavedBootServices->AllocatePages (AllocateAnyPages, EfiBootServicesData, 1);
gSavedBootServices->FreePages (Pages, 1);
if (Pages > 0x10) {
return EFI_NOT_READY;
}
Status = gSavedBootServices->LocateProtocol (
&gEfiSerialIoProtocolGuid,
NULL,
&gDebugOutputProtocol2
);
if (EFI_ERROR (Status)) {
gDebugOutputProtocol2 = NULL;
}
}
return Status;
}
/**
*Debug print with level check and format conversion.
*
*Converts %r (EFI_STATUS format) to the standard %r and
* %s (wide char) to %s / %g (GUID) to %g before forwarding
*to the debug output protocol.
*
* @param ErrorLevel Debug error level mask.
* @param Format Format string (modified in-place for %r->%s conversion).
* @param ... Variable arguments.
*
* @return Result from the debug output protocol, or error status.
*/
UINTN BoardInfoDebugPrint (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
UINTN Result;
UINTN Ret;
UINTN DebugLevel;
CHAR8 *Fmt;
VA_LIST Args;
VA_LIST ArgsCopy;
VA_START (ArgsCopy, Format);
VA_START (Args, Format);
Result = DebugLibInitialize ();
if (!EFI_ERROR (Result)) {
DebugLevel = gDebugOutputProtocol2;
if (gDebugInitialized) {
DebugLevel = (UINTN)gDebugOutputProtocol2;
}
Ret = DebugGetPlatformDebugLevel ();
if ((UINTN)DebugLevel & (UINTN)Ret) {
//
// Convert %r (EFI_STATUS) to %r and %s/%g to ASCII-compatible format
//
Fmt = (CHAR8 *)Format;
if (*Format != 0) {
do {
if (*Fmt == '%') {
if (*(Fmt + 1) == 's') {
*(Fmt + 1) = 'a'; /* %s -> %a for CHAR8 strings */
} else if (*(Fmt + 1) == 'G') {
*(Fmt + 1) = 'g'; /* %G -> %g for GUIDs */
}
}
Fmt++;
} while (*Fmt != 0);
Fmt = (CHAR8 *)Format;
}
return ((UINTN ( *)(UINTN, CHAR8 *, VA_LIST))DebugLevel)(
ErrorLevel,
Fmt,
VA_ARGS (Args)
);
}
}
return Result;
}
/**
*Debug print with ASSERT-level error level.
*
* @param ErrorLevel Error level (always 0x80000000 = EFI_D_ERROR).
* @param Format Format string.
* @param ... Variable arguments.
*
* @return Result from the debug output protocol.
*/
UINTN DebugVPrint (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
VA_LIST Args;
VA_LIST ArgsCopy;
UINTN Result;
UINTN Ret;
VOID *DebugOutput;
VA_START (ArgsCopy, Format);
VA_START (Args, Format);
Result = (UINTN)DebugLibGetDebugOutput ();
DebugOutput = (VOID *)Result;
if (DebugOutput != NULL) {
Ret = DebugGetPlatformDebugLevel ();
if (((UINTN)Result & ErrorLevel) != 0) {
return ((UINTN ( *)(UINTN, CONST CHAR8 *, VA_LIST))DebugOutput)(
ErrorLevel,
Format,
VA_ARGS (Args)
);
}
}
return Result;
VA_END (Args);
VA_END (ArgsCopy);
}
/**
*Debug assertion handler.
*
*Prints the failed assertion via the debug output protocol.
*
* @param FileName Source file name.
* @param LineNumber Line number of the assertion.
* @param FailedCondition The failed assertion expression.
*/
VOID DebugPrintAssert (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *FailedCondition
)
{
VOID *DebugOutput;
DebugOutput = DebugLibGetDebugOutput ();
if (DebugOutput != NULL) {
((VOID ( *)(CONST CHAR8 *, UINTN, CONST CHAR8 *))DebugOutput)(
FileName,
LineNumber,
FailedCondition
);
}
}
/*=============================================================================
*HOB (HAND-OFF BLOCK) FUNCTIONS
*============================================================================*/
/**
*Get the HOB list pointer.
*
*Traverses the SystemTable's HOB list entries looking for the
*PHIT (Phase Hand-off Information Table) HOB which contains
*the pointer to the start of the HOB list. The HOB list is
*identified by comparing HOB GUIDs against known GUIDs
* (gEfiHobListGuid or similar).
*
* @return Pointer to the HOB list, or NULL if not found.
*/
VOID *GetHobList (
VOID
)
{
UINTN Count;
EFI_GUID *HobGuid;
VOID *HobList;
HobList = gHobList;
if (HobList != NULL) {
return HobList;
}
gHobList = NULL;
Count = 0;
HobList = NULL;
if (gSystemTable->NumberOfTableEntries != 0) {
//
// Walk the configuration table looking for HOB list GUID
//
while (Count < gSystemTable->NumberOfTableEntries) {
if (HobIsMatchingGuid (
(EFI_GUID *)(UINTN)Count,
*(EFI_GUID **)(gSystemTable->ConfigurationTable + HobList + 24 *Count)
)) {
gHobList = *(VOID **)((UINTN)gSystemTable->ConfigurationTable + 24 *Count + 16);
break;
}
Count++;
HobList = (CHAR8 *)HobList + 24;
}
if (gHobList == NULL) {
DebugVPrint (
EFI_D_ERROR,
"\nASSERT_EFI_ERROR (Status = %r)\n",
EFI_NOT_FOUND
);
DebugPrintAssert (
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
54,
"!EFI_ERROR (Status)"
);
}
}
if (gHobList == NULL) {
DebugPrintAssert (
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
55,
"mHobList != ((void *) 0)"
);
}
return gHobList;
}
/**
*Read a 64-bit value from a potentially unaligned buffer.
*
* @param Buffer Pointer to the 64-bit value (may be unaligned).
*
* @return The 64-bit value read from the buffer.
*/
UINT64 ReadUnaligned64 (
IN CONST UINT64 *Buffer
)
{
ASSERT (Buffer != NULL);
return *Buffer;
}
/**
*Compare two HOB GUIDs for equality.
*
* @param Guid1 First GUID.
* @param Guid2 Second GUID.
*
* @return TRUE if the GUIDs are equal, FALSE otherwise.
*/
BOOLEAN HobIsMatchingGuid (
IN CONST EFI_GUID *Guid1,
IN CONST EFI_GUID *Guid2
)
{
return ReadUnaligned64 ((UINT64 *)Guid1) == ReadUnaligned64 ((UINT64 *)Guid2)
&& ReadUnaligned64 ((UINT64 *)Guid1 + 1) == ReadUnaligned64 ((UINT64 *)Guid2 + 1);
}
/**
*Compare two memory buffers.
*
* @param Buffer1 First buffer.
* @param Buffer2 Second buffer.
* @param Length Number of bytes to compare.
*
* @return 0 if the buffers are equal; negative if Buffer1 < Buffer2;
*positive if Buffer1 > Buffer2.
*/
INTN CompareMem (
IN CONST VOID *Buffer1,
IN CONST VOID *Buffer2,
IN UINTN Length
)
{
//
// Optimized comparison handling misaligned start, aligned 8-byte blocks,
// and trailing bytes.
//
CONST UINT8 *B1;
CONST UINT8 *B2;
UINTN AlignDelta;
B1 = (CONST UINT8 *)Buffer1;
B2 = (CONST UINT8 *)Buffer2;
AlignDelta = (UINTN)Buffer1 & 7;
//
// Handle head misalignment if both pointers have same alignment
//
if (AlignDelta != 0 && AlignDelta == ((UINTN)Buffer2 & 7)) {
UINTN HeadBytes = 8 - AlignDelta;
while (HeadBytes != 0 && Length > 0) {
if (*B1 != *B2) {
return *B1 - *B2;
}
B1++;
B2++;
HeadBytes--;
Length--;
}
}
//
// Compare aligned 8-byte chunks
//
while (Length >= 8 && *(UINT64 *)B1 == *(UINT64 *)B2) {
B1 += 8;
B2 += 8;
Length -= 8;
}
//
// Compare remaining bytes
//
while (Length > 0) {
if (*B1 != *B2) {
return *B1 - *B2;
}
B1++;
B2++;
Length--;
}
return 0;
}
/**
*Find HOB data matching a specific signature and optional name filter.
*
*Traverses the HOB entries looking for a protocol-data HOB with
*a matching signature (32-bit tag). If a name filter is provided,
*additional comparison is performed against the name.
*
*The HOB data format expected:
* - DataSize = HOB data length
* - DataAddr = Physical address of the HOB data
*
* @param DataAddr [out] Address of the matching HOB data.
* @param DataSize [out] Size of the matching HOB data.
* @param Signature 32-bit signature to match (e.g. 'DATA').
* @param NameFilter Optional name string to match against HOB name.
*
* @return EFI_SUCCESS Data found.
*EFI_NOT_FOUND No matching HOB data found.
*/
EFI_STATUS HobFindProtocolData (
OUT UINT64 *DataAddr,
OUT UINT64 *DataSize,
IN UINT32 Signature,
IN CHAR8 *NameFilter OPTIONAL
)
{
UINT64 HobEntryCount;
UINT64 Index;
UINT64 *HobHandles;
UINT64 Size;
UINT64 DataAddress;
UINT64 HobListHandle;
UINT64 *HobData;
EFI_STATUS Status;
UINT64 HobHandle;
UINT8 SearchType;
UINT64 EntryDataAddr, EntryDataSize;
UINT64 EntryPtr;
UINT64 DataPhysicalAddr;
UINT64 HobBuffer;
*DataAddr = 0;
*DataSize = 0;
HobHandles = NULL;
//
// Get the HOB protocol handle list via gBS->LocateHandle
//
Status = gSavedBootServices->LocateHandle (
AllHandles,
&gEfiHobProtocolGuid,
NULL,
&HobEntryCount,
&HobHandles
);
if (EFI_ERROR (Status)) {
return Status;
}
for (Index = 0; Index < HobEntryCount; Index++) {
//
// Open the HOB protocol for this handle
//
Status = gSavedBootServices->OpenProtocol (
HobHandles[Index],
&gEfiHobProtocolGuid,
&HobData,
...
);
if (EFI_ERROR (Status)) {
continue;
}
for (;;) {
//
// Get the next HOB entry
//
SearchType = (NameFilter != NULL) ? HobTypeCodeWithName : HobTypeCode;
Status = HobData->GetNextHob (HobData, SearchType, Index, &HobBuffer);
if (Status == EFI_NOT_FOUND) {
break;
}
EntryDataAddr = HobBuffer;
EntryDataSize = *(UINT64 *)(EntryDataAddr + 8);
//
// If name filter provided, copy and compare the name
//
if (NameFilter != NULL) {
if (CompareMem (
(VOID *)(UINTN)HobBuffer,
NameFilter,
*(UINT8 *)(HobBuffer + 16)
) != 0) {
//
// Name doesn't match; adjust data pointer and free
//
EntryDataSize -= 16;
DataPhysicalAddr = HobGetDataPtr ((VOID *)(UINTN)EntryDataSize);
HobBuffer = DataPhysicalAddr;
if (DataPhysicalAddr != 0) {
InternalCopyMem (
(VOID *)(UINTN)DataPhysicalAddr,
(VOID *)(UINTN)(EntryDataAddr + 16),
EntryDataSize
);
}
gSavedBootServices->FreePages (HobBuffer, 1);
}
//
// Name matches; fall through to return
//
}
//
// Success: return the data address and size
//
gSavedBootServices->FreePages (HobHandles, 1);
*DataAddr = HobBuffer;
*DataSize = EntryDataSize;
return EFI_SUCCESS;
}
if (HobBuffer != 0) {
gSavedBootServices->FreePages (HobBuffer, 1);
}
}
gSavedBootServices->FreePages (HobHandles, 1);
return EFI_NOT_FOUND;
}
/**
*Get the pointer to the data section of a HOB.
*
*Uses gBS->GetHobData to retrieve a pointer to the HOB's data payload.
*
* @param Hob Pointer to the HOB entry.
*
* @return Pointer to the data section of the HOB, or 0 if error.
*/
VOID *HobGetDataPtr (
IN CONST VOID *Hob
)
{
UINT64 DataPtr;
DataPtr = 0;
gSavedBootServices->GetHobData (4, (UINT64)Hob, &DataPtr);
return (VOID *)(UINTN)DataPtr;
}
/**
*Search the HOB list for a specific GUID.
*
*Walks the HOB list looking for a HOB entry whose GUID matches
*the given GUID (passed as a UINT64 signature).
*
* @param Signature 64-bit signature to match (little-endian ASCII GUID).
* @param Hob [out] Pointer to the matching HOB entry.
* @param HobList Pointer to the HOB list (third arg via ).
*
* @return EFI_SUCCESS Matching HOB found.
*EFI_NOT_FOUND No matching HOB found.
*EFI_INVALID_PARAMETER Invalid input.
*/
EFI_STATUS HobFindGuid (
IN EFI_GUID *Guid,
OUT VOID **Hob,
...
)
{
UINT64 *HobListStart;
HobListStart = (UINT64 *)Hob;
if (Hob == NULL || HobListStart == NULL) {
return EFI_INVALID_PARAMETER;
}
if (*HobListStart == 8) {
return EFI_NOT_FOUND;
}
while (*(UINT64 *)(UINTN)HobListStart != (UINT64)Guid) {
HobListStart++;
if ((UINTN)HobListStart >= (UINTN)(*HobListStart - 8)) {
return EFI_NOT_FOUND;
}
}
*Hob = (VOID *)HobListStart;
return EFI_SUCCESS;
}
/**
*Internal memory copy with overlap handling.
*
*Copies Length bytes from Source to Destination, correctly
*handling overlapping regions by detecting direction and
*selecting forward/backward copy as appropriate.
*
* @param Destination Pointer to the destination buffer.
* @param Source Pointer to the source buffer.
* @param Length Number of bytes to copy.
*
* @return Destination pointer.
*/
VOID *InternalCopyMem (
OUT VOID *Destination,
IN CONST VOID *Source,
IN UINTN Length
)
{
UINT8 *Dst;
CONST UINT8 *Src;
UINT8 Direction;
UINTN AlignDelta;
UINT8 Count;
Dst = (UINT8 *)Destination;
Src = (CONST UINT8 *)Source;
Direction = 0;
//
// Detect overlap: if Source < Destination and overlap exists,
// copy backwards from the end.
//
if (Src < Dst && Src + Length > Dst) {
Src += Length;
Dst += Length;
Direction = 1;
}
//
// If aligned and length >= 8, copy aligned head first
//
if (Length >= 8 && (UINTN)Src - (UINTN)Dst < 8) {
if (Direction) {
Src -= 7;
Dst -= 7;
}
//
// Copy misaligned head
//
AlignDelta = (UINTN)Src & 7;
if ((AlignDelta & 7) == ((UINTN)Dst & 7) && AlignDelta != 0) {
if (!Direction) {
AlignDelta = 8 - AlignDelta;
}
CopyMem (Dst, Src, AlignDelta);
Src += AlignDelta;
Dst += AlignDelta;
Length -= AlignDelta;
}
if (Direction) {
Src -= 7;
Dst -= 7;
}
}
//
// Copy aligned 8-byte chunks
//
if (Length >= 8) {
CopyMem (Dst, Src, Length & ~7);
Src += Length & ~7;
Dst += Length & ~7;
Length &= 7;
}
//
// Copy trailing bytes
//
if (Length != 0) {
if (Direction) {
Src += 8;
Dst += 8;
}
CopyMem (Dst, Src, Length);
}
return Destination;
}
/*=============================================================================
*MAIN DRIVER ENTRY POINTS
*============================================================================*/
/**
*Standard UEFI DXE driver entry point.
*
*Initializes global variables, locates the HOB list, then
*calls AmiBoardInfo2Entry to perform board info collection.
*
* @param ImageHandle Handle for this image.
* @param SystemTable Pointer to the UEFI system table.
*
* @return EFI_STATUS from AmiBoardInfo2Entry.
*/
EFI_STATUS EFIAPI _ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
//
// Save global pointers with ASSERT checks (standard UEFI boilerplate)
//
gImageHandle = ImageHandle;
ASSERT (gImageHandle != NULL);
gSystemTable = SystemTable;
ASSERT (gSystemTable != NULL);
gBootServices = SystemTable->BootServices;
ASSERT (gBootServices != NULL);
gRuntimeServices = SystemTable->RuntimeServices;
ASSERT (gRuntimeServices != NULL);
//
// Initialize the HOB list
//
GetHobList ();
//
// Dispatch to the main board info entry function
//
return AmiBoardInfo2Entry (ImageHandle, SystemTable);
}
/**
*Main board information driver entry.
*
*Collects platform board configuration by:
*1. Checking if Multi-Platform Board Info protocol already exists
* (if so, prints message and exits)
*2. Finding DSDT ACPI table data in HOBs
*3. Finding SIO (Super I/O) configuration data in HOBs
*4. Finding IOAPIC configuration data in HOBs
*5. Installing the AMI Board Info protocol with collected data
*
*The HOBs are identified by their signature strings:
* "$PCIDATA" (DSDT),
* "$SIODATA" (SIO),
* "$APIDATA" (IOAPIC)
*
* @param ImageHandle Handle for this image.
* @param SystemTable Pointer to the UEFI system table.
*
* @return EFI_SUCCESS Protocol installed.
*EFI_ALREADY_STARTED Multi-Platform Board Info already present.
*EFI_NOT_FOUND Required HOB data missing.
*/
EFI_STATUS AmiBoardInfo2Entry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
UINT64 DsdtHobAddr;
UINT64 DsdtHobDataAddr;
UINT64 SioHobAddr;
UINT64 IoApicHobAddr;
EFI_STATUS Status;
BOOLEAN HasProtocolData;
AMI_BOARD_INFO2_PROTOCOL *BoardInfo;
DsdtHobAddr = 0;
DsdtHobDataAddr = 0;
//
// Save SystemTable, BootServices, RuntimeServices on first call
//
if (gSavedSystemTable == NULL) {
gSavedSystemTable = SystemTable;
gSavedBootServices = SystemTable->BootServices;
gSavedRuntimeServices = SystemTable->RuntimeServices;
}
//
// Check if the Multi-Platform Board Info protocol already exists
// (gBS->LocateProtocol). If so, this is a second call -- exit.
//
BoardInfo = NULL;
Status = gSavedBootServices->LocateProtocol (
&gAmiBoardInfoProtocolGuid,
NULL,
(VOID **)&BoardInfo
);
if (!EFI_ERROR (Status)) {
BoardInfoDebugPrint (
EFI_D_ERROR,
"AmiBrdInfo: Multi-Platform BrdInfo present Status=%r Exiting",
Status
);
return EFI_ALREADY_STARTED;
}
//
// Find the protocol-data HOBs (they contain DSDT, SIO, IOAPIC data)
//
HasProtocolData = FALSE;
Status = HobFindProtocolData (
&gProtocolDataBase,
&gProtocolDataSize,
HOB_SIGNATURE_0,
(CHAR8 *)&gNameFilter
);
if (EFI_ERROR (Status)) {
DebugVPrint (EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
DebugPrintAssert (
"e:\\hs\\AmiModulePkg\\BoardInfo\\AmiBoardInfo2.c",
158,
"!EFI_ERROR (Status)"
);
return Status;
}
//
// Find DSDT HOB data
//
if (gProtocolDataBase != 0) {
Status = HobFindGuid (
(EFI_GUID *)HOB_SIGNATURE_DSDT,
(VOID **)&DsdtHobAddr,
(VOID *)(UINTN)gProtocolDataBase
);
DsdtHobDataAddr = DsdtHobAddr;
}
if (EFI_ERROR (Status)) {
DebugVPrint (EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
DebugPrintAssert (
"e:\\hs\\AmiModulePkg\\BoardInfo\\AmiBoardInfo2.c",
167,
"!EFI_ERROR (Status)"
);
return Status;
}
//
// Store DSDT data pointer in the protocol structure (slot 2)
//
BoardInfo = (AMI_BOARD_INFO2_PROTOCOL *)&gBoardInfoProtocolStructure;
BoardInfo->DsdtHobDataAddr = DsdtHobDataAddr;
//
// Find DSDT ACPI table via HOB protocol (optional)
//
Status = HobFindProtocolData (
&BoardInfo->DsdtDataPtr,
&BoardInfo->DsdtDataSize,
HOB_SIGNATURE_0 & 0xFFFFFFFF,
NULL
);
if (!EFI_ERROR (Status)) {
//
// Store DSDT data pointer and size (slots 5, 6)
//
} else {
BoardInfoDebugPrint (-1, "\n======================================================================================\n");
BoardInfoDebugPrint (
-1,
"AmiBrdInfo: !!!WARNING!!! Can't find DSDT Table in BIOS FV - %r.\n"
" !!!WARNING!!! Check your project ACPI settings...\n",
Status
);
BoardInfoDebugPrint (-1, "======================================================================================\n\n");
}
//
// Find SIO (Super I/O) data HOB
//
SioHobAddr = 0;
if (gProtocolDataBase != 0) {
Status = HobFindGuid (
(EFI_GUID *)HOB_SIGNATURE_SIO,
(VOID **)&SioHobAddr,
(VOID *)(UINTN)gProtocolDataBase
);
}
if (!EFI_ERROR (Status)) {
BoardInfo->SioHobDataAddr = SioHobAddr;
} else {
BoardInfoDebugPrint (-1, "\n======================================================================================\n");
BoardInfoDebugPrint (
-1,
"AmiBrdInfo: !!!WARNING!!! Can't find SIO Data Table in BIOS FV - %r.\n"
" !!!WARNING!!! Check your project SIO settings...\n",
Status
);
BoardInfoDebugPrint (-1, "======================================================================================\n\n");
}
//
// Find IOAPIC data HOB
//
IoApicHobAddr = 0;
if (gProtocolDataBase != 0) {
Status = HobFindGuid (
(EFI_GUID *)HOB_SIGNATURE_IOAPIC,
(VOID **)&IoApicHobAddr,
(VOID *)(UINTN)gProtocolDataBase
);
}
if (!EFI_ERROR (Status)) {
BoardInfo->IoApicHobDataAddr = IoApicHobAddr;
} else {
BoardInfoDebugPrint (-1, "\n======================================================================================\n");
BoardInfoDebugPrint (
-1,
"AmiBrdInfo: !!!WARNING!!! Can't find IOAPIC Data Table in BIOS FV - %r.\n"
" !!!WARNING!!! Check your project APIC and ROUTER settings...\n",
Status
);
BoardInfoDebugPrint (-1, "======================================================================================\n\n");
}
//
// Install the AMI Board Info protocol
//
return gSavedBootServices->InstallMultipleProtocolInterfaces (
&gBoardInfoProtocolHandle,
&gAmiBoardInfoProtocolGuid,
BoardInfo,
NULL
);
}