/** @file
SlotDataUpdateDxeLightningRidgeEXECB2 - Platform Slot Table (PSLT) update driver
for LightningRidge EXEC B2 platforms.
This driver is part of the Lenovo UBA (Universal BIOS Architecture) framework.
It provides platform-specific PCIe slot configuration data for the LightningRidge
EXEC B2 platform by registering PSLT entries through the UBA protocol.
Build source path: PurleyRpPkg/Uba/UbaMain/Dxe/TypeLightningRidgeEXECB2/
SlotDataUpdateDxe/SlotDataUpdateDxe/
PDB: SlotDataUpdateDxeLightningRidgeEXECB2.pdb
Build: VS2015, DEBUG, X64
Image size: 0xD00 (3328 bytes)
Entry point: 0x390 (_ModuleEntryPoint)
Copyright (C) 2026, Lenovo. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "SlotDataUpdateDxeLightningRidgeEXECB2.h"
//
// =============================================================================
// GUID Definitions
// =============================================================================
//
/**
UBA Protocol GUID for LightningRidge EXEC B2.
36232936-0E76-31C8-A13A-3AF2FC1C3932 at 0xB60
**/
EFI_GUID gUbaProtocolGuid = UBA_PROTOCOL_GUID;
/**
UBA Slot Data PSLT Entry 1 GUID.
B93613E1-48F0-4B32-B3A8-4FEDFC7C1365 at 0xB90
**/
EFI_GUID gUbaSlotDataPsl1Guid = UBA_SLOT_DATA_PSLT1_GUID;
/**
UBA Slot Config GUID.
226763AE-972C-4E3C-80D1-73B25E8CBBA3 at 0xB80
**/
EFI_GUID gUbaSlotConfigGuid = UBA_SLOT_CONFIG_GUID;
/**
DXE Services Table GUID (gEfiDxeServicesTableGuid).
7739F24C-93D7-11D4-9A3A-0090273FC14D at 0xBA0
**/
EFI_GUID gEfiDxeServicesTableGuid = DXE_SERVICES_TABLE_GUID;
//
// =============================================================================
// Global Variables
// =============================================================================
//
/** @brief Cached ImageHandle from entry point. [at 0xC18] */
EFI_HANDLE gImageHandle = NULL;
/** @brief Cached SystemTable pointer from entry point. [at 0xC08] */
EFI_SYSTEM_TABLE *gSystemTable = NULL;
/** @brief Cached BootServices pointer (SystemTable->BootServices). [at 0xC10] */
EFI_BOOT_SERVICES *gBootServices = NULL;
/** @brief Cached RuntimeServices pointer (SystemTable->RuntimeServices). [at 0xC20] */
EFI_RUNTIME_SERVICES *gRuntimeServices = NULL;
/** @brief Cached UBA protocol interface, lazy-initialized by UbaGetProtocolInterface(). [at 0xC28] */
VOID *gUbaProtocol = NULL;
/** @brief Cached HOB list pointer, initialized by GetHobList(). [at 0xC30] */
VOID *gHobList = NULL;
/** @brief Cached platform type byte from CMOS register 0x4B. [at 0xC38] */
UINT8 gPlatformType = 0;
//
// =============================================================================
// Platform Slot Data (PSLT entries embedded in .data section)
//
// The PSLT entries are stored statically in the .data section and registered
// with the UBA protocol during initialization. They define the PCIe slot layout
// for the LightningRidge EXEC B2 platform.
//
// PSLT_HEADER layout:
// Offset Size Field
// ------ ---- -----
// 0 4 Signature ("PSLT" = 0x544C5350)
// 4 4 Version (1)
// 8 4 TotalDataSize (total PSLT data size in bytes)
// 12 4 SlotCountFunc (RVA of GetSlotCount function)
// 16 4 Reserved (pad)
// 20 4 SlotDataFunc (RVA of GetSlotData function)
// 24 8 ConfigData (platform slot config flags)
//
// =============================================================================
//
/**
PSLT Entry 1 (at 0xBC0, 32 bytes): Primary PSLT.
- Signature: "PSLT"
- Version: 1
- TotalDataSize: 0xBB0 (2992 bytes)
- SlotCountFunc: 0x4B0 (GetSlotCount returning 2 slots)
- SlotDataFunc: 0x4B4 (GetSlotData identity passthrough)
- NumberOfSlots: 1
**/
PSLT_HEADER gSlotDataBuffer1 = {
.Signature = 0x544C5350, ///< "PSLT"
.Version = 1, ///< PSLT format version 1
.TotalDataSize = 0xBB0, ///< 2992 bytes total
.SlotCountFunc = 0x4B0, ///< RVA GetSlotCount()
.Reserved = 0, ///< Zero pad
.SlotDataFunc = 0x4B4, ///< RVA GetSlotData()
.ConfigData = { 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 } ///< One slot, no special flags
};
/**
PSLT Entry 2 (at 0xBE0, 40 bytes): Extended PSLT with extra config callback.
Same as PSLT Entry 1 but extended with:
- ExtraConfig: RVA of GetSlotData (0x4B4) as extended callback
Registered via gUbaSlotConfigGuid (GUID: 226763AE-972C-4E3C-...).
**/
SLOT_CONFIG gSlotDataBuffer2 = {
.Header = {
.Signature = 0x544C5350, ///< "PSLT"
.Version = 1, ///< PSLT format version 1
.TotalDataSize = 0xBB0, ///< 2992 bytes total
.SlotCountFunc = 0x4B0, ///< RVA GetSlotCount()
.Reserved = 0, ///< Zero pad
.SlotDataFunc = 0x4B4, ///< RVA GetSlotData()
.ConfigData = { 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 } ///< One slot, no special flags
},
.ExtraConfig = 0x4B4 ///< Extended callback: GetSlotData
};
// =============================================================================
// Function Implementations
// =============================================================================
/**
Returns the number of PCIe slots on this platform.
For LightningRidge EXEC B2, the platform always has 2 slots.
@return UINT8 2 (fixed slot count for EXEC B2).
**/
UINT8
GetSlotCount (
VOID
)
{
return 2;
}
/**
Platform slot data identity passthrough.
Returns the DefaultData pointer unchanged. For EXEC B2, no per-slot
data customization is required beyond the template PSLT entries.
This function is referenced by the UBA PSLT framework at RVA 0x4B4.
@param[in] Slot Slot index (unused on EXEC B2).
@param[in] DefaultData Default slot data to pass through unchanged.
@return VOID* The unmodified DefaultData pointer.
**/
VOID *
GetSlotData (
IN UINTN Slot,
IN VOID *DefaultData
)
{
return DefaultData;
}
/**
Lazily resolves and caches the UBA protocol interface.
Checks if gUbaProtocol is already set. If not, allocates a 31-byte pool
buffer (EfiBootServicesData type) and frees it to verify pool memory is
operational. If the allocation succeeds (AllocatePool returns > 0x10),
proceeds to locate the UBA protocol via gBS->LocateProtocol().
@return UBA_PROTOCOL* The cached UBA protocol interface, or NULL if:
- Pool allocation returned <= 0x10 (pool not functional)
- LocateProtocol failed to find the UBA protocol
**/
UBA_PROTOCOL *
UbaGetProtocolInterface (
VOID
)
{
//
// Return cached protocol if already located (lazy init check).
//
if (gUbaProtocol != NULL) {
return (UBA_PROTOCOL *)gUbaProtocol;
}
gUbaProtocol = NULL;
//
// Allocate a small test buffer to verify pool availability.
// Size 31 = 0x1F bytes via gBS->AllocatePool (BootServices + 24).
// This is a probe to verify the UEFI memory system is operational.
//
{
UINTN TestBufferSize;
VOID *TestBuffer;
TestBufferSize = (UINTN)gBootServices->AllocatePool (
EfiBootServicesData,
31,
&TestBuffer
);
gBootServices->FreePool (TestBuffer);
//
// Check if AllocatePool succeeded by verifying it returned > 0x10.
// (AllocatePool returns EFI_STATUS = ERROR for failure, which is negative)
//
if (TestBufferSize <= 0x10) {
return NULL;
}
}
//
// Locate the UBA protocol using LocateProtocol (BootServices + 320 = 0x140).
//
{
EFI_STATUS Status;
Status = gBootServices->LocateProtocol (
&gUbaProtocolGuid, ///< {36232936-0E76-31C8-A13A-3AF2FC1C3932}
NULL, ///< No registration key
&gUbaProtocol ///< Output: protocol interface
);
if (EFI_ERROR (Status)) {
gUbaProtocol = NULL;
}
}
return (UBA_PROTOCOL *)gUbaProtocol;
}
/**
Sends a debug message through the UBA protocol with CMOS platform-type
filtering.
Reads the platform type from RTC CMOS register 0x4B using I/O ports
0x70 (address) and 0x71 (data). The N3/PlatformType byte determines
the debug routing mask:
- N3 > 3 and N3 != 0: Use N3 as-is (valid platform type)
- N3 == 0: Read hardware strap from 0xFDAF0490 bit 1, OR with 1
- N3 == 1: DebugRoute = 0x80000004 (EFI_D_INFO)
- N3 >= 2: DebugRoute = 0x80000006 (EFI_D_VERBOSE)
The caller's Severity is ANDed with DebugRoute. If any bits match,
the message is forwarded to the UBA protocol's DebugPrint function
(offset +0x00 of the protocol interface).
@param[in] Severity Debug message severity mask (e.g., 0x80000000 = EFI_D_ERROR).
@param[in] Format Print format string.
@param[in] ... Variable argument list for format substitution.
**/
VOID
EFIAPI
UbaDebugPrint (
IN UINT64 Severity,
IN CONST CHAR8 *Format,
...
)
{
UINT64 DebugRoute;
UINT8 PlatformType;
UINT8 N3;
UBA_PROTOCOL *Uba;
UBA_DEBUG_PRINT UbaDebugFunc;
VA_LIST Va;
//
// Get the UBA protocol interface (lazy init through cached result).
//
Uba = UbaGetProtocolInterface ();
DebugRoute = 0;
if (Uba != NULL) {
//
// Read platform type from RTC CMOS register 0x4B.
// I/O port 0x70 is the CMOS address port, 0x71 is the data port.
// We preserve bit 7 (NMI mask) of the address register.
//
PlatformType = IoRead8 (0x70); // Read current CMOS address
IoWrite8 (0x70, (PlatformType & 0x80) | 0x4B); // Select reg 0x4B, keep NMI mask
N3 = IoRead8 (0x71); // Read platform type byte
//
// Determine debug routing based on platform type (N3).
//
if (N3 > 3) {
// N3 is in valid range > 3, use as-is (no remapping needed)
} else if (N3 == 0) {
//
// Platform type 0: read hardware strap from memory-mapped IO.
// 0xFDAF0490 is the LPC/strap register. Bit 1 indicates the
// platform type. OR with 1 to ensure N3 is at least 1.
//
N3 = (*(volatile UINT8 *)0xFDAF0490 & 0x02) | 0x01;
}
// else N3 is 1, 2, or 3: use directly without remapping
//
// Map platform type to debug route value.
// Valid range: N3 - 1 <= 0xFD (check that N3 is not 0 after remap)
//
if ((UINT8)(N3 - 1) <= 0xFD) {
if (N3 == 1) {
DebugRoute = 0x80000004; // EFI_D_INFO route
} else {
DebugRoute = 0x80000006; // EFI_D_VERBOSE route (N3 >= 2)
}
}
//
// If the debug level matches the routing mask, call UBA debug output.
//
if ((DebugRoute & Severity) != 0) {
//
// UBA protocol function index 0 (offset 0x00): DebugPrint
// Signature: VOID (*)(UINTN DebugLevel, CONST CHAR8 *Format, VA_LIST Va)
//
UbaDebugFunc = (UBA_DEBUG_PRINT)(Uba->DebugPrint);
VA_START (Va, Format);
UbaDebugFunc ((UINTN)Severity, Format, (UINT64 *)&Va);
VA_END (Va);
}
}
}
/**
UBA-aware ASSERT replacement.
Locates the UBA protocol interface and calls its DebugAssert function
(offset +0x08 of the protocol interface) with the file name, line number,
and assertion expression. This function never returns.
@param[in] FileName Source file name where the assertion occurred.
@param[in] LineNumber Line number where the assertion occurred.
@param[in] Expression The assertion expression string that failed.
**/
VOID
EFIAPI
UbaDebugAssert (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Expression
)
{
UBA_PROTOCOL *Uba;
UBA_DEBUG_ASSERT UbaAssertFunc;
//
// Get the UBA protocol and call its assertion handler.
// UBA protocol function index 1 (offset 0x08) is the assert handler:
// VOID (*)(UINT64 FileName, UINTN LineNumber, UINT64 Description)
//
Uba = UbaGetProtocolInterface ();
if (Uba != NULL) {
UbaAssertFunc = (UBA_DEBUG_ASSERT)(Uba->DebugAssert);
UbaAssertFunc (
(UINT64)(UINTN)FileName,
LineNumber,
(UINT64)(UINTN)Expression
);
}
}
/**
Reads a UINT64 value from a potentially unaligned memory address.
Wraps the BaseLib ReadUnaligned64 concept with a NULL pointer check.
If Buffer is NULL, an assertion is triggered referencing the standard
MDE library source file.
@param[in] Buffer Pointer to the memory to read. Must not be NULL.
@return UINT64 The 64-bit value at the given address.
**/
UINT64
ReadUnaligned64 (
IN CONST UINT64 *Buffer
)
{
if (Buffer == NULL) {
UbaDebugAssert (
"e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
192,
"Buffer != ((void *) 0)"
);
}
return *(const UINT64 *)Buffer;
}
/**
Checks whether two GUIDs are equal by comparing their 64-bit halves.
Performs a double 64-bit compare rather than a byte-by-byte or 128-bit
compare, reading the GUIDs as two 64-bit values. This is sufficient for
GUID equality checks on x64 where unaligned access is supported.
@param[in] Guid1 Pointer to the first GUID to compare.
@param[in] Guid2 Pointer to the second GUID to compare.
@return TRUE if the GUIDs are equal, FALSE otherwise.
**/
BOOLEAN
IsHobGuidMatch (
IN CONST EFI_GUID *Guid1,
IN CONST EFI_GUID *Guid2
)
{
UINT64 Guid1Low;
UINT64 Guid1High;
UINT64 Guid2Low;
UINT64 Guid2High;
//
// Read each GUID as two 64-bit values (low and high halves)
// and compare. The ReadUnaligned64 wrapper includes NULL checking.
//
Guid1Low = ReadUnaligned64 ((CONST UINT64 *)Guid1);
Guid1High = ReadUnaligned64 ((CONST UINT64 *)((CONST UINT8 *)Guid1 + 8));
Guid2Low = ReadUnaligned64 ((CONST UINT64 *)Guid2);
Guid2High = ReadUnaligned64 ((CONST UINT64 *)((CONST UINT8 *)Guid2 + 8));
return (BOOLEAN)(Guid1Low == Guid2Low && Guid1High == Guid2High);
}
/**
Retrieves the HOB (Hand-Off Block) list pointer by locating the
DXE Services HOB from the system table's configuration table.
Algorithm:
1. Check cached gHobList (return immediately if non-NULL).
2. Read NumberOfTableEntries from SystemTable + 104 (0x68).
3. Read ConfigurationTable pointer from SystemTable + 112 (0x70).
4. Walk the configuration table entries (each 24 bytes):
- Bytes 0-15: EFI_GUID (VendorGuid)
- Bytes 16-23: VOID* (VendorTable)
5. Compare each entry's GUID against gEfiDxeServicesTableGuid
({7739F24C-93D7-11D4-9A3A-0090273FC14D}).
6. Cache and return the matching VendorTable pointer.
If no matching entry is found, triggers UbaDebugAssert and
UbaDebugPrint with the EDK2 HOB library source file reference.
@return VOID* Pointer to the HOB list (VendorTable from config table),
or NULL if no HOB matches the DXE Services GUID.
**/
VOID *
GetHobList (
VOID
)
{
UINTN HobCount;
UINT8 *HobEntries;
UINTN Index;
//
// Return cached HOB list if already located.
//
if (gHobList != NULL) {
return gHobList;
}
gHobList = NULL;
//
// SystemTable + 104 (0x68) = NumberOfTableEntries (UINTN)
// SystemTable + 112 (0x70) = ConfigurationTable (EFI_CONFIGURATION_TABLE *)
//
// EFI_CONFIGURATION_TABLE layout:
// +0: EFI_GUID VendorGuid (16 bytes)
// +16: VOID* VendorTable (8 bytes)
// Total entry size: 24 bytes
//
HobCount = *(UINTN *)((UINT8 *)gSystemTable + 104);
HobEntries = *(UINT8 **)((UINT8 *)gSystemTable + 112);
if (HobCount > 0) {
//
// Walk the configuration table to find the DXE Services HOB entry.
//
for (Index = 0; Index < HobCount; Index++) {
if (IsHobGuidMatch (
(EFI_GUID *)(HobEntries + Index * 24),
&gEfiDxeServicesTableGuid ///< {0x7739F24C, 0x93D7, 0x11D4, ...}
)) {
//
// Found the DXE Services HOB - cache its VendorTable pointer.
//
gHobList = *(VOID **)(HobEntries + Index * 24 + 16);
break;
}
}
if (gHobList == NULL) {
//
// DXE Services HOB not found in config table - report error.
//
UbaDebugPrint (0x80000000LL, "\nASSERT_EFI_ERROR (Status = %r)\n");
UbaDebugAssert (
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
54,
"!EFI_ERROR (Status)"
);
}
}
if (gHobList == NULL) {
//
// HobList is still NULL after scanning all config entries.
// This triggers a CpuDeadLoop (via the UBA assert).
//
UbaDebugAssert (
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
55,
"mHobList != ((void *) 0)"
);
}
return gHobList;
}
/**
Installs PSLT Slot Data entries via the UBA protocol.
This is the main function of the driver (called from _ModuleEntryPoint).
It performs:
1. Prints a debug banner via UbaDebugPrint identifying this module.
2. Locates the UBA protocol via gBS->LocateProtocol().
3. Calls the UBA protocol's Register function (v4+0x10, SetData)
twice with different PSLT configuration entries.
The PSLT entries registered:
- PSLT1 (GUID B93613E1-...): Primary PSLT, 32 bytes from gSlotDataBuffer1
- PSLT2 (GUID 226763AE-...): Extended PSLT, 40 bytes from gSlotDataBuffer2
@return EFI_STATUS Result of the installation. Returns the first error
encountered, or EFI_SUCCESS if all registrations succeed.
**/
EFI_STATUS
InstallSlotData (
VOID
)
{
EFI_STATUS Status;
UBA_PROTOCOL *Uba;
UBA_REGISTER UbaRegister;
//
// Print debug banner identifying this module.
// String: "UBA:SlotDataUpdate-TypeLightningRidgeEXECB2\\n" at 0x7C0
// Severity: 0x80000000 (EFI_D_ERROR is normally ERROR but here used as banner)
//
UbaDebugPrint (0x80000000, "UBA:SlotDataUpdate-TypeLightningRidgeEXECB2\\n");
//
// Locate the UBA protocol interface via LocateProtocol.
// BootServices + 320 (0x140) = LocateProtocol
// GUID: {36232936-0E76-31C8-A13A-3AF2FC1C3932} at 0xB60
// Registration key: NULL
// Output: Uba protocol interface pointer
//
Status = gBootServices->LocateProtocol (
&gUbaProtocolGuid, ///< UBA protocol GUID
NULL, ///< No registration key
(VOID **)&Uba ///< Output protocol pointer
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// UBA protocol function at offset +0x10 (Register): SetData.
// Signature: EFI_STATUS (*)(UBA_PROTOCOL *This, EFI_GUID *Guid,
// VOID *Data, UINTN DataSize)
//
UbaRegister = (UBA_REGISTER)(Uba->RegisterFunc);
//
// Register PSLT Entry 1: Primary slot table with GUID B93613E1-...
// Data: gSlotDataBuffer1 (32 bytes at 0xBC0)
//
Status = UbaRegister (
Uba,
&gUbaSlotDataPsl1Guid, ///< {B93613E1-48F0-4B32-B3A8-4FEDFC7C1365}
(VOID *)&gSlotDataBuffer1, ///< PSLT entry 1 at 0xBC0
32 ///< sizeof(PSLT_HEADER)
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Register PSLT Entry 2: Extended slot config with GUID 226763AE-...
// Data: gSlotDataBuffer2 (40 bytes at 0xBE0)
//
Status = UbaRegister (
Uba,
&gUbaSlotConfigGuid, ///< {226763AE-972C-4E3C-80D1-73B25E8CBBA3}
(VOID *)&gSlotDataBuffer2, ///< PSLT entry 2 at 0xBE0
40 ///< sizeof(SLOT_CONFIG)
);
return Status;
}
/**
UEFI DXE driver entry point.
Called by the DXE Core during driver dispatch. Performs:
1. Caches ImageHandle, SystemTable, BootServices, RuntimeServices.
2. Validates all pointers with UbaDebugAssert NULL checks.
3. Calls GetHobList() to locate the DXE HOB list.
4. Calls InstallSlotData() to register PSLT entries.
@param[in] ImageHandle The firmware-allocated handle for this driver image.
@param[in] SystemTable A pointer to the EFI System Table.
@return EFI_STATUS EFI_SUCCESS on success, or error from
LocateProtocol/RegisterSlotData.
**/
EFI_STATUS
EFIAPI
_ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
UBA_PROTOCOL *Uba;
//
// ========================================================================
// Phase 1: Cache and validate global UEFI pointers
// ========================================================================
//
//
// Save ImageHandle globally and ASSERT if NULL.
//
gImageHandle = ImageHandle;
if (gImageHandle == NULL) {
UbaDebugAssert (
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
51,
"gImageHandle != ((void *) 0)"
);
}
//
// Save SystemTable globally and ASSERT if NULL.
//
gSystemTable = SystemTable;
if (gSystemTable == NULL) {
UbaDebugAssert (
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
57,
"gST != ((void *) 0)"
);
}
//
// Save BootServices pointer from SystemTable and ASSERT if NULL.
//
gBootServices = SystemTable->BootServices;
if (gBootServices == NULL) {
UbaDebugAssert (
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
63,
"gBS != ((void *) 0)"
);
}
//
// Save RuntimeServices pointer from SystemTable and ASSERT if NULL.
//
gRuntimeServices = SystemTable->RuntimeServices;
if (gRuntimeServices == NULL) {
UbaDebugAssert (
"e:\\hs\\MdePkg\\Library\\UefiRuntimeServicesTableLib\\UefiRuntimeServicesTableLib.c",
47,
"gRT != ((void *) 0)"
);
}
//
// ========================================================================
// Phase 2: Initialize HOB list from system table configuration
// ========================================================================
//
// GetHobList() scans SystemTable->ConfigurationTable for
// gEfiDxeServicesTableGuid ({7739F24C-93D7-11D4-...}) and caches
// the associated VendorTable pointer in gHobList.
//
GetHobList ();
//
// ========================================================================
// Phase 3: Register platform slot data with UBA protocol
// ========================================================================
//
// InstallSlotData() does the following:
// 1. Prints "UBA:SlotDataUpdate-TypeLightningRidgeEXECB2\\n" banner
// 2. Locates UBA protocol via LocateProtocol ({36232936-0E76-31C8-...})
// 3. Registers PSLT entry 1 with Register(GUID_B936..., data_BC0, 32)
// 4. Registers PSLT entry 2 with Register(GUID_2267..., data_BE0, 40)
//
Status = InstallSlotData ();
return Status;
}