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 |
| 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:
_ModuleEntryPoint (0x5CC)
sub_30D8 (0x30D8) - library constructor chain (12 constructors)
sub_3550 (0x3550) - main init
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:
- SMI received -> SMM SW Dispatch handler fires
- Dispatches to
sub_3810 / sub_3844 which iterate registered callbacks
- Callbacks registered via
sub_36B8 (notification) or sub_35C8 (source)
Setup Variable Read Flow:
sub_2690 reads all platform variables
- Reads variables described by table at
off_70D0
- Either via gRT->GetVariable (DXE) or SmmVariableProtocol (SMM)
- 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
- This module has dual-mode operation: DXE (standard entry at startup) and SMM (interrupt-driven entry via SMI).
- The
off_6B60 callback table at 0x6B60 likely contains function pointers for SMM SW Dispatch handlers registered in sub_3970.
- The module communicates with the FPGA to configure error handling at runtime via the FPGA Configuration HOB.
- Debug strings reference "LenovoServerPkg/Library/LnvPurleyLib/OemRasLib/OemRasLib.c" for OEM RAS policy reading.
- The EMCA platform hooks library at
PurleySktPkg/Library/emcaplatformhookslib/emcaplatformhookslib.c provides the platform-specific MC bank initialization.
- sub_3B94 at 0x3B94 initializes a large ~400+ byte structure with error policy configuration (per-socket/per-bank error enable/disable settings, thresholds).