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,