Example #1
0
EFI_STATUS
RestoreQncS3SwCallback (
  IN  EFI_HANDLE                    DispatchHandle,
  IN  CONST VOID                    *DispatchContext,
  IN  OUT VOID                      *CommBuffer,
  IN  OUT UINTN                     *CommBufferSize
  )
/*++

Routine Description:
  SMI handler to retore QncS3 code & context for S3 path
  This will be only triggered when BootScript got executed during resume

Arguments:
  DispatchHandle  - EFI Handle
  DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT

Returns:
  Nothing

--*/
{
  //
  // Restore to original address by default
  //
  RestoreLockBox(&gQncS3CodeInLockBoxGuid, NULL, NULL);
  RestoreLockBox(&gQncS3ContextInLockBoxGuid, NULL, NULL);
  return EFI_SUCCESS;
}
/**
  Dispatch function for SMM lock box restore.

  Caution: This function may receive untrusted input.
  Restore buffer and length are external input, so this function will validate
  it is in SMRAM.

  @param LockBoxParameterRestore  parameter of lock box restore
**/
VOID
SmmLockBoxRestore (
  IN EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *LockBoxParameterRestore
  )
{
  EFI_STATUS                     Status;
  EFI_SMM_LOCK_BOX_PARAMETER_RESTORE TempLockBoxParameterRestore;

  CopyMem (&TempLockBoxParameterRestore, LockBoxParameterRestore, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE));

  //
  // Sanity check
  //
  if (!SmmIsBufferOutsideSmmValid ((UINTN)TempLockBoxParameterRestore.Buffer, (UINTN)TempLockBoxParameterRestore.Length)) {
    DEBUG ((EFI_D_ERROR, "SmmLockBox Restore address in SMRAM or buffer overflow!\n"));
    LockBoxParameterRestore->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
    return ;
  }

  //
  // Restore data
  //
  if ((TempLockBoxParameterRestore.Length == 0) && (TempLockBoxParameterRestore.Buffer == 0)) {
    Status = RestoreLockBox (
               &TempLockBoxParameterRestore.Guid,
               NULL,
               NULL
               );
  } else {
    Status = RestoreLockBox (
               &TempLockBoxParameterRestore.Guid,
               (VOID *)(UINTN)TempLockBoxParameterRestore.Buffer,
               (UINTN *)&TempLockBoxParameterRestore.Length
               );
    if (Status == EFI_BUFFER_TOO_SMALL) {
      LockBoxParameterRestore->Length = TempLockBoxParameterRestore.Length;
    }
  }
  LockBoxParameterRestore->Header.ReturnStatus = (UINT64)Status;
  return ;
}
/**
  Report status code listener for PEI. This is used to record the performance
  data for S3 FullResume in FPDT.

  @param[in]  PeiServices         An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
  @param[in]  CodeType            Indicates the type of status code being reported.
  @param[in]  Value               Describes the current status of a hardware or software entity.
                                  This included information about the class and subclass that is used to
                                  classify the entity as well as an operation.
  @param[in]  Instance            The enumeration of a hardware or software entity within
                                  the system. Valid instance numbers start with 1.
  @param[in]  CallerId            This optional parameter may be used to identify the caller.
                                  This parameter allows the status code driver to apply different rules to
                                  different callers.
  @param[in]  Data                This optional parameter may be used to pass additional data.

  @retval EFI_SUCCESS             Status code is what we expected.
  @retval EFI_UNSUPPORTED         Status code not supported.

**/
EFI_STATUS
EFIAPI
FpdtStatusCodeListenerPei (
  IN CONST  EFI_PEI_SERVICES        **PeiServices,
  IN        EFI_STATUS_CODE_TYPE    CodeType,
  IN        EFI_STATUS_CODE_VALUE   Value,
  IN        UINT32                  Instance,
  IN CONST  EFI_GUID                *CallerId,
  IN CONST  EFI_STATUS_CODE_DATA    *Data
  )
{
  EFI_STATUS                           Status;
  UINT64                               CurrentTime;
  EFI_PEI_READ_ONLY_VARIABLE2_PPI      *VariableServices;
  UINTN                                VarSize;
  FIRMWARE_PERFORMANCE_VARIABLE        PerformanceVariable;
  S3_PERFORMANCE_TABLE                 *AcpiS3PerformanceTable;
  EFI_ACPI_5_0_FPDT_S3_RESUME_RECORD   *AcpiS3ResumeRecord;
  UINT64                               S3ResumeTotal;
  EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD  S3SuspendRecord;
  EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD  *AcpiS3SuspendRecord;

  //
  // Check whether status code is what we are interested in.
  //
  if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) != EFI_PROGRESS_CODE) ||
  	  (Value != (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_OS_WAKE))) {
    return EFI_UNSUPPORTED;
  }

  //
  // Retrieve current time as early as possible.
  //
  CurrentTime = GetTimeInNanoSecond (GetPerformanceCounter ());

  Status = PeiServicesLocatePpi (
             &gEfiPeiReadOnlyVariable2PpiGuid,
             0,
             NULL,
             (VOID **) &VariableServices
             );
  ASSERT_EFI_ERROR (Status);

  //
  // Update S3 Resume Performance Record.
  //
  VarSize = sizeof (FIRMWARE_PERFORMANCE_VARIABLE);
  Status = VariableServices->GetVariable (
                               VariableServices,
                               EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,
                               &gEfiFirmwarePerformanceGuid,
                               NULL,
                               &VarSize,
                               &PerformanceVariable
                               );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  AcpiS3PerformanceTable = (S3_PERFORMANCE_TABLE *) (UINTN) PerformanceVariable.S3PerformanceTablePointer;
  ASSERT (AcpiS3PerformanceTable != NULL);
  ASSERT (AcpiS3PerformanceTable->Header.Signature == EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE);
  AcpiS3ResumeRecord = &AcpiS3PerformanceTable->S3Resume;
  AcpiS3ResumeRecord->FullResume = CurrentTime;
  //
  // Calculate average S3 resume time.
  //
  S3ResumeTotal = MultU64x32 (AcpiS3ResumeRecord->AverageResume, AcpiS3ResumeRecord->ResumeCount);
  AcpiS3ResumeRecord->ResumeCount++;
  AcpiS3ResumeRecord->AverageResume = DivU64x32 (S3ResumeTotal + AcpiS3ResumeRecord->FullResume, AcpiS3ResumeRecord->ResumeCount);

  DEBUG ((EFI_D_INFO, "FPDT: S3 Resume Performance - ResumeCount   = %d\n", AcpiS3ResumeRecord->ResumeCount));
  DEBUG ((EFI_D_INFO, "FPDT: S3 Resume Performance - FullResume    = %ld\n", AcpiS3ResumeRecord->FullResume));
  DEBUG ((EFI_D_INFO, "FPDT: S3 Resume Performance - AverageResume = %ld\n", AcpiS3ResumeRecord->AverageResume));

  //
  // Update S3 Suspend Performance Record.
  //
  AcpiS3SuspendRecord = &AcpiS3PerformanceTable->S3Suspend;
  VarSize = sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD);
  ZeroMem (&S3SuspendRecord, sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD));
  Status = RestoreLockBox (
             &gEfiFirmwarePerformanceGuid,
             &S3SuspendRecord,
             &VarSize
             );
  ASSERT_EFI_ERROR (Status);

  AcpiS3SuspendRecord->SuspendStart = S3SuspendRecord.SuspendStart;
  AcpiS3SuspendRecord->SuspendEnd   = S3SuspendRecord.SuspendEnd;

  DEBUG ((EFI_D_INFO, "FPDT: S3 Suspend Performance - SuspendStart = %ld\n", AcpiS3SuspendRecord->SuspendStart));
  DEBUG ((EFI_D_INFO, "FPDT: S3 Suspend Performance - SuspendEnd   = %ld\n", AcpiS3SuspendRecord->SuspendEnd));

  return EFI_SUCCESS;
}
/**
  DxeSmmReadyToLock Protocol notification event handler.
  We reuse S3 ACPI NVS reserved memory to do capsule process
  after reset.

  @param[in] Event    Event whose notification function is being invoked.
  @param[in] Context  Pointer to the notification function's context.
**/
VOID
EFIAPI
DxeSmmReadyToLockNotification (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  EFI_STATUS                    Status;
  VOID                          *DxeSmmReadyToLock;
  UINTN                         VarSize;
  EFI_PHYSICAL_ADDRESS          TempAcpiS3Context;
  ACPI_S3_CONTEXT               *AcpiS3Context;
  EFI_CAPSULE_LONG_MODE_BUFFER  LongModeBuffer;
  UINTN                         TotalPagesNum;
  UINT8                         PhysicalAddressBits;
  VOID                          *Hob;
  UINT32                        NumberOfPml4EntriesNeeded;
  UINT32                        NumberOfPdpEntriesNeeded;
  BOOLEAN                       LockBoxFound;

  Status = gBS->LocateProtocol (
                  &gEfiDxeSmmReadyToLockProtocolGuid,
                  NULL,
                  &DxeSmmReadyToLock
                  );
  if (EFI_ERROR (Status)) {
    return ;
  }

  //
  // Get the ACPI NVS pages reserved by AcpiS3Save
  //
  LockBoxFound = FALSE;
  VarSize = sizeof (EFI_PHYSICAL_ADDRESS);
  Status = RestoreLockBox (
             &gEfiAcpiVariableGuid,
             &TempAcpiS3Context,
             &VarSize
             );
  if (!EFI_ERROR (Status)) {
    AcpiS3Context = (ACPI_S3_CONTEXT *)(UINTN)TempAcpiS3Context;
    ASSERT (AcpiS3Context != NULL);
    
    Status = RestoreLockBox (
               &gEfiAcpiS3ContextGuid,
               NULL,
               NULL
               );
    if (!EFI_ERROR (Status)) {
      LongModeBuffer.PageTableAddress = AcpiS3Context->S3NvsPageTableAddress;
      LongModeBuffer.StackBaseAddress = AcpiS3Context->BootScriptStackBase;
      LongModeBuffer.StackSize        = AcpiS3Context->BootScriptStackSize;
      LockBoxFound                    = TRUE;
    }
  }
  
  if (!LockBoxFound) {
    //
    // Page table base address and stack base address can not be found in lock box,
    // allocate both here. 
    //

    //
    // Get physical address bits supported from CPU HOB.
    //
    PhysicalAddressBits = 36;
    
    Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
    if (Hob != NULL) {
      PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
    }
    
    //
    // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
    //
    ASSERT (PhysicalAddressBits <= 52);
    if (PhysicalAddressBits > 48) {
      PhysicalAddressBits = 48;
    }
    
    //
    // Calculate page table size and allocate memory for it.
    //
    if (PhysicalAddressBits <= 39 ) {
      NumberOfPml4EntriesNeeded = 1;
      NumberOfPdpEntriesNeeded =  1 << (PhysicalAddressBits - 30);
    } else {
      NumberOfPml4EntriesNeeded = 1 << (PhysicalAddressBits - 39);
      NumberOfPdpEntriesNeeded = 512;
    }
    
    TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;
    LongModeBuffer.PageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (EFI_PAGES_TO_SIZE (TotalPagesNum));
    ASSERT (LongModeBuffer.PageTableAddress != 0);
    
    //
    // Allocate stack
    //
    LongModeBuffer.StackSize        = PcdGet32 (PcdCapsulePeiLongModeStackSize);
    LongModeBuffer.StackBaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (PcdGet32 (PcdCapsulePeiLongModeStackSize));
    ASSERT (LongModeBuffer.StackBaseAddress != 0);
  }

  Status = gRT->SetVariable (
                  EFI_CAPSULE_LONG_MODE_BUFFER_NAME,
                  &gEfiCapsuleVendorGuid,
                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
                  sizeof (EFI_CAPSULE_LONG_MODE_BUFFER),
                  &LongModeBuffer
                  );
  ASSERT_EFI_ERROR (Status);

  //
  // Close event, so it will not be invoked again.
  //
  gBS->CloseEvent (Event);

  return ;
}