/** @file
SlotDataUpdateDxeCLX64L - PCIe Slot Data Update Driver for CLX64L Platform
This DXE driver provides platform-specific PCIe slot data configuration
for the CLX64L (Cooper Lake Xeon 64L) platform. It installs PSLT
(Platform Slot Table) entries via the UBA (Universal BIOS Architecture)
protocol to describe the physical PCIe slot topology and capabilities.
The driver locates the UBA Slot Data Update protocol by GUID, then
installs two PSLT entries:
- One for the physical slot table (40 bytes at 0xB80)
- One for an extended slot configuration (40 bytes at 0xBB0)
Build path:
e:\hs\Build\HR6N0XMLK\DEBUG_VS2015\X64\PurleyRpPkg\Uba\UbaMain\Dxe\TypeCLX64L\SlotDataUpdateDxe
Copyright (c) 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "SlotDataUpdateDxeCLX64L.h"
//
// Global UEFI table pointers (set by _ModuleEntryPoint)
//
EFI_HANDLE gImageHandle = NULL;
EFI_SYSTEM_TABLE *gSystemTable = NULL;
EFI_BOOT_SERVICES *gBootServices = NULL;
EFI_RUNTIME_SERVICES *gRuntimeServices = NULL;
//
// Cached UBA debug protocol pointer
//
VOID *gUbaDebugProtocol = NULL;
//
// Cached HOB list pointer
//
VOID *gHobList = NULL;
//
// UBA Slot Data Update Protocol GUID
// {E03E0D46-5263-4845-B0A4-58D57B3177E2}
//
STATIC CONST EFI_GUID mSlotDataUpdateProtocolGuid = SLOT_DATA_UPDATE_PROTOCOL_GUID;
//
// Slot Data Entry Protocol GUID
// {B93613E1-48F0-4B32-B3A8-4FEDFC7C1365}
//
STATIC CONST EFI_GUID mSlotDataEntryGuid = SLOT_DATA_ENTRY_PROTOCOL_GUID;
//
// HOB List GUID
// {4CF27739-93D7-11D4-9A3A-0090273FC14D}
//
STATIC CONST EFI_GUID mGetHobListGuid = GET_HOB_LIST_PROTOCOL_GUID;
//
// First PSLT entry: physical slot configuration for CLX64L platform
// Format: PSLT header + slot mapping data
// - Slot 0: Bus 0x00, Dev 0x02, Func 0x00, Port 0x01
// - Slot 1: Bus 0x01, Dev 0x02, Func 0x01, Port 0x00
// - Uplink: Bus 0x01, Dev 0x00 (bridge)
//
STATIC CONST PSLT_HEADER mSlotTableEntry1 = {
PSLT_SIGNATURE, // Signature = "PSLT"
1, // Version
0xBA0, // TableOffset
0x4B0, // TableLength
{ // SlotData[24]:
0x00, 0x02, 0x00, 0x01, // Slot 0: B0:D2:F0 -> Port 1
0x01, 0x02, 0x01, 0x00, // Slot 1: B1:D2:F1 -> Port 0
0x01, 0x00, 0x00, 0x00, // Slot mapping attribute
0x00, 0x00, 0x00, 0x00, // Reserved
0x00, 0x00, 0x00, 0x00, // Reserved
0x00, 0x00, 0x00, 0x00 // Reserved
}
};
//
// Second PSLT entry: extended slot configuration
// Contains null table offset (placeholder/reserved entry)
//
STATIC CONST PSLT_HEADER mSlotTableEntry2 = {
PSLT_SIGNATURE, // Signature = "PSLT"
1, // Version
0xBA0, // TableOffset
0x4B0, // TableLength
{ // SlotData[24]:
0x00, 0x00, 0x00, 0x00, // No slot mapping
0x00, 0x00, 0x00, 0x00, // Reserved
0xB4, 0x04, 0x00, 0x00, // Secondary table reference
0x00, 0x00, 0x00, 0x00, // Reserved
0x00, 0x00, 0x00, 0x00, // Reserved
0x00, 0x00, 0x00, 0x00 // Reserved
}
};
//
// UBA debug protocol GUID (internal UBA protocol for debug services)
// This GUID varies by platform; located via gBS->LocateProtocol
//
STATIC CONST EFI_GUID mUbaDebugProtocolGuid = {
0x7739F24C, 0x93D7, 0x11D4, { 0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }
};
/**
Read a 64-bit value from a buffer with NULL-pointer assertion.
Wrapper around standard BaseLib ReadUnaligned64 with an additional
NULL pointer check that triggers a UBA assert if the buffer is NULL.
@param[in] Buffer Pointer to the buffer to read from.
@return The 64-bit value at the buffer address.
**/
UINT64
EFIAPI
ReadUnaligned64 (
IN CONST VOID *Buffer
)
{
if (Buffer == NULL) {
UbaAssert (
"e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
192,
"Buffer != ((void *) 0)"
);
}
return *(UINT64 *)Buffer;
}
/**
Get the UBA debug protocol instance.
Allocates pool, locates the UBA debug protocol by GUID, and caches
the result globally. The protocol provides DebugPrint and DebugAssert
services used by the UBA framework.
@return Pointer to the UBA_DEBUG_PROTOCOL, or NULL if the protocol
could not be located or pool allocation failed.
**/
UBA_DEBUG_PROTOCOL *
EFIAPI
GetUbaDebugProtocol (
VOID
)
{
EFI_STATUS Status;
UBA_DEBUG_PROTOCOL *Protocol;
//
// Return cached protocol if already located
//
if (gUbaDebugProtocol != NULL) {
return gUbaDebugProtocol;
}
//
// Allocate pool for the protocol instance
//
Status = gBootServices->AllocatePool (
EfiBootServicesData,
31,
(VOID **)&Protocol
);
if (EFI_ERROR (Status)) {
return NULL;
}
//
// Zero the allocated pool
//
gBootServices->SetMem (Protocol, 31, 0);
//
// Locate the UBA debug protocol
//
Status = gBootServices->LocateProtocol (
&mUbaDebugProtocolGuid,
NULL,
&gUbaDebugProtocol
);
if (EFI_ERROR (Status)) {
gUbaDebugProtocol = NULL;
return NULL;
}
return gUbaDebugProtocol;
}
/**
UBA debug print function.
Queries the CMOS debug level (RTC index 0x4B) to determine if the
requested severity level is enabled, and if so, forwards the message
to the UBA debug protocol's DebugPrint function.
The CMOS register at index 0x4B uses the following encoding:
Bit 7 = NMI mask
Bits 6-0 = Debug level:
0 = Disabled
1 = Errors only
2 = Errors + Warnings
3 = Full debug
@param[in] Severity Debug message severity level.
@param[in] DebugString Debug format string.
@param[in] ... Variable arguments for format string.
@return Status from the UBA debug protocol print function, or
EFI_UNSUPPORTED if debug output is suppressed.
**/
EFI_STATUS
EFIAPI
LogUbaMessage (
IN UINTN Severity,
IN CHAR8 *DebugString,
...
)
{
UBA_DEBUG_PROTOCOL *Protocol;
UINT64 SeverityLevel;
UINT8 CmosIndex;
UINT8 CmosValue;
UINT8 DebugLevel;
Protocol = GetUbaDebugProtocol ();
SeverityLevel = 0;
if (Protocol != NULL) {
//
// Read CMOS debug level
//
CmosIndex = __inbyte (RTC_INDEX_PORT);
__outbyte (RTC_INDEX_PORT, (CmosIndex & RTC_NMI_BIT) | RTC_DEBUG_INDEX);
CmosValue = __inbyte (RTC_TARGET_PORT);
DebugLevel = CmosValue;
//
// Determine if debug is enabled for this severity
//
if (DebugLevel > 3) {
//
// Non-standard debug level; check if CMOS was zero (disabled)
//
if (DebugLevel == 0) {
DebugLevel = (UINT8)((UINTN)(MEMORY[0xFDAF0490] & 2) | 1);
}
}
if ((DebugLevel - 1) <= 0xFD) {
//
// Map debug level to UBA severity mask
//
SeverityLevel = (DebugLevel == 1) ?
(UINT64)UBA_DEBUG_WARN :
(UINT64)UBA_DEBUG_ERROR;
}
//
// If severity matches, forward to UBA debug print
//
if ((SeverityLevel & Severity) != 0) {
return Protocol->DebugPrint (Severity, DebugString, (UINT64 *)&DebugString);
}
}
return EFI_UNSUPPORTED;
}
/**
ASSERT helper via UBA debug protocol.
Triggers a debug assert through the UBA debug protocol's DebugAssert
function. Used as the platform assert handler for UBA-based modules.
@param[in] FileName Source file name of the assert.
@param[in] LineNumber Line number of the assert.
@param[in] AssertString Assertion expression string.
**/
VOID
EFIAPI
UbaAssert (
IN CHAR8 *FileName,
IN UINTN LineNumber,
IN CHAR8 *AssertString
)
{
UBA_DEBUG_PROTOCOL *Protocol;
Protocol = GetUbaDebugProtocol ();
if (Protocol != NULL) {
Protocol->DebugAssert (FileName, LineNumber, AssertString);
}
}
/**
Check if a HOB entry matches the expected GUIDs.
Compares the HOB entry's GUID fields against the context GUID and
the known HOB list GUID to determine if this is the target HOB.
@param[in] ContextGuid The context/expected GUID value.
@param[in] HobEntry Pointer to a HOB entry structure.
@retval TRUE The HOB entry matches both context and HOB list GUID.
@retval FALSE The HOB entry does not match.
**/
BOOLEAN
EFIAPI
MatchHobGuid (
IN UINT64 ContextGuid,
IN VOID *HobEntry
)
{
UINT64 Guid1;
UINT64 Guid2;
//
// Read the first 8 bytes of the HOB header
//
Guid1 = ReadUnaligned64 (HobEntry);
Guid2 = ReadUnaligned64 ((VOID *)((UINTN)HobEntry + 8));
return (ReadUnaligned64 (&mSlotDataEntryGuid) == Guid1) &&
(ReadUnaligned64 (&mGetHobListGuid) == Guid2);
}
/**
Retrieve the HOB list pointer.
Iterates through the HOB entries in the system configuration HOB
list to find the one matching the slot data entry GUID. The result
is cached globally.
@param[in] Context Optional context value (currently unused).
@return Pointer to the matching HOB list entry data field, or NULL
if no matching HOB was found.
**/
UINT64
EFIAPI
GetHobList (
IN UINT64 Context
)
{
UINT64 Result;
UINTN Index;
UINTN EntryOffset;
//
// Return cached HOB list if already located
//
if (gHobList != NULL) {
return (UINT64)(UINTN)gHobList;
}
//
// Initialize
//
gHobList = NULL;
//
// Iterate through HOB entries from the system table
//
if (gSystemTable->NumberOfTableEntries != 0) {
Index = 0;
EntryOffset = 0;
while (Index < gSystemTable->NumberOfTableEntries) {
if (MatchHobGuid (
Context,
(VOID *)((UINTN)gSystemTable->ConfigurationTable + EntryOffset)
)) {
//
// Found matching HOB; return the data field at offset 16
//
Result = *(UINT64 *)((UINTN)gSystemTable->ConfigurationTable +
EntryOffset + 16);
gHobList = (VOID *)(UINTN)Result;
return Result;
}
Index++;
EntryOffset += sizeof (EFI_CONFIGURATION_TABLE);
}
//
// No matching HOB found - assert
//
LogUbaMessage (
UBA_DEBUG_ERROR,
"\nASSERT_EFI_ERROR (Status = %r)\n",
(UINT64)0x800000000000000E
);
UbaAssert (
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
54,
"!EFI_ERROR (Status)"
);
}
//
// Verify HOB list was found
//
if (gHobList == NULL) {
UbaAssert (
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
55,
"mHobList != ((void *) 0)"
);
}
return (UINT64)(UINTN)gHobList;
}
/**
Platform-specific slot data update entry point for CLX64L.
This is the main entry point called after UEFI core initialization.
It performs the following:
1. Locates the UBA Slot Data Update protocol
2. Installs the first PSLT entry (physical slot mapping)
3. Installs the second PSLT entry (extended slot config)
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@return EFI_SUCCESS Slot data updated successfully.
@return EFI_UNSUPPORTED Slot data update protocol not found.
@return EFI_INVALID_PARAMETER Invalid slot data provided.
**/
EFI_STATUS
EFIAPI
_ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
SLOT_DATA_UPDATE_PROTOCOL *SlotProtocol;
//
// Save global UEFI table pointers
//
gImageHandle = ImageHandle;
if (ImageHandle == NULL) {
UbaAssert (
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
51,
"gImageHandle != ((void *) 0)"
);
}
gSystemTable = SystemTable;
if (SystemTable == NULL) {
UbaAssert (
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
57,
"gST != ((void *) 0)"
);
}
//
// Cache boot services pointer from system table (offset 0x60)
//
gBootServices = SystemTable->BootServices;
if (gBootServices == NULL) {
UbaAssert (
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
63,
"gBS != ((void *) 0)"
);
}
//
// Cache runtime services pointer from system table (offset 0x58)
//
gRuntimeServices = SystemTable->RuntimeServices;
if (gRuntimeServices == NULL) {
UbaAssert (
"e:\\hs\\MdePkg\\Library\\UefiRuntimeServicesTableLib\\UefiRuntimeServicesTableLib.c",
47,
"gRT != ((void *) 0)"
);
}
//
// Initialize HOB list cache
//
GetHobList (0);
//
// Log initialization message
//
LogUbaMessage (UBA_DEBUG_ERROR, "UBA:SlotDataUpdate-TypeClx64L\n");
//
// Locate the UBA Slot Data Update protocol (BootServices->LocateProtocol)
// BootServices[0x140] = LocateProtocol function pointer
//
Status = gBootServices->LocateProtocol (
&mSlotDataUpdateProtocolGuid,
NULL,
(VOID **)&SlotProtocol
);
if (!EFI_ERROR (Status)) {
//
// Install first PSLT entry: physical slot table (40 bytes)
// SlotProtocol[0x10] = GetSlotData function pointer
//
Status = SlotProtocol->GetSlotData (
SlotProtocol,
&mSlotDataEntryGuid,
(VOID *)&mSlotTableEntry1,
sizeof (PSLT_HEADER) + 24
);
if (!EFI_ERROR (Status)) {
//
// Install second PSLT entry: extended slot config (40 bytes)
//
return SlotProtocol->GetSlotData (
SlotProtocol,
&mSlotDataEntryGuid,
(VOID *)&mSlotTableEntry2,
sizeof (PSLT_HEADER) + 24
);
}
}
return Status;
}