Newer
Older
AMI-Aptio-BIOS-Reversed / AmiIpmiPkg / Ipmi / DxeFrb / DxeFrb.c
@Ajax Dong Ajax Dong 2 days ago 24 KB Full restructure
/**
 * DxeFrb.c -- FRB (Fault Resilient Boot) DXE Driver
 * Lenovo HR650X UEFI BIOS
 *
 * Manages the hardware FRB2 watchdog timer and OS boot watchdog timer
 * through the WCHG (Watchdog Chip) accessed via CMOS I/O ports 0x70/0x71.
 *
 * FRB2: Fault Resilient Boot Phase 2 timer. During boot phases where the
 * system could hang (option ROM init, password prompt, setup), FRB2 is
 * temporarily disabled. It is re-enabled after each critical phase completes.
 *
 * OS Boot WDT: A separate watchdog that supervises the OS boot process.
 * It is disabled before entering the UEFI Shell.
 *
 * Debug output uses the WCHG debug protocol (accessed via sub_E3C / GetDebugProtocol).
 */

#include "DxeFrb.h"

// ============================================================================
// Globals
// ============================================================================
EFI_HANDLE               gImageHandle    = NULL;
EFI_SYSTEM_TABLE        *gST             = NULL;
EFI_BOOT_SERVICES       *gBS             = NULL;
EFI_RUNTIME_SERVICES    *gRT             = NULL;

VOID                     *gWatchdogProtocol;    // qword_2110 -- EFI_WATCHDOG_TIMER_ARCH_PROTOCOL
VOID                     *gHobList;             // qword_1CC8 -- HOB list pointer
FRB2_DRIVER              *gFrb2Driver;          // qword_1CD8 -- Allocated driver instance
VOID                     *gDebugOutputProtocol; // qword_1CC0 -- WCHG debug protocol

BOOLEAN                   gFrb2Enabled  = FALSE;  // byte_1CE6
BOOLEAN                   gOsWdtEnabled = FALSE;  // byte_1CEB
BOOLEAN                   gOsWdtArmed   = FALSE;  // byte_1CEE
UINT16                    gOsWdtTimeout = 600;    // n600 (600 * 100ms = 60s)
BOOLEAN                   gOpromDone    = FALSE;  // byte_1CD1

//
// WCHG timer state storage -- 3 timers * 6 bytes each (at 0x2120)
//
UINT8                     gWchgTimerState[0x30];

//
// GUIDs used by this module
//
EFI_GUID  gEfiWatchdogTimerArchProtocolGuid  = EFI_WATCHDOG_TIMER_ARCH_PROTOCOL_GUID;
EFI_GUID  gEfiEventReadyToBootGuid           = EFI_EVENT_GROUP_READY_TO_BOOT;

// ============================================================================
// Internal Helpers
// ============================================================================

/**
 * Acquire the WCHG debug output protocol.
 * Allocates a small pool buffer then locates the protocol.
 *
 * The protocol provides:
 *   +0x00: DebugPrint  (variadic printf-like debug output)
 *   +0x08: DebugAssert (file/line/desc assert handler)
 */
VOID *
GetDebugProtocol (
  VOID
  )
{
  EFI_STATUS  Status;
  VOID       *Protocol;
  VOID       *Buffer;

  if (gDebugOutputProtocol != NULL) {
    return gDebugOutputProtocol;
  }

  Status = gBS->AllocatePool (EfiBootServicesData, 0x10, &Buffer);
  if (EFI_ERROR (Status)) {
    return NULL;
  }

  Status = gBS->LocateProtocol (&gEfiDebugProtocolGuid, NULL, &Protocol);
  if (EFI_ERROR (Status)) {
    Protocol = NULL;
  }

  gDebugOutputProtocol = Protocol;
  return Protocol;
}

/**
 * Debug print via WCHG debug protocol.
 * Checks debug level mask against a CMOS debug level register at
 * CMOS index 0x4B (port 0x70/0x71).  Levels: 1=ERROR, 2=WARN, 4=INFO.
 */
