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

PlatformErrorHandler Module

Overview

SMM platform error handler for Intel Purley platform. This DXE driver runs in SMM to handle platform RAS (Reliability, Availability, Serviceability) errors. It initializes EMCA (Enhanced Machine Check Architecture) platform hooks, populates RAS topology structures (SMBIOS Type 16/17), configures FPGA error handling policies from UEFI setup variables, registers SMM software dispatch callbacks for error notification, and manages per-socket error tracking via linked callbacks.

Source file: PurleyPlatPkg/Ras/Smm/ErrHandling/PlatformErrorHandler/PlatformErrorHandler.c

Address Range

0x300 - 0x5480 (83 functions, 5180 bytes .text)

Module State: Global Variables

Note: qword_ prefix variables are in the .data segment (0x6880-0x2AF00).

Address Name Purpose
0x72D8 qword_72D8 Module status/result code (initialized to 0x8000000000000001 = EFI_NOT_FOUND?)
0x72E0 i Linked list head for error source registrations (fwd callbacks)
0x72E8 i_1 Tail pointer for error source linked list
0x72F0 i_0 Linked list head for error notification callbacks
0x72F8 qword_72F8 Tail pointer for notification callback list
0x7300 SystemTable EFI System Table pointer
0x7308 BootServices EFI Boot Services table pointer (gBS)
0x7310 qword_7310 ImageHandle
0x7318 qword_7318 Runtime Services table pointer (gRT)
0x7320 qword_7320 SMM System Table 2 pointer (gSmst)
0x7368 qword_7368 EMCA Platform Protocol interface pointer (GUID {F4CCBFB7-F6E0-47FD-9DD4-10A8F150C191})
0x7370 qword_7370 SMM System Table pointer (from EMCA protocol)
0x7378 qword_7378 SMM MC Bank Protocol
0x7380 qword_7380 Platform Info Policy (from EMCA, offset 1780 has boot mode info)
0x7388 qword_7388 MC Bank list table (array of 32-byte entries per bank, indexed by socket)
0x7390 n6 Number of MC banks (per sub_1AB0)
0x7398 qword_7398 Error policy table
0x73A0 qword_73A0 MC Bank enable/control table
0x73A8 n2 Number of sockets?
0x73B0 qword_73B0 MSR MCG_STATUS (0x179) cached value
0x73B8 qword_73B8 gDS (EFI_DRIVER_SERVICES table)
0x73C0 unk_73C0 SMM IPMI Transport Protocol interface pointer
0x73C8 unk_73C8 SMM Variable Protocol interface pointer
0x73D0 qword_73D0 SMM Variable Protocol (setup lib)
0x73D8 byte_73D8 Is in SMM context flag (from EMCA probe)
0x73E0 qword_73E0 EMCA Platform Protocol (setup lib usage)
0x7400 qword_7400 SMM Communication buffer pointer (from SMM Comm protocol)
0x7408 qword_7408 Setup variable data pointer (VariableGet)
0x7410 qword_7410 Setup variable data pointer (HOB)
0x7418 qword_7418 Runtime Memory descriptor?
0x7420 qword_7420 Accumulated setup variables data buffer (size 0x2A3B)

Key Functions

Address Name Purpose
0x5CC _ModuleEntryPoint DXE driver entry point; calls library constructors and main init
0x594 sub_594 Alternate entry point (SMM module entry via SW dispatch?)
0x30D8 sub_30D8 AutoGen library constructor dispatcher (calls 12 library constructors)
0x3550 sub_3550 Main driver initialization logic
0x34E0 sub_34E0 Fallback error init (called if main init fails)
0x3088 sub_3088 Status coalescing + set event (restore event to -1)

Entry Points (Public API)

  • 0x5CC _ModuleEntryPoint: Standard UEFI DXE driver entry. Calls sub_30D8 for library constructor chain, then sub_3550 for main initialization. If main init returns error (<0), calls sub_34E0 fallback.

  • 0x594 sub_594: SMM module entry path (registered via SMM SW dispatch or standalone entry). Calls sub_F0C (gSmst init) then sub_34E0.

