Newer
Older
AMI-Aptio-BIOS-Reversed / SmbiosDataUpdateDxeLightningRidgeEXRP / SmbiosDataUpdateDxeLightningRidgeEXRP.md
@Ajax Dong Ajax Dong 2 days ago 20 KB Init

SmbiosDataUpdateDxeLightningRidgeEXRP

Function Table

Address Name Description
ReadUnaligned64
WriteUnaligned64
AsciiStrLen
StrLen
AsciiStrnLenS
UnicodeStrnToAsciiStrS
ReadUnaligned32
CompareGuid
FreePool
GetConfigTable
GetPlatformLang
DebugPrint
AssertHandler
AddSmbiosString
FindFirstSmbiosString
RemoveAndAddSmbiosString
RemoveAllSmbiosStringsOfType
GetSmbiosStructuresAfterField
UpdateSmbiosStringField
BuildSmbiosStringRecord
BuildSmbiosType9Record
BuildSmbiosType41Record
MmPciWriteConfig
SmbiosDataUpdateDispatch
SmbiosDataUpdateEntry
SmbiosDataUpdateInit
ModuleEntryPoint
Global UEFI system table pointers (initialized by SmbiosDataUpdateInit)
EFI_HANDLE gImageHandle = NULL; ///< 0x3928 - EFI image handle
Cached protocol/state pointers
VOID *mDebugProtocol = NULL; ///< 0x3938 - Cached DebugLib protocol
Global state
EFI_GUID mSmbiosConfigGuid; ///< 0x38F0 - Board-specific SMBIOS config GUID
GUID Definitions (protocol and config identifiers)
GUID for the UBA config protocol opened from ImageHandle.
Contains board-specific SMBIOS configuration data.
static EFI_GUID mUbaConfigProtocolGuid = {
GUID for "en-US" default language (RFC 4646).
Used as default platform language when PlatformLang variable is not set.
static UINT16 mDefaultLanguage[] = L"en-US";
HOB list GUID for configuration table lookup.
static EFI_GUID mHobListGuid = {
DXE Services Table GUID.
static EFI_GUID mDxeServicesTableGuid = {
Global Variable GUID for UEFI standard variables (PlatformLang).
static EFI_GUID mGlobalVariableGuid = {
DebugLib protocol GUID.
static EFI_GUID mDebugLibProtocolGuid = {
HII Font protocol GUID.
static EFI_GUID mHiiFontProtocolGuid = {
HII Database protocol GUID.
static EFI_GUID mHiiDatabaseProtocolGuid = {
HII Package List protocol GUID.
static EFI_GUID mHiiPackageListProtocolGuid = {
HII String protocol GUID.
static EFI_GUID mHiiStringProtocolGuid = {
static EFI_GUID mSmbiosProtocolGuid = {
MM PCIe Base protocol GUID.
static EFI_GUID mMmPciBaseProtocolGuid = {
UBA SMBIOS Data protocol GUID.
This protocol is used to register SMBIOS data update configuration.
static EFI_GUID mUbaSmbiosDataProtocolGuid = {
SMBIOS string package GUID for HII registration.
Identifies this driver's HII string package for SMBIOS strings.
static EFI_GUID mSmbiosStringPackageGuid = {
SMBIOS String Descriptor Table
SMBIOS Type 2 (Baseboard) string descriptor table (30 entries).
Each entry is 10 bytes: {Type, FieldNum, StringId(16), Encoding, Offset, MaxLen, Flags, Reserved(16)}
These descriptors define which SMBIOS Type 2 string fields to update and
which HII string tokens to use for localized string lookup.
SMBIOS Type 2 fields: Manufacturer, ProductName, Version, SerialNumber
static CONST SMBIOS_STRING_DESC mSmbiosType2Descriptors[30] = {
Entry 0: Type=8 (Type2), Field=3, StrId=0x0002, Enc=0x08, Off=8, Max=3, Flag=0x08000000
Entry 1: Type=8 (Type2), Field=4, StrId=0x04, Enc=0x10, Off=8, Max=16, Flag=5
Entries 2-29 follow the same pattern with different field numbers
string IDs, encodings, offsets, max lengths, and flags.
Full descriptor table details available in the disassembly at sub_77C.
The table is a 300-byte (30 * 10) embedded constant array.
Key field numbers: 5 (Manufacturer), 6 (ProductName), 7 (Version)
8 (SerialNumber), 9 (AssetTag), 10-29 (additional board strings).
Forward Declarations of Internal Functions
Zero 8-byte aligned chunks first.
SetMem (Buf, Length & ~7, 0);
Zero remaining bytes (0-7).
SetMem (&Buf[Length & ~7], Length & 7, 0);
Copy backwards from the end to avoid corruption.
Src = &Src[Length - 1];
Copy remaining 8-byte chunks backward
No overlap or destination before source: copy forward.
CountQwords = Length >> 3;
Copy 8-byte aligned chunks.
CopyMem (Dst, Src, CountQwords * 8);
Copy remaining bytes.
CopyMem (Dst, Src, CountRemaining);
Memory and String Library Functions
Check for overlap between source and destination buffers.
Overlap = FALSE;
Overlap error, treated as buffer error
Convert each UCS-2 character to ASCII.
while (*Src != 0) {
GUID Manipulation
Memory Allocation
Status = gBootServices->AllocatePool (
Status = gBootServices->FreePool (Buffer);
Configuration Table Access
Compare GUIDs using 128-bit comparison.
if (CompareGuid (&ConfigTable[Index].VendorGuid, TableGuid)) {
HOB List Access
Return cached pointer if already initialized.
HobList = mHobList;
Find the HOB list in the configuration table.
Status = GetConfigTable (&mHobListGuid, &mHobList);
Verify the HOB list was found.
if (mHobList == NULL) {
Language and Variable Services
Call GetVariable with zero size first to get required buffer size.
Status = gRuntimeServices->GetVariable (
Allocate buffer of required size.
LangBuffer = AllocatePool (BufferSize);
Read the variable data.
Determine the length of the language to check.
If full match mode (LanguageMatch != 0) is disabled (0)
use the full string; otherwise truncate to 3 characters.
if (LanguageMatch == 0) {
Full match: use the complete string length, but truncated
to 3 chars if zero mode is off and string is long.
SupportedLen = 0;
Scan the supported languages string for a match.
if (LanguageMatch != 0) {
Full match mode: iterate through each language list entry.
Supported = SupportedLanguages;
Skip ';' separators.
while (*Supported == ';') {
Get the length of this supported language entry.
Match found - allocate buffer and copy the language.
ResultLen = SupportedLen + 1;
Short match mode: truncate language to 3 characters, compare.
if (CheckLen <= 3) {
Scan supported languages.
If full check fails, try truncating to 3 chars.
if (CheckLen > 3 && 3 <= SupportedLen) {
Handle RFC 4646 language tags with '-' separator.
while (Supported[SupportedLen] == '-') {
Move to next language string in varargs.
LangToCheck = VA_ARG (Args, CONST CHAR8 *);
Debug Output
DebugProtocol = mDebugProtocol;
Allocate pool as a probe. The allocation size is 31 bytes
PoolSize = MEMORY_TYPE_BOOT_SERVICES_DATA;
This is a non-standard check unique to this implementation.
if ((UINTN)mDebugProtocol > 0x10) {
Status = gBootServices->LocateProtocol (
Suspicious allocation pointer - treat as failure.
mDebugProtocol = NULL;
Get the DebugLib protocol; if not available, skip the print.
DebugProtocol = GetDebugLibProtocol ();
Read the platform SKU from RTC CMOS register 0x4B.
The NMI-disable bit (0x80) is preserved in the index write.
IoWrite8 **(RTC_CMOS_INDEX_PORT, (IoRead8 (RTC_CMOS_INDEX_PORT) & 0x80) RTC_CMOS_INDEX_SKU);**
Determine effective SKU:
EffectiveSku = CmosSku;
Read platform info register for IIO mode detection.
Bit 1 of 0xFDAF0490 indicates IIO configuration mode.
EffectiveSku *= ((volatile UINT8 *)PLATFORM_INFO_REGISTER & 0x02) 0x01;**
Map platform SKU to debug level filter mask.
Valid SKU range (1-4 maps to 0-3).
FilterMask = UBA_DEBUG_ERROR; // Default: only errors
If the requested debug level passes the filter, call DebugPrint.
if ((FilterMask & DebugLevel) != 0) {
DebugProtocol layout:
Call DebugProtocol->Assert (at offset +8).
HII Protocol Services
Call with NULL buffer to get required size.
Now get the actual string.
Status = ((EFI_HII_GET_STRING_INFO)((VOID )mHiiFont)[3])(**
Validate parameters.
if (HiiHandle == NULL) {
Get the supported languages for this HII string package.
SupportedLanguages = GetHiiSupportedLanguages (HiiHandle, StringId, Type, MaxLen);
Get the current platform language.
Match the platform language against supported languages.
Use "en-US" as default language for matching.
Fall back to the first supported language.
MatchedLanguage = GetSupportedLanguage (
Get the localized string size by calling HiiFont->StringToImage (offset +8)
with NULL buffer to get required size.
Allocate buffer for the string.
ResultString = AllocatePool (StringSize);
Get the actual string.
Status = ((EFI_HII_STRING_TO_IMAGE)((VOID )mHiiFont)[1])(**
Clean up temporary allocations.
FreePool (SupportedLanguages);
ResultString was allocated separately, keep it
Call StringToImage with NULL buffer to get required size.
Allocate buffer.
String = AllocatePool (Size);
if (Guid == NULL) {
If no string entries, return NULL handle.
if (StringPackage == NULL) {
Calculate total package size.
Each entry header has size-4 in the first 4 bytes.
We need to sum all entry sizes (excluding the 4-byte header
contribution counted as size-4 per entry).
Entry = StringPackage;
Allocate buffer for the entire package list (header + data).
The HII package list header is sizeof(EFI_HII_PACKAGE_LIST_HEADER)
which includes a GUID (16 bytes) and package length (24 bytes total).
DataSize = TotalSize + sizeof (EFI_HII_PACKAGE_LIST_HEADER);
Fill in the package list header.
Copy the GUID to the beginning of the package list.
CopyGuid ((EFI_GUID *)PackageData, Guid);
Copy all package entries.
Add the terminating 4-byte zero entry.
CopyMem (Dst, &mZeroGuid, 4);
Call HiiDatabase->NewPackageList (at offset +0 of qword_3968).
Get or locate the SMBIOS protocol.
SmbiosProto = mSmbiosProtocol3;
Initialize handle to "uninitialized" (0xFFFE).
The SMBIOS AddString function at protocol offset 0 uses:
Handle = SMBIOS_HANDLE_UNINITIALIZED;
SmbiosProto = mSmbiosProtocol1;
Search for the first matching string.
The SMBIOS protocol GetNext function at offset +24 enumerates strings:
SearchType = TypeId;
Find and remove the current string, then add the replacement.
Status = FindFirstSmbiosString (TypeId, &Handle);
Remove the old string at protocol offset +16.
Add the new string at protocol offset 0.
SmbiosProto = mSmbiosProtocol2;
Locate the SMBIOS protocol.
if (gBootServices->LocateProtocol (
Enumerate and remove all strings of the given type.
Remove each string of this type.
for (; Count > 0; Count--) {
FieldCount *TotalLength = Length;
Scan through the string data to find the end.
Strings are terminated by a double-null (one after each string
plus a final null to mark end of all strings).
while (TRUE) {
Found a null terminator. Check if it's the end of strings
if (*++Scan == '\0') {
Count characters until next null.
for (Index = 0; Index < 64; Index++) {
No null found in 64 chars - likely an error.
Get the source string length.
StringLen = AsciiStrLen (NewString);
Get the SMBIOS structure length.
GetSmbiosStructuresAfterField (RecordBuffer, &TotalLen);
Calculate the field position within the record.
FieldPos = Buf[1]; // FieldCount (offset to first string)
Scan through fields to find the target field position.
if (FieldIndex > 1) {
Check if the new string length matches the field's existing length.
If AsciiStrLen of FieldPtr's region matches StringLen, we can do an
FieldLen = AsciiStrLen (FieldPtr);
Same length - in-place replacement.
if (FieldPtr != NULL) {
if *(FieldPtr >= (UINT8 )NewString **
No overlap, direct copy.
if (FieldPtr == (UINT8 *)NewString) {
Same pointer, nothing to do.
return EFI_SUCCESS;
Recalculate the structure after the field.
Overlap detected - use auxiliary buffer for safe copy.
SMBIOS_STRING_RECORD_SIZE if (RecordBuffer2 == NULL) {
Copy the record to auxiliary buffer, modify, and copy back.
CopyMem (RecordBuffer2, RecordBuffer, FieldPos + v13 + Buf[1]);
Write new string.
AsciiStrCpyS (
Copy back and recalculate.
GetSmbiosStructuresAfterField (RecordBuffer2, &TotalLen);
Copy the updated record back.
CopyMem (&Buf[FieldPos + v13 + Buf[1]], &FieldPtr[FieldLen - StringLen + 1], StringLen + 1);
Final size update.
Null field pointer - append? This is a complex path.
Different length - need to insert/remove space.
Allocate auxiliary buffer for safe manipulation.
AuxBuffer = (UINTN)AllocateZeroPool (SMBIOS_STRING_RECORD_SIZE);
Copy the part before the new string.
Copy the part after the old string, skipping it.
Calculate new total length.
AuxTotalLen = TotalLen - FieldLen + StringLen;
Copy back to original buffer.
GetSmbiosStructuresAfterField ((VOID *)AuxBuffer, &TotalLen);
Clean up.
FreePool ((VOID *)AuxBuffer);
Get the descriptor entry for this index.
Desc = &mSmbiosType2Descriptors[DescriptorIndex];
Initialize the SMBIOS string record header.
Byte 0: Type (8 = Type 2 Baseboard)
Byte 1: FieldCount (29 = total fields -1)
Word 2-3: Handle (0xFFFE = uninitialized)
SMBIOS type 2
30 fields, index 0-29
Copy the descriptor field metadata into the record header at offsets 4-7.
From the original binary (sub_77C, 0x77C):
If StringId is non-zero, look up the localized string.
A zero StringId means this descriptor has no associated string.
if (StringId != 0) {
Get the localized string from HII font protocol.
LocalizedString = GetHiiString (
Write the string into the SMBIOS record buffer.
The function handles buffer manipulation, overlap-safe
No explicit FreePool needed here.
The function at address 0xA20 constructs Type 9 SMBIOS records.
It follows a similar pattern to BuildSmbiosStringRecord but for
SMBIOS Type 9 (System Slots) fields.
From the dispatch function (SmbiosDataUpdateDispatch), this function
is called for 8 iterations (0-7). It takes a working buffer and index
builds the record, and the caller then writes it to SMBIOS.
return EFI_UNSUPPORTED;
The function at address 0xD98 constructs Type 41 SMBIOS records.
SMBIOS Type 41 (Onboard Devices Extended Information) fields.
is called for 4 iterations (0-3). It takes a working buffer and index
MM PCI Configuration
Encode the PCI address.
Address **format: ((Func & 7) (8 * ((Dev & 0x1F) (32 Bus)))) << 12*
UINT32 Address;
Prepare address structure for MmPciBase->Write.
Encode the PCI address: Bits [14:12] = Func, [19:15] = Dev, [24:20] = Bus.
Call MmPciUsra->Write (at offset +24) with the address structure.
if (mMmPciUsra == NULL) {
SMBIOS Data Update Dispatch
Allocate working buffer for SMBIOS string record construction.
WorkBuffer = AllocateZeroPool (SMBIOS_STRING_RECORD_SIZE);
Phase 1: Process 30 SMBIOS Type 2 (Baseboard) string fields.
Remove all existing Type 2 strings first.
RemoveAllSmbiosStringsOfType (SMBIOS_TYPE_BASEBOARD);
Process each Type 2 string field.
for (i = 0; i < SMBIOS_TYPE2_COUNT; i++) {
Phase 2: Process 8 SMBIOS Type 9 (System Slot) string fields.
RemoveAllSmbiosStringsOfType (SMBIOS_TYPE_SYSTEM_SLOTS);
Phase 3: Process 4 SMBIOS Type 41 (Onboard Device) string fields.
RemoveAllSmbiosStringsOfType (SMBIOS_TYPE_ONBOARD_DEVICES);
FreePool (WorkBuffer);
Main Entry Point (SmbiosDataUpdateEntry)
Open the UBA config protocol installed on ImageHandle.
Status = gBootServices->OpenProtocol (
Print module identification string.
Copy the board-specific SMBIOS config GUID from UBA config data.
The config data is at UbaConfig + 4 bytes (first 4 bytes are header).
CopyGuid (&mSmbiosConfigGuid, (EFI_GUID )((UINT8 )UbaConfig + 4));
Register the HII string package.
gSmbiosStringPackHandle = RegisterHiiPackageList (
String data from HII table
Prepare the dispatch configuration buffer.
ZeroMem (ConfigBuffer, sizeof (ConfigBuffer));
Version ConfigBuffer[2] = 9; // Dispatch function index
Locate the UBA SMBIOS Data protocol.
if (mUbaSmbiosDataProtocol == NULL) {
Register the SMBIOS config with the UBA protocol.
This call triggers the SmbiosDataUpdateDispatch callback.
return ((UBA_SMBIOS_DATA_PROTOCOL *)mUbaSmbiosDataProtocol)->SetSmbiosData (
Initialization Function (SmbiosDataUpdateInit)
The initialization logic from the original sub_38C (address 0x38C)
has been inlined into ModuleEntryPoint() below.
This function is kept as a stub for documentation purposes since the
original binary had this as a separate function called from the entry
MM PCIe base protocol) is now performed directly in ModuleEntryPoint().
Module Entry Point
Step 1: Initialize global UEFI service table pointers.
gImageHandle = ImageHandle;
Step 2: Locate HII services protocols.
Locate HII Font protocol.
Locate HII String protocol.
Locate HII Database protocol.
Locate HII Package List protocol.
Locate HII Package List protocol interface.
Step 3: Find DXE Services Table from SystemTable->ConfigurationTable.
Status = GetConfigTable (&mDxeServicesTableGuid, &mHobList);
Step 4: Optionally locate MM PCIe base protocol.
This may already be cached from a previous lookup.
Step 5: Initialize HOB list.
HobLibInit ();
Step 6: Perform SMBIOS data update.
Status = SmbiosDataUpdateEntry (ImageHandle);

Generated by HR650X BIOS Decompilation Project