VOID
EFIAPI
DebugPrint (
  IN UINTN       ErrorLevel,
  IN CONST CHAR8 *Format,
  ...
  )
{
  VA_LIST         Marker;
  VOID           *DebugProto;
  UINT8           DebugLevel;
  UINT8           SavedCMOSIndex;
  UINT64          AllowedLevels;
  DEBUG_PRINT    *PrintFunc;

  DebugProto = GetDebugProtocol ();
  if (DebugProto == NULL) {
    return;
  }

  //
  // Read CMOS index 0x4B to get current debug level
  //
  SavedCMOSIndex = IoRead8 (0x70);
  IoWrite8 (0x70, (SavedCMOSIndex & 0x80) | 0x4B);
  DebugLevel = IoRead8 (0x71);

  //
  // Normalize debug level
  //
  if (DebugLevel > 3) {
    if (DebugLevel == 0) {
      DebugLevel = (*(UINT8 *)(UINTN)0xFDAF0490 & 2) | 1;
    }
  }

  switch (DebugLevel) {
    case 1: AllowedLevels = DEBUG_ERROR; break;
    case 2: AllowedLevels = DEBUG_WARN;  break;
    case 4: AllowedLevels = DEBUG_INFO;  break;
    default:
      // 0 or 3 => ERROR | WARN
      AllowedLevels = DEBUG_ERROR | DEBUG_WARN;
      break;
  }

  if ((AllowedLevels & ErrorLevel) == 0) {
    return;
  }

  VA_START (Marker, Format);
  PrintFunc = (DEBUG_PRINT *)((UINTN)DebugProto + 0);
  PrintFunc (ErrorLevel, Format, Marker);
  VA_END (Marker);
}

/**
 * Debug assert via WCHG debug protocol.
 */
VOID
EFIAPI
DebugAssert (
  IN CONST CHAR8 *FileName,
  IN UINTN        LineNumber,
  IN CONST CHAR8 *Description
  )
{
  VOID          *DebugProto;
  DEBUG_ASSERT  *AssertFunc;

  DebugProto = GetDebugProtocol ();
  if (DebugProto == NULL) {
    return;
  }

  AssertFunc = (DEBUG_ASSERT *)((UINTN)DebugProto + 8);
  AssertFunc (FileName, LineNumber, Description);
}

/**
 * Read 8 bytes from an unaligned pointer (BaseLib Unaligned.c).
 */
UINT64
ReadUnaligned64 (
  IN CONST VOID  *Buffer
  )
{
  if (Buffer == NULL) {
    DEBUG_ASSERT (FALSE, "Buffer != NULL");
  }
  return *(UINT64 *)Buffer;
}

/**
 * Compare two GUIDs as two UINT64 values.
 */
BOOLEAN
CompareGuid (
  IN CONST EFI_GUID  *Guid1,
  IN CONST EFI_GUID  *Guid2
  )
{
  return (ReadUnaligned64 (Guid1) == ReadUnaligned64 (Guid2)) &&
         (ReadUnaligned64 ((UINT8 *)Guid1 + 8) == ReadUnaligned64 ((UINT8 *)Guid2 + 8));
}

/**
 * Locate the HOB list from the SystemTable HOB pointer array.
 *
 * SystemTable + 0x68 (104) = number of HOB entries
 * SystemTable + 0x70 (112) = array of {GUID_lo, GUID_hi, pointer} entries
 */
EFI_STATUS
GetHobList (
  OUT VOID  **HobList
  )
{
  UINTN       Index;
  UINTN       HobCount;
  UINTN      *HobBase;

  if (HobList == NULL) {
    DEBUG_ASSERT (FALSE, "Table != NULL");
    return EFI_INVALID_PARAMETER;
  }

  *HobList = NULL;

  HobCount = *(UINTN *)((UINT8 *)gST + 0x68);
  if (HobCount == 0) {
    return EFI_NOT_FOUND;
  }

  HobBase = *(UINTN **)((UINT8 *)gST + 0x70);

  for (Index = 0; Index < HobCount; Index++) {
    if (CompareGuid (
          (EFI_GUID *)(HobBase + Index * 3),
          (EFI_GUID *)(HobBase + Index * 3 + 1)
          )) {
      *HobList = (VOID *)(HobBase[Index * 3 + 2]);
      return EFI_SUCCESS;
    }
  }

  return EFI_NOT_FOUND;
}