Internal Helpers

Library Constructors (called from sub_30D8 chain):

Address Name Source
0x6BC sub_6BC UefiBootServicesTableLib constructor - sets gImageHandle, gST, gBS
0x758 sub_758 SmmServicesTableLib constructor - sets gSmst
0x794 sub_794 DxeHobLib constructor
0xC28 sub_C28 BaseLib constructor
0xEA8 sub_EA8 SmmMemoryAllocationLib constructor
0xF0C sub_F0C Thunk to gSmst init
0x1094 sub_1094 BaseSynchronizationLib constructor
0x10FC sub_10FC IoLib constructor
0x13CC sub_13CC EmcaPlatformHooksLib constructor
0x1B6C sub_1B6C EmcaPlatformHooksLib main constructor - locates EMCA protocol, MC banks, SMM MC Bank protocol
0x248C sub_248C DxeServicesTableLib constructor - locates gDS
0x25A8 sub_25A8 SmmLnvSendIpmiCmdLib + SmmVariableLib constructors - locates IPMI transport + SMM variable protocols

RAS Topology & Setup Variable Handlers:

Address Name Purpose
0x3970 sub_3970 Main initialization body: reads RAS topology from HOB, reads Setup variables, registers SMM SW dispatch handler, calls EMCA platform hooks init, sends IPMI commands
0x4700 sub_4700 PopulateRasTopologyStructure - Reads HOB to build RAS topology (socket/channel/dimm counts, SMBIOS Type16/17 data)
0x3E0C sub_3E0C Read setup variables from HOB - queries FPGA and platform config
0x3D4C sub_3D4C Read single setup variable (size 30) and initialize error policy defaults
0x5354 sub_5354 Apply error policy based on setup variable values (handles error modes 3/4/5)
0x5390 sub_5390 Iterate SMM variable protocol to read setup data into per-socket tables
0x2690 sub_2690 DxeSetupLib implementation - reads all platform setup variables into accumulated buffer

Error Policy Initialization:

Address Name Purpose
0x3890 sub_3890 EmcaPlatformHooks init - allocates per-socket MC bank structures (512 banks x 216 bytes each)
0x1AB0 sub_1AB0 Initialize MC bank list for detected socket configuration (6 banks x 2 sockets or 4-6 banks)
0x29A4 sub_29A4 Read OemRasLib setup variable (offset 145 = bit9?), configure error enable mask (clear bit 4)
0x23EC sub_23EC Read MSR 0x179 (MCG_STATUS) to detect error state; check for MC status bits from EMCA platform protocol callback
0x2AE0 sub_2AE0 FPGA Configuration HOB management - reads from HOB or creates a new FPGA config structure; merges setup variable data into HOB

Callback Registration (Public API for notification consumers):

Address Name Purpose
0x36B8 sub_36B8 RegisterErrorNotificationCallback - Allocates a 24-byte callback node, inserts into priority-sorted linked list (head at qword_72F0, tail at qword_72F8). Sorted by priority byte at offset +16. Returns EFI_INVALID_PARAMETER if a1 is NULL.
0x35C8 sub_35C8 RegisterErrorSource - Allocates a 16-byte node, inserts into source linked list (head at qword_72E0). Returns EFI_INVALID_PARAMETER if a1 is NULL.

Callback Dispatch:

Address Name Purpose
0x3810 sub_3810 DispatchNotification - Iterates all registered notification callbacks (head at qword_72F0), calls each with the context pointer
0x3844 sub_3844 DispatchWithEarlyOut - Same as above but with a "stop" flag (char at [rbp+0x10]), stops when flag set

EMCA MC Bank Access (from emcaplatformhookslib.c):

