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 ; }