// ============================================================================
// WCHG Hardware Access Layer
// ============================================================================

/**
 * WchgGetState -- Read FRB2/OSWDT hardware timer state from WCHG.
 *
 * TimerIndex: 1=FRB2, 2=reserved, 3=OS Boot WDT.
 * (sub_3F0)
 */
EFI_STATUS
EFIAPI
WchgGetState (
  IN  FRB2_DRIVER    *This,
  IN  UINTN           TimerIndex,
  OUT WCHG_HW_STATE  *State
  )
{
  UINT8       WchgData[6];
  UINT8       ResultSize;
  EFI_STATUS  Status;

  if (State == NULL) {
    return EFI_INVALID_PARAMETER;
  }
  if (TimerIndex - 1 > 2) {
    return EFI_UNSUPPORTED;
  }

  ResultSize = 8;
  Status = ((WCHG_REGISTER_PROTOCOL *)gWatchdogProtocol)->RegisterSet (
              gWatchdogProtocol,
              6,              // Register index (timer state)
              0,
              37,             // Access type: read
              0,
              0,
              WchgData,
              &ResultSize
              );

  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Decode returned data
  //
  State->TimerRunning   = (WchgData[0] & 0x40) != 0;
  State->CountdownValue = 100000ULL * *(UINT16 *)&WchgData[3];
  State->CpuBusNo       = WchgData[1] & 7;
  State->ErrorAction    = (WchgData[1] >> 4) & 7;

  switch (TimerIndex) {
    case 1: State->TimeoutAction = (WchgData[2] >> 1) & 1; break;
    case 2: State->TimeoutAction = (WchgData[2] >> 2) & 1; break;
    case 3: State->TimeoutAction = (WchgData[2] >> 3) & 1; break;
  }

  return EFI_SUCCESS;
}

/**
 * WchgSetTimerValue -- Set countdown value for a timer.
 * Value is in 100-microsecond units.
 * (sub_500)
 */
EFI_STATUS
EFIAPI
WchgSetTimerValue (
  IN FRB2_DRIVER  *This,
  IN UINTN         TimerIndex,
  IN UINT64       *Value
  )
{
  if (TimerIndex - 1 > 2) {
    return EFI_UNSUPPORTED;
  }
  if (Value == NULL || *Value == 0) {
    return EFI_INVALID_PARAMETER;
  }

  gWchgTimerState[6 * TimerIndex]     = (UINT8)((*Value / 100000) & 0xFF);
  gWchgTimerState[6 * TimerIndex + 1] = (UINT8)((*Value / 100000) >> 8);

  return EFI_SUCCESS;
}

/**
 * WchgSetEnableFlags -- Set enable/disabled state for a timer.
 * (sub_558)
 */
EFI_STATUS
EFIAPI
WchgSetEnableFlags (
  IN FRB2_DRIVER  *This,
  IN UINTN         TimerIndex,
  IN UINT8        *Enable,
  IN UINT8         ArmedState
  )
{
  if (TimerIndex - 1 > 2) {
    return EFI_UNSUPPORTED;
  }

  gWchgTimerState[6 * TimerIndex + 2] = (Enable != NULL) ? *Enable : 0;
  gWchgTimerState[6 * TimerIndex + 3] = ArmedState;

  return EFI_SUCCESS;
}

/**
 * WchgSetActionFlags -- Set action on timeout for a timer.
 * (sub_594)
 */
EFI_STATUS
EFIAPI
WchgSetActionFlags (
  IN FRB2_DRIVER  *This,
  IN UINTN         TimerIndex,
  IN UINT8         Action
  )
{
  if (TimerIndex - 1 > 2) {
    return EFI_UNSUPPORTED;
  }

  gWchgTimerState[6 * TimerIndex + 4] = Action;

  return EFI_SUCCESS;
}

