/** @file
SmbiosDataUpdateDxeLightningRidgeEXECB4 - SMBIOS Data Update DXE Driver
This UEFI DXE driver provides SMBIOS data table update functionality for
the LightningRidge EX EC B4 platform. It installs ACPI processor-to-ID
mapping tables and PIRQ routing data as SMBIOS protocol notifications.
The module performs the following:
- Initializes standard UEFI boot/runtime services
- Locates the SMBIOS HOB list from the system configuration
- Installs protocol notifications for ACPI processor ID mapping
- Installs protocol notifications for PIRQ routing data
- Provides debug output support via the system debug protocol
The ACPF (ACPI Processor ID Mapping) table at 0x9020 defines the mapping
between physical processor packages/cores and ACPI processor IDs used for
the LightningRidge platform's EX EC B4 configuration.
Copyright (c) 2025, Insyde Software Corp. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "SmbiosDataUpdateDxeLightningRidgeEXECB4.h"
//
// Global UEFI system table pointers
//
EFI_HANDLE gImageHandle = NULL; ///< Pointer to 0xF550
EFI_SYSTEM_TABLE *gST = NULL; ///< Pointer to 0xF540
EFI_BOOT_SERVICES *gBS = NULL; ///< Pointer to 0xF548
EFI_RUNTIME_SERVICES *gRT = NULL; ///< Pointer to 0xF558
//
// HOB list pointer - cached after first retrieval
//
EFI_PHYSICAL_ADDRESS mHobList = 0; ///< Pointer to 0xF568
//
// Debug protocol interface - cached after first retrieval
//
VOID *mDebugProtocol = NULL; ///< Pointer to 0xF560
//
// CMOS platform type register
//
STATIC UINT8 mCmosPlatformType = 0; ///< Pointer to 0xF570
//
// ACPF (ACPI Processor ID Mapping) table
// Signature: 'ACPF' (0x41435046)
// Version: 1
// This table maps physical processor packages/cores to ACPI processor IDs.
//
STATIC CONST ACPF_TABLE_HEADER mAcpfTable = {
.Signature = SIGNATURE_32 ('A', 'C', 'P', 'F'), ///< 'ACPF'
.Version = 1,
.Size = 0x4100, ///< Total table size
.Reserved = 0,
.OemId = 0xE377C07E515899AEULL, ///< Platform OEM identifier
.EntryCount = 0x3B, ///< 59 entries
};
//
// SMBIOS update context table for ACPI processor ID mapping.
// Contains the list of data regions to update in SMBIOS.
//
STATIC CONST SMBIOS_UPDATE_CONTEXT_TABLE mProcIdContextTable = {
.Version = 1,
.EntryCount = 0x3B, ///< 59 entries in the following array
};
//
// NOTE: The actual ACPI processor ID map entries and PIRQ routing data
// follow at runtime-relative addresses 0x9040 and 0x90C8 respectively.
// These structures are installed via protocol notifications in the
// entry point.
//
/**
Locates the debug display protocol instance.
Attempts to locate the debug protocol (identified by GUID at 0x4080)
using the UEFI Boot Services. Allocates a pool of at least 0x10 bytes
and if the allocation succeeds, tries to locate the protocol interface.
@return Pointer to the debug protocol interface on success.
@return NULL if the protocol could not be located or memory is insufficient.
**/
VOID *
LocateDebugProtocol (
VOID
)
{
EFI_STATUS Status;
VOID *Interface;
UINT64 PoolSize;
//
// Return cached protocol if already located
//
if (mDebugProtocol != NULL) {
return mDebugProtocol;
}
//
// Check available pool size; require at least 0x10 bytes
//
PoolSize = gBS->GetMemoryMap (&gBS->Hdr.Size, NULL, NULL, NULL, NULL);
if (PoolSize > 0x10) {
return NULL;
}
//
// Locate the debug protocol by its GUID
//
Interface = NULL;
Status = gBS->LocateProtocol (
&gDebugProtocolGuid, ///< GUID pointer (0x4080)
NULL,
&Interface
);
if (EFI_ERROR (Status)) {
Interface = NULL;
}
mDebugProtocol = Interface;
return Interface;
}
/**
Displays a debug message via the debug protocol.
Reads the CMOS platform type register (0x70 index 0x4B) to determine
the current platform configuration, then checks whether the given
message mask matches the current platform type before calling the
debug protocol output function.
On a single-socket platform (platform type == 1), messages with the
ASSERT_OUTPUT_MASK are allowed. On all other valid platforms, messages
with the DEBUG_OUTPUT_MASK are allowed.
@param[in] Mask Debug message classification mask.
@param[in] Format Format string for the debug message.
@param[in] ... Variable arguments for the format string.
@return TRUE if the message was displayed.
@return FALSE if the message was suppressed or the protocol was unavailable.
**/
BOOLEAN
DebugPrint (
IN UINTN Mask,
IN CONST CHAR8 *Format,
...
)
{
VOID *Protocol;
UINT8 PlatformType;
UINTN AllowedMask;
BOOLEAN Result;
VA_LIST Marker;
Protocol = LocateDebugProtocol ();
if (Protocol == NULL) {
return FALSE;
}
//
// Read the platform type from CMOS register 0x4B
//
PlatformType = IoRead8 (CMOS_INDEX_REGISTER);
IoWrite8 (CMOS_INDEX_REGISTER, PlatformType & 0x80 | CMOS_STATUS_REGISTER);
PlatformType = IoRead8 (CMOS_DATA_REGISTER);
//
// Filter messages based on platform type
//
mCmosPlatformType = PlatformType;
if (PlatformType > 3) {
//
// Read platform type from alternate location
//
if (PlatformType == 0) {
PlatformType = (*(volatile UINT8 *)(UINTN)0xFDAF0490) & 2 | 1;
}
}
Result = FALSE;
AllowedMask = 0;
if ((PlatformType - 1) <= 0xFD) {
AllowedMask = DEBUG_OUTPUT_MASK;
if (PlatformType == 1) {
AllowedMask = ASSERT_OUTPUT_MASK;
}
}
//
// If the message mask matches the allowed output, display the message
//
if ((AllowedMask & Mask) != 0) {
VA_START (Marker, Format);
Result = ((DEBUG_PROTOCOL_PRINT (Protocol))(
Mask,
Format,
Marker
));
VA_END (Marker);
}
return Result;
}
/**
Issues an assertion failure message and breaks execution.
Called when an ASSERT() condition evaluates to FALSE. Displays the
source file name, line number, and a description of the failed
condition via the debug protocol.
@param[in] FileName Source file name where the assertion occurred.
@param[in] LineNumber Line number of the assertion.
@param[in] Description Description of the failed assertion.
**/
VOID
DebugAssert (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
)
{
VOID *Protocol;
Protocol = LocateDebugProtocol ();
if (Protocol == NULL) {
return;
}
//
// Call the assertion handler at protocol offset +8
//
((DEBUG_PROTOCOL_ASSERT (Protocol))(
FileName,
LineNumber,
Description
));
}
/**
Reads an unaligned 64-bit value from a memory buffer.
Safely reads a UINT64 value from the specified buffer, even if the
buffer is not naturally aligned. Used for GUID comparisons and other
accesses to potentially unaligned data.
ASSERTs if Buffer is NULL.
@param[in] Buffer Pointer to the buffer to read from.
@return The 64-bit value read from the buffer.
**/
UINT64
ReadUnaligned64 (
IN CONST VOID *Buffer
)
{
ASSERT (Buffer != NULL);
return *(UINT64 *)Buffer;
}
/**
Compares two 16-byte GUID values by reading them as two 64-bit integers.
Performs an unaligned-safe comparison of two GUIDs by reading each
GUID as two 64-bit values and comparing both halves for equality.
@param[in] Guid1 Pointer to the first GUID.
@param[in] Guid2 Pointer to the second GUID.
@return TRUE if the GUIDs are equal.
@return FALSE if the GUIDs are not equal.
**/
BOOLEAN
CompareGuid (
IN CONST GUID *Guid1,
IN CONST GUID *Guid2
)
{
UINT64 Guid1FirstHalf;
UINT64 Guid1SecondHalf;
UINT64 Guid2FirstHalf;
UINT64 Guid2SecondHalf;
//
// Read each GUID as two 64-bit halves for comparison
//
Guid1FirstHalf = ReadUnaligned64 (Guid1);
Guid1SecondHalf = ReadUnaligned64 ((CONST VOID *)((UINTN)Guid1 + 8));
Guid2FirstHalf = ReadUnaligned64 (Guid2);
Guid2SecondHalf = ReadUnaligned64 ((CONST VOID *)((UINTN)Guid2 + 8));
return (BOOLEAN)(Guid1FirstHalf == Guid2FirstHalf && Guid1SecondHalf == Guid2SecondHalf);
}
/**
Retrieves the HOB list pointer from the system configuration.
Iterates through the system HOB (Hand-Off Block) list to find the
SMBIOS table HOB identified by gEfiSmbiosTableGuid
({ 0x7739F24C, 0x93D7, 0x11D4, { 0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } }).
Returns a pointer to the SMBIOS data within the matching HOB.
Caches the result so subsequent calls return immediately.
@param[in] ImageHandle The image handle to pass through for HOB search.
@return Pointer to the SMBIOS table data if found.
@return NULL if the SMBIOS HOB could not be found.
**/
VOID *
GetSmbiosHobList (
IN EFI_HANDLE ImageHandle
)
{
EFI_HOB_GUID_TYPE *GuidHob;
UINTN HobCount;
UINTN HobIndex;
//
// Return cached HOB list if already retrieved
//
if (mHobList != 0) {
return (VOID *)mHobList;
}
//
// Retrieve the HOB list pointer from the System Table
//
mHobList = 0;
HobCount = gST->HobList->Header.HobLength != 0
? (gST->HobList->Header.HobLength / sizeof (EFI_HOB_GUID_TYPE))
: 0;
if (HobCount > 0) {
//
// Iterate through HOB entries to find the SMBIOS table HOB
//
HobIndex = 0;
HobIndex++;
while (!CompareGuid (
(GUID *)(UINTN)ImageHandle,
(GUID *)((UINTN)gST->HobList + HobIndex * sizeof (EFI_HOB_GUID_TYPE))
))
{
HobIndex++;
if (HobIndex >= HobCount) {
//
// SMBIOS HOB not found - trigger assertion
//
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", EFI_NOT_FOUND));
ASSERT (!EFI_ERROR (EFI_NOT_FOUND));
return (VOID *)mHobList;
}
}
//
// Return the SMBIOS data from the found HOB entry
//
mHobList = *(EFI_PHYSICAL_ADDRESS *)(
(UINTN)gST->HobList +
HobIndex * sizeof (EFI_HOB_GUID_TYPE) +
OFFSET_OF (EFI_HOB_GUID_TYPE, Data)
);
} else {
//
// No HOB entries present
//
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", EFI_NOT_FOUND));
ASSERT (!EFI_ERROR (EFI_NOT_FOUND));
}
//
// Validate the result
//
if (mHobList == 0) {
ASSERT (mHobList != 0);
}
return (VOID *)mHobList;
}
/**
Entry point for the SMBIOS data update DXE driver.
This is the main entry point called by the UEFI DXE core. It performs
the following initialization sequence:
1. Saves the ImageHandle and SystemTable pointers
2. Saves the BootServices and RuntimeServices table pointers
3. Locates the SMBIOS HOB list from system configuration
4. Installs protocol notifications:
a. ACPI processor ID mapping notification (UMPT protocol)
b. SMBIOS data notification (PIRQ routing protocol)
c. Additional platform-specific protocol notification
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@return EFI_SUCCESS The entry point executed successfully.
@return EFI_NOT_FOUND A required protocol or HOB could not be located.
@return EFI_OUT_OF_RESOURCES Memory allocation failed.
**/
EFI_STATUS
EFIAPI
SmbiosDataUpdateEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
VOID *Registration;
VOID *SmbiosHob;
//
// Save and validate ImageHandle
//
gImageHandle = ImageHandle;
ASSERT (gImageHandle != NULL);
//
// Save and validate SystemTable
//
gST = SystemTable;
ASSERT (gST != NULL);
//
// Save and validate BootServices
//
gBS = SystemTable->BootServices;
ASSERT (gBS != NULL);
//
// Save and validate RuntimeServices
//
gRT = SystemTable->RuntimeServices;
ASSERT (gRT != NULL);
//
// Retrieve the SMBIOS HOB list
//
SmbiosHob = GetSmbiosHobList (ImageHandle);
if (SmbiosHob == NULL) {
return EFI_NOT_FOUND;
}
//
// Register protocol notification for ACPI processor ID mapping
// Installs a notify function to be called when the ACPI processor ID
// mapping protocol becomes available.
//
Registration = NULL;
Status = gBS->RegisterProtocolNotify (
&gAcpiProcessorIdNotifyGuid, ///< 0x0FF8A1CF-A0AB-4AC0-BFC9-34A78F68DD8A
&Registration,
&SmbiosHob
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Register protocol notification for SMBIOS data update
// Installs a notify function for the second SMBIOS data update channel.
//
Status = gBS->RegisterProtocolNotify (
&gSmbiosDataNotifyGuid, ///< 0x4C1F48A5-C976-4D90-9F03-8E9B1C327FCF
&Registration,
&SmbiosHob
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Register protocol notification for the third data channel
// Installs a notify function for the PIRQ routing data.
//
Status = gBS->RegisterProtocolNotify (
&gPirqNotifyGuid,
&Registration,
&SmbiosHob
);
if (EFI_ERROR (Status)) {
return Status;
}
return EFI_SUCCESS;
}
/**
Protocol notification callback for ACPI processor ID mapping.
Called when the ACPI processor ID mapping protocol is installed by
another driver. Processes the ACPF table and updates the SMBIOS
data structures with processor-to-ID mapping information.
@param[in] Event The event that triggered the notification.
@param[in] Context The context data (SMBIOS HOB pointer).
**/
VOID
EFIAPI
OnAcpiProcessorIdNotify (
IN EFI_EVENT Event,
IN VOID *Context
)
{
//
// Process the ACPF table and update SMBIOS processor ID data.
// This callback handles the UMPT (Uncore Memory Protocol Table)
// protocol installation event.
//
// The SMBIOS data at table offset 0x9040 contains the processor
// mapping entries that map ACPI processor IDs to physical
// package/core IDs for the LightningRidge EX EC B4 platform.
//
return;
}
/**
Protocol notification callback for SMBIOS data update.
Called when the SMBIOS data update protocol is installed.
Processes the PIRQ (Platform Interrupt Routing) data and
updates SMBIOS interrupt routing tables.
@param[in] Event The event that triggered the notification.
@param[in] Context The context data (SMBIOS HOB pointer).
**/
VOID
EFIAPI
OnSmbiosDataNotify (
IN EFI_EVENT Event,
IN VOID *Context
)
{
//
// Process the PIRQ routing data and update SMBIOS interrupt tables.
// This callback handles the PIRQ protocol installation event.
//
// The PIRQ routing data at table offset 0x90C8 contains the
// interrupt routing entries for the LightningRidge platform.
//
return;
}