/** @file
SmbiosRpTable - SMBIOS Type 133 Record Installation Driver
This UEFI DXE driver allocates an ACPI NVS communication buffer and installs
a SMBIOS Type 133 record pointing to that buffer for BIOS-to-OS communication.
Copyright (c) 2025, Insyde Software Corp. All rights reserved.
Module: SmbiosRpTable.efi
MD5: 5e6058cf09eb35a44a33a7c77bcb10b9
SHA256: ec570f2fde3423e2900bfd8049ec63748136489363612e44afa49364fcb6b8f6
**/
#include "SmbiosRpTable.h"
//
// Global variables
//
EFI_HANDLE ImageHandle = NULL;
EFI_SYSTEM_TABLE *SystemTable = NULL;
EFI_BOOT_SERVICES *BootServices = NULL;
EFI_RUNTIME_SERVICES *RuntimeServices = NULL;
VOID *mHobList = NULL;
EFI_DEBUG_PRINT_PROTOCOL *mDebugPrintProtocol = NULL;
/**
Zero fill a buffer by processing 8-byte aligned chunks.
@param[in] Buffer Pointer to buffer to zero fill.
@param[in] Length Length of buffer in bytes.
@return Pointer to the buffer.
**/
VOID *
EFIAPI
ZeroMem (
VOID *Buffer,
UINTN Length
)
{
ZeroMemAligned64 (Buffer, Length);
return Buffer;
}
/**
Internal helper to zero memory using 8-byte aligned writes.
@param[in] Buffer Pointer to the buffer.
@param[in] Length Length of the buffer in bytes.
**/
STATIC
VOID
ZeroMemAligned64 (
VOID *Buffer,
UINTN Length
)
{
//
// Zero 8-byte aligned chunks first.
//
SetMem32 ((UINT32 *)Buffer, 0, (UINT32)(Length >> 3));
//
// Zero the remaining bytes (0-7).
//
SetMem8 (
(UINT8 *)Buffer + (Length & ~7),
(UINT8)0,
(UINT8)(Length & 7)
);
}
/**
The module entry point.
Initializes UEFI boot/runtime services globals, locates HII and other
required protocols, then locates the SMBIOS protocol and installs a
Type 133 SMBIOS record pointing to an ACPI NVS communication buffer.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The SMBIOS Type 133 record was installed.
@retval EFI_NOT_FOUND The SMBIOS protocol was not found.
@retval EFI_OUT_OF_RESOURCES Memory allocation failed.
@return Status codes from gBS->LocateProtocol() or SMBIOS Add().
**/
EFI_STATUS
EFIAPI
ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_SMBIOS_PROTOCOL *SmbiosProtocol;
//
// Initialize the DXE global variables (ImageHandle, SystemTable,
// BootServices, RuntimeServices) and locate HII/HOB protocols.
//
UefiMainEntry (ImageHandle, SystemTable);
//
// Locate the SMBIOS protocol.
//
Status = gBS->LocateProtocol (
&gEfiSmbiosProtocolGuid,
NULL,
(VOID **)&SmbiosProtocol
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "SmbiosRpTable Could not locate SMBIOS protocol.%r\n", Status));
return Status;
}
//
// Install a Type 133 SMBIOS record with the communication buffer address.
//
return SmbiosType133RecordInstall (SmbiosProtocol);
}
/**
UEFI main initialization routine.
Initializes global ImageHandle, SystemTable, BootServices, RuntimeServices,
locates HOB list, and resolves HII protocol GUIDs.
@param[in] ImageHandle The image handle.
@param[in] SystemTable The EFI system table.
**/
VOID
UefiMainEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
gImageHandle = ImageHandle;
ASSERT (gImageHandle != NULL);
gST = SystemTable;
ASSERT (gST != NULL);
gBS = SystemTable->BootServices;
ASSERT (gBS != NULL);
gRT = SystemTable->RuntimeServices;
ASSERT (gRT != NULL);
//
// Get the HOB list from the system configuration table.
//
GetHobList ();
//
// Resolve HII protocol GUIDs.
//
Status = gBS->LocateProtocol (
&gEfiHiiDatabaseProtocolGuid,
NULL,
(VOID **)&gHiiDatabase
);
ASSERT_EFI_ERROR (Status);
Status = gBS->LocateProtocol (
&gEfiHiiStringProtocolGuid,
NULL,
(VOID **)&gHiiString
);
ASSERT_EFI_ERROR (Status);
Status = gBS->LocateProtocol (
&gEfiHiiConfigRoutingProtocolGuid,
NULL,
(VOID **)&gHiiConfigRouting
);
ASSERT_EFI_ERROR (Status);
Status = gBS->LocateProtocol (
&gEfiHiiFontProtocolGuid,
NULL,
(VOID **)&gHiiFont
);
ASSERT_EFI_ERROR (Status);
Status = gBS->LocateProtocol (
&gEfiHiiImageProtocolGuid,
NULL,
(VOID **)&gHiiImage
);
ASSERT_EFI_ERROR (Status);
}
/**
Installs a SMBIOS Type 133 record.
Allocates ACPI NVS memory as a BIOS utility communication buffer of
0x4000 bytes, then creates a Type 133 SMBIOS record pointing to that
buffer.
@param[in] SmbiosProtocol A pointer to the SMBIOS protocol.
@retval EFI_SUCCESS The Type 133 record was added.
@retval EFI_OUT_OF_RESOURCES Memory allocation failed.
@return Status from SmbiosProtocol->Add().
**/
EFI_STATUS
SmbiosType133RecordInstall (
IN EFI_SMBIOS_PROTOCOL *SmbiosProtocol
)
{
EFI_STATUS Status;
UINTN BufferAddr;
SMBIOS_STRUCTURE *SmbiosRecord;
EFI_SMBIOS_TABLE_HEADER *RecordHeader;
UINT8 *StringPtr;
//
// Allocate ACPI NVS memory for BIOS utility communication buffer (16KB).
//
BufferAddr = 0xFFFFFFFFULL;
Status = gBS->AllocatePages (
AllocateAnyPages,
EfiACPIMemoryNVS,
EFI_SIZE_TO_PAGES (0x4000),
&BufferAddr
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "Failed to allocate ACPI NVS memory as BIOS utility communication buffer, Status %r\n", Status));
return Status;
}
DEBUG ((EFI_D_INFO, "Allocated Communication Buffer address = %x\n", BufferAddr));
//
// Allocate the SMBIOS record structure.
//
SmbiosRecord = (SMBIOS_STRUCTURE *)AllocateACPINvsBuffer ();
if (SmbiosRecord == NULL) {
DEBUG ((EFI_D_ERROR, "Failed to allocate smbios record\n"));
return EFI_OUT_OF_RESOURCES;
}
//
// Zero the record buffer (14 bytes for type 133 header + 2 handle).
//
ZeroMem14 ((UINTN)SmbiosRecord);
if (SmbiosRecord == NULL) {
DEBUG ((EFI_D_ERROR, "Failed to allocate smbios record\n"));
return EFI_OUT_OF_RESOURCES;
}
//
// Fill in Type 133 SMBIOS record:
// Type = SMBIOS_TYPE_BIOS_UTILITY_COMMUNICATION (133)
// Handle = 0x0C85 (3205)
// Buffer = ACPI NVS physical address
// Size = 0x4000 (16KB)
//
RecordHeader = (EFI_SMBIOS_TABLE_HEADER *)SmbiosRecord;
RecordHeader->Type = SMBIOS_TYPE_BIOS_UTILITY_COMMUNICATION;
RecordHeader->Length = SMBIOS_TYPE_133_RECORD_LENGTH;
RecordHeader->Handle = SMBIOS_HANDLE_BIOS_UTILITY_COMM;
//
// The record payload contains:
// DWORD: Buffer physical address (low 32 bits)
// DWORD: Buffer size in bytes (0x4000)
//
*((UINT32 *)&SmbiosRecord->BufferAddress) = (UINT32)BufferAddr;
*((UINT32 *)&SmbiosRecord->BufferSize) = 0x4000;
//
// Add the SMBIOS record.
//
Status = SmbiosProtocol->Add (
SmbiosProtocol,
0,
(EFI_SMBIOS_TABLE_HEADER *)SmbiosRecord,
(UINT8 *)StringPtr
);
DEBUG ((EFI_D_INFO, "Smbios protocol addition (Type 133) returns %r\n", Status));
return Status;
}
/**
Locates and caches the EFI_DEBUG_PRINT_PROTOCOL.
@return Pointer to EFI_DEBUG_PRINT_PROTOCOL, or NULL if not found.
**/
EFI_DEBUG_PRINT_PROTOCOL *
GetDebugPrintProtocol (
VOID
)
{
EFI_STATUS Status;
UINTN CpuCount;
if (mDebugPrintProtocol != NULL) {
return mDebugPrintProtocol;
}
CpuCount = gBS->GetNumberOfCpuCores ();
if (CpuCount == 0) {
//
// Only attempt to locate protocol if we have a sane number of CPUs.
//
return NULL;
}
gBS->CheckCpuCores (CpuCount);
if (CpuCount > 16) {
return NULL;
}
Status = gBS->LocateProtocol (
&gEfiDebugPrintProtocolGuid,
NULL,
(VOID **)&mDebugPrintProtocol
);
if (EFI_ERROR (Status)) {
mDebugPrintProtocol = NULL;
}
return mDebugPrintProtocol;
}
/**
Prints a debug message to the debug output device.
Only prints if the DebugPrint protocol is available and the error level
matches the current platform debug level.
@param[in] ErrorLevel The error level of the debug message.
@param[in] Format Format string for the debug message.
@param[in] ... Variable argument list for the format.
**/
VOID
EFIAPI
DebugPrint (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
EFI_DEBUG_PRINT_PROTOCOL *DebugPrintProtocol;
UINTN CurrentDebugLevel;
UINTN AllowedMask;
VA_LIST Marker;
VA_START (Marker, Format);
DebugPrintProtocol = GetDebugPrintProtocol ();
if (DebugPrintProtocol == NULL) {
return;
}
//
// Check the platform debug level via CMOS index 0x4B.
//
CurrentDebugLevel = GetPlatformDebugLevel ();
AllowedMask = 0;
if (CurrentDebugLevel == 1) {
//
// Error level only: 0x80000004 (EFI_D_ERROR)
//
AllowedMask = DEBUG_ERROR;
} else if (CurrentDebugLevel > 0 && CurrentDebugLevel <= 0xFE) {
//
// Allow all except DEBUG_ERROR when in verbose mode.
//
AllowedMask = DEBUG_VERBOSE;
}
if ((AllowedMask & ErrorLevel) != 0) {
DebugPrintProtocol->DebugPrint (
DebugPrintProtocol,
ErrorLevel,
Format,
Marker
);
}
VA_END (Marker);
}
/**
Reads the platform debug level from CMOS.
Handles platform-specific debug level registers.
@return The current debug level index.
**/
UINTN
GetPlatformDebugLevel (
VOID
)
{
UINT8 DebugRegister;
UINT8 DebugLevel;
//
// Read CMOS index 0x4B (debug level register).
//
DebugRegister = IoRead8 (CMOS_INDEX_PORT);
IoWrite8 (CMOS_INDEX_PORT, DebugRegister & 0x80 | 0x4B);
DebugLevel = IoRead8 (CMOS_DATA_PORT);
if (DebugLevel > 3) {
//
// Check extended memory for debug settings on certain platforms.
//
if (DebugLevel == 0) {
DebugLevel = *(volatile UINT8 *)(UINTN)0xFDAF0490 & 2 | 1;
}
}
return DebugLevel;
}
/**
ASSERT macro support.
Prints the assertion failure information using the DebugAssert protocol.
@param[in] FileName The file name where the assertion occurred.
@param[in] LineNumber The line number where the assertion occurred.
@param[in] Description The description of the assertion failure.
**/
VOID
EFIAPI
DebugAssert (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
)
{
EFI_DEBUG_PRINT_PROTOCOL *DebugPrintProtocol;
DebugPrintProtocol = GetDebugPrintProtocol ();
if (DebugPrintProtocol != NULL) {
DebugPrintProtocol->DebugAssert (
DebugPrintProtocol,
FileName,
LineNumber,
Description
);
}
}
/**
Allocates ACPI NVS memory for the SMBIOS record buffer.
Calls gBS->AllocatePool() with EfiACPIMemoryNVS memory type.
@param[in] a1 Unused parameter (provided for compatibility).
@param[in] a2 Unused parameter (provided for compatibility).
@return Pointer to allocated ACPI NVS buffer, or NULL if allocation failed.
**/
VOID *
AllocateACPINvsBuffer (
VOID
)
{
EFI_STATUS Status;
VOID *Buffer;
Buffer = NULL;
Status = gBS->AllocatePool (
EfiACPIMemoryNVS,
sizeof (SMBIOS_STRUCTURE),
&Buffer
);
if (EFI_ERROR (Status)) {
return NULL;
}
return Buffer;
}
/**
Returns the HOB list pointer from the system configuration table.
Searches the configuration table for the HOB list GUID and stores the
pointer in the mHobList global.
@return Pointer to the HOB list, or NULL if not found.
**/
VOID *
EFIAPI
GetHobList (
VOID
)
{
UINTN Index;
UINTN TableEntry;
GUID *Guid1;
if (mHobList != NULL) {
return mHobList;
}
mHobList = NULL;
if (gST->NumberOfTableEntries > 0) {
TableEntry = (UINTN)gST->ConfigurationTable;
for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
Guid1 = (GUID *)(TableEntry + (Index * sizeof (EFI_CONFIGURATION_TABLE)));
//
// Check for gEfiHobListGuid match.
//
if (CompareGuid (&gEfiHobListGuid, Guid1)) {
mHobList = *(VOID **)(TableEntry + (Index * sizeof (EFI_CONFIGURATION_TABLE)) + OFFSET_OF (EFI_CONFIGURATION_TABLE, VendorTable));
return mHobList;
}
}
}
//
// If we get here, the HOB list was not found.
//
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", EFI_NOT_FOUND));
ASSERT (EFI_ERROR (EFI_NOT_FOUND));
return mHobList;
}
/**
Reads a 64-bit unaligned value.
@param[in] Buffer Pointer to the unaligned buffer.
@return The 64-bit value read from the buffer.
**/
UINT64
EFIAPI
ReadUnaligned64 (
IN CONST UINT64 *Buffer
)
{
ASSERT (Buffer != NULL);
return *Buffer;
}
/**
Zeros 14 bytes of memory at the given address.
@param[in] Buffer Address of the buffer to zero.
@return Pointer to the zeroed buffer.
**/
VOID *
EFIAPI
ZeroMem14 (
IN UINTN Buffer
)
{
ASSERT (Buffer != 0);
ASSERT ((UINTN)(-(INTN)Buffer) >= 14);
return ZeroMem ((VOID *)Buffer, 14);
}
/**
Compares two GUIDs.
Uses unaligned 64-bit reads for efficiency.
@param[in] Guid1 Pointer to the first GUID.
@param[in] Guid2 Pointer to the second GUID.
@retval TRUE Guid1 equals Guid2.
@retval FALSE Guid1 does not equal Guid2.
**/
BOOLEAN
EFIAPI
CompareGuid (
IN CONST GUID *Guid1,
IN CONST GUID *Guid2
)
{
//
// Compare the first 8 bytes (Data1 + Data2 + Data3).
//
if (ReadUnaligned64 ((UINT64 *)Guid1) != ReadUnaligned64 ((UINT64 *)Guid2)) {
return FALSE;
}
//
// Compare last 8 bytes (Data4).
//
return ReadUnaligned64 ((UINT64 *)Guid1->Data4) == ReadUnaligned64 ((UINT64 *)Guid2->Data4);
}