/**
 * WchgProgramAndArm -- Program WCHG hardware and arm the watchdog timer.
 * If ResetSystem is TRUE, uses a reset-asserting action bitmask (0x3E).
 * (sub_5BC)
 */
EFI_STATUS
EFIAPI
WchgProgramAndArm (
  IN FRB2_DRIVER  *This,
  IN UINTN         TimerIndex,
  IN VOID         *Unused1,
  IN VOID         *Unused2,
  IN BOOLEAN       ResetSystem
  )
{
  UINT8       WchgData[6];
  UINT8       ResultSize;
  EFI_STATUS  Status;
  UINT16      Countdown;

  if (TimerIndex - 1 > 2) {
    return EFI_UNSUPPORTED;
  }

  //
  // For FRB2 (timer 1), check if this is a cold boot via HOB
  //
  if (TimerIndex == 1) {
    Status = GetHobList ((VOID **)&Countdown);
    if (EFI_ERROR (Status)) {
      return Status;
    }
    if (*(UINT16 *)Countdown != 1) {
      return EFI_NOT_FOUND;
    }
    if (*(UINT32 *)((UINT8 *)Countdown + 12) == 32) {
      return EFI_UNSUPPORTED;   // S3 resume -- skip
    }
  }

  //
  // Prepare WCHG register data
  //
  Countdown = *(UINT16 *)&gWchgTimerState[6 * TimerIndex];
  if (Countdown == 0) {
    return EFI_SUCCESS;   // Countdown of 0 means timer is disabled
  }

  WchgData[0] = 6;
  WchgData[1] = (WchgData[1] & 0x38) | (TimerIndex & 7);
  WchgData[2] = (WchgData[2] & 0x88) |
                (gWchgTimerState[6 * TimerIndex + 4] & 7) |
                (16 * (gWchgTimerState[6 * TimerIndex + 3] & 7));
  WchgData[3] = gWchgTimerState[6 * TimerIndex + 2];
  WchgData[4] = HIBYTE (Countdown);
  WchgData[5] = LOBYTE (Countdown);

  //
  // Set action mask based on whether this is a full system reset
  //
  if (!ResetSystem) {
    if (TimerIndex == 1) {
      WchgData[5] |= 0x02;  // FRB2 action
    } else if (TimerIndex == 2) {
      WchgData[5] |= 0x04;
    } else if (TimerIndex == 3) {
      WchgData[5] |= 0x08;  // OS WDT action
    }
  } else {
    WchgData[5] |= 0x3E;    // Full system reset action
  }

  //
  // Write register data
  //
  ResultSize = 6;
  Status = ((WCHG_REGISTER_PROTOCOL *)gWatchdogProtocol)->RegisterSet (
              gWatchdogProtocol,
              6,
              0,
              36,                 // Access type: write
              &WchgData[1],
              6,
              0,
              &ResultSize
              );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Second write to commit/arm
  //
  ResultSize = 0;
  Status = ((WCHG_REGISTER_PROTOCOL *)gWatchdogProtocol)->RegisterSet (
              gWatchdogProtocol,
              6,
              0,
              34,                 // Access type: commit/arm
              NULL,
              6,
              0,
              &ResultSize
              );

  return Status;
}

/**
 * WchgReadBackVerify -- Read back WCHG state and verify.
 * If the timer was previously disabled, returns EFI_ALREADY_STARTED.
 * (sub_78C)
 */
