S3BootScriptLibInitialize (
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE     *SystemTable
  )
{
  EFI_STATUS                      Status;
  SCRIPT_TABLE_PRIVATE_DATA      *S3TablePtr;
  SCRIPT_TABLE_PRIVATE_DATA      *S3TableSmmPtr;
  VOID                           *Registration;
  EFI_SMM_BASE2_PROTOCOL         *SmmBase2;
  BOOLEAN                        InSmm;
  EFI_PHYSICAL_ADDRESS           Buffer;

  if (!PcdGetBool (PcdAcpiS3Enable)) {
    mAcpiS3Enable = FALSE;
    DEBUG ((DEBUG_INFO, "%a: Skip S3BootScript because ACPI S3 disabled.\n", gEfiCallerBaseName));
    return RETURN_SUCCESS;
  }

  S3TablePtr = (SCRIPT_TABLE_PRIVATE_DATA*)(UINTN)PcdGet64(PcdS3BootScriptTablePrivateDataPtr);
  //
  // The Boot script private data is not be initialized. create it
  //
  if (S3TablePtr == 0) {
    Buffer = SIZE_4GB - 1;
    Status = gBS->AllocatePages (
                    AllocateMaxAddress,
                    EfiReservedMemoryType,
                    EFI_SIZE_TO_PAGES(sizeof(SCRIPT_TABLE_PRIVATE_DATA)),
                    &Buffer
                    );
    ASSERT_EFI_ERROR (Status);
    mS3BootScriptTableAllocated = TRUE;
    S3TablePtr = (VOID *) (UINTN) Buffer;

    Status = PcdSet64S (PcdS3BootScriptTablePrivateDataPtr, (UINT64) (UINTN)S3TablePtr);
    ASSERT_EFI_ERROR (Status);
    ZeroMem (S3TablePtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA));
    //
    // Create event to notify the library system enter the SmmLocked phase.
    //
    mEventDxeSmmReadyToLock = EfiCreateProtocolNotifyEvent (
                                &gEfiDxeSmmReadyToLockProtocolGuid,
                                TPL_CALLBACK,
                                S3BootScriptEventCallBack,
                                NULL,
                                &Registration
                                );
    ASSERT (mEventDxeSmmReadyToLock != NULL);
  }
  mS3BootScriptTablePtr = S3TablePtr;

  //
  // Get InSmm, we need to register SmmReadyToLock if this library is linked to SMM driver.
  //
  Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID**) &SmmBase2);
  if (EFI_ERROR (Status)) {
    return RETURN_SUCCESS;
  }
  Status = SmmBase2->InSmm (SmmBase2, &InSmm);
  if (EFI_ERROR (Status)) {
    return RETURN_SUCCESS;
  }
  if (!InSmm) {
    return RETURN_SUCCESS;
  }
  //
  // Good, we are in SMM
  //
  Status = SmmBase2->GetSmstLocation (SmmBase2, &mBootScriptSmst);
  if (EFI_ERROR (Status)) {
    return RETURN_SUCCESS;
  }

  S3TableSmmPtr = (SCRIPT_TABLE_PRIVATE_DATA*)(UINTN)PcdGet64(PcdS3BootScriptTablePrivateSmmDataPtr);
  //
  // The Boot script private data in SMM is not be initialized. create it
  //
  if (S3TableSmmPtr == 0) {
    Status = mBootScriptSmst->SmmAllocatePool (
                                EfiRuntimeServicesData,
                                sizeof(SCRIPT_TABLE_PRIVATE_DATA),
                                (VOID **) &S3TableSmmPtr
                                );
    ASSERT_EFI_ERROR (Status);
    mS3BootScriptTableSmmAllocated = TRUE;

    Status = PcdSet64S (PcdS3BootScriptTablePrivateSmmDataPtr, (UINT64) (UINTN)S3TableSmmPtr);
    ASSERT_EFI_ERROR (Status);
    ZeroMem (S3TableSmmPtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA));

    //
    // Register SmmExitBootServices and SmmLegacyBoot notification.
    //
    Status = mBootScriptSmst->SmmRegisterProtocolNotify (
                                &gEdkiiSmmExitBootServicesProtocolGuid,
                                S3BootScriptSmmAtRuntimeCallBack,
                                &mRegistrationSmmExitBootServices
                                );
    ASSERT_EFI_ERROR (Status);

    Status = mBootScriptSmst->SmmRegisterProtocolNotify (
                                &gEdkiiSmmLegacyBootProtocolGuid,
                                S3BootScriptSmmAtRuntimeCallBack,
                                &mRegistrationSmmLegacyBoot
                                );
    ASSERT_EFI_ERROR (Status);
  }
  mS3BootScriptTableSmmPtr = S3TableSmmPtr;

  //
  // Register SmmReadyToLock notification.
  //
  Status = mBootScriptSmst->SmmRegisterProtocolNotify (
                              &gEfiSmmReadyToLockProtocolGuid,
                              S3BootScriptSmmEventCallBack,
                              &mRegistrationSmmReadyToLock
                              );
  ASSERT_EFI_ERROR (Status);

  return RETURN_SUCCESS;
}