/*
*PiSmmCore.c - UEFI SMM Core driver implementation
*
*Source file: PiSmmCore.efi (HR650X server BIOS)
*Compiled from: MdeModulePkg/Core/PiSmmCore/ (primary)
*AmiModulePkg/Library/SmmCoreAmiBufferValidationLib (buffer validation)
*PurleyPlatPkg/Override/MdeModulePkg/Library/SmmCorePlatformHookLib (platform hooks)
*AmiModulePkg/Library/SmmCorePerformanceLib (perf tracing)
*MdePkg/Library/ (BaseLib, BasePrintLib, BaseDebugLibSerialPort)
*MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib
*MdePkg/Library/SmmPciExpressLib
*Build: DEBUG_VS2015 X64 (VS2015 toolchain)
*
*Overview:
*PiSmmCore.efi is the SMM Core driver -- the SMM equivalent of the DXE
*Core. It is the first SMM driver loaded by the SMM foundation and provides
*the EFI_SMM_SYSTEM_TABLE2 (SMST) protocol services to all other SMM drivers.
*This HR650X variant includes AMI-specific platform hooks for PCH dispatch,
*communication buffer validation with mailbox-based lock/unlock protocol,
*and SMM performance measurement (SmmCorePerformanceLib).
*
* ============================================================================
*Architecture Summary:
* ============================================================================
*
*1. INITIALIZATION (sub_480 -> sub_9D0 -> sub_1158):
*sub_480 (SmmCoreEntry):
* - Saves gImageHandle, gST, gBS, gRT from UefiBootServicesTableLib
* - Calls SmmCoreMemoryAllocationLibInit (sub_7AD4) to init SMRAM ranges
* - Locates and saves CPU I/O protocol (EFI_PEI_SERVICES or similar)
* - Calls SmmCoreSectionExtractionInit (sub_B618) for FV section extraction
* - Calls SmmAmiBufferValidationLibInit (sub_90B4) for AMI comm buffer init
*sub_9D0 (SmmMain):
* - Saves ImageHandle, copies mFullSmramRanges from handoff data
* - Registers SMI handlers from the SMI handler table at 0x11280
* (32-byte entries: {GUID ptr, HandlerFunc, reserved}). Iterates
*calling sub_3C98 (SmiHandlerRegister) for each non-null entry.
* - Calls sub_1158 (SmmInstallConfigurationTable) to construct SMST
* - Registers sub_2620 (SmmMemoryAttributesTable callback) via
*SmiHandlerRegister for EndOfDxe notification
*sub_1158 (SmmInstallConfigurationTable):
* - Allocates 96-byte configuration table via BS->AllocatePool
* - Zeroes it, sets struct size=4096 (0x1000)
* - Copies SMRAM ranges from ImageHandle[1], SystemTable pointer
* - Installs via BS->InstallProtocolInterface with GUID at 0x11000
* - Allocates 264-byte SMST structure via SmmAllocatePool
* - Zeroes it, sets signature="SMST" (0x54534D53 at offset 0xA8)
* - Populates SMST fields from ImageHandle data
* - Self-installs SMST as a protocol via SmmInstallProtocolInterface
* (sub_41F4) with the SMST protocol GUID
*
*2. SMI DISPATCH (sub_34C0 -> sub_E4C -> sub_3B34 -> sub_3A5C -> handler):
*sub_34C0 (thin wrapper):
* - Calls sub_E4C with the argument structure {CommBuffer, Size,
*InLegacyBoot, CommBufferSizeReturned}
*sub_E4C (SmmEntryPoint core):
* - Saves CommBuffer/Size to globals (qword_113F0/qword_113F8)
* - Saves InLegacyBoot and CommBufferSizeReturned to qword_11400/qword_11408
* - Saves image handle extended fields to qword_11410
* - Sets gInSmmEntryPoint flag (ImageHandle_0+41 = 1)
* (unless byte_14020 is set, which skips this for special modes)
* - Executes PRE-handler callbacks: iterates off_10BA0 to qword_10BB0
*calling each function pointer with argument 1
* - PCH-specific SMI dispatch (if qword_141C8 and qword_14218+8 set):
* - Checks PCH TCO status via qword_14210+8 (EFI_PCH_SMM_IO or similar)
*with command value 318783732 (= 0x13000074, TCO_STS check)
* - If result != 1, iterates 4 threads x 2 cores for each active
*PCH SMM source (qword_14208+6 bitmask), calls qword_14210+40
*with 100679988 (= 0x06000034, SMI_STS clear)
* - AMI buffer validation: if byte_14020 is NOT set:
* - Loads CommBuffer from ImageHandle_0+56, verifies not overlapping
*ImageHandle_0 region (SMRAM overflow check)
* - Calls sub_853C (AmiBufferValidation->ValidateCommBuffer)
* - If validation OK: calls sub_3B34 (SmiManage/SmiHandlerInvoke)
*with the actual comm buffer (skipping 24-byte AMI mailbox header)
* - Sets ImageHandle_0+72 to EFI_NOT_FOUND or EFI_INVALID_PARAMETER
* - Even if no comm buffer: calls sub_3B34(0,0,0,0) for root handlers
* - Executes POST-handler callbacks: iterates off_10BA8 down to off_10BA0
* - Restores PCH TCO state (clears the interrupt bit via mask)
* - Clears gInSmmEntryPoint flag
* - DEBUG "SmmEntryPoint Exit"
*sub_3B34 (SmiHandlerInvoke):
* - If a1 (CommBuffer) is provided: calls sub_3A5C to find matching
*SMI_HANDLER entry by GUID from gSmiHandlerList at 0x11508
* (signature 0x65696D73 "smie"), walks per-GUID handler chain (offset +40)
* - If no a1: uses root "smie" handler (global at 0x114D0)
* - For each SMHC_ENTRY (signature 0x68634D53 "SMHC") on the handler's
*per-GUID list:
* - Prints "Calling SMI Handler %p; Handle = 0x%X"
* - Calls handler function with (SMHC_ENTRY*, Context, CommBuffer, Size)
* - Processes return code:
*0 (EFI_SUCCESS) -> returns 0 immediately if GUID match, else continues
*0x2000000000000000 (SMI_INTERRUPT_PENDING) -> continues
*0x2000000000000001 (SMI_INTERRUPT_PENDING_NEXT) -> sets flag, continues
*0xA000000000000000 (SMI_NOT_HANDLED) -> continues if no GUID match
*Other -> ASSERT(0)
*sub_3A5C (SmiHandlerFindOrCreate - GUID lookup in gSmiHandlerList):
* - Walks off_11508 linked list
* - Each node is SMI_HANDLER (signature 0x65696D73 "smie") located at
*list_entry - 8 bytes
* - Uses sub_627C (64-bit comparison via two qword compares) to match GUID
* - If not found and a2 (create_flag) is set: allocates 56-byte entry,
*copies GUID, initializes per-GUID handler list, links into off_11508
*
*3. SMI HANDLER REGISTRATION / UNREGISTRATION:
*sub_3C98 (SmiHandlerRegister):
* - Params: (GUID *HandlerGuid, SMI_HANDLER_FUNC Handler,
*EFI_HANDLE *DispatchHandle)
* - Allocates 64-byte SMHC_ENTRY, sets signature=0x68634D53 "SMHC"
* - Sets HandlerGuid pointer and handler function pointer
* - If HandlerGuid is provided: calls sub_3A5C(Guid, 1) to find/create
*the SMI_HANDLER entry in gSmiHandlerList
* - If HandlerGuid is NULL: uses root "smie" handler (global at 0x114D0)
*for handlers that match all SMIs
* - Links SMHC_ENTRY onto the SMI_HANDLER's per-GUID list (offset +40)
* - Returns SMHC_ENTRY pointer as the DispatchHandle
*sub_3D70 (SmiHandlerUnRegister):
* - Validates DispatchHandle signature = 0x68634D53 "SMHC"
* - Unlinks SMHC_ENTRY from its list (sub_6464)
* - Frees SMHC_ENTRY (sub_7A74)
* - If the parent SMI_HANDLER's per-GUID list is now empty:
*unlinks and frees the SMI_HANDLER entry too
*
*4. PROTOCOL DATABASE MANAGEMENT (Handle.c/Notify.c):
*sub_41F4 (SmmInstallProtocolInterface):
* - Params: (EFI_HANDLE *Handle, EFI_GUID *Protocol, VOID *Interface)
* - Validates: Handle != NULL, Protocol != NULL, no third arg expected
* - Debug prints: "%a %p" if name found, "%g %p" otherwise
* - If *Handle is NULL or not found in database:
* - Calls sub_4068 (SmmCreateProtocolEntry) to find/create PROTOCOL_ENTRY
* - Allocates new SHND_ENTRY (0x30 bytes, signature 0x6C6E6F77 "wonk")
*if *Handle is NULL, or validates existing handle via sub_4038
* - Creates PRTI_ENTRY (0x40 bytes, signature 0x636C666E "nflc")
* - Links: PRTI_ENTRY onto handle's protocol list and PROTOCOL_ENTRY's
*protocol interface list
* - Fires notifications: walks PROTOCOL_ENTRY's notify list (offset +56),
*finds NOTIFY_ENTRY entries (signature 0x6E656F74 "toen" at
*list_entry-16), calls each notify function with (Protocol, Interface, Handle)
* - Returns *Handle (now populated)
*sub_4598 (SmmFindProtocolInterface):
* - Searches handle's protocol list for matching GUID+Interface
*sub_4148 (SmmFindProtocolInterface):
* - Searches handle's protocol list for matching GUID
*sub_4038 (SmmValidateHandle):
* - Validates SHND_ENTRY signature = 0x6C6E6F77 "wonk"
*sub_4068 (SmmCreateProtocolEntry):
* - Searches PROTOCOL_ENTRY database (off_13F60 list) for matching GUID
* - Creates new PROTOCOL_ENTRY (signature 0x6E6F6874 "thon") if not found
* - Links into off_13F60 global list
*sub_4F80 (SmmLocateProtocol / SmmHandleProtocol):
* - Locates a protocol by GUID on a given handle
*sub_4C68 (SmmLocateHandle):
* - Locates handles in database by protocol GUID or search type
*
*5. MEMORY MANAGEMENT (Page.c / Pool.c):
*sub_4F80 (SmmAllocatePool):
* - Params: (UINT32 PoolType, UINTN Size, VOID **Buffer)
* - Validates PoolType is 5 (EfiRuntimeServicesCode) or 6
* (EfiRuntimeServicesData), else ASSERT + return EFI_INVALID_PARAMETER
* - Splits on Size+40 (header+data+tail) vs 0x800 boundary:
*SMALL POOL PATH (<=0x800):
* - Computes pool index: ((Size+40+63)>>6) -> next power of 2
* - Calls sub_4C68 (SmmInternalAllocatePool) with PoolType, pool index
* - sub_4C68: pools are indexed 0-6 per bucket. Bucket 6 uses
*page allocator (falls through to sub_57AC for 1 page).
*Buckets 0-5 use pool free list at unk_143A0 (96-byte stride,
*16-byte per-index entries: unk_143A0+96*bucket+16*index).
*If free list is empty, recursively calls with next index,
*splits the larger block in half, marks as Available=1,
*and links one half back into the free list.
* - Sets POOL_HEADER signature="phd0" (0x30646870),
*Available=0, Type=PoolType, Size=64<<index
* - Sets POOL_TAIL signature="ptal" (0x6C617470), Size=header.Size
* - Returns Buffer = POOL_HEADER + 0x18
*LARGE POOL PATH (>0x800):
* - Pages needed = (Size+40 + 0xFFF) >> 12
* - Searches page free list (off_13F70 -> ::i linked list)
*for a descriptor with enough pages
* - If found: calls sub_57AC to split the allocation
* - Calls sub_5554 to set pool type
* - Calls sub_5260 to update free list accounting
* - Sets POOL_PAGE header: signature="phd0", Type=PoolType,
*Size=pages<<12
*sub_5100 (SmmFreePool):
* - Params: (VOID *Buffer)
* - Computes header = Buffer - 0x18
* - Validates POOL_HEADER: signature="phd0", Available=0
* - Validates POOL_TAIL: signature="ptal", Size matches
* - If total size <= 0x800: calls sub_4E64 (small free)
*which returns the block to the pool free list
* - If total size > 0x800: validates page alignment, calls
*sub_59E8 (SmmFreePages) to return pages to page allocator
*
*6. IMAGE MANAGEMENT for MemoryAttributesTable (MemoryAttributesTable.c):
*sub_2708 (SmmLoadImage):
* - Loads SMM driver PE32+ image into SMRAM via firmware volume protocol
* - Uses gBS->LoadImage and gBS->StartImage (BootServices at offset 0x60)
* - Handles DEPEX evaluation before loading
*sub_1E38 (SmmInsertImageRecord):
* - Creates IMAGE_RECORD (0x40 bytes, signature "IPRD")
* - Walks PE32+ section table, creates CODE_SECTION entries (0x28 bytes,
*signature "SC\T") for each executable section
* - Validates section alignment (must be 4K)
* - Calls sub_1B7C, sub_1C40, sub_1D08 for validation and insertion
* - Links into gImageRecordList at off_11490
* - Updates qword_11480 (record count), qword_11488 (max code segments)
*sub_2620 (SmmMemoryAttributesTable callback):
* - Registered as EndOfDxe SMI handler
* - Dumps gImageRecordList, builds memory attributes table
* - If gMemoryProtectionAttribute & 1: sets NX on data pages
*sub_1D08 (SmmUpdateMemoryAttributes):
* - Applies page-level memory protection to SMRAM pages based on
*image code segment records
*
*7. AMI BUFFER VALIDATION (SmmCoreAmiBufferValidationLib):
*sub_853C (AmiBufferValidation_Validate):
* - Entry point for SMI dispatch buffer validation
* - Calls sub_8414 which runs the actual checks
* - Prints "[%a]: SMM buffer security violation" on failure
*sub_8414 (AmiBufferValidation_CheckBuffer):
* - Checks against multiple exclusion/inclusion regions:
*1. sub_8270(buffer, size, qword_14110, qword_14140):
*Checks buffer is NOT in SMRAM ranges
*2. If byte_14148 (RT check enabled):
*a. sub_8270(buffer, size, qword_14130, qword_14150):
*Checks buffer does NOT overlap RT driver code sections
*b. sub_82E0(buffer, size, qword_140D8, n2):
*Checks buffer IS in firmware-reserved RT access region
*c. sub_834C: additional validation (MMIO ranges)
*3. If byte_140E8 (MMIO check enabled):
*sub_82E0(buffer, size, qword_13FA0, 2)
*sub_8270 (AmiBufferValidation_CheckOverlap):
* - Generic range overlap check against a region list
*sub_82E0 (AmiBufferValidation_CheckInside):
* - Checks buffer is inside a region list
*sub_834C (AmiBufferValidation_CheckMmiO):
* - Validates MMIO range permissions
*sub_8BE8 (AmiBufferValidation_MailboxProtocol):
* - AMI communication buffer mailbox lock/unlock protocol
* - Params: (buffer, size, mailbox_ptr, mailbox_size_ptr)
* - Lock flow:
* - Validates qword_14118 (mailbox_addr) is set
* - Validates qword_14108 (PciRootBridgeIo or similar) is set
* - Reads CommBufferHeader_Size (offset 44) via MMIO read (function 4)
* - Reads CommBufferHeader_Flags (offset 45) via MMIO read
* - Checks if already locked (byte_14158 && !Flags.bit0)
* - Checks size <= dword_14128 (supported max size, typically 0x20000)
* - If OK: sets byte_14158=1, increments dword_14138 (session counter)
* - Writes mailbox: {Command=1, Identifier=140F0, Sequence=counter}
* - Writes back CommBufferHeader_Size and CommBufferHeader_Flags
* - Unlock flow:
* - Reads CommBufferHeader_Status (offset 40) from buffer
* - If status == -1073741822 (EFI_ACCESS_DENIED):
* - Checks mailbox state: Command==1, Identifier==140F0, counter matches
* - Clears byte_14158=0, zeroes Session and Sequence
* - Sets buffer status via sub_8B78
*sub_90B4 (AmiBufferValidationLibInit):
* - Initializes AMI buffer validation library
* - Reads MMIO ranges, SMRAM ranges, RT regions from PCH config
* - Sets up globals (qword_14108, qword_14110, qword_14118, etc.)
*
*8. AMI PLATFORM HOOKS (SmmCorePlatformHookLib):
*sub_B158 (AmiSmmCorePlatformHookInit):
* - Initializes pre/post SMI callback table at off_10BA0-0x10BA8
* - Populates qword_10BB0 with end-of-table sentinel
* - These callbacks are invoked on every SMI entry/exit
*off_10BA0 (pre-SMI callbacks):
* - Array of function pointers called at SMI entry before handler dispatch
* - Each called with argument 1 by sub_E4C
*off_10BA8 (post-SMI callbacks):
* - Array of function pointers called at SMI exit after handler dispatch
* - Each called with argument 0 by sub_E4C
*
*9. SMM PERFORMANCE (SmmCorePerformanceLib):
*sub_9464 (SmmPerformanceStart):
* - Called at SMI entry if byte_14228 (performance enabled) is set
* - Logs "SMM" performance start marker
*sub_9598 (SmmPerformanceEnd):
* - Called at SMI exit if byte_14228 is set
* - Logs "SMM" performance end marker
*sub_9A18 (SmmPerformanceProtocolInstall):
* - Installs SMM performance protocol
*sub_98B8 (SmmPerformanceGetTimer):
* - Reads hardware timer for performance measurement
*
* ============================================================================
*DEBUG OUTPUT:
* ============================================================================
*sub_7834 - SMM debug output via serial port
* - Checks CMOS 0x4C debug level against requested level
* - Uses I/O ports 0x70/0x71 for CMOS access
* - Serial output at 0x3F8 or 0x2F8 (115200 baud, 8N1)
*sub_7908 - SMM assertion handler (calls sub_7834 then infinite loop)
* - Format: "ASSERT [file](line): description\n"
*
* ============================================================================
*KEY GLOBAL VARIABLES:
* ============================================================================
*0x14078: gST (SystemTable pointer)
*0x14080: gBS (BootServices pointer)
*0x14088: gImageHandle
*0x14090: gRT (RuntimeServices pointer)
*0x14098: SMST (SMM System Table pointer)
*0x113F0: gCommBuffer (current SMI comm buffer address)
*0x113F8: gCommBufferSize (current SMI comm buffer size)
*0x11400: gInLegacyBoot (pointer to legacy boot flag)
*0x11408: gCommBufferSizeReturned (pointer to size-returned field)
*0x11410: gImageHandleExtended (extra image handle data)
*0x11480: gImageRecordCount (number of loaded images)
*0x11488: gMaxCodeSegmentCount (max code segments across all images)
*0x11490: gImageRecordList (list head for IMAGE_RECORD entries)
*0x114D0: gRootSmiHandler ("smie" root handler, matches all SMIs)
*0x11508: gSmiHandlerList (list head for GUID-matching SMI_HANDLER entries)
*0x11530: gGuidToNameTable (449-entry sorted table for debug name lookup)
*0x13F60: gHandleList (list head for SHND_ENTRY global list)
*0x13F70: gPageFreeList (list head for free page descriptors)
*0x13F78: gPageDescriptor (::i iterator for page free list)
*0x143A0: gPoolFreeLists (6 buckets x 7 sizes = 42 LIST_ENTRY heads)
*0x14020: byte_14020 (flag to skip SMRAM check, possibly RAS recovery)
*0x140D8: gCommBufferSafeRegion (list of safe comm buffer regions)
*0x140E8: byte_140E8 (MMIO range check enable)
*0x140F0: gMailboxIdentifier (AMI mailbox session identifier)
*0x14108: gPciRootBridgeIo (protocol for MMIO accesses)
*0x14110: gSmramRanges (list of SMRAM ranges for exclusion check)
*0x14118: gMailboxAddr (AMI communication buffer mailbox address)
*0x14128: gMaxCommBufferSize (typically 0x20000 = 128KB)
*0x14130: gRtDriverCodeRanges (RT driver code section ranges)
*0x14138: dword_14138 (mailbox session sequence counter)
*0x14140: qword_14140 (SMRAM range count for exclusion)
*0x14148: byte_14148 (RT code check enable)
*0x14150: qword_14150 (RT code range count)
*0x14158: byte_14158 (buffer lock state)
*0x141C8: qword_141C8 (PCH SMM enable flag)
*0x14208: qword_14208 (PCH SMM configuration data)
*0x14210: qword_14210 (PCH SMM I/O protocol)
*0x14218: qword_14218 (PCH SMM feature enable data)
*0x14228: byte_14228 (SMM performance measurement enable)
*0x14470: qword_14470 (memory protection attributes)
*0x14478: qword_14478 (mFullSmramRanges backup)
*0x14480: qword_14480 (SMST structure pointer)
*0x14488: qword_14488 (mSmramRangeCount)
*0x14490: qword_14490 (SMM configuration table pointer)
*0x14498: ImageHandle_0 (global image handle reference)
*0x10BA0: off_10BA0 (pre-SMI callback function table start)
*0x10BA8: off_10BA8 (post-SMI callback function table start)
*0x10BB0: qword_10BB0 (pre-callback end sentinel)
*
* ============================================================================
*SMI HANDLER TABLE (at 0x11280):
* ============================================================================
*32-byte entries: {GUID_ptr (16 bytes?), HandlerFunc, NotifyFlag}
*Iterated by sub_9D0 to register built-in SMI handlers via sub_3C98.
*Terminated by null pointer at 0x11288 (first entry's handler field).
*Known handlers:
*0x111E0: GUID for SmmMemoryAttributesTable (sub_2620)
*
* ============================================================================
*STRUCTURE SIGNATURES (validated by CR macros):
* ============================================================================
*0x68634D53 "SMHC" -> SMHC_ENTRY (SMI Handler Context, 64 bytes)
*0x65696D73 "smie" -> SMI_HANDLER (per-GUID handler node, 56 bytes)
*0x6C6E6F77 "wonk" -> SHND_ENTRY (SMM protocol handle, 48 bytes)
*0x636C666E "nflc" -> PRTI_ENTRY (Protocol Interface, 64 bytes)
*0x6E6F6874 "thon" -> PROTOCOL_ENTRY (Protocol Database Entry, 56 bytes)
*0x6E656F74 "toen" -> NOTIFY_ENTRY (Protocol Notify, 48 bytes)
*0x44525049 "IPRD" -> IMAGE_RECORD (64 bytes)
*0x545C4353 "SC\T" -> CODE_SECTION (40 bytes)
*0x30646870 "phd0" -> POOL_HEADER (allocated, 24 bytes)
*0x30666870 "phf0" -> POOL_HEADER (free, 24 bytes)
*0x6C617470 "ptal" -> POOL_TAIL (16 bytes)
*
* ============================================================================
*CALLING CONVENTIONS:
* ============================================================================
*sub_61D0 (ZeroMem): (VOID *Buffer, UINTN Size)
*sub_6134 (CopyMem): (VOID *Dst, VOID *Src, UINTN Size)
*sub_6234 (CompareMem): (VOID *Buf1, VOID *Buf2, UINTN Size) -> INTN
*sub_627C (GuidEqual): compares two qwords (GUID.Data1 + upper 4 bytes)
* -> returns BOOLEAN
*sub_6350 (InitializeListHead): (LIST_ENTRY *ListHead)
*sub_6388 (InsertHeadList): (LIST_ENTRY *List, LIST_ENTRY *Entry)
*sub_63D8 (InsertTailList): (LIST_ENTRY *List, LIST_ENTRY *Entry)
*sub_642C (IsListEmpty): (LIST_ENTRY *List) -> BOOLEAN
*sub_6464 (RemoveEntryList): (LIST_ENTRY *Entry)
*sub_62E4 (IsNull): (LIST_ENTRY *List, LIST_ENTRY *Entry) -> BOOLEAN
*sub_79A0 (AllocateZeroPool): (UINTN Size) -> VOID*
*sub_79D0 (AllocatePool): (UINTN Size) -> VOID*
*sub_7A74 (FreePool): (VOID *Buffer)
*sub_7834 (DebugPrint): (UINTN ErrorLevel, CHAR8 *Format, ...)
*sub_7908 (Assert): (CHAR8 *FileName, UINTN Line, CHAR8 *Desc)
*
* ============================================================================
*SMI HANDLER RETURN CODES:
* ============================================================================
*0x0000000000000000: EFI_SUCCESS - handler claimed the SMI
*0x2000000000000000: SMI_INTERRUPT_PENDING - handler needs re-dispatch
*0x2000000000000001: SMI_INTERRUPT_PENDING_NEXT - re-dispatch requested
*0xA000000000000000: SMI_NOT_HANDLED - handler does not claim this SMI
*/