EFI_STATUS
EFIAPI
WchgReadBackVerify (
  IN FRB2_DRIVER  *This,
  IN UINTN         TimerIndex,
  IN VOID         *Unused,
  IN VOID         *Unused2
  )
{
  UINT8       WchgData[6];
  UINT8       ResultSize;
  EFI_STATUS  Status;

  if (TimerIndex - 1 > 2) {
    return EFI_UNSUPPORTED;
  }

  //
  // Read hardware state
  //
  ResultSize = 8;
  Status = ((WCHG_REGISTER_PROTOCOL *)gWatchdogProtocol)->RegisterSet (
              gWatchdogProtocol,
              6,
              0,
              37,
              0,
              0,
              WchgData,
              &ResultSize
              );

  if (EFI_ERROR (Status)) {
    return Status;
  }

  if ((WchgData[0] & 0x40) != 0) {
    //
    // Timer is running -- verify index, sync state
    //
    if ((WchgData[0] & 7) != TimerIndex) {
      return EFI_NOT_FOUND;
    }

    gWchgTimerState[6 * TimerIndex]     = WchgData[1];
    gWchgTimerState[6 * TimerIndex + 1] = WchgData[2];
    gWchgTimerState[6 * TimerIndex + 4] = WchgData[1] & 7;
    gWchgTimerState[6 * TimerIndex + 3] = (WchgData[1] >> 4) & 7;

    //
    // Re-arm the timer
    //
    WchgData[0] = 6;
    WchgData[1] = TimerIndex & 7;
    WchgData[2] = 0;
    WchgData[3] = 0;
    *(UINT16 *)&WchgData[3] = 0;
    WchgData[3] = 0;

    ResultSize = 6;
    Status = ((WCHG_REGISTER_PROTOCOL *)gWatchdogProtocol)->RegisterSet (
                gWatchdogProtocol,
                6,
                0,
                36,
                WchgData,
                6,
                0,
                &ResultSize
                );

    return Status;
  } else {
    //
    // Timer not running -- already disabled
    //
    DEBUG ((DEBUG_ERROR, "%a: EfiFrb2 already disabled\n", __FUNCTION__));
    return EFI_ALREADY_STARTED;
  }
}

// ============================================================================
// Boot Phase Notification Handlers
// ============================================================================

/**
 * Frb2OpromNotify -- Called before/after option ROM dispatch.
 * Toggles FRB2 off during OPROM and back on after.
 * (sub_CAC)
 */
VOID
EFIAPI
Frb2OpromNotify (
  IN EFI_EVENT  Event,
  IN VOID      *Context
  )
{
  EFI_STATUS  Status;

  if (!gOpromDone) {
    Status = WchgReadBackVerify (gFrb2Driver, 1, NULL, NULL);
    if (!EFI_ERROR (Status)) {
      DEBUG ((DEBUG_INFO, "EfiFrb2 disabled Before OPRom Status = %r\n", Status));
      gOpromDone = TRUE;
    }
  }

  if (gOpromDone) {
    Status = WchgProgramAndArm (gFrb2Driver, 1, NULL, NULL, FALSE);
    if (!EFI_ERROR (Status)) {
      gOpromDone = FALSE;
      DEBUG ((DEBUG_INFO, "EfiFrb2 Enabled after OPRom Status = %r\n", Status));
    }
  }
}

/**
 * Frb2PasswordNotify -- Disable FRB2 before password prompt.
 * (sub_D38)
 */
VOID
EFIAPI
Frb2PasswordNotify (
  IN EFI_EVENT  Event,
  IN VOID      *Context
  )
{
  EFI_STATUS  Status;

  Status = WchgReadBackVerify (gFrb2Driver, 1, NULL, NULL);
  DEBUG ((DEBUG_INFO, "EfiFrb2 Disabled Before Giving Password= %r\n", Status));
}

/**
 * Frb2PasswordDoneNotify -- Re-enable FRB2 after password.
 * (sub_D68)
 */
VOID
EFIAPI
Frb2PasswordDoneNotify (
  IN EFI_EVENT  Event,
  IN VOID      *Context
  )
{
  EFI_STATUS  Status;

  Status = WchgProgramAndArm (gFrb2Driver, 1, NULL, NULL, FALSE);
  DEBUG ((DEBUG_INFO, "EfiFrb2 Enabled after Giving Password= %r\n", Status));
}

/**
 * Frb2PromptTimeoutNotify -- Disable FRB2 before prompt timeout.
 * (sub_DA0)
 */
VOID
EFIAPI
Frb2PromptTimeoutNotify (
  IN EFI_EVENT  Event,
  IN VOID      *Context
  )
{
  EFI_STATUS  Status;

  Status = WchgReadBackVerify (gFrb2Driver, 1, NULL, NULL);
  DEBUG ((DEBUG_INFO, "EfiFrb2 Disabled Before PromptTimeOut Start= %r\n", Status));
}

