/*
* BootScriptExecutorDxe.c
* Lenovo HR650X BIOS - S3 Boot Script Executor DXE Driver
*
* This module executes S3 boot script entries during S3 resume.
*
* Source files compiled into this module:
* - MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.c (actual entry)
* - MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c
* - MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptExecute.c
* - MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c
* - MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.c
* - MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.c
* - MdePkg/Library/UefiLib/UefiLib.c
* - MdePkg/Library/BaseLib/BaseLib.c (selected functions)
* - MdePkg/Library/BaseMemoryLibRepStr/* (CopyMem, SetMem, CompareMem)
* - MdePkg/Library/BaseIoLibIntrinsic/IoLib.c
* - MdePkg/Library/BasePciSegmentLibPci/PciSegmentLib.c
* - MdePkg/Library/BasePeCoffLib/BasePeCoff.c
* - MdePkg/Library/BasePrintLib/PrintLibInternal.c
* - MdePkg/Library/BaseSynchronizationLib/SynchronizationMsc.c
* - UefiCpuPkg/Library/CpuExceptionHandlerLib/* (X64 exception handling)
* - CpPlatPkg/Library/BaseSmbusLibNull/BaseSmbusLibNull.c
*
* Image: 0289_BootScriptExecutorDxe
* SHA256: 3431687650e4715332a06fb311d2fe2884da682fa16f6a2115d8ac7976416d09
*/
#include "BootScriptExecutorDxe.h"
// =========================================================================
// Global variables
// =========================================================================
EFI_HANDLE gImageHandle = NULL; /* 0xC7C0 */
EFI_SYSTEM_TABLE *gSystemTable = NULL; /* 0xC7B0 */
EFI_BOOT_SERVICES *gBootServices = NULL; /* 0xC7B8 */
EFI_RUNTIME_SERVICES *gRuntimeServices = NULL; /* 0xC7C8 */
UINT64 gBSFunctionTable; /* 0xC7D8 - pointer to BS function table */
UINT8 gBootScriptLibInitialized; /* 0xC800 */
VOID *gEventDxeSmmReadyToLock; /* 0xC808 */
UINT64 gS3BootScriptTablePtr; /* 0xD460 */
UINT64 gS3BootScriptTablePtr2; /* 0xD468 */
UINT64 gBootScriptCloseEvent; /* 0xC818 */
UINT64 gBootScriptReadyEvent; /* 0xC820 */
UINT64 gMemoryRanges; /* 0xC830 */
UINT64 gSmmReadyEvent; /* 0xC7F8 */
UINT8 gBootScriptCloseRegistered; /* 0xC828 */
//
// Data section variables
//
UINT64 gUnknownData_0xC850; /* 0xC850 */
UINT64 gUnknownData_0xC858; /* 0xC858 */
//
// Protocol/Notify structures
//
VOID *gEfiBootScriptNotifyProtocol; /* 0xC710 */
VOID *gEfiBootScriptExecutorProtocol; /* 0xC730 */
VOID *gEfiBootScriptTableGuid; /* 0xC770 */
// =========================================================================
// Module Entry Point
// =========================================================================
EFI_STATUS
EFIAPI
ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
DriverInit (ImageHandle, SystemTable);
Status = BootScriptGetS3BootScriptGuid ();
if (EFI_ERROR (Status)) {
ModuleEntryPointDeinit ();
}
return Status;
}
// =========================================================================
// Driver Init - Serial port init and boot script setup
// =========================================================================
EFI_STATUS
DriverInit (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
// Store global pointers
gImageHandle = ImageHandle;
gSystemTable = SystemTable;
gBootServices = SystemTable->BootServices;
gRuntimeServices = SystemTable->RuntimeServices;
//
// Read CMOS/RTC to detect serial baud rate
// CMOS index 0x5C stores the UART baud rate index:
// 0xA7 -> 115200, 0xA6 -> 57600, 0xA5 -> 38400,
// 0xA4 -> 19200, 0xA3 -> 9600
//
IoWrite8 (RTC_ADDR_PORT, 0x5C);
UINT8 BaudIndex = IoRead8 (RTC_DATA_PORT);
IoWrite8 (RTC_ADDR_PORT, 0x6C);
UINT8 BaudRateVal = IoRead8 (RTC_DATA_PORT);
UINT32 BaudRate;
switch (BaudRateVal) {
case 0xA7: BaudRate = 115200; break;
case 0xA6: BaudRate = 57600; break;
case 0xA5: BaudRate = 38400; break;
case 0xA4: BaudRate = 19200; break;
default: BaudRate = 115200;
case 0xA3: BaudRate = 9600; break;
}
UINT16 Divisor = 0x1C200 / BaudRate;
//
// Configure 16550 UART at detected base address
// UART base is determined from CMOS (typically 0x3F8 for COM1)
//
UINT16 UartBase = 1016; /* 0x3F8 */
if (BaudIndex == 33) {
UartBase = 760; /* 0x2F8 - COM2 */
}
UINT16 UartLcrReg = UartBase + 3;
// Detect current UART configuration
UINT8 LcrValue = IoRead8 (UartLcrReg);
UINT8 LcrOrig = LcrValue;
UINT8 DllOrig = IoRead8 (UartLcrReg);
UINT8 DlmOrig;
// Set DLAB bit to access divisor latches
IoWrite8 (UartLcrReg, DllOrig | 0x80);
DlmOrig = IoRead8 (UartBase + 1);
UINT16 CurrentDivisor = IoRead8 (UartBase) | (DlmOrig << 8);
IoWrite8 (UartLcrReg, DllOrig & 0x7F);
// Only reconfigure if baud rate doesn't match
BOOLEAN NeedsReconfig = ((LcrOrig & 0x3F) == 3) && (CurrentDivisor == Divisor);
if (!NeedsReconfig) {
// Wait for UART idle (TSR empty)
while ((IoRead8 (UartBase + 5) & 0x60) != 0x60);
// Set DLAB, write divisor, clear DLAB, set 8N1
IoWrite8 (UartLcrReg, 0x80);
IoWrite8 (UartBase + 1, (Divisor >> 8) & 0xFF);
IoWrite8 (UartBase, Divisor & 0xFF);
IoWrite8 (UartLcrReg, 0x03); /* 8N1 */
IoWrite8 (UartBase + 2, 0); /* FIFO off */
IoWrite8 (UartBase + 2, 1); /* FIFO on */
IoWrite8 (UartBase + 4, 0); /* DTR/RTS off */
}
// Allocate boot script table
gBSFunctionTable = UefiBootServicesTableLibConstructor ();
gBSFunctionTable = (*(UINT64 (*)(UINT64))(gBSFunctionTable + 32))(5);
BootScriptLockInit ();
// PCD check: enable watchdog if appropriate
if ((INT8)*UefiLibGetVariable (1024068) >= 0) {
UINT64 PcdValue = UefiLibGetVariable (1024064);
CopyMemWithOverlap (PcdValue, 1280);
*UefiLibGetVariable (1024068) |= 0x80;
}
// Check CR0 (cache settings)
UINT16 Cr0Value = BaseLibGetCr0 ();
BOOLEAN CacheEnabled = (Cr0Value & 0x200) != 0;
// Performance counter delay loop
BaseLibDisableCache ();
UINT32 StartCounter = BaseLibGetPerformanceCounter (
BaseLibGetInterruptState (1288), 0, 23);
BaseLibEnableCache ();
while (1) {
UINT32 CurrentCounter = BaseLibGetPerformanceCounter (
BaseLibGetInterruptState (1288), 0, 23);
if (((StartCounter + 357 - CurrentCounter) & 0x800000) != 0)
break;
BaseLibCpuPause ();
}
BaseLibEnableCache ();
// Restore cache state
if (CacheEnabled)
BaseLibEnableCache ();
else
BaseLibDisableCache ();
// Call main boot script driver init
EFI_STATUS Status = BootScriptDriverInit (0, 0);
if (EFI_ERROR (Status)) {
UefiDebugAssert (0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
}
return Status;
}
// =========================================================================
// Boot Script Driver Init (from PiDxeS3BootScriptLib/BootScriptSave.c)
// =========================================================================
EFI_STATUS
BootScriptDriverInit (
IN UINT64 a1,
IN UINT64 a2
)
{
// Note: this function initializes the PiDxeS3BootScriptLib library
// constructs, registers notify callbacks for S3 resume, and installs
// the boot script notification protocols.
// Allocate S3 boot script context
UINT64 Context = (*(UINT64 (*)(UINT64))(gBSFunctionTable + 32))(137);
if (Context == 0) {
// Allocate S3 boot script table via boot services
UINT64 AllocationSize = 0xFFFFFFFF;
EFI_STATUS Status = gBootServices->AllocatePool (1, 0, 1, &AllocationSize);
if (EFI_ERROR (Status)) {
UefiDebugAssert (0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
}
Context = AllocationSize;
gBootScriptLibInitialized = 1;
// Register with BS function table
(*(UINT64 (*)(UINT64, UINT64))(gBSFunctionTable + 144))(137, Context);
UefiBootServicesTableLibDestructor (Context, 32);
// Create DxeSmmReadyToLock event
gEventDxeSmmReadyToLock = BootScriptCreateEvent (
BootScriptNotifyDxeSmmReadyToLock);
}
gS3BootScriptTablePtr = Context;
// Check if BootScript Notify protocol is available
// If so, register S3 ready event and close done callbacks
if (gBootServices->LocateProtocol (&gEfiBootScriptNotifyProtocol, 0, ...) >= 0) {
// Allocate second context
UINT64 Context2 = (*(UINT64 (*)(UINT64))(gBSFunctionTable + 32))(138);
if (Context2 == 0) {
// Allocate from S3 boot script protocol
EFI_STATUS Status = (*(UINT64 (*)(UINT64, UINT64, UINT64*))(gS3BootScriptTablePtr + 80))(6, 32, &Context2);
if (EFI_ERROR (Status)) {
UefiDebugAssert (0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
}
gBootScriptCloseRegistered = 1;
(*(UINT64 (*)(UINT64, UINT64))(gBSFunctionTable + 144))(138, Context2);
UefiBootServicesTableLibDestructor (Context2, 32);
// Register boot script close callbacks
(*(UINT64 (*)(VOID*, UINT64 (*)(), UINT64*))(gS3BootScriptTablePtr + 192))(
&gBootScriptCloseEvent, BootScriptCloseDoneCallback, &gBootScriptReadyEvent);
}
gS3BootScriptTablePtr2 = Context2;
// Register S3 ready callback
(*(UINT64 (*)(VOID*, UINT64 (*)(), UINT64*))(gS3BootScriptTablePtr + 192))(
&gEfiBootScriptExecutorProtocol, BootScriptS3ReadyCallback, &gBootScriptReadyEvent);
}
return EFI_SUCCESS;
}
// =========================================================================
// Boot Script Table Entry Execution
// =========================================================================
//
// S3BootScriptExecuteTable - Main entry for executing the boot script table
// Parses each entry by opcode and dispatches to the appropriate handler.
// Called during S3 resume.
//
UINT64
BootScriptExecuteTable (
VOID
)
{
// This is the core function at 0x4C94
// It iterates through the boot script table entries, parsing the
// common header (opcode, width, size) and dispatching to:
//
// - BootScriptExecuteIoWrite (opcode 0x00)
// - BootScriptExecuteIoReadWrite (opcode 0x01)
// - BootScriptExecuteMemoryWrite (opcode 0x02)
// - BootScriptExecutePciCfgWrite (opcode 0x04)
// - BootScriptExecutePciCfgRead (opcode 0x05)
// - BootScriptExecuteSmbusEntry (opcode 0x06)
// - BootScriptExecuteStall (opcode 0x07)
// - BootScriptExecuteDispatch (opcode 0x08)
// - BootScriptExecuteMemPoll (opcode 0x09)
// - BootScriptExecuteInformation (opcode 0x0A)
// - BootScriptExecutePciCfg2Write (opcode 0x0B)
// - BootScriptExecutePciCfg2Read (opcode 0x0C)
// For the full decompiled pseudocode, see the IDB at:
// BootScriptExecuteTable @ 0x4C94
return 0;
}
// =========================================================================
// Library: UefiBootServicesTableLib
// =========================================================================
//
// UefiBootServicesTableLibConstructor @ 0x1B9C
// Constructor for the UEFI Boot Services Table Library.
// Stores pointer to function table.
//
UINT64
UefiBootServicesTableLibConstructor (
VOID
)
{
// Returns the gBS function table pointer
return gBootServices;
}
// =========================================================================
// Library: SmmLockBoxDxeLib
// =========================================================================
//
// SmmLockBoxSaveLockBox @ 0x21A4
// Saves a buffer to a LockBox identified by GUID.
// Uses SMM communication buffer protocol.
//
UINT64
SmmLockBoxSaveLockBox (
UINT64 Guid,
UINT64 Buffer,
UINT64 Length
)
{
DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib SaveLockBox - Enter\n"));
if (Guid == 0 || Buffer == 0 || Length == 0) {
return EFI_INVALID_PARAMETER;
}
// Get SMM communication buffer
// Build SMM LockBox save request
// Send to SMM via communication buffer
// Return status
DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib SaveLockBox - Exit (%r)\n", Status));
return Status;
}
//
// SmmLockBoxRestoreLockBox @ 0x2414
// Restores a buffer from a LockBox identified by GUID.
// Allocates boot services buffer for the restored data.
//
UINT64
SmmLockBoxRestoreLockBox (
UINT64 a1,
UINT64 a2,
UINT64 a3
)
{
DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib RestoreLockBox - Enter\n"));
// Build LockBox restore request with SMM comm buffer
// Buffer layout:
// +0x00: Header (16 bytes)
// +0x10: Request function (Restore=3)
// +0x14: Size
// +0x28: GUID (copied from input)
// +0x38: Data buffer pointer
// +0x40: Data size
// Call SMM communication protocol
// Return restored data status
DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib RestoreLockBox - Exit (%r)\n", Status));
return Status;
}
//
// SmmLockBoxSetAttributes @ 0x22E8
// Sets attributes on an existing LockBox.
// Currently only supports EFI_LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE (bit 0).
//
UINT64
SmmLockBoxSetAttributes (
UINT64 Guid,
UINT64 Attributes
)
{
DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib SetLockBoxAttributes - Enter\n"));
// Build SMM request with Attributes=4 (SetAttributes)
// GUID is embedded in the request buffer
DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib SetLockBoxAttributes - Exit (%r)\n", Status));
return Status;
}
// =========================================================================
// Library: X64 Exception Handling
// =========================================================================
//
// X64ExceptionDumpCpuContext @ 0x6D30
// Dumps full CPU context for an X64 exception.
// Called by the exception handler to print register state.
//
UINT64
X64ExceptionDumpCpuContext (
UINT64 ExceptionType,
UINT64 *SystemContext,
DOUBLE ApicInfo
)
{
UINT32 ApicId = ExceptionHandlerGetApicId ();
X64ExceptionDebugPrint (
"!!!! X64 Exception Type - %02x(%a) CPU Apic ID - %08x !!!!\n",
ExceptionType, ApicInfo, ApicId
);
if (((1 << ExceptionType) & 0x27D00) != 0) {
// Exception has data (page fault, etc.)
X64ExceptionDebugPrint ("ExceptionData - %016lx", *SystemContext);
if (ExceptionType == 14) { // Page fault
X64ExceptionDebugPrint (
" I:%x R:%x U:%x W:%x P:%x PK:%x S:%x",
(*SystemContext >> 4) & 1,
(*SystemContext >> 3) & 1,
(*SystemContext >> 2) & 1,
(*SystemContext >> 1) & 1,
*SystemContext & 1,
(*SystemContext >> 5) & 1,
(*SystemContext >> 15) & 1
);
}
X64ExceptionDebugPrint ("\n");
}
// Dump all general purpose and system registers
X64ExceptionDebugPrint ("RIP - %016lx, CS - %016lx, RFLAGS - %016lx\n",
SystemContext[84], SystemContext[89], SystemContext[77]);
X64ExceptionDebugPrint ("RAX - %016lx, RCX - %016lx, RDX - %016lx\n",
SystemContext[98], SystemContext[97], SystemContext[96]);
X64ExceptionDebugPrint ("RBX - %016lx, RSP - %016lx, RBP - %016lx\n",
SystemContext[95], SystemContext[94], SystemContext[93]);
X64ExceptionDebugPrint ("RSI - %016lx, RDI - %016lx\n",
SystemContext[92], SystemContext[91]);
X64ExceptionDebugPrint ("R8 - %016lx, R9 - %016lx, R10 - %016lx\n",
SystemContext[99], SystemContext[100], SystemContext[101]);
X64ExceptionDebugPrint ("R11 - %016lx, R12 - %016lx, R13 - %016lx\n",
SystemContext[102], SystemContext[103], SystemContext[104]);
X64ExceptionDebugPrint ("R14 - %016lx, R15 - %016lx\n",
SystemContext[105], SystemContext[106]);
X64ExceptionDebugPrint ("DS - %016lx, ES - %016lx, FS - %016lx\n",
SystemContext[88], SystemContext[87], SystemContext[86]);
X64ExceptionDebugPrint ("GS - %016lx, SS - %016lx\n",
SystemContext[85], SystemContext[90]);
X64ExceptionDebugPrint ("CR0 - %016lx, CR2 - %016lx, CR3 - %016lx\n",
SystemContext[71], SystemContext[73], SystemContext[74]);
X64ExceptionDebugPrint ("CR4 - %016lx, CR8 - %016lx\n",
SystemContext[75], SystemContext[76]);
X64ExceptionDebugPrint ("DR0 - %016lx, DR1 - %016lx, DR2 - %016lx\n",
SystemContext[65], SystemContext[66], SystemContext[67]);
X64ExceptionDebugPrint ("DR3 - %016lx, DR6 - %016lx, DR7 - %016lx\n",
SystemContext[68], SystemContext[69], SystemContext[70]);
X64ExceptionDebugPrint ("GDTR - %016lx %016lx, LDTR - %016lx\n",
SystemContext[80], SystemContext[81], SystemContext[78]);
X64ExceptionDebugPrint ("IDTR - %016lx %016lx, TR - %016lx\n",
SystemContext[82], SystemContext[83], SystemContext[79]);
X64ExceptionDebugPrint ("FXSAVE_STATE - %016lx\n", (UINT64)SystemContext + 8);
return EFI_SUCCESS;
}
// =========================================================================
// Library: BaseLib and support functions
// =========================================================================
//
// BaseLibGetPerformanceCounter @ 0x19F4
// Reads the current performance counter value.
// Uses the TSC (Time Stamp Counter).
//
UINT64
BaseLibGetPerformanceCounter (
VOID
)
{
return __rdtsc ();
}
//
// CopyMem @ 0x72EC
// Copies memory from source to destination.
//
VOID *
CopyMem (
VOID *Destination,
VOID *Source,
UINTN Length
)
{
// Delegates to CopyMemInternal at 0x9C0
return CopyMemInternal (Destination, Source, Length);
}
//
// SetMem @ 0x7388
// Fills memory with a byte value.
//
VOID *
SetMem (
VOID *Buffer,
UINTN Length,
UINT8 Value
)
{
// Delegates to SetMemInternal at 0xA10
return SetMemInternal (Buffer, Length, Value);
}