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

StatusCodeSmm

Function Table

Address Name Description
ModuleEntryPoint
SmmStatusCodeDriverInit
SmmStatusCodeRegisterProtocols
SmmStatusCodeRegisterCallback
SmmStatusCodeUnregisterCallback
SmmStatusCodeDispatchCallbacks
SmmStatusCodeHandler
SmmStatusCodeAssertHandler
SmmStatusCodeProgress
StatusCodeFormatString
StatusCodeReportError
StatusCodeWriteSerial
StatusCodeReportToSerial
StatusCodeWritePort80
StatusCodeCheckAndEnable
SMM Status Code Reporting Driver
Decompiled and reconstructed from IDA Pro analysis of the
Lenovo HR650X BIOS UEFI firmware image. All functions have been
identified and renamed for clarity.
This SMM driver provides status code reporting infrastructure
within System Management Mode. It intercepts SMI events triggered
by status code writes and routes them to configurable output
channels (serial, port 80 POST codes) and registered callbacks.
Global variable storage
EFI_HANDLE gImageHandle;
Static data tables (defined in .rdata)
Error code lookup table.
Each entry: {UINT32 StatusCode, UINT32 StringOffset}
Terminated by {0, 0}.
Correctable memory error
CPU thermal error
CPU low voltage
CPU high voltage
Correctable CPU ECC error
terminator };
Module Entry Point (_ModuleEntryPoint at 0x500)
Standard UEFI driver entry. Initializes SMM environment, registers
SMI handlers with error recovery via SetJump/LongJump.
EFI_STATUS EFIAPI
These ASSERTs fire only if LongJump fails (should never happen)
SmmStatusCodeDriverInit (0x5B4)
Initializes the SMM driver environment:
VOID SmmStatusCodeDriverInit (
Save global pointers
Locate SMM Base2 protocol
Locate SMM Access2 protocol to get SMRAM sizes
Read PCI Express base address from PCD
Locate HOB list
Configure LPC serial port (if enabled)
PCI config address 0xFA004 = LPC command register (B0/D31/F0/Reg4)
PCI config address 0xFA000 = LPC vendor/device ID register
Set I/O base to 0x500
Enable memory space (bit 1 of command register)
Wait for TCO timer to stabilize
Port 0x508 is the TCO I/O base register
Restore interrupt state
SmmStatusCodeRegisterProtocols (0xCD0)
Registers three SMM handlers:
EFI_STATUS SmmStatusCodeRegisterProtocols (
Handler #1: Register SmmStatusCodeHandler via EFI_SMM_CPU_IO2_PROTOCOL
This causes the handler to fire on CPU I/O operations that generate
status code SMI events.
via gSmmStatusCodeHandlerPtr
Handler #2: Register callback management protocol
Handler #3: Register progress/status code protocol
SmmStatusCodeRegisterCallback (0x8F0)
Registers a callback function pointer in the callback table.
Callbacks are invoked when status code events occur.
UINT64 SmmStatusCodeRegisterCallback (
RETURN_INVALID_PARAMETER }
Reuse empty slot
SmmStatusCodeUnregisterCallback (0x8A8)
Removes a callback function pointer from the callback table.
UINT64 SmmStatusCodeUnregisterCallback (
SmmStatusCodeDispatchCallbacks (0x988)
Iterates all registered callback functions and invokes each with
the status code parameters.
Uses a reentrancy guard (gReentrancyGuard) to prevent recursive
callback dispatch.
is already in progress
UINT64 SmmStatusCodeDispatchCallbacks (
SmmStatusCodeHandler (0xB84)
The main SMI status code handler. Called when a status code SMI
dispatches registered callbacks, and outputs to serial.
VOID SmmStatusCodeHandler (
Invoke per-status-code callbacks
SmmStatusCodeAssertHandler (0xC24)
Invoked when an ASSERT condition fires in SMM. Formats the assert
message with file/line info, dispatches assert-specific callbacks
and outputs via serial.
UINT64 SmmStatusCodeAssertHandler (
Invoke assert-specific callbacks
SmmStatusCodeProgress (0xA58)
Handles status code progress (type 1) and error (type 2) events.
Dispatches registered callbacks, runs enable/disable checks
formats the status string, outputs to serial, and handles
For EFI progress codes (type == 2), also queries a progress function
table for matching dispatch.
UINT64 SmmStatusCodeProgress (
Run enable/disable filter check callbacks
Run progress-specific callbacks
For progress type 2, dispatch via progress function table
StatusCodeFormatString (0xE1C)
Examines the status code data GUID to determine its type and
formats the output string accordingly:
Extracts text from data payload, converts Unicode to ASCII
Uses format string from offset +120 and args from offset +24
Reads line number and file/description from payload.
Requires type=2, class=0x90, subclass=7.
Reads line number at offset +60 and file at offset +80.
No GUID match + Type 2: delegates to StatusCodeReportError
No GUID match + other types: returns 0 (no output)
UINT64 StatusCodeFormatString (
Skip header to get GUID
Check #1: Plain string data GUID
Copy string from payload
Check #2: Standard string type GUID
Check #3: AMI DataHub ASSERT GUID
Check #4: AMI ASSERT GUID
Fall through to FormatAssert
StatusCodeReportError (0xD94)
Looks up a status code in the known error code table (gErrorCodeTable).
If the code is found, formats "ERROR: %a" with the error description
string from the status code data payload.
If the code is not found (or table empty), formats the raw status
code as three hex fields: "ERROR: Class:%X; Subclass:%X; Operation: %X\n"
UINT64 StatusCodeReportError (
Found in table - format with string from data payload
Not found - format raw hex values
StatusCodeWriteSerial (0xFE8)
Writes a string to the serial port with proper CR/LF handling.
UINT64 StatusCodeWriteSerial (
Bare "\n" - flush accumulated prefix and emit "\r\n"
StatusCodeReportToSerial (0x105C)
Dispatches to StatusCodeWriteSerial (primary) and any additional
output handlers registered in the output callback table.
UINT64 StatusCodeReportToSerial (
Primary serial output
StatusCodeWritePort80 (0x109C)
Writes a byte to the hardware POST code display port (0x80).
Used for debug POST cards or BMC POST code capture.
UINT64 StatusCodeWritePort80 (
StatusCodeCheckAndEnable (0x10A8)
For type 1 (progress) and type 2 (error), looks up the status code
value in the enable/disable table. If the code is enabled, invokes
the port 80 write callbacks (including StatusCodeWritePort80).
UINT64 StatusCodeCheckAndEnable (
Walk the enable table for this type
These are standard UEFI library implementations compiled into this
module by the build system (MdePkg BaseLib, BasePrintLib, etc.).
They are documented here for completeness.
SetJump (0x2C0) / LongJump (0x360)
SetJump saves: RBP, stack pointer, return address, XMM regs
LongJump restores context and jumps to the saved return point.
SetJumpValidate (0x1130)
Validates the jump buffer alignment (must be 8-byte aligned).
DebugAssert (0x132C)
Formats an ASSERT message string using AsciiSPrint.
DebugAssertWorker (0x1210)
Callback to the standard error interface (via protocol at 0x3ED0).
If the protocol is available, formats: file, line, message.
GetStandardErrorInterface (0x1178)
Locates the SMM standard error protocol (GUID at 0x3ED0) and caches
it in qword_4F68.
DebugPrint (0x11C8)
Conditional debug print: checks error level against current setting
invokes the standard error interface if enabled.
GetDebugPrintErrorLevel (0x2AC8)
Reads the debug print error level from CMOS offset 0x4C.
If the CMOS value is out of range, checks a memory-mapped
location (0xFDAF0490) for the BMC-preserved value.
Returns 0 (disabled), 0x80000004 (level 1), or 0x80000006 (level 2+).
SerialPortWrite (0x2A18)
Detects Super I/O type via SIO port 0x72/0x73:
Writes bytes to serial port data register at (base + 0).
Waits for THR empty (LSR bit 6). Bursts up to 16 bytes per
AsciiSPrint (0x1404) - ~3573 bytes (0xDF5)
Full UEFI AsciiSPrint implementation from BasePrintLib.
Supports format specifiers:
String length limited to 0xF4240 (1,000,000) characters.
AsciiSPrintUnsafe (0x2984)
Thin wrapper that va_start's and calls SPrint.
SPrint (0x2544) - Unicode-aware printf
Full SPrint implementation from PrintLibInternal.c supporting
all standard format specifiers documented above.
StatusToString (0x247C)
Converts EFI_STATUS value to human-readable string:
EFI_SUCCESS (0) -> "EFI_SUCCESS"
Warning codes (0x2xxxxxxx) -> "EFIWARN..."
Error codes (0x8xxxxxxx) -> various error strings
Interrupt codes (0xAxxxxxxx) -> "EFI_INTERRUPTPENDING..."
Unrecognized values -> NULL
String table is embedded in .rdata at known offsets.
ValueToString (0x2334)
Converts integer value to ASCII string in given base (10 or 16).
Supports negative values for base 10.
AsciiStrDecimalToUintn (0x23A8)
Parses a decimal string to UINTN. Skips leading whitespace
handles +/- sign. Supports hex digits a-f/A-F (returns base-10).
AsciiStrSetChar (0x1358)
Fills a buffer with repeated character (1-byte ASCII or 2-byte Unicode).
Uint64ToAsciiString (0x138C)
Converts UINT64 to ASCII hex string using LookupTable "0123456789ABCDEF".
CompareMem (0x29A4)
Memory compare. Compares byte-by-byte with qword optimization for
aligned sections.
IsAddressInSmram (0x1250)
Checks if an address falls within any known SMRAM descriptor range.
SmmAllocatePool (0x1294)
Allocates SMM pool memory via gSmst->SmmAllocatePool.
SmmFreePool (0x12C4)
Frees memory via gSmst->SmmFreePool if in SMRAM, or gBS->FreePool
if not. Used during module unload or error cleanup.
IsHobGuidType (0x2BF4)
Checks if a HOB entry matches a known GUID type by comparing
the Buffer_ and Buffer__0 GUIDs.
GetHobList (0x225C)
Walks the System Table firmware volume HOB entries to find the
HOB matching known GUIDs. Caches result in qword_4F78.
GetPcdProtocol (0x2CD4)
Locates the EFI_PCD_PROTOCOL (GUID {11B34006-...})
via gBS->LocateProtocol. Caches result in qword_4F90.
PciExpressGetAddress (0x2220)
Calculates the MMIO address for a PCI config space register:
result = Address + gPciExpressBaseAddress
Requires Address < 0x10000000.
PciExpressWrite8 (0x21FC)
Writes a byte to PCI config space via the PCIe MMIO address window.
Standard UEFI BaseLib string utility functions.
CpuPause (0x3E0), ReadTsc (0x3F0)
EnableInterrupts (0x400), DisableInterrupts (0x410)
GetCallerEflags (0x420)
Intrinsic functions:
CpuPause = _mm_pause()
ReadTsc = __rdtsc()
EnableInterrupts = _enable() (STI)
DisableInterrupts = _disable() (CLI)
GetCallerEflags = __getcallerseflags() (PUSHFQ)
IoWrite16 (0x2C64) - Write 16-bit value to I/O port
IoRead32 (0x2CA4) - Read 32-bit value from I/O port
ReadUnaligned16 (0x2B18) - Read 16-bit from potentially unaligned addr
ReadUnaligned64 (0x2B48) - Read 64-bit from potentially unaligned addr
StrLen (0x2B78) - Unicode string length
AsciiStrLen (0x2BD0) - ASCII string length

Generated by HR650X BIOS Decompilation Project