/**
 * Frb2PromptTimeoutDoneNotify -- Re-enable FRB2 after prompt timeout.
 * (sub_DD0)
 */
VOID
EFIAPI
Frb2PromptTimeoutDoneNotify (
  IN EFI_EVENT  Event,
  IN VOID      *Context
  )
{
  EFI_STATUS  Status;

  Status = WchgProgramAndArm (gFrb2Driver, 1, NULL, NULL, FALSE);
  DEBUG ((DEBUG_INFO, "EfiFrb2 Enabled after Prompt TimeOut Ends= %r\n", Status));
}

/**
 * ShellEntryNotify -- Disable OS boot WDT when entering UEFI Shell.
 * (sub_E08)
 */
VOID
EFIAPI
ShellEntryNotify (
  IN EFI_EVENT  Event,
  IN VOID      *Context
  )
{
  EFI_STATUS  Status;

  Status = WchgReadBackVerify (gFrb2Driver, 3, NULL, NULL);
  DEBUG ((DEBUG_INFO, "OS WDT is disabled on entering shell. Status = %r\n", Status));
}

/**
 * ReadyToBootCallback -- Fires at ReadyToBoot.
 * Disables FRB2 and arms the OS boot WDT.
 * (sub_8D8)
 */
VOID
EFIAPI
ReadyToBootCallback (
  IN EFI_EVENT  Event,
  IN VOID      *Context
  )
{
  EFI_STATUS  Status;

  if (gFrb2Enabled) {
    Status = WchgReadBackVerify (gFrb2Driver, 1, NULL, NULL);
    DEBUG ((DEBUG_INFO, "EfiFrb2 disabled Status = %r\n", Status));
  }

  if (gOsWdtEnabled) {
    UINT64  TimeoutUs;

    TimeoutUs = 1000000ULL * gOsWdtTimeout;

    WchgSetTimerValue (gFrb2Driver, 3, &TimeoutUs);
    gWchgTimerState[21] = 0;
    gWchgTimerState[22] = gOsWdtArmed;

    Status = WchgProgramAndArm (gFrb2Driver, 3, NULL, NULL, FALSE);
    DEBUG ((DEBUG_INFO, "EfiOsBootWdt Enabled Status = %r\n", Status));
  }
}

/**
 * BootPhaseNotify -- Disable FRB2 and OS WDT before setup.
 * (sub_C44)
 */
VOID
EFIAPI
BootPhaseNotify (
  IN EFI_EVENT  Event,
  IN VOID      *Context
  )
{
  EFI_STATUS  Status;

  if (gFrb2Enabled) {
    Status = WchgReadBackVerify (gFrb2Driver, 1, NULL, NULL);
    DEBUG ((DEBUG_INFO, "EfiFrb2 disabled Before setup Status = %r\n", Status));

    if (gOsWdtEnabled) {
      Status = WchgReadBackVerify (gFrb2Driver, 3, NULL, NULL);
      DEBUG ((DEBUG_INFO, "EfiOsBootWdt disabled Before setup Status = %r\n", Status));
    }
  }
}

// ============================================================================
// Event Registration Helpers
// ============================================================================

/**
 * RegisterBootEvent -- Create a TPL notify event for a boot phase GUID.
 * Based on UefiLib's EfiCreateProtocolNotifyEvent pattern.
 * (sub_10A4)
 */
