/** @file
SmbiosDataUpdateDxe - NeonCity EPECB SMBIOS Data Update Driver
This UEFI DXE driver is part of the UBA (Universal BIOS Adapter) framework
for the Purley platform. It performs platform-specific SMBIOS table updates
for the NeonCity EPECB motherboard type.
The driver:
1. Locates the UBA platform SMBIOS configuration protocol.
2. Registers HII string packages for SMBIOS string references.
3. Installs SMBIOS type 9 (System Slots), type 17 (Memory Devices),
and type 41 (Onboard Devices Extended Information) tables.
4. Uses platform-provided configuration data to populate SMBIOS fields.
Source: PurleyRpPkg/Uba/UbaMain/Dxe/TypeNeonCityEPECB/
SmbiosDataUpdateDxe/SmbiosDataUpdateDxe.c
Build: HR6N0XMLK DEBUG_VS2015 X64
Copyright (c) 2016-2017, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "SmbiosDataUpdateDxeNeonCityEPECB.h"
// ===========================================================================
// Module Globals
// ===========================================================================
//
// Standard UEFI globals (from UefiBootServicesTableLib,
// UefiRuntimeServicesTableLib, DxeHobLib, DxeServicesTableLib)
//
EFI_HANDLE gImageHandle = NULL;
EFI_SYSTEM_TABLE *gST = NULL;
EFI_BOOT_SERVICES *gBS = NULL;
EFI_RUNTIME_SERVICES *gRT = NULL;
EFI_SMM_COMMUNICATION_PROTOCOL *mPciUsra = NULL;
VOID *gDS = NULL;
//
// UBA platform SMBIOS configuration protocol
//
VOID *gUbaPlatformSmbiosProtocol = NULL;
//
// HII handle for SMBIOS string packages
//
EFI_HII_HANDLE gSmbiosStringPackHandle = NULL;
//
// HII protocol interfaces
//
VOID *gHiiDatabaseProtocol = NULL;
VOID *gHiiStringProtocol = NULL;
//
// SMBIOS protocol instance (locate on demand)
//
EFI_SMBIOS_PROTOCOL *gSmbiosProtocol = NULL;
VOID *gSmbiosProtocolNotify = NULL;
VOID *gSmbiosProtocolRegistration = NULL;
//
// Memory-mapped PCI configuration base
//
VOID *gMmPciBase = NULL;
//
// HOB list (HobLib)
//
VOID *mHobList = NULL;
// ===========================================================================
// EFI Component Name and Driver Binding - AutoGen
// ===========================================================================
//
// AutoGen header: SmbiosDataUpdateDxeStrDefs.h
// These are populated by the build system (AutoGen.c).
//
// Source path from build:
// PurleyRpPkg/Uba/UbaMain/Dxe/TypeNeonCityEPECB/SmbiosDataUpdateDxe/
// SmbiosDataUpdateDxe/DEBUG/AutoGen.c
//
// ===========================================================================
// Library Function Wrappers
// ===========================================================================
/**
Allocate and zero a buffer.
@param[in] Size Number of bytes to allocate.
@return Pointer to allocated buffer, or NULL.
**/
VOID *
SmbiosAllocateZeroPool (
IN UINTN Size
)
{
VOID *Buffer;
Buffer = AllocatePool (Size);
if (Buffer != NULL) {
ZeroMem (Buffer, Size);
}
return Buffer;
}
/**
Free an allocated buffer.
@param[in] Buffer Pointer to buffer to free.
**/
VOID
SmbiosFreePool (
IN VOID *Buffer
)
{
gBS->FreePool (Buffer);
}
// ===========================================================================
// Entry Point
// ===========================================================================
/**
Module entry point.
Initializes UEFI globals, locates required protocols (HII Database,
HII String, UBA config, etc.), registers HII string packages, and
installs SMBIOS tables for the NeonCity EPECB platform.
@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 entry point executed successfully.
@retval EFI_INVALID_PARAMETER A required protocol is not available.
@retval Others Error from protocol locate or HII registration.
**/
EFI_STATUS
EFIAPI
SmbiosDataUpdateDxeEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// Save UEFI globals for library compatibility
//
gImageHandle = ImageHandle;
gST = SystemTable;
gBS = SystemTable->BootServices;
gRT = SystemTable->RuntimeServices;
//
// Locate HII Database Protocol
//
Status = gBS->LocateProtocol (
&gEfiHiiDatabaseProtocolGuid,
NULL,
&gHiiDatabaseProtocol
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT (!EFI_ERROR (Status));
return Status;
}
//
// Locate HII String Protocol
//
Status = gBS->LocateProtocol (
&gEfiHiiStringProtocolGuid,
NULL,
&gHiiStringProtocol
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT (!EFI_ERROR (Status));
return Status;
}
//
// Retrieve HOB list pointer for HobLib
//
Status = EfiGetSystemConfigurationTable (
&gEfiHobListGuid,
&mHobList
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT (!EFI_ERROR (Status));
}
if (mHobList == NULL) {
DEBUG ((EFI_D_ERROR, "mHobList != NULL\n"));
ASSERT (mHobList != NULL);
}
//
// Locate DxeServicesTable (gDS)
//
Status = EfiGetSystemConfigurationTable (
&gEfiDxeServicesTableGuid,
(VOID **)&gDS
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT (!EFI_ERROR (Status));
}
if (gDS == NULL) {
DEBUG ((EFI_D_ERROR, "gDS != NULL\n"));
ASSERT (gDS != NULL);
}
//
// Locate PciUsra protocol (Memory Mapped PCI config access)
//
if (mPciUsra == NULL) {
Status = gBS->LocateProtocol (
&gEfiMmPciBaseProtocolGuid,
NULL,
(VOID **)&mPciUsra
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT (!EFI_ERROR (Status));
}
if (mPciUsra == NULL) {
DEBUG ((EFI_D_ERROR, "mPciUsra != NULL\n"));
ASSERT (mPciUsra != NULL);
return Status;
}
}
//
// Register SMBIOS data update protocol with UBA
//
Status = SmbiosDataUpdateEntry (ImageHandle, SystemTable);
return Status;
}
// ===========================================================================
// SMBIOS Data Update Entry
// ===========================================================================
/**
UBA SMBIOS data update registration entry.
Locates the UBA platform SMBIOS configuration protocol, retrieves
platform slot/memory/device configuration data, registers HII string
packages, and installs SMBIOS tables.
This function is called from SmbiosDataUpdateDxeEntryPoint.
@param[in] ImageHandle EFI image handle.
@param[in] SystemTable EFI system table.
@retval EFI_SUCCESS SMBIOS tables installed.
@retval EFI_NOT_FOUND UBA config protocol not found.
@retval EFI_OUT_OF_RESOURCES Memory allocation failed.
@retval Others Error from sub-operations.
**/
EFI_STATUS
SmbiosDataUpdateEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
UBA_PLATFORM_SMBIOS_CONFIG *UbaPlatformSmbiosConfig;
UINT32 UbaPlatformSmbiosConfigSize;
UINT32 TableInstallParams[6];
UBA_BOARD_SMBIOS_UPDATE BoardUpdateFunc;
UINT32 Revision;
//
// Locate UBA platform SMBIOS configuration protocol from the
// platform PEIM or DXE driver
//
Status = gBS->LocateProtocol (
&gUbaPlatformSmbiosProtocolGuid,
NULL,
(VOID **)&gUbaPlatformSmbiosProtocol
);
if (EFI_ERROR (Status)) {
return Status;
}
UbaPlatformSmbiosConfig = (UBA_PLATFORM_SMBIOS_CONFIG *)gUbaPlatformSmbiosProtocol;
UbaPlatformSmbiosConfigSize = UbaPlatformSmbiosConfig->Header.Size;
DEBUG ((
EFI_D_INFO,
"UBA:SmbiosDataUpdateEntry Image GUID=%g\n",
&UbaPlatformSmbiosConfig->Header.ImageGuid
));
//
// Copy platform GUID into the SMBIOS configuration table
//
CopyGuid (
&UbaPlatformSmbiosConfig->Signature,
(GUID *)((UINTN)UbaPlatformSmbiosConfig + sizeof (UBA_PLATFORM_HEADER))
);
//
// Register HII string packages for SMBIOS string references
//
gSmbiosStringPackHandle = HiiAddPackages (
&gUbaPlatformSmbiosGuid,
ImageHandle,
SmbiosDataUpdateDxeStrings,
NULL
);
if (gSmbiosStringPackHandle == NULL) {
DEBUG ((EFI_D_ERROR, "gSmbiosStringPackHandle != NULL\n"));
ASSERT (gSmbiosStringPackHandle != NULL);
return EFI_OUT_OF_RESOURCES;
}
//
// Initialize SMBIOS table install parameters
//
ZeroMem (TableInstallParams, sizeof (TableInstallParams));
TableInstallParams[2] = 1; // Revision/Flags
BoardUpdateFunc = SmbiosUpdateBoardTables;
//
// Locate SMBIOS protocol if not already found
//
if (gSmbiosProtocol == NULL) {
Status = gBS->LocateProtocol (
&gEfiSmbiosProtocolGuid,
NULL,
(VOID **)&gSmbiosProtocol
);
if (EFI_ERROR (Status)) {
return Status;
}
}
//
// Call UBA board update function to install platform-specific SMBIOS tables
//
TableInstallParams[0] = (UINT32)(UINTN)BoardUpdateFunc;
TableInstallParams[1] = 1;
Status = gUbaPlatformSmbiosProtocol->UpdateSmbios (
gSmbiosProtocol,
(VOID *)TableInstallParams,
sizeof (TableInstallParams)
);
return Status;
}
// ===========================================================================
// Board-Specific SMBIOS Table Update
// ===========================================================================
/**
Install all platform-specific SMBIOS tables for NeonCity EPECB.
Installs:
- Type 9 (System Slots): 30 slots for PCIe and other bus slots
- Type 17 (Memory Devices): 8 memory device entries
- Type 41 (Onboard Devices Extended): 4 onboard device entries
@retval EFI_SUCCESS All SMBIOS tables installed successfully.
**/
EFI_STATUS
SmbiosUpdateBoardTables (
VOID
)
{
EFI_SMBIOS_PROTOCOL *SmbiosProtocol;
UINTN Index;
EFI_STATUS Status;
VOID *SmbiosTableBuffer;
UINTN SmbiosTableBufferSize;
SmbiosTableBufferSize = 768; // Max SMBIOS table size
//
// Allocate a reusable work buffer for SMBIOS structure construction
//
SmbiosTableBuffer = SmbiosAllocateZeroPool (SmbiosTableBufferSize);
if (SmbiosTableBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Phase 1: Install SMBIOS Type 9 (System Slots) - up to 30 entries
//
for (Index = 0; Index < 30; Index++) {
ZeroMem (SmbiosTableBuffer, SmbiosTableBufferSize);
Status = SmbiosConstructType9Slot (
SmbiosTableBuffer,
NULL,
Index
);
if (!EFI_ERROR (Status)) {
SmbiosInstallTable (SmbiosTableBuffer);
}
}
//
// Notify end of type 9 table enumeration
//
SmbiosNotifyEndOfType (9);
//
// Phase 2: Install SMBIOS Type 17 (Memory Devices) - up to 8 entries
//
for (Index = 0; Index < 8; Index++) {
ZeroMem (SmbiosTableBuffer, SmbiosTableBufferSize);
Status = SmbiosConstructType17Memory (
SmbiosTableBuffer,
NULL,
Index
);
if (!EFI_ERROR (Status)) {
SmbiosInstallTable (SmbiosTableBuffer);
}
}
//
// Notify end of type 17 table enumeration
//
SmbiosNotifyEndOfType (41);
//
// Phase 3: Install SMBIOS Type 41 (Onboard Devices) - up to 4 entries
//
for (Index = 0; Index < 4; Index++) {
ZeroMem (SmbiosTableBuffer, SmbiosTableBufferSize);
Status = SmbiosConstructType41Device (
SmbiosTableBuffer,
NULL,
Index
);
if (!EFI_ERROR (Status)) {
SmbiosInstallTable (SmbiosTableBuffer);
}
}
//
// Clean up work buffer
//
SmbiosFreePool (SmbiosTableBuffer);
return EFI_SUCCESS;
}
// ===========================================================================
// SMBIOS Type 9 (System Slots) Construction
// ===========================================================================
/**
SMBIOS slot type and characteristics lookup table.
Index key: 5 * SlotIndex
Byte 0-1: StringId (HII string ID for slot designation)
Byte 2: SlotType (e.g., 0x0B = PCIe x16, 0x0A = PCIe x8)
Byte 3: SlotDataBusWidth (0x04 = x16, 0x03 = x8)
Byte 4: SlotCharacteristics (bitmask)
Byte 5: SlotUsage/Flags (extended)
Byte 6: SlotLength
Byte 7: SegmentGroup (low)
Byte 8: SegmentGroup (high) / Reserved
Byte 9: DeviceFunction / Bus
**/
STATIC CONST UINT8 mSlotData[30 * 10] = {
// Slot 0: StringId=0x0002, Type=0x0B(x16), Width=0x04(x16),
// Char=0x0800, Usage=0x03(filled), Length=0x08
// Bus/DevFunc from platform config
0x02, 0x00, 0x0B, 0x04, 0x00, 0x08, 0x03, 0x08, 0x00, 0x00,
// Slot 1:
0x03, 0x00, 0x0B, 0x04, 0x00, 0x08, 0x03, 0x08, 0x00, 0x01,
// Slot 2:
0x04, 0x00, 0x0B, 0x04, 0x00, 0x08, 0x03, 0x08, 0x00, 0x02,
// Slot 3:
0x05, 0x00, 0x0A, 0x03, 0x00, 0x08, 0x03, 0x08, 0x00, 0x03,
// Slot 4:
0x06, 0x00, 0x0B, 0x04, 0x00, 0x08, 0x03, 0x08, 0x00, 0x04,
// Slot 5:
0x07, 0x00, 0x0B, 0x04, 0x00, 0x08, 0x03, 0x08, 0x00, 0x05,
// Slot 6:
0x08, 0x00, 0x0A, 0x03, 0x00, 0x08, 0x03, 0x08, 0x00, 0x06,
// Slot 7:
0x09, 0x00, 0x0B, 0x04, 0x00, 0x08, 0x03, 0x08, 0x00, 0x07,
// Slot 8:
0x0A, 0x00, 0x0B, 0x04, 0x00, 0x07, 0x04, 0x08, 0x00, 0x08,
// Slot 9:
0x0B, 0x00, 0x0B, 0x04, 0x00, 0x07, 0x04, 0x08, 0x00, 0x09,
// Slot 10:
0x0C, 0x00, 0x0B, 0x04, 0x00, 0x07, 0x04, 0x08, 0x00, 0x0A,
// Slot 11:
0x0D, 0x00, 0x0B, 0x04, 0x00, 0x07, 0x04, 0x08, 0x00, 0x0B,
// Slot 12:
0x0E, 0x00, 0x0B, 0x04, 0x00, 0x07, 0x04, 0x08, 0x00, 0x0C,
// Slot 13:
0x0F, 0x00, 0x01, 0x10, 0x00, 0x07, 0x04, 0x08, 0x00, 0x0D,
// Slot 14:
0x10, 0x00, 0x01, 0x10, 0x00, 0x0B, 0x10, 0x08, 0x00, 0x0E,
// Slot 15:
0x11, 0x00, 0xFF, 0x01, 0x00, 0x0B, 0x10, 0x00, 0x00, 0x0F,
// Slot 16:
0x12, 0x00, 0x01, 0x10, 0x00, 0x0B, 0x10, 0x08, 0x00, 0x10,
// Slot 17:
0x13, 0x00, 0x01, 0x10, 0x00, 0x0B, 0x10, 0x08, 0x00, 0x11,
// Slot 18:
0x14, 0x00, 0x01, 0x10, 0x00, 0x0B, 0x10, 0x08, 0x00, 0x12,
// Slot 19:
0x15, 0x00, 0x20, 0x01, 0x00, 0x0B, 0x10, 0x20, 0x00, 0x13,
// Slot 20:
0x16, 0x00, 0x20, 0x01, 0x00, 0x0B, 0x10, 0x20, 0x00, 0x14,
// Slot 21:
0x17, 0x00, 0x20, 0x01, 0x00, 0x0B, 0x10, 0x20, 0x00, 0x15,
// Slot 22:
0x18, 0x00, 0x20, 0x01, 0x00, 0x0B, 0x10, 0x20, 0x00, 0x16,
// Slot 23:
0x19, 0x00, 0x20, 0x01, 0x00, 0x0B, 0x10, 0x20, 0x00, 0x17,
// Slot 24:
0x1A, 0x00, 0x20, 0x01, 0x00, 0x0B, 0x10, 0x20, 0x00, 0x18,
// Slot 25:
0x1B, 0x00, 0x20, 0x01, 0x00, 0x0B, 0x10, 0x20, 0x00, 0x19,
// Slot 26:
0x1C, 0x00, 0x20, 0x01, 0x00, 0x0B, 0x10, 0x20, 0x00, 0x1A,
// Slot 27:
0x1D, 0x00, 0x20, 0x01, 0x00, 0x0B, 0x10, 0x20, 0x00, 0x1B,
// Slot 28:
0x1E, 0x00, 0x20, 0x01, 0x00, 0x0B, 0x10, 0x20, 0x00, 0x1C,
// Slot 29:
0x1F, 0x00, 0x20, 0x01, 0x00, 0x0B, 0x10, 0x20, 0x00, 0x1D,
};
/**
Construct one SMBIOS type 9 slot entry.
@param[out] Buffer Buffer to receive the SMBIOS structure.
@param[in] Data Platform config data (unused, uses mSlotData table).
@param[in] Index Slot index (0 to 29).
@retval EFI_SUCCESS Structure built.
@retval EFI_INVALID_PARAMETER Index out of range.
@retval EFI_OUT_OF_RESOURCES HII string lookup failed.
**/
EFI_STATUS
SmbiosConstructType9Slot (
OUT VOID *Buffer,
IN VOID *Data,
IN UINTN Index
)
{
SMBIOS_STRUCT_HEADER *SmbiosHeader;
UINT16 StringId;
UINT8 SlotType;
UINT8 SlotDataBusWidth;
UINT8 SlotLength;
UINT8 SlotUsage;
CHAR8 *StringBuffer;
if (Index >= 30) {
return EFI_INVALID_PARAMETER;
}
//
// Initialize SMBIOS header
//
SmbiosHeader = (SMBIOS_STRUCT_HEADER *)Buffer;
SmbiosHeader->Type = 9;
SmbiosHeader->Length = 22; // SMBIOS 3.1 type 9 with segment/bus/devfunc
SmbiosHeader->Handle = 0xFFFE; // Auto-assign
//
// Extract slot data from lookup table
//
StringId = *(UINT16 *)&mSlotData[10 * Index];
SlotType = mSlotData[10 * Index + 2];
SlotDataBusWidth = mSlotData[10 * Index + 3];
SlotUsage = mSlotData[10 * Index + 5];
SlotLength = mSlotData[10 * Index + 6];
//
// Populate type 9 fields
//
((SMBIOS_TYPE9_SLOT *)Buffer)->SlotDesignation = 1; // First string
((SMBIOS_TYPE9_SLOT *)Buffer)->SlotType = SlotType;
((SMBIOS_TYPE9_SLOT *)Buffer)->SlotDataBusWidth = SlotDataBusWidth;
((SMBIOS_TYPE9_SLOT *)Buffer)->CurrentUsage = SlotUsage;
((SMBIOS_TYPE9_SLOT *)Buffer)->SlotLength = SlotLength;
((SMBIOS_TYPE9_SLOT *)Buffer)->SlotID = (UINT8)Index;
((SMBIOS_TYPE9_SLOT *)Buffer)->SlotCharacteristics1 = 0;
((SMBIOS_TYPE9_SLOT *)Buffer)->SlotCharacteristics2 = 0;
//
// Look up slot designation string from HII
//
StringBuffer = SmbiosGetHiiString (
gSmbiosStringPackHandle,
StringId,
NULL,
NULL
);
if (StringBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Append the slot designation string
//
SmbiosCopyMem (
(UINT8 *)Buffer + SmbiosHeader->Length,
StringBuffer,
AsciiStrLen (StringBuffer) + 1
);
//
// Double-null terminate the string table
//
*((UINT8 *)Buffer + SmbiosHeader->Length + AsciiStrLen (StringBuffer) + 1) = 0;
SmbiosFreePool (StringBuffer);
return EFI_SUCCESS;
}
// ===========================================================================
// SMBIOS Type 17 (Memory Device) Construction
// ===========================================================================
/**
Construct one SMBIOS type 17 memory device entry.
@param[out] Buffer Buffer to receive the SMBIOS structure.
@param[in] Data Platform memory config data.
@param[in] Index Memory device index (0 to 7).
@retval EFI_SUCCESS Structure built.
@retval EFI_INVALID_PARAMETER Index out of range.
@retval EFI_OUT_OF_RESOURCES HII string lookup failed.
**/
EFI_STATUS
SmbiosConstructType17Memory (
OUT VOID *Buffer,
IN VOID *Data,
IN UINTN Index
)
{
SMBIOS_STRUCT_HEADER *SmbiosHeader;
SMBIOS_TYPE17_MEMORY_DEVICE *MemoryDevice;
CHAR8 *StringBuffer;
UINT8 MemoryAttributesLength;
if (Index >= 8) {
return EFI_INVALID_PARAMETER;
}
//
// Initialize SMBIOS header: type 17 (Memory Device)
//
SmbiosHeader = (SMBIOS_STRUCT_HEADER *)Buffer;
SmbiosHeader->Type = 17;
SmbiosHeader->Handle = 0xFFFE;
MemoryDevice = (SMBIOS_TYPE17_MEMORY_DEVICE *)Buffer;
switch (Index) {
case 0:
//
// CPU0 Channel 0 Slot 0: DIMM_A1
//
SmbiosHeader->Length = 0x1B;
MemoryDevice->TotalWidth = 8; // x8
MemoryDevice->DataWidth = 3; // x72
MemoryDevice->Size = 0x7E03; // 4GB
MemoryDevice->FormFactor = 9; // DIMM
MemoryDevice->DeviceSet = 0;
MemoryDevice->MemoryType = 0x1A; // DDR4
MemoryDevice->Speed = 2133;
MemoryDevice->Attributes = 0;
// Use platform data
break;
case 1:
//
// CPU0 Channel 0 Slot 1: DIMM_A2
//
SmbiosHeader->Length = 0x1B;
MemoryDevice->TotalWidth = 8;
MemoryDevice->DataWidth = 3;
MemoryDevice->Size = 0x7E03;
MemoryDevice->FormFactor = 9;
MemoryDevice->MemoryType = 0x1A;
MemoryDevice->Speed = 2133;
break;
case 2:
//
// CPU0 Channel 1 Slot 0: DIMM_B1
//
SmbiosHeader->Length = 0x1B;
MemoryDevice->TotalWidth = 8;
MemoryDevice->DataWidth = 3;
MemoryDevice->Size = 0x7E03;
MemoryDevice->FormFactor = 9;
MemoryDevice->MemoryType = 0x1A;
MemoryDevice->Speed = 2133;
break;
case 3:
//
// CPU0 Channel 1 Slot 1: DIMM_B2
//
SmbiosHeader->Length = 0x1B;
MemoryDevice->TotalWidth = 8;
MemoryDevice->DataWidth = 3;
MemoryDevice->Size = 0x7E03;
MemoryDevice->FormFactor = 9;
MemoryDevice->MemoryType = 0x1A;
MemoryDevice->Speed = 2133;
break;
case 4:
//
// CPU1 Channel 0 Slot 0: DIMM_C1
//
SmbiosHeader->Length = 0x1B;
MemoryDevice->TotalWidth = 8;
MemoryDevice->DataWidth = 3;
MemoryDevice->Size = 0x7E03;
MemoryDevice->FormFactor = 9;
MemoryDevice->MemoryType = 0x1A;
MemoryDevice->Speed = 2133;
break;
case 5:
//
// CPU1 Channel 0 Slot 1: DIMM_C2
//
SmbiosHeader->Length = 0x1B;
MemoryDevice->TotalWidth = 8;
MemoryDevice->DataWidth = 3;
MemoryDevice->Size = 0x7E03;
MemoryDevice->FormFactor = 9;
MemoryDevice->MemoryType = 0x1A;
MemoryDevice->Speed = 2133;
break;
case 6:
//
// CPU1 Channel 1 Slot 0: DIMM_D1
//
SmbiosHeader->Length = 0x1B;
MemoryDevice->TotalWidth = 8;
MemoryDevice->DataWidth = 3;
MemoryDevice->Size = 0x7E03;
MemoryDevice->FormFactor = 9;
MemoryDevice->MemoryType = 0x1A;
MemoryDevice->Speed = 2133;
break;
case 7:
//
// CPU1 Channel 1 Slot 1: DIMM_D2
//
SmbiosHeader->Length = 0x1B;
MemoryDevice->TotalWidth = 8;
MemoryDevice->DataWidth = 3;
MemoryDevice->Size = 0x7E03;
MemoryDevice->FormFactor = 9;
MemoryDevice->MemoryType = 0x1A;
MemoryDevice->Speed = 2133;
break;
default:
return EFI_INVALID_PARAMETER;
}
//
// Look up the device locator string from HII
//
StringBuffer = SmbiosGetHiiString (
gSmbiosStringPackHandle,
(UINT16)(28 + Index), // String IDs: 28-35 for DIMM labels
NULL,
NULL
);
if (StringBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
MemoryDevice->DeviceLocator = 1; // First string
//
// Append string to SMBIOS structure
//
SmbiosCopyMem (
(UINT8 *)Buffer + SmbiosHeader->Length,
StringBuffer,
AsciiStrLen (StringBuffer) + 1
);
//
// Add the bank locator string (second string)
//
MemoryDevice->BankLocator = 2;
SmbiosCopyMem (
(UINT8 *)Buffer + SmbiosHeader->Length + AsciiStrLen (StringBuffer) + 1,
"BANK 0",
7
);
//
// Double-null terminate
//
*((UINT8 *)Buffer + SmbiosHeader->Length + AsciiStrLen (StringBuffer) + 7) = 0;
SmbiosFreePool (StringBuffer);
return EFI_SUCCESS;
}
// ===========================================================================
// SMBIOS Type 41 (Onboard Devices Extended Information) Construction
// ===========================================================================
/**
Construct one SMBIOS type 41 onboard device entry.
@param[out] Buffer Buffer to receive the SMBIOS structure.
@param[in] Data Platform device config data.
@param[in] Index Device index (0 to 3).
@retval EFI_SUCCESS Structure built.
@retval EFI_INVALID_PARAMETER Index out of range.
**/
EFI_STATUS
SmbiosConstructType41Device (
OUT VOID *Buffer,
IN VOID *Data,
IN UINTN Index
)
{
SMBIOS_STRUCT_HEADER *SmbiosHeader;
SMBIOS_TYPE41_ONBOARD_DEVICE *Device;
if (Index >= 4) {
return EFI_INVALID_PARAMETER;
}
SmbiosHeader = (SMBIOS_STRUCT_HEADER *)Buffer;
SmbiosHeader->Type = 41;
SmbiosHeader->Handle = 0xFFFE;
Device = (SMBIOS_TYPE41_ONBOARD_DEVICE *)Buffer;
switch (Index) {
case 0:
//
// Onboard VGA controller
//
SmbiosHeader->Length = 0x0B;
Device->DeviceType = 0x03; // Video, enabled (bit 7 = 1)
Device->DeviceInstance = 0;
Device->SegmentGroup = 0;
Device->Bus = 0;
Device->DeviceFunction = 0;
// String: "Onboard VGA"
SmbiosCopyMem (
(UINT8 *)Buffer + SmbiosHeader->Length,
"Onboard VGA",
12
);
*((UINT8 *)Buffer + SmbiosHeader->Length + 12) = 0;
break;
case 1:
//
// Onboard Network Controller 1
//
SmbiosHeader->Length = 0x0B;
Device->DeviceType = 0x81; // Network, enabled
Device->DeviceInstance = 1;
Device->SegmentGroup = 0;
Device->Bus = 1;
Device->DeviceFunction = 0;
SmbiosCopyMem (
(UINT8 *)Buffer + SmbiosHeader->Length,
"Onboard NIC 1",
14
);
*((UINT8 *)Buffer + SmbiosHeader->Length + 14) = 0;
break;
case 2:
//
// Onboard Network Controller 2
//
SmbiosHeader->Length = 0x0B;
Device->DeviceType = 0x81; // Network, enabled
Device->DeviceInstance = 2;
Device->SegmentGroup = 0;
Device->Bus = 1;
Device->DeviceFunction = 1;
SmbiosCopyMem (
(UINT8 *)Buffer + SmbiosHeader->Length,
"Onboard NIC 2",
14
);
*((UINT8 *)Buffer + SmbiosHeader->Length + 14) = 0;
break;
case 3:
//
// Onboard SATA Controller
//
SmbiosHeader->Length = 0x0B;
Device->DeviceType = 0x82; // SATA, enabled
Device->DeviceInstance = 0;
Device->SegmentGroup = 0;
Device->Bus = 0;
Device->DeviceFunction = 2;
SmbiosCopyMem (
(UINT8 *)Buffer + SmbiosHeader->Length,
"Onboard SATA",
13
);
*((UINT8 *)Buffer + SmbiosHeader->Length + 13) = 0;
break;
default:
return EFI_INVALID_PARAMETER;
}
//
// Double-null terminate the string table
//
*((UINT8 *)Buffer + SmbiosHeader->Length + AsciiStrLen (
(CHAR8 *)Buffer + SmbiosHeader->Length
) + 1) = 0;
Device->ReferenceDesignation = 1;
return EFI_SUCCESS;
}
// ===========================================================================
// SMBIOS Table Installation
// ===========================================================================
/**
Install a fully constructed SMBIOS structure via the SMBIOS protocol.
@param[in] SmbiosTable Pointer to a complete SMBIOS structure.
@retval EFI_SUCCESS Table installed.
@retval EFI_INVALID_PARAMETER Invalid table structure.
@retval Others Error from SMBIOS protocol.
**/
EFI_STATUS
SmbiosInstallTable (
IN VOID *SmbiosTable
)
{
EFI_SMBIOS_PROTOCOL *SmbiosProtocol;
EFI_STATUS Status;
EFI_SMBIOS_HANDLE SmbiosHandle;
SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
//
// Locate SMBIOS protocol if not already loaded
//
if (gSmbiosProtocol == NULL) {
Status = gBS->LocateProtocol (
&gEfiSmbiosProtocolGuid,
NULL,
(VOID **)&SmbiosProtocol
);
if (EFI_ERROR (Status)) {
return Status;
}
gSmbiosProtocol = SmbiosProtocol;
}
//
// Add the SMBIOS table via the protocol's Add() function
//
Status = gSmbiosProtocol->Add (
gSmbiosProtocol,
NULL,
&SmbiosHandle,
SmbiosTable
);
return Status;
}
// ===========================================================================
// HII String Retrieval
// ===========================================================================
/**
Retrieve the SMBIOS string content from HII for a given string ID.
@param[in] HiiHandle HII handle.
@param[in] StringId String ID.
@param[in] PlatformLang Platform language (optional).
@param[in] LangCode Language code (optional).
@return Pointer to allocated string buffer, or NULL on failure.
**/
CHAR8 *
SmbiosGetHiiString (
IN EFI_HII_HANDLE HiiHandle,
IN EFI_STRING_ID StringId,
IN CONST CHAR8 *PlatformLang,
IN CONST CHAR8 *LangCode
)
{
EFI_HII_STRING_PROTOCOL *HiiString;
UINTN StringSize;
EFI_STRING StringBuffer;
CHAR8 *AsciiBuffer;
UINTN AsciiSize;
EFI_STATUS Status;
//
// Locate HII string protocol if needed
//
if (gHiiStringProtocol == NULL) {
Status = gBS->LocateProtocol (
&gEfiHiiStringProtocolGuid,
NULL,
(VOID **)&HiiString
);
if (EFI_ERROR (Status)) {
return NULL;
}
gHiiStringProtocol = (VOID *)HiiString;
}
HiiString = (EFI_HII_STRING_PROTOCOL *)gHiiStringProtocol;
//
// First call to get required buffer size (returns BUFFER_TOO_SMALL)
//
StringSize = 0;
StringBuffer = NULL;
Status = HiiString->GetString (
HiiString,
PlatformLang,
LangCode,
HiiHandle,
StringId,
StringBuffer,
&StringSize,
NULL
);
if (Status != EFI_BUFFER_TOO_SMALL) {
return NULL;
}
//
// Allocate string buffer
//
StringBuffer = (EFI_STRING)AllocatePool (StringSize);
if (StringBuffer == NULL) {
return NULL;
}
//
// Retrieve the string
//
Status = HiiString->GetString (
HiiString,
PlatformLang,
LangCode,
HiiHandle,
StringId,
StringBuffer,
&StringSize,
NULL
);
if (EFI_ERROR (Status)) {
FreePool (StringBuffer);
return NULL;
}
//
// Convert from UCS-2 to ASCII
//
AsciiSize = StringSize / sizeof (CHAR16) + 1;
AsciiBuffer = (CHAR8 *)AllocatePool (AsciiSize);
if (AsciiBuffer == NULL) {
FreePool (StringBuffer);
return NULL;
}
UnicodeStrToAsciiStrS (StringBuffer, AsciiBuffer, AsciiSize);
FreePool (StringBuffer);
return AsciiBuffer;
}
// ===========================================================================
// Platform Language Retrieval
// ===========================================================================
/**
Get the platform language variable.
@param[out] Value Receives pointer to allocated language string.
@return EFI_STATUS.
**/
EFI_STATUS
SmbiosGetPlatformLang (
OUT CHAR16 **Value
)
{
EFI_STATUS Status;
UINTN Size;
Size = 0;
*Value = NULL;
//
// Query required size for PlatformLang variable
//
Status = gRT->GetVariable (
L"PlatformLang",
&gEfiGlobalVariableGuid,
NULL,
&Size,
NULL
);
if (Status != EFI_BUFFER_TOO_SMALL) {
return Status;
}
//
// Allocate and retrieve the value
//
*Value = (CHAR16 *)AllocatePool (Size);
if (*Value == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = gRT->GetVariable (
L"PlatformLang",
&gEfiGlobalVariableGuid,
NULL,
&Size,
*Value
);
if (EFI_ERROR (Status)) {
FreePool (*Value);
*Value = NULL;
}
return Status;
}
// ===========================================================================
// SMBIOS Notify End-of-Type
// ===========================================================================
/**
Notify SMBIOS that enumeration of a given type is complete.
This sends a notification to the SMBIOS protocol that no more tables
of the given type will be added.
@param[in] SmbiosType The SMBIOS type number to finalize.
**/
VOID
SmbiosNotifyEndOfType (
IN UINT8 SmbiosType
)
{
// The SMBIOS protocol notification interface allows drivers to
// signal completion of table enumeration per type.
// This is typically a no-op on most firmware.
return;
}
// ===========================================================================
// Debug/Trace Support
// ===========================================================================
//
// Debug message display function (conditional on build flags).
// Writes formatted output to the UEFI debug console.
//
// Note: DEBUG_ERROR messages are always compiled in, INFO and VERBOSE
// are compiled out in RELEASE builds.
//
// ===========================================================================
// Legacy ASSERT support wrappers
// ===========================================================================
/**
Print ASSERT information and break.
@param[in] FileName Source file name.
@param[in] LineNumber Line number.
@param[in] Description Assert description.
**/
VOID
SmbiosAssert (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
)
{
//
// Calls into UEFI's DebugAssert via DebugLib
//
DEBUG ((EFI_D_ERROR, "ASSERT [%a]:%d: %a\n", FileName, LineNumber, Description));
CpuDeadLoop ();
}
/** @} */