Newer
Older
AMI-Aptio-BIOS-Reversed / MdeModulePkg / Universal / Acpi / BootScriptExecutorDxe / BootScriptExecutorDxe.c
@Ajax Dong Ajax Dong 2 days ago 17 KB Full restructure
/*
 * 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);
}