EFI_STATUS
RegisterBootEvent (
  IN EFI_GUID          *EventGroupGuid,
  IN UINTN              NotifyTpl,
  IN EFI_EVENT_NOTIFY   NotifyFunction,
  ...
  )
{
  EFI_STATUS  Status;
  EFI_EVENT   Event;
  VA_LIST     Context;
  VOID       *Registration;

  if (EventGroupGuid == NULL) {
    DEBUG_ASSERT (FALSE, "Name != NULL");
    return EFI_INVALID_PARAMETER;
  }
  if (NotifyFunction == NULL) {
    DEBUG_ASSERT (FALSE, "NotifyFunction != NULL");
    return EFI_INVALID_PARAMETER;
  }

  Status = gBS->CreateEventEx (
                  EVT_NOTIFY_SIGNAL,
                  NotifyTpl,
                  NotifyFunction,
                  NULL,
                  EventGroupGuid,
                  &Event
                  );
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
    DEBUG_ASSERT (FALSE, "!EFI_ERROR (Status)");
  }

  VA_START (Context, NotifyFunction);
  Registration = VA_ARG (Context, VOID *);
  VA_END (Context);

  Status = gBS->RegisterProtocolNotify (EventGroupGuid, Event, Registration);
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
    DEBUG_ASSERT (FALSE, "!EFI_ERROR (Status)");
  }

  return Status;
}

/**
 * RegisterReadyToBootEvent -- Register the ReadyToBoot event callback.
 * Requires UEFI spec >= 2.0.
 * (sub_11BC)
 */
EFI_STATUS
RegisterReadyToBootEvent (
  OUT EFI_EVENT  *ReadyToBootEvent
  )
{
  if (ReadyToBootEvent == NULL) {
    DEBUG_ASSERT (FALSE, "ReadyToBootEvent != NULL");
    return EFI_INVALID_PARAMETER;
  }

  if (gST->Hdr.Revision >= EFI_SPECIFICATION_VERSION_2_0) {
    return gBS->CreateEventEx (
                  EVT_NOTIFY_SIGNAL,
                  TPL_NOTIFY,
                  ReadyToBootCallback,
                  NULL,
                  &gEfiEventReadyToBootGuid,
                  ReadyToBootEvent
                  );
  } else {
    DEBUG ((DEBUG_ERROR, "EFI1.1 can't support ReadyToBootEvent!\n"));
    DEBUG_ASSERT (FALSE, "((BOOLEAN)(0==1))");
    return EFI_UNSUPPORTED;
  }
}

// ============================================================================
// Driver Entry Point
// ============================================================================

/**
 * InitializeHobList -- Get the HOB list pointer, used as early init.
 * (sub_1260)
 *
 * This is called early in ModuleEntryPoint, before the main init.
 * It caches the HOB list pointer so it is available for later use.
 */
EFI_STATUS
InitializeHobList (
  VOID
  )
{
  EFI_STATUS  Status;

  if (gHobList != NULL) {
    return EFI_SUCCESS;
  }

  Status = GetHobList (&gHobList);
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
    DEBUG_ASSERT (__FILE__, __LINE__, "!EFI_ERROR (Status)");
  }

  if (gHobList == NULL) {
    DEBUG_ASSERT (__FILE__, __LINE__, "mHobList != NULL");
  }

  return (gHobList != NULL) ? EFI_SUCCESS : EFI_NOT_FOUND;
}

/**
 * AllocateZeroPool -- Allocate and zero a pool buffer.
 * (sub_F84) + (sub_12DC)
 */
VOID *
AllocateZeroPool (
  IN UINTN  Size
  )
{
  VOID        *Buffer;
  EFI_STATUS   Status;

  Status = gBS->AllocatePool (EfiBootServicesData, Size, &Buffer);
  if (EFI_ERROR (Status)) {
    return NULL;
  }

  ZeroMem (Buffer, Size);
  return Buffer;
}

/**
 * FreePool -- Release a pool buffer.
 * (sub_FBC)
 */
VOID
FreePool (
  IN VOID  *Buffer
  )
{
  EFI_STATUS  Status;

  Status = gBS->FreePool (Buffer);
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
    DEBUG_ASSERT (__FILE__, __LINE__, "!EFI_ERROR (Status)");
  }
}

/**
 * DxeFrbEntryPoint -- Main driver entry point.
 *
 * 1. Locate EFI_WATCHDOG_TIMER_ARCH_PROTOCOL
 * 2. Allocate and initialize FRB2 driver instance
 * 3. Install protocol on image handle
 * 4. Read "ServerSetup" variable for configuration
 * 5. Register boot phase notification callbacks
 *
 * (sub_984)
 */
