X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=UefiCpuPkg%2FUniversal%2FAcpi%2FS3Resume2Pei%2FS3Resume.c;h=ad81c19590f34a92e12c5bce96ed8dbc2d463927;hb=2cd086a675535b6fc4cb54a75d10ca6f26a2da9e;hp=179f7afd14a3aacd5fe9148c5d99734f5cf02a7f;hpb=c56b65665de7a665e29107ee9c377c1e2e84d343;p=mirror_edk2.git diff --git a/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume.c b/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume.c index 179f7afd14..ad81c19590 100644 --- a/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume.c +++ b/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume.c @@ -4,7 +4,7 @@ This module will excute the boot script saved during last boot and after that, control is passed to OS waking up handler. - Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+ Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions @@ -193,6 +193,18 @@ S3RestoreConfig2 ( IN EFI_PEI_S3_RESUME2_PPI *This ); +/** + Set data segment selectors value including DS/ES/FS/GS/SS. + + @param[in] SelectorValue Segment selector value to be set. + +**/ +VOID +EFIAPI +AsmSetDataSelectors ( + IN UINT16 SelectorValue + ); + // // Globals // @@ -232,6 +244,8 @@ GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = { /* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, }; +#define DATA_SEGEMENT_SELECTOR 0x18 + // // IA32 Gdt register // @@ -284,7 +298,9 @@ WriteToOsS3PerformanceData ( NULL, (VOID **) &VariableServices ); - ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return; + } VarSize = sizeof (EFI_PHYSICAL_ADDRESS); Status = VariableServices->GetVariable ( @@ -365,6 +381,41 @@ WriteToOsS3PerformanceData ( PerfHeader->S3EntryNum = (UINT32) Index; } +/** + The function will check if current waking vector is long mode. + + @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT + + @retval TRUE Current context need long mode waking vector. + @retval FALSE Current context need not long mode waking vector. +**/ +BOOLEAN +IsLongModeWakingVector ( + IN ACPI_S3_CONTEXT *AcpiS3Context + ) +{ + EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs; + + Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable)); + if ((Facs == NULL) || + (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) || + ((Facs->FirmwareWakingVector == 0) && (Facs->XFirmwareWakingVector == 0)) ) { + // Something wrong with FACS + return FALSE; + } + if (Facs->XFirmwareWakingVector != 0) { + if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) && + ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) && + ((Facs->Flags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) { + // Both BIOS and OS wants 64bit vector + if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { + return TRUE; + } + } + } + return FALSE; +} + /** Jump to OS waking vector. The function will install boot script done PPI, report S3 resume status code, and then jump to OS waking vector. @@ -390,6 +441,8 @@ S3ResumeBootOs ( // AsmWriteIdtr (&PeiS3ResumeState->Idtr); + PERF_END (NULL, "ScriptExec", NULL, 0); + // // Install BootScriptDonePpi // @@ -408,17 +461,17 @@ S3ResumeBootOs ( return ; } - // - // report status code on S3 resume - // - REPORT_STATUS_CODE (EFI_PROGRESS_CODE, EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_OS_WAKE); - // // Install EndOfPeiPpi // Status = PeiServicesInstallPpi (&mPpiListEndOfPeiTable); ASSERT_EFI_ERROR (Status); + // + // report status code on S3 resume + // + REPORT_STATUS_CODE (EFI_PROGRESS_CODE, EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_OS_WAKE); + PERF_CODE ( WriteToOsS3PerformanceData (); ); @@ -479,10 +532,12 @@ S3ResumeBootOs ( If BootScriptExector driver will not run in 64-bit mode, this function will do nothing. @param S3NvsPageTableAddress PageTableAddress in ACPINvs + @param Build4GPageTableOnly If BIOS just build 4G page table only **/ VOID RestoreS3PageTables ( - IN UINTN S3NvsPageTableAddress + IN UINTN S3NvsPageTableAddress, + IN BOOLEAN Build4GPageTableOnly ) { if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { @@ -509,7 +564,7 @@ RestoreS3PageTables ( // // The assumption is : whole page table is allocated in CONTINOUS memory and CR3 points to TOP page. // - DEBUG ((EFI_D_ERROR, "S3NvsPageTableAddress - %x\n", S3NvsPageTableAddress)); + DEBUG ((EFI_D_ERROR, "S3NvsPageTableAddress - %x (%x)\n", (UINTN)S3NvsPageTableAddress, (UINTN)Build4GPageTableOnly)); // // By architecture only one PageMapLevel4 exists - so lets allocate storgage for it. @@ -518,11 +573,13 @@ RestoreS3PageTables ( S3NvsPageTableAddress += SIZE_4KB; Page1GSupport = FALSE; - AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); - if (RegEax >= 0x80000001) { - AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx); - if ((RegEdx & BIT26) != 0) { - Page1GSupport = TRUE; + if (PcdGetBool(PcdUse1GPageTable)) { + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); + if (RegEax >= 0x80000001) { + AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx); + if ((RegEdx & BIT26) != 0) { + Page1GSupport = TRUE; + } } } @@ -550,6 +607,14 @@ RestoreS3PageTables ( PhysicalAddressBits = 48; } + // + // NOTE: In order to save time to create full page table, we just create 4G page table by default. + // And let PF handler in BootScript driver to create more on request. + // + if (Build4GPageTableOnly) { + PhysicalAddressBits = 32; + ZeroMem (PageMap, EFI_PAGES_TO_SIZE(2)); + } // // Calculate the table entries needed. // @@ -579,8 +644,7 @@ RestoreS3PageTables ( PageMapLevel4Entry->Bits.Present = 1; if (Page1GSupport) { - PageDirectory1GEntry = (VOID *) S3NvsPageTableAddress; - S3NvsPageTableAddress += SIZE_4KB; + PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry; for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) { // @@ -651,6 +715,7 @@ S3ResumeExecuteBootScript ( IA32_DESCRIPTOR *IdtDescriptor; VOID *IdtBuffer; PEI_S3_RESUME_STATE *PeiS3ResumeState; + BOOLEAN InterruptStatus; DEBUG ((EFI_D_ERROR, "S3ResumeExecuteBootScript()\n")); @@ -678,25 +743,22 @@ S3ResumeExecuteBootScript ( NULL, (VOID **) &SmmAccess ); + if (!EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Close all SMRAM regions before executing boot script\n")); + + for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) { + Status = SmmAccess->Close ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index); + } - DEBUG ((EFI_D_ERROR, "Close all SMRAM regions before executing boot script\n")); - - for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) { - Status = SmmAccess->Close ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index); - } - - DEBUG ((EFI_D_ERROR, "Lock all SMRAM regions before executing boot script\n")); - - for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) { - Status = SmmAccess->Lock ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index); + DEBUG ((EFI_D_ERROR, "Lock all SMRAM regions before executing boot script\n")); + + for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) { + Status = SmmAccess->Lock ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index); + } } } if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { - // - // Need reconstruct page table here, since we do not trust ACPINvs. - // - RestoreS3PageTables ((UINTN)AcpiS3Context->S3NvsPageTableAddress); AsmWriteCr3 ((UINTN)AcpiS3Context->S3NvsPageTableAddress); } @@ -711,15 +773,30 @@ S3ResumeExecuteBootScript ( // IdtBuffer = AllocatePages (EFI_SIZE_TO_PAGES((IdtDescriptor->Limit + 1) + 16)); ASSERT (IdtBuffer != NULL); + // + // Additional 16 bytes allocated to save IA32 IDT descriptor and Pei Service Table Pointer + // IA32 IDT descriptor will be used to setup IA32 IDT table for 32-bit Framework Boot Script code + // + ZeroMem (IdtBuffer, 16); + AsmReadIdtr ((IA32_DESCRIPTOR *)IdtBuffer); CopyMem ((VOID*)((UINT8*)IdtBuffer + 16),(VOID*)(IdtDescriptor->Base), (IdtDescriptor->Limit + 1)); IdtDescriptor->Base = (UINTN)((UINT8*)IdtBuffer + 16); *(UINTN*)(IdtDescriptor->Base - sizeof(UINTN)) = (UINTN)GetPeiServicesTablePointer (); } + InterruptStatus = SaveAndDisableInterrupts (); // // Need to make sure the GDT is loaded with values that support long mode and real mode. // AsmWriteGdtr (&mGdt); + // + // update segment selectors per the new GDT. + // + AsmSetDataSelectors (DATA_SEGEMENT_SELECTOR); + // + // Restore interrupt state. + // + SetInterruptState (InterruptStatus); // // Prepare data for return back @@ -735,6 +812,8 @@ S3ResumeExecuteBootScript ( // AsmReadIdtr (&PeiS3ResumeState->Idtr); + PERF_START (NULL, "ScriptExec", NULL, 0); + if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { // // X64 S3 Resume @@ -810,7 +889,6 @@ S3RestoreConfig2 ( PEI_SMM_ACCESS_PPI *SmmAccess; UINTN Index; ACPI_S3_CONTEXT *AcpiS3Context; - EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices; EFI_PHYSICAL_ADDRESS TempEfiBootScriptExecutorVariable; EFI_PHYSICAL_ADDRESS TempAcpiS3Context; BOOT_SCRIPT_EXECUTOR_VARIABLE *EfiBootScriptExecutorVariable; @@ -818,28 +896,13 @@ S3RestoreConfig2 ( EFI_SMRAM_DESCRIPTOR *SmramDescriptor; SMM_S3_RESUME_STATE *SmmS3ResumeState; VOID *GuidHob; + BOOLEAN Build4GPageTableOnly; + BOOLEAN InterruptStatus; - DEBUG ((EFI_D_ERROR, "Enter S3 PEIM\r\n")); + TempAcpiS3Context = 0; + TempEfiBootScriptExecutorVariable = 0; - Status = PeiServicesLocatePpi ( - &gPeiSmmAccessPpiGuid, - 0, - NULL, - (VOID **) &SmmAccess - ); - for (Index = 0; !EFI_ERROR (Status); Index++) { - Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index); - } - - Status = PeiServicesLocatePpi ( - &gEfiPeiReadOnlyVariable2PpiGuid, - 0, - NULL, - (VOID **) &VariableServices - ); - if (EFI_ERROR (Status)) { - return Status; - } + DEBUG ((EFI_D_ERROR, "Enter S3 PEIM\r\n")); VarSize = sizeof (EFI_PHYSICAL_ADDRESS); Status = RestoreLockBox ( @@ -849,9 +912,6 @@ S3RestoreConfig2 ( ); ASSERT_EFI_ERROR (Status); - AcpiS3Context = (ACPI_S3_CONTEXT *)(UINTN)TempAcpiS3Context; - ASSERT (AcpiS3Context != NULL); - Status = RestoreLockBox ( &gEfiAcpiS3ContextGuid, NULL, @@ -859,7 +919,10 @@ S3RestoreConfig2 ( ); ASSERT_EFI_ERROR (Status); - VarSize = sizeof (TempEfiBootScriptExecutorVariable); + AcpiS3Context = (ACPI_S3_CONTEXT *)(UINTN)TempAcpiS3Context; + ASSERT (AcpiS3Context != NULL); + + VarSize = sizeof (EFI_PHYSICAL_ADDRESS); Status = RestoreLockBox ( &gEfiBootScriptExecutorVariableGuid, &TempEfiBootScriptExecutorVariable, @@ -875,6 +938,7 @@ S3RestoreConfig2 ( ASSERT_EFI_ERROR (Status); EfiBootScriptExecutorVariable = (BOOT_SCRIPT_EXECUTOR_VARIABLE *) (UINTN) TempEfiBootScriptExecutorVariable; + ASSERT (EfiBootScriptExecutorVariable != NULL); DEBUG (( EFI_D_ERROR, "AcpiS3Context = %x\n", AcpiS3Context)); DEBUG (( EFI_D_ERROR, "Waking Vector = %x\n", ((EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable)))->FirmwareWakingVector)); @@ -895,11 +959,33 @@ S3RestoreConfig2 ( CpuDeadLoop (); } + if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { + // + // Need reconstruct page table here, since we do not trust ACPINvs. + // + if (IsLongModeWakingVector (AcpiS3Context)) { + Build4GPageTableOnly = FALSE; + } else { + Build4GPageTableOnly = TRUE; + } + RestoreS3PageTables ((UINTN)AcpiS3Context->S3NvsPageTableAddress, Build4GPageTableOnly); + } + // // Attempt to use content from SMRAM first // GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid); if (GuidHob != NULL) { + Status = PeiServicesLocatePpi ( + &gPeiSmmAccessPpiGuid, + 0, + NULL, + (VOID **) &SmmAccess + ); + for (Index = 0; !EFI_ERROR (Status); Index++) { + Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index); + } + SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob); SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart; @@ -941,10 +1027,20 @@ S3RestoreConfig2 ( // Switch to long mode to complete resume. // + InterruptStatus = SaveAndDisableInterrupts (); // // Need to make sure the GDT is loaded with values that support long mode and real mode. // AsmWriteGdtr (&mGdt); + // + // update segment selectors per the new GDT. + // + AsmSetDataSelectors (DATA_SEGEMENT_SELECTOR); + // + // Restore interrupt state. + // + SetInterruptState (InterruptStatus); + AsmWriteCr3 ((UINTN)SmmS3ResumeState->SmmS3Cr3); AsmEnablePaging64 ( 0x38,