Address Name Purpose
0x1D8C sub_1D8C Get McBank status + 1 (offset 0 from 32-byte entry)
0x1DE4 sub_1DE4 Get McBank status + 2 (offset 4 from 32-byte entry)
0x1E3C sub_1E3C Get McBank status + 3 (offset 8 from 32-byte entry)

IO/Port Access:

Address Name Purpose
0x1360 sub_1360 Read CPU package ID via IO ports (uses 0x0CF8/0x0CFC PCI config mechanism)
0x510 sub_510 IoWrite32 (port IO write)
0x540 sub_540 IoRead32 (port IO read)

Memory Helpers:

Address Name Source
0x9CC sub_9CC SetMem (memset)
0xA3C sub_A3C ZeroMem
0x920 sub_920 CopyMem
0xDF8 sub_DF8 AllocatePool (via Smst->AllocatePool)
0x130C sub_130C InitializeSpinLock
0x3020 sub_3020 CompareGuid

ASSERT/Debug Helpers:

Address Name Purpose
0xB10 sub_B10 DebugPrint - prints formatted debug message
0xB9C sub_B9C DebugAssert - ASSERT failure handler
0xC00 sub_C00 Get debug error level flag
0xC0C sub_C0C Check if debug is enabled
0xC18 sub_C18 Check debug level

Data Structures

MC Bank Entry (32 bytes per bank, indexed by socket number):

+0x00: uint32_t bank_status_1
+0x04: uint32_t bank_status_2  
+0x08: uint32_t bank_status_3
+...  : (rest 20 bytes)

Referenced via qword_7388, accessed by sub_1D8C, sub_1DE4, sub_1E3C with 32 * socket_index offset.

Notification Callback Node (24 bytes):

+0x00: uint64_t callback_function_pointer
+0x08: uint64_t next_node_ptr (linked list)
+0x10: uint8_t  priority (lower = higher priority, inserted sorted)

Allocated by sub_36B8, stored in priority-sorted linked list. Head: qword_72F0, Tail: qword_72F8.

Error Source Node (16 bytes):

+0x00: uint64_t source_data
+0x08: uint64_t next_node_ptr

Allocated by sub_35C8, stored in linked list. Head: qword_72E0.

FPGA Configuration HOB Structure (38 bytes):

Used by sub_2AE0 for FPGA config. Various bitfields for error enable/disable.

Setup Variable Table (at off_70D0, 3-word entries):

Triplets of (GUID_ptr, Name_ptr, Size) for each platform setup variable read by sub_2690:

  • SocketIioConfig (0x1A0C bytes from 0x68B0/GUID)
  • SocketCommonRcConfig (0xE0 bytes)
  • SocketMpLinkConfig (0x155 bytes)
  • SocketMemoryConfig (0x202 bytes)
  • SocketPowerManagementConfig (0x1CE bytes)
  • SocketProcessorCoreConfig (0x12D bytes)
  • IntelSetup (0x2A4 bytes)
  • PchRcConfiguration (0x5D7 bytes)
  • MeRcConfiguration
  • FpgaSocketConfig

GUIDs Used

Protocol GUIDs:

Address GUID Protocol
0x6940 {6820ABD4-A292-4817-9147-D91DC8C53542} gEfiSmmSwDispatch2ProtocolGuid
0x6950 {86B091ED-1463-43B5-82A1-2C8B83CB8917} gEfiSmmCommunicationProtocolGuid?
0x6970 {3FDDA605-A76E-4F46-AD29-12F4531B3D08} gEfiSmmBase2ProtocolGuid
0x69C0 {F4CCBFB7-F6E0-47FD-9DD4-10A8F150C191} mLnvPurleySmmProtocolGuid (EMCA Platform Protocol)
0x69D0 {ED32D533-99E6-4209-9CC0-2D72CDD998A7} gEfiSmmVariableProtocolGuid
0x6A10 {A7CED760-C71C-4E1A-ACB1-89604D5216CB} gEfiSmmMcBankProtocolGuid?
0x6990 {0067835F-9A50-433A-8CBB-852078197814} EmcaSmmVariableProtocolGuid?
0x68A0 {05AD34BA-6F02-4214-952E-4DA0398E2BB9} gEfiDxeServicesTableGuid
0x6A40 {1DBD1503-0A60-4230-AAA3-8016D8C3DE2F} gEfiSmmIpmiTransportProtocolGuid
0x6930 {D759C710-49EA-4D26-9F7C-DE1064876E2F} FPGA Configuration HOB GUID