EFI_STATUS
EFIAPI
DxeFrbEntryPoint (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE *SystemTable
  )
{
  EFI_STATUS    Status;
  FRB2_DRIVER  *Driver;
  VOID         *ServerSetup;
  UINTN         VariableSize;

  //
  // 1. Locate EFI_WATCHDOG_TIMER_ARCH_PROTOCOL
  //
  Status = gBS->LocateProtocol (
                  &gEfiWatchdogTimerArchProtocolGuid,
                  NULL,
                  &gWatchdogProtocol
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // 2. Allocate and initialize the FRB2 driver instance
  //
  Driver = AllocateZeroPool (sizeof (FRB2_DRIVER));
  if (Driver == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  gFrb2Driver = Driver;

  //
  // 3. Populate function table
  //
  Driver->GetState              = WchgGetState;
  Driver->SetTimerValue         = WchgSetTimerValue;
  Driver->SetEnableFlags        = WchgSetEnableFlags;
  Driver->SetActionFlags        = WchgSetActionFlags;
  Driver->ProgramAndArm         = WchgProgramAndArm;
  Driver->ReadBackVerify        = WchgReadBackVerify;

  //
  // 4. Install the FRB2 driver protocol on the image handle
  //
  Status = gBS->InstallProtocolInterface (
                  &ImageHandle,
                  &gFrb2DriverBindingGuid,
                  EFI_NATIVE_INTERFACE,
                  Driver
                  );
  if (EFI_ERROR (Status)) {
    FreePool (Driver);
    return Status;
  }

  //
  // 5. Read configuration from "ServerSetup" UEFI variable
  //
  VariableSize = sizeof (ServerSetup);
  Status = gRT->GetVariable (
                  L"ServerSetup",
                  &gEfiServerSetupGuid,
                  NULL,
                  &VariableSize,
                  &ServerSetup
                  );

  if (EFI_ERROR (Status)) {
    //
    // Defaults when variable not found
    //
    gFrb2Enabled   = TRUE;
    gOsWdtTimeout  = 600;     // 60 seconds (600 * 100ms)
    gOsWdtEnabled  = FALSE;
    gOsWdtArmed    = TRUE;
  }

  //
  // 6. Register event notification callbacks
  //
  if (gFrb2Enabled) {
    RegisterBootEvent (&gEfiEventOpromGuid,            8,  Frb2OpromNotify,              NULL);
    RegisterBootEvent (&gEfiEventPasswordGuid,        16,  Frb2PasswordNotify,           NULL);
    RegisterBootEvent (&gEfiEventPasswordDoneGuid,    16,  Frb2PasswordDoneNotify,       NULL);
    RegisterBootEvent (&gEfiEventPromptTimeoutGuid,   16,  Frb2PromptTimeoutNotify,      NULL);
    RegisterBootEvent (&gEfiEventPromptTimeoutDoneGuid,16, Frb2PromptTimeoutDoneNotify,  NULL);
  }

  if (gOsWdtEnabled) {
    RegisterBootEvent (&gEfiEventOsWdtGuid1,          16,  ShellEntryNotify,             NULL);
    RegisterBootEvent (&gEfiEventOsWdtGuid2,          16,  ShellEntryNotify,             NULL);
    RegisterBootEvent (&gEfiEventOsWdtGuid3,          16,  NullNotify,                   NULL);
  }

  if (gFrb2Enabled || gOsWdtEnabled) {
    RegisterBootEvent (&gEfiEventBootPhaseGuid1,       8,  BootPhaseNotify,              NULL);
    RegisterBootEvent (&gEfiEventBootPhaseGuid2,       8,  ReadyToBootCallback,          NULL);
    RegisterBootEvent (&gEfiEventBootPhaseGuid3,       8,  ReadyToBootCallback,          NULL);

    Status = RegisterReadyToBootEvent (&gReadyToBootEvent);

    DEBUG ((DEBUG_INFO, "EfiFrb2 disabled Before boot Status = %r\n", Status));
  }

  return EFI_SUCCESS;
}