/** @file
Setup Configuration Update driver for NeonCity EP EC B platform.
This DXE driver implements the platform-specific setup configuration update
for the NeonCity EP EC B platform. It registers a setup configuration
protocol data structure via the UBA (Universal BIOS Architecture) board-type
protocol.
The driver follows the standard UBA SetupConfigUpdate pattern:
1. Caches UEFI globals (ImageHandle, SystemTable, BootServices, RuntimeServices)
2. Locates the HOB list for platform configuration
3. Logs the driver start via UBA debug protocol
4. Locates the UBA board-type protocol
5. Calls the protocol's RegisterSetupConfig function to publish the
platform-specific setup configuration data
Copyright (c) 2020-2023, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "SetupConfigUpdateDxeNeonCityEPECB.h"
//
// ============================================================================
// Module-Level Global Variables (.data section layout)
// ============================================================================
//
// These global variables occupy memory in the .data section at fixed offsets.
// They are accessed directly by the compiled code via RIP-relative addressing.
//
// Address Name Description
// ------- ---- -----------
// 0xB40 mDebugProtocolGuid UBA Debug Protocol GUID
// 0xB50 mUbaBoardTypeProtocolGuid UBA Board-Type Protocol GUID
// 0xB60 mEfiHobListGuid EFI HOB List GUID
// 0xB68 mEfiHobListGuidSecondHalf Second 8 bytes of HOB List GUID
// 0xB70 mUbaSetupConfigGuid UBA Setup Config Protocol GUID
// 0xB80 mSetupConfigData UBA_SETUP_CONFIG_DATA structure
// 0xBA0 gBS_global Cached BootServices pointer
// 0xBA8 gImageHandle_global Cached ImageHandle
// 0xBB0 gRT_global Cached RuntimeServices pointer
// 0xBB8 mDebugProtocol Cached Debug Protocol interface
// 0xBC0 mHobList Cached HOB List pointer
// 0xBC8 mCmosDebugLevel Cached CMOS debug level
// 0xB98 gST_global Cached SystemTable pointer
//
//
// UBA Debug Protocol GUID
//
EFI_GUID mDebugProtocolGuid = UBA_DEBUG_PROTOCOL_GUID;
//
// UBA Board-Type Protocol GUID for NeonCity EP EC B
//
EFI_GUID mUbaBoardTypeProtocolGuid = UBA_BOARD_TYPE_PROTOCOL_GUID;
//
// EFI HOB List GUID - used to locate the HOB list from the system
// configuration table. The GUID is split into two 64-bit halves for
// the optimized comparison in IsHobListGuid().
// First 8 bytes: 0x11D493D77739F24C (GUID.Data1 + Data2 + Data3 high)
// Second 8 bytes: 0x4DC13F2700903A9A (GUID.Data3 low + Data4)
//
EFI_GUID mEfiHobListGuid = EFI_HOB_LIST_GUID;
//
// UBA Setup Config Protocol GUID for NeonCity EP EC B
//
EFI_GUID mUbaSetupConfigGuid = UBA_SETUP_CONFIG_PROTOCOL_GUID;
//
// Setup Configuration Data block.
// Signature "PSET" (Platform SETup), Version 1, DataSize 0x48C (1164 bytes).
// This data is provided to the setup engine via the board-type protocol.
//
UBA_SETUP_CONFIG_DATA mSetupConfigData = {
{ 'P', 'S', 'E', 'T' }, // Signature
1, // Version
0x48C, // DataSize
0x48C // DataSize2 (duplicate)
};
//
// Cached UEFI global pointers.
//
EFI_HANDLE *gImageHandle_global = NULL; // 0xBA8
EFI_SYSTEM_TABLE *gST_global = NULL; // 0xB98
EFI_BOOT_SERVICES *gBS_global = NULL; // 0xBA0
EFI_RUNTIME_SERVICES *gRT_global = NULL; // 0xBB0
//
// Cached protocol and data pointers.
//
VOID *mDebugProtocol = NULL; // 0xBB8 - Cached Debug Protocol
VOID *mHobList = NULL; // 0xBC0 - Cached HOB List
UINT8 mCmosDebugLevel = 0; // 0xBC8 - Cached CMOS Debug Level
// ============================================================================
// Function Implementations
// ============================================================================
/**
Returns the UEFI status code for "Not Found".
This is a simple helper that returns a constant. It is used in contexts
where a function pointer returning EFI_STATUS is needed.
@return EFI_NOT_FOUND (0x800000000000000E).
**/
UINT64
EFIAPI
ReturnNotFound (
VOID
)
{
return EFI_NOT_FOUND;
}
/**
Retrieves the UBA Debug Protocol interface.
Attempts to locate the UBA Debug Protocol via gBS->LocateProtocol().
Before doing so, performs a small pool allocation test to verify that
the UEFI boot services are functioning correctly.
The result is cached in mDebugProtocol for subsequent calls.
@return Pointer to the UBA Debug Protocol interface, or NULL if not found.
**/
UINT64 *
GetDebugProtocol (
VOID
)
{
UINTN PoolSize;
UINT64 *Protocol;
//
// Return cached value if already resolved.
//
Protocol = mDebugProtocol;
if (Protocol != NULL) {
return Protocol;
}
//
// Allocate a small buffer (31 bytes = EfiBootServicesData pool type index)
// and immediately free it. This validates that boot services are operational.
// If the returned pointer value is > 0x10, the environment may not support
// protocol lookup.
//
PoolSize = (UINTN)gBS_global->AllocatePool (EfiBootServicesData, 31);
gBS_global->FreePool ((VOID *)PoolSize);
if (PoolSize <= 0x10) {
//
// Valid UEFI environment. Locate the UBA Debug Protocol.
//
gBS_global->LocateProtocol (
&mDebugProtocolGuid,
NULL,
&mDebugProtocol
);
//
// Cache the result (or NULL if not found).
//
Protocol = mDebugProtocol;
if (Protocol == NULL) {
mDebugProtocol = NULL;
return NULL;
}
} else {
mDebugProtocol = NULL;
return NULL;
}
return Protocol;
}
/**
Debug assertion handler via UBA Debug Protocol.
Calls the assertion function (at offset 0x08 in the protocol interface)
of the UBA Debug Protocol to report a failed assertion.
@param[in] FileName Pointer to the source file name string.
@param[in] LineNumber Line number where the assertion occurred.
@param[in] Description Pointer to the description of the failed assertion.
@return The return value from the protocol assertion handler, or 0 if the
protocol is not available.
**/
UINTN
DebugAssert (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
)
{
UINT64 *Protocol;
Protocol = GetDebugProtocol ();
if (Protocol != NULL) {
//
// Call the assertion handler at protocol offset 0x08.
// Args: rcx = FileName, rdx = LineNumber, r8 = Description
//
return ((UBA_DEBUG_PROTOCOL *)Protocol)->DebugAssert (
FileName,
LineNumber,
Description
);
}
return 0;
}
/**
Debug print function via UBA Debug Protocol.
This function resolves the UBA Debug Protocol and, if the requested
error level is enabled by the CMOS debug level configuration, calls
the protocol's print function.
The CMOS debug level is read from RTC port 0x70/0x71 at register index
0x4B. The level determines which debug messages are filtered:
- Level 0: Fallback to MMIO board config register 0xFDAF0490
- Level 1: Filter mask = 0x80000004 (DEBUG_INIT | DEBUG_INFO)
- Level >1: Filter mask = 0x80000046 (DEBUG_INIT | DEBUG_WARN |
DEBUG_ERROR | DEBUG_INFO)
- Level >3: Use cached value or board config fallback
@param[in] ErrorLevel Debug error level mask.
@param[in] Format Format string for the debug message.
@param[in] ... Variable arguments for the format string.
@return The return value from the protocol print function, or 0.
**/
UINTN
EFIAPI
DebugPrint (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
UINT64 *Protocol;
UINTN Result;
UINT8 CmosValue;
UINT8 DebugLevel;
UINT32 DebugMask;
VA_LIST VaList;
VA_START (VaList, Format);
//
// Get the UBA Debug Protocol interface.
//
Protocol = GetDebugProtocol ();
Result = 0;
if (Protocol != NULL) {
//
// Read the current CMOS index register, preserving bit 7 (NMI enable).
// Select CMOS register index 0x4B for the debug level.
//
CmosValue = IoRead8 (RTC_INDEX_PORT);
CmosValue = (CmosValue & 0x80) | CMOS_DEBUG_LEVEL_REGISTER;
IoWrite8 (RTC_INDEX_PORT, CmosValue);
//
// Read the debug level from CMOS data port 0x71.
//
DebugLevel = IoRead8 (RTC_DATA_PORT);
//
// Determine the effective debug level.
//
if (DebugLevel > 3) {
//
// Level > 3 means the raw value is not a simple level encoding.
// Use the cached value.
//
DebugLevel = mCmosDebugLevel;
if (DebugLevel == 0) {
//
// Fallback: read board configuration from MMIO register 0xFDAF0490.
// Bit 1 indicates the board type, and bit 0 is always set.
//
DebugLevel = (MmioRead32 (BOARD_CONFIG_MMIO_ADDR) & 2) | 1;
}
}
//
// Calculate the debug mask from the level.
// Level must be >= 1 and level - 1 <= 0xFD.
//
if ((DebugLevel > 0) && ((DebugLevel - 1) <= 0xFD)) {
//
// Map platform ID to debug filter mask.
// Level 1: mask = 0x80000004 (DEBUG_INIT | DEBUG_INFO)
// Level >1: mask = 0x80000046 (multiple debug flags)
//
if (DebugLevel == 1) {
DebugMask = 0x80000004;
} else {
DebugMask = 0x80000046;
}
//
// If the requested ErrorLevel is enabled by the mask, call the
// protocol's print function at offset 0x00.
//
if ((DebugMask & ErrorLevel) != 0) {
Result = ((UBA_DEBUG_PROTOCOL *)Protocol)->DebugPrint (
ErrorLevel,
Format,
VaList
);
}
}
}
return Result;
}
/**
Locates the HOB (Hand-Off Block) list from the UEFI System Table.
Scans SystemTable->ConfigurationTable[] for an entry whose VendorGuid
matches EFI_HOB_LIST_GUID. The comparison is done by splitting the
16-byte GUID into two 8-byte halves.
The result is cached in mHobList for subsequent calls.
@return Pointer to the HOB list, or NULL if not found.
**/
VOID *
GetHobList (
VOID
)
{
UINTN Index;
UINTN TableCount;
EFI_CONFIGURATION_TABLE *ConfigTable;
//
// Return cached value if already resolved.
//
if (mHobList != NULL) {
return mHobList;
}
//
// Initialize to NULL.
//
mHobList = NULL;
//
// Check if there are configuration table entries.
//
TableCount = gST_global->NumberOfTableEntries;
if (TableCount > 0) {
//
// Get pointer to the configuration table array.
//
ConfigTable = gST_global->ConfigurationTable;
for (Index = 0; Index < TableCount; Index++) {
//
// Compare the current entry's VendorGuid against EFI_HOB_LIST_GUID.
//
if (IsHobListGuid (&ConfigTable[Index].VendorGuid)) {
//
// Found the HOB list. Extract the VendorTable pointer.
//
mHobList = ConfigTable[Index].VendorTable;
return mHobList;
}
}
}
//
// HOB list not found. Raise ASSERT_EFI_ERROR.
//
DebugPrint (0x80000000, L"\nASSERT_EFI_ERROR (Status = %r)\n", EFI_NOT_FOUND);
DebugAssert (
L"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
54,
L"!EFI_ERROR (Status)"
);
//
// If mHobList is still NULL, raise another assertion.
//
if (mHobList == NULL) {
DebugAssert (
L"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
55,
L"mHobList != ((void *) 0)"
);
}
return mHobList;
}
/**
Compares a given GUID against the EFI HOB List GUID.
The comparison uses two 8-byte unaligned reads (via ReadUnaligned64)
to compare the GUID halves independently, rather than a full 16-byte
EFI_GUID comparison.
@param[in] GuidPtr Pointer to the EFI_GUID to compare.
@retval TRUE The GUID matches EFI_HOB_LIST_GUID.
@retval FALSE The GUID does not match.
**/
BOOLEAN
IsHobListGuid (
IN EFI_GUID *GuidPtr
)
{
//
// Compare first 8 bytes of the GUID against the first half of the
// cached EFI_HOB_LIST_GUID.
//
if (ReadUnaligned64 (&mEfiHobListGuid) != ReadUnaligned64 (GuidPtr)) {
return FALSE;
}
//
// Compare second 8 bytes of the GUID (at offset 8).
//
return ReadUnaligned64 ((UINT8 *)&mEfiHobListGuid + 8) ==
ReadUnaligned64 ((UINT8 *)GuidPtr + 8);
}
/**
Reads an unaligned 64-bit value from memory.
Wraps a simple volatile memory read with a NULL pointer check.
@param[in] Buffer Pointer to the memory to read. Must not be NULL.
@return The 64-bit value read from the given address.
**/
UINT64
ReadUnaligned64 (
IN CONST VOID *Buffer
)
{
if (Buffer == NULL) {
DebugAssert (
L"e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
192,
L"Buffer != ((void *) 0)"
);
}
return *(volatile UINT64 *)Buffer;
}
/**
Module entry point for SetupConfigUpdateDxeNeonCityEPECB.
This function initializes the driver by:
1. Caching UEFI global pointers with assertion checks.
2. Locating the HOB list.
3. Logging driver initialization via UBA debug protocol.
4. Locating the UBA board-type protocol for NeonCity EP EC B.
5. Calling RegisterSetupConfig to publish the setup configuration data.
@param[in] ImageHandle The firmware-allocated handle for this driver image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The setup config data was registered.
@retval EFI_INVALID_PARAMETER A required parameter was NULL.
@retval Others Error from LocateProtocol if the UBA
board-type protocol is not available.
**/
EFI_STATUS
EFIAPI
SetupConfigUpdateDxeNeonCityEPECBEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
UBA_BOARD_TYPE_PROTOCOL *BoardProtocol;
//
// Cache ImageHandle with assertion check.
//
gImageHandle_global = (EFI_HANDLE *)ImageHandle;
if (ImageHandle == NULL) {
DebugAssert (
L"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
51,
L"gImageHandle != ((void *) 0)"
);
}
//
// Cache SystemTable with assertion check.
//
gST_global = SystemTable;
if (SystemTable == NULL) {
DebugAssert (
L"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
57,
L"gST != ((void *) 0)"
);
}
//
// Cache BootServices from SystemTable with assertion check.
//
gBS_global = SystemTable->BootServices;
if (gBS_global == NULL) {
DebugAssert (
L"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
63,
L"gBS != ((void *) 0)"
);
}
//
// Cache RuntimeServices from SystemTable with assertion check.
//
gRT_global = SystemTable->RuntimeServices;
if (gRT_global == NULL) {
DebugAssert (
L"e:\\hs\\MdePkg\\Library\\UefiRuntimeServicesTableLib\\UefiRuntimeServicesTableLib.c",
47,
L"gRT != ((void *) 0)"
);
}
//
// Locate the HOB list from the system configuration table.
//
GetHobList ();
//
// Print debug banner.
//
DebugPrint (0x80000000, L"UBA:SETUPConfigUpdate-TypeNeonCityEPECB\n");
//
// Locate the UBA board-type protocol.
//
BoardProtocol = NULL;
Status = gBS_global->LocateProtocol (
&mUbaBoardTypeProtocolGuid,
NULL,
(VOID **)&BoardProtocol
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Call the board-type protocol's RegisterSetupConfig function.
// This registers the setup configuration GUID and data block for
// the NeonCity EP EC B platform.
//
return BoardProtocol->RegisterSetupConfig (
BoardProtocol,
&mUbaSetupConfigGuid,
&mSetupConfigData,
sizeof (UBA_SETUP_CONFIG_DATA)
);
}