Calling Patterns

Driver Initialization Flow:

  1. _ModuleEntryPoint (0x5CC)
  2. sub_30D8 (0x30D8) - library constructor chain (12 constructors)
  3. sub_3550 (0x3550) - main init
  4. sub_3970 (0x3970) - core logic:
    a. Read RAS topology from HOB via sub_4700
    b. Read setup variables via sub_3E0C / sub_3D4C
    c. Apply error policy from setup via sub_5354
    d. Initialize OEM RAS via sub_29A4
    e. Save back setup via sub_F0C / sub_2998
    f. Init EMCA platform hooks via sub_3890
    g. Register SMM SW dispatch handlers (sub_252C + sub_25A8)
    h. Register SMM communication protocol

Error Notification Flow:

  1. SMI received -> SMM SW Dispatch handler fires
  2. Dispatches to sub_3810 / sub_3844 which iterate registered callbacks
  3. Callbacks registered via sub_36B8 (notification) or sub_35C8 (source)

Setup Variable Read Flow:

  1. sub_2690 reads all platform variables
  2. Reads variables described by table at off_70D0
  3. Either via gRT->GetVariable (DXE) or SmmVariableProtocol (SMM)
  4. Accumulates into qword_7420 buffer (size 0x2A3B)

Dependencies

Consumed (this module calls):

  • gBS (Boot Services): LocateProtocol, FreePool, etc.
  • gSmst (SMM System Table 2): AllocatePool, LocateProtocol, SMM SW Dispatch2 register
  • gRT (Runtime Services): GetVariable (for setup variables)
  • EMCA Platform Protocol ({F4CCBFB7-F6E0-47FD-9DD4-10A8F150C191}): GetSmmSystemTable, IsInSmm, ReadMca
  • SMM MC Bank Protocol: MC bank access
  • SMM IPMI Transport Protocol ({1DBD1503-0A60-4230-AAA3-8016D8C3DE2F}): Send IPMI commands
  • SMM Variable Protocol ({ED32D533-99E6-4209-9CC0-2D72CDD998A7}): Setup variable access in SMM
  • SMM SW Dispatch2 Protocol ({6820ABD4-A292-4817-9147-D91DC8C53542}): Register SMI handlers

Consumed By (other modules call this):

  • UEFI DXE drivers: Call _ModuleEntryPoint as standard DXE driver
  • SMM modules: Call via SMM SW Dispatch (SMI triggers)
  • RAS error handlers: Register callbacks via sub_36B8 (register notification callback) for error event delivery
  • Platform OEM libraries: Via EMCA platform hooks protocol (OemRasLib.c sources)

Notes

  1. This module has dual-mode operation: DXE (standard entry at startup) and SMM (interrupt-driven entry via SMI).
  2. The off_6B60 callback table at 0x6B60 likely contains function pointers for SMM SW Dispatch handlers registered in sub_3970.
  3. The module communicates with the FPGA to configure error handling at runtime via the FPGA Configuration HOB.
  4. Debug strings reference "LenovoServerPkg/Library/LnvPurleyLib/OemRasLib/OemRasLib.c" for OEM RAS policy reading.
  5. The EMCA platform hooks library at PurleySktPkg/Library/emcaplatformhookslib/emcaplatformhookslib.c provides the platform-specific MC bank initialization.
  6. sub_3B94 at 0x3B94 initializes a large ~400+ byte structure with error policy configuration (per-socket/per-bank error enable/disable settings, thresholds).