/** @file
StaticSkuDataDxeLightningRidgeEXECB4 - Static SKU Data Driver
Provides LightningRidge EX EC B4 platform-specific static data tables
for the UBA (Unified BIOS Abstraction) protocol. The driver registers
ACPI name-to-path mappings for NVDIMM NVDR devices N011 and N020,
enabling the platform policy layer to resolve control method paths at
runtime under the _SB_.NVDR namespace.
Each NVDR device publishes eight ACPI methods:
FXCD - Flex Capacity Data
FXST - Flex Status
FXIN - Flex Input
FXOU - Flex Output
FXBS - Flex Buffer Status
FXFH - Flex Flush
CENA - Capability Enable
CFIS - Capability Status
Copyright (c) 2024, Dell Technologies. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/IoLib.h>
#include "StaticSkuDataDxeLightningRidgeEXECB4.h"
//
// ---------------------------------------------------------------------------
// GUID definitions for the UBA protocol and HOB matching.
// These GUIDs are consumed by the entry point but defined in the platform
// BDS / UBA DXE driver package.
// ---------------------------------------------------------------------------
extern EFI_GUID gPlatformUbaProtocolGuid;
extern EFI_GUID gUbaNvdrProtocolGuid;
extern EFI_GUID gHobTargetGuidHi;
extern EFI_GUID gHobTargetGuidLo;
//
// ---------------------------------------------------------------------------
// Module globals
// ---------------------------------------------------------------------------
EFI_HANDLE gImageHandle = NULL;
EFI_SYSTEM_TABLE *gSystemTable = NULL;
EFI_BOOT_SERVICES *gBootServices = NULL;
EFI_RUNTIME_SERVICES *gRuntimeServices = NULL;
STATIC VOID *mSkuProtocol = NULL; ///< Cached UBA protocol
STATIC VOID *mHobList = NULL; ///< Cached HOB list
//
// ---------------------------------------------------------------------------
// UBA protocol function-table offsets
// ---------------------------------------------------------------------------
#define UBA_OFFSET_DEBUG_PRINT 0
#define UBA_OFFSET_ASSERT 8
#define UBA_OFFSET_INSTALL_DATA 16
//
// ---------------------------------------------------------------------------
// UBA protocol dispatch-table function type definitions
// ---------------------------------------------------------------------------
/**
DebugPrint routine in the UBA protocol.
@param[in] ErrorLevel Debug message error level.
@param[in] Format Print format string.
@param[in] VaList Variable argument list.
@return Number of characters printed, or implementation-defined.
**/
typedef
UINTN
(EFIAPI *UBA_DEBUG_PRINT)(
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
VA_LIST VaList
);
/**
Assert routine in the UBA protocol.
@param[in] FileName Source file name.
@param[in] LineNumber Assertion line number.
@param[in] Description Assertion description.
**/
typedef
VOID
(EFIAPI *UBA_ASSERT)(
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
);
//
// ---------------------------------------------------------------------------
// ACPI name-path entry layout
//
// Each entry occupies 32 bytes:
// [0..3] 4-character ACPI method name
// [4..7] zero padding
// [8..31] Full ACPI path string (null-terminated, zero-padded to 24 bytes)
// ---------------------------------------------------------------------------
#define ACPI_ENTRY_SIZE 32
//
// NVDR Device N011 -- Socket 0, Channel 3
//
STATIC CONST UINT8 mN011AcpiEntries[8 * ACPI_ENTRY_SIZE] = {
'F','X','C','D', 0,0,0,0, '_','S','B','_','.','N','V','D','R','.','N','0','1','1','.','F','X','C','D',0,0,0,0,0,
'F','X','S','T', 0,0,0,0, '_','S','B','_','.','N','V','D','R','.','N','0','1','1','.','F','X','S','T',0,0,0,0,0,
'F','X','I','N', 0,0,0,0, '_','S','B','_','.','N','V','D','R','.','N','0','1','1','.','F','X','I','N',0,0,0,0,0,
'F','X','O','U', 0,0,0,0, '_','S','B','_','.','N','V','D','R','.','N','0','1','1','.','F','X','O','U',0,0,0,0,0,
'F','X','B','S', 0,0,0,0, '_','S','B','_','.','N','V','D','R','.','N','0','1','1','.','F','X','B','S',0,0,0,0,0,
'F','X','F','H', 0,0,0,0, '_','S','B','_','.','N','V','D','R','.','N','0','1','1','.','F','X','F','H',0,0,0,0,0,
'C','E','N','A', 0,0,0,0, '_','S','B','_','.','N','V','D','R','.','N','0','1','1','.','C','E','N','A',0,0,0,0,
'C','F','I','S', 0,0,0,0, '_','S','B','_','.','N','V','D','R','.','N','0','1','1','.','C','F','I','S',0,0,0,0,
};
//
// NVDR Device N020 -- Socket 0, Channel 4
//
STATIC CONST UINT8 mN020AcpiEntries[8 * ACPI_ENTRY_SIZE] = {
'F','X','C','D', 0,0,0,0, '_','S','B','_','.','N','V','D','R','.','N','0','2','0','.','F','X','C','D',0,0,0,0,0,
'F','X','S','T', 0,0,0,0, '_','S','B','_','.','N','V','D','R','.','N','0','2','0','.','F','X','S','T',0,0,0,0,0,
'F','X','I','N', 0,0,0,0, '_','S','B','_','.','N','V','D','R','.','N','0','2','0','.','F','X','I','N',0,0,0,0,0,
'F','X','O','U', 0,0,0,0, '_','S','B','_','.','N','V','D','R','.','N','0','2','0','.','F','X','O','U',0,0,0,0,0,
'F','X','B','S', 0,0,0,0, '_','S','B','_','.','N','V','D','R','.','N','0','2','0','.','F','X','B','S',0,0,0,0,0,
'F','X','F','H', 0,0,0,0, '_','S','B','_','.','N','V','D','R','.','N','0','2','0','.','F','X','F','H',0,0,0,0,0,
'C','E','N','A', 0,0,0,0, '_','S','B','_','.','N','V','D','R','.','N','0','2','0','.','C','E','N','A',0,0,0,0,
'C','F','I','S', 0,0,0,0, '_','S','B','_','.','N','V','D','R','.','N','0','2','0','.','C','F','I','S',0,0,0,0,
};
//
// ---------------------------------------------------------------------------
// ReadUnaligned64
// ---------------------------------------------------------------------------
UINT64
EFIAPI
ReadUnaligned64 (
IN CONST UINT64 *Buffer
)
{
ASSERT (Buffer != NULL);
return *Buffer;
}
//
// ---------------------------------------------------------------------------
// GuidCompareByPair
//
// Compares two EFI_GUID values by splitting each into two UINT64 words.
// This matches the code pattern used in the original binary.
// ---------------------------------------------------------------------------
BOOLEAN
EFIAPI
GuidCompareByPair (
IN EFI_GUID *Guid1,
IN EFI_GUID *Guid2
)
{
UINT64 W1, W2, W3, W4;
W1 = ReadUnaligned64 ((UINT64 *)Guid1);
W2 = ReadUnaligned64 ((UINT64 *)((UINT8 *)Guid1 + 8));
W3 = ReadUnaligned64 ((UINT64 *)Guid2);
W4 = ReadUnaligned64 ((UINT64 *)((UINT8 *)Guid2 + 8));
return (BOOLEAN)(W1 == W3 && W2 == W4);
}
//
// ---------------------------------------------------------------------------
// LocateUbaProtocol
//
// Finds the UBA protocol via BootServices->LocateProtocol and caches the
// result. Before the lookup, the function probes memory availability by
// allocating and immediately freeing a small pool.
// ---------------------------------------------------------------------------
STATIC
VOID *
LocateUbaProtocol (
VOID
)
{
EFI_STATUS Status;
UINT64 PoolSize;
VOID *Pool;
if (mSkuProtocol != NULL) {
return mSkuProtocol;
}
//
// Memory-probe: allocate and immediately free a small pool.
//
PoolSize = 0x1F;
Pool = NULL;
gBootServices->AllocatePool (EfiBootServicesData, (UINTN)PoolSize, &Pool);
if (Pool != NULL) {
gBootServices->FreePool (Pool);
}
//
// If the pool was small enough (<= 0x10), proceed to look up the protocol.
//
if (PoolSize <= 0x10) {
Status = gBootServices->LocateProtocol (
&gPlatformUbaProtocolGuid,
NULL,
&mSkuProtocol
);
if (EFI_ERROR (Status)) {
mSkuProtocol = NULL;
}
}
return mSkuProtocol;
}
//
// ---------------------------------------------------------------------------
// UbaAssert
//
// Dispatches an assertion through the UBA protocol's assert routine at
// offset +8.
// ---------------------------------------------------------------------------
VOID
EFIAPI
UbaAssert (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
)
{
VOID *Protocol;
UBA_ASSERT AssertRoutine;
Protocol = LocateUbaProtocol ();
if (Protocol != NULL) {
AssertRoutine = *(UBA_ASSERT *)((UINT8 *)Protocol + UBA_OFFSET_ASSERT);
if (AssertRoutine != NULL) {
AssertRoutine (FileName, LineNumber, Description);
}
}
}
//
// ---------------------------------------------------------------------------
// UbaDebugPrint
//
// Conditionally prints a debug message via the UBA protocol's debug print
// routine at offset +0. The decision is based on the platform type read
// from CMOS scratch register 0x4B.
//
// CMOS 0x4B platform type detection:
// - Values 1..3 are direct platform identifiers.
// - Value 0 falls back to MMIO at 0xFDAF0490.
// - Platform type 1 uses error mask 0x80000004; others use 0x80000006.
// ---------------------------------------------------------------------------
UINTN
EFIAPI
UbaDebugPrint (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
VOID *Protocol;
UBA_DEBUG_PRINT DebugRoutine;
UINT8 PlatformByte;
UINTN Result;
VA_LIST VaList;
VA_START (VaList, Format);
Result = 0;
Protocol = LocateUbaProtocol ();
if (Protocol == NULL) {
VA_END (VaList);
return Result;
}
//
// Select CMOS index 0x4B (preserve bit 7 of port 0x70).
//
IoWrite8 (0x70, (IoRead8 (0x70) & 0x80) | 0x4B);
PlatformByte = IoRead8 (0x71);
//
// Normalise: values > 3 that are also 0 need the MMIO fallback.
//
if (PlatformByte > 3) {
if (PlatformByte == 0) {
PlatformByte = (MmioRead8 (0xFDAF0490) & 2) | 1;
}
}
//
// Map platform byte -> acceptable error-level mask.
//
if ((UINT8)(PlatformByte - 1) <= 0xFD) {
if (PlatformByte == 1) {
Result = 0x80000004;
} else {
Result = 0x80000006;
}
}
//
// Forward call if the mask matches the caller's ErrorLevel.
//
if ((Result & ErrorLevel) != 0) {
DebugRoutine = *(UBA_DEBUG_PRINT *)((UINT8 *)Protocol + UBA_OFFSET_DEBUG_PRINT);
if (DebugRoutine != NULL) {
Result = DebugRoutine (ErrorLevel, Format, VaList);
}
}
VA_END (VaList);
return Result;
}
//
// ---------------------------------------------------------------------------
// FindHobList
//
// Scans the system table's configuration table for a GUID pair that matches
// the HOB list GUID. When found, the pointer at offset +16 is returned as
// the HOB list.
// ---------------------------------------------------------------------------
STATIC
VOID *
FindHobList (
IN EFI_HANDLE ImageHandle
)
{
UINTN Index;
if (mHobList != NULL) {
return mHobList;
}
if (gSystemTable->NumberOfTableEntries == 0) {
goto NoHob;
}
for (Index = 0; Index < gSystemTable->NumberOfTableEntries; Index++) {
EFI_GUID *EntryGuid;
EFI_GUID TargetGuid;
EntryGuid = (EFI_GUID *)(
(UINT8 *)gSystemTable->ConfigurationTable +
Index * sizeof (EFI_CONFIGURATION_TABLE)
);
//
// Reconstruct the target GUID from the two module-embedded UINT64 values.
//
TargetGuid.Data1 = ReadUnaligned64 ((UINT64 *)&gHobTargetGuidHi);
TargetGuid.Data2 = ReadUnaligned64 ((UINT64 *)&gHobTargetGuidLo);
if (GuidCompareByPair (EntryGuid, &TargetGuid)) {
mHobList = *(VOID **)((UINT8 *)EntryGuid + 16);
break;
}
}
NoHob:
if (mHobList == NULL) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", EFI_NOT_FOUND));
ASSERT (!EFI_ERROR (EFI_NOT_FOUND));
ASSERT (mHobList != NULL);
}
return mHobList;
}
//
// ---------------------------------------------------------------------------
// GetAcpiPathPointers
//
// Returns three pointers into the ACPI path entry tables:
// *N011CenaEntry -> mN011AcpiEntries[6 * 32] ("_SB_.NVDR.N011.CENA")
// *N011FxBsEntry -> mN011AcpiEntries[4 * 32] ("_SB_.NVDR.N011.FXBS")
// *N020FxStEntry -> mN020AcpiEntries[1 * 32] ("_SB_.NVDR.N020.FXST")
// ---------------------------------------------------------------------------
EFI_STATUS
EFIAPI
GetAcpiPathPointers (
OUT UINT8 **N011CenaEntry,
OUT UINT8 **N011FxBsEntry,
OUT UINT8 **N020FxStEntry
)
{
*N011CenaEntry = (UINT8 *)&mN011AcpiEntries[6 * ACPI_ENTRY_SIZE];
*N011FxBsEntry = (UINT8 *)&mN011AcpiEntries[4 * ACPI_ENTRY_SIZE];
*N020FxStEntry = (UINT8 *)&mN020AcpiEntries[1 * ACPI_ENTRY_SIZE];
return EFI_SUCCESS;
}
//
// ---------------------------------------------------------------------------
// Entry Point
// ---------------------------------------------------------------------------
EFI_STATUS
EFIAPI
StaticSkuDataDxeEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
UINT64 Interface;
UINT8 *Table0;
UINT8 *Table1;
UINT8 *Table2;
//
// 1. Initialise global service table pointers.
//
gImageHandle = ImageHandle;
ASSERT (gImageHandle != NULL);
gSystemTable = SystemTable;
ASSERT (gSystemTable != NULL);
gBootServices = SystemTable->BootServices;
ASSERT (gBootServices != NULL);
gRuntimeServices = SystemTable->RuntimeServices;
ASSERT (gRuntimeServices != NULL);
//
// 2. Locate the HOB list.
//
FindHobList (ImageHandle);
//
// 3. Register this platform by sending a debug-print via UBA.
//
UbaDebugPrint (0x80000000, "UBA:UsbOcUpdate-TypeLightningRidgeEXECB4\n");
//
// 4. Locate the UBA protocol and install the ACPI path data.
//
Interface = 0;
Status = gBootServices->LocateProtocol (
&gUbaNvdrProtocolGuid,
NULL,
(VOID **)&Interface
);
if (!EFI_ERROR (Status)) {
GetAcpiPathPointers (&Table0, &Table1, &Table2);
//
// Invoke InstallData at offset +16 in the protocol dispatch table.
// Signature: (This, Table0, Table1, Size = 16)
//
Status = ((EFI_STATUS (EFIAPI *)(UINT64, UINT8 *, UINT8 *, UINTN))(
(UINT8 *)Interface + UBA_OFFSET_INSTALL_DATA
))(
Interface,
Table0,
Table1,
16
);
}
return Status;
}