]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume.c
Create 4G page table by default, and using PF to handle >4G MMIO access, to improve...
[mirror_edk2.git] / UefiCpuPkg / Universal / Acpi / S3Resume2Pei / S3Resume.c
index 3afd0ff0e395859679c22afae22fc51bd9fa368a..de3aec85e185375cce9660e05c219160d461b741 100644 (file)
@@ -4,7 +4,7 @@
   This module will excute the boot script saved during last boot and after that,\r
   control is passed to OS waking up handler.\r
 \r
   This module will excute the boot script saved during last boot and after that,\r
   control is passed to OS waking up handler.\r
 \r
-  Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
 \r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions\r
 \r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions\r
@@ -284,7 +284,9 @@ WriteToOsS3PerformanceData (
              NULL,\r
              (VOID **) &VariableServices\r
              );\r
              NULL,\r
              (VOID **) &VariableServices\r
              );\r
-  ASSERT_EFI_ERROR (Status);\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
 \r
   VarSize   = sizeof (EFI_PHYSICAL_ADDRESS);\r
   Status = VariableServices->GetVariable (\r
 \r
   VarSize   = sizeof (EFI_PHYSICAL_ADDRESS);\r
   Status = VariableServices->GetVariable (\r
@@ -365,6 +367,41 @@ WriteToOsS3PerformanceData (
   PerfHeader->S3EntryNum = (UINT32) Index;\r
 }\r
 \r
   PerfHeader->S3EntryNum = (UINT32) Index;\r
 }\r
 \r
+/**\r
+  The function will check if current waking vector is long mode.\r
+\r
+  @param  AcpiS3Context                 a pointer to a structure of ACPI_S3_CONTEXT\r
+\r
+  @retval TRUE   Current context need long mode waking vector.\r
+  @retval FALSE  Current context need not long mode waking vector.\r
+**/\r
+BOOLEAN\r
+IsLongModeWakingVector (\r
+  IN ACPI_S3_CONTEXT                *AcpiS3Context\r
+  )\r
+{\r
+  EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *Facs;\r
+\r
+  Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable));\r
+  if ((Facs == NULL) ||\r
+      (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ||\r
+      ((Facs->FirmwareWakingVector == 0) && (Facs->XFirmwareWakingVector == 0)) ) {\r
+    // Something wrong with FACS\r
+    return FALSE;\r
+  }\r
+  if (Facs->XFirmwareWakingVector != 0) {\r
+    if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&\r
+        ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) &&\r
+        ((Facs->Flags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) {\r
+      // Both BIOS and OS wants 64bit vector\r
+      if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
+        return TRUE;\r
+      }\r
+    }\r
+  }\r
+  return FALSE;\r
+}\r
+\r
 /**\r
   Jump to OS waking vector.\r
   The function will install boot script done PPI, report S3 resume status code, and then jump to OS waking vector.\r
 /**\r
   Jump to OS waking vector.\r
   The function will install boot script done PPI, report S3 resume status code, and then jump to OS waking vector.\r
@@ -390,6 +427,8 @@ S3ResumeBootOs (
   //\r
   AsmWriteIdtr (&PeiS3ResumeState->Idtr);\r
 \r
   //\r
   AsmWriteIdtr (&PeiS3ResumeState->Idtr);\r
 \r
+  PERF_END (NULL, "ScriptExec", NULL, 0);\r
+\r
   //\r
   // Install BootScriptDonePpi\r
   //\r
   //\r
   // Install BootScriptDonePpi\r
   //\r
@@ -408,17 +447,17 @@ S3ResumeBootOs (
     return ;\r
   }\r
 \r
     return ;\r
   }\r
 \r
-  //\r
-  // report status code on S3 resume\r
-  //\r
-  REPORT_STATUS_CODE (EFI_PROGRESS_CODE, EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_OS_WAKE);\r
-\r
   //\r
   // Install EndOfPeiPpi\r
   //\r
   Status = PeiServicesInstallPpi (&mPpiListEndOfPeiTable);\r
   ASSERT_EFI_ERROR (Status);\r
 \r
   //\r
   // Install EndOfPeiPpi\r
   //\r
   Status = PeiServicesInstallPpi (&mPpiListEndOfPeiTable);\r
   ASSERT_EFI_ERROR (Status);\r
 \r
+  //\r
+  // report status code on S3 resume\r
+  //\r
+  REPORT_STATUS_CODE (EFI_PROGRESS_CODE, EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_OS_WAKE);\r
+\r
   PERF_CODE (\r
     WriteToOsS3PerformanceData ();\r
     );\r
   PERF_CODE (\r
     WriteToOsS3PerformanceData ();\r
     );\r
@@ -479,10 +518,12 @@ S3ResumeBootOs (
   If BootScriptExector driver will not run in 64-bit mode, this function will do nothing. \r
 \r
   @param S3NvsPageTableAddress   PageTableAddress in ACPINvs\r
   If BootScriptExector driver will not run in 64-bit mode, this function will do nothing. \r
 \r
   @param S3NvsPageTableAddress   PageTableAddress in ACPINvs\r
+  @param Build4GPageTableOnly    If BIOS just build 4G page table only\r
 **/\r
 VOID\r
 RestoreS3PageTables (\r
 **/\r
 VOID\r
 RestoreS3PageTables (\r
-  IN UINTN                                         S3NvsPageTableAddress\r
+  IN UINTN                                         S3NvsPageTableAddress,\r
+  IN BOOLEAN                                       Build4GPageTableOnly\r
   )\r
 {\r
   if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
   )\r
 {\r
   if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
@@ -509,7 +550,7 @@ RestoreS3PageTables (
     //\r
     // The assumption is : whole page table is allocated in CONTINOUS memory and CR3 points to TOP page.\r
     //\r
     //\r
     // The assumption is : whole page table is allocated in CONTINOUS memory and CR3 points to TOP page.\r
     //\r
-    DEBUG ((EFI_D_ERROR, "S3NvsPageTableAddress - %x\n", S3NvsPageTableAddress));\r
+    DEBUG ((EFI_D_ERROR, "S3NvsPageTableAddress - %x (%x)\n", (UINTN)S3NvsPageTableAddress, (UINTN)Build4GPageTableOnly));\r
 \r
     //\r
     // By architecture only one PageMapLevel4 exists - so lets allocate storgage for it.\r
 \r
     //\r
     // By architecture only one PageMapLevel4 exists - so lets allocate storgage for it.\r
@@ -552,6 +593,14 @@ RestoreS3PageTables (
       PhysicalAddressBits = 48;\r
     }\r
 \r
       PhysicalAddressBits = 48;\r
     }\r
 \r
+    //\r
+    // NOTE: In order to save time to create full page table, we just create 4G page table by default.\r
+    // And let PF handler in BootScript driver to create more on request.\r
+    //\r
+    if (Build4GPageTableOnly) {\r
+      PhysicalAddressBits = 32;\r
+      ZeroMem (PageMap, EFI_PAGES_TO_SIZE(2));\r
+    }\r
     //\r
     // Calculate the table entries needed.\r
     //\r
     //\r
     // Calculate the table entries needed.\r
     //\r
@@ -679,25 +728,22 @@ S3ResumeExecuteBootScript (
                               NULL,\r
                               (VOID **) &SmmAccess\r
                               );\r
                               NULL,\r
                               (VOID **) &SmmAccess\r
                               );\r
+    if (!EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "Close all SMRAM regions before executing boot script\n"));\r
+  \r
+      for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {\r
+        Status = SmmAccess->Close ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);\r
+      }\r
 \r
 \r
-    DEBUG ((EFI_D_ERROR, "Close all SMRAM regions before executing boot script\n"));\r
-\r
-    for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {\r
-      Status = SmmAccess->Close ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);\r
-    }\r
-\r
-    DEBUG ((EFI_D_ERROR, "Lock all SMRAM regions before executing boot script\n"));\r
-\r
-    for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {\r
-      Status = SmmAccess->Lock ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);\r
+      DEBUG ((EFI_D_ERROR, "Lock all SMRAM regions before executing boot script\n"));\r
+  \r
+      for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {\r
+        Status = SmmAccess->Lock ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);\r
+      }\r
     }\r
   }\r
 \r
   if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
     }\r
   }\r
 \r
   if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
-    //\r
-    // Need reconstruct page table here, since we do not trust ACPINvs.\r
-    //\r
-    RestoreS3PageTables ((UINTN)AcpiS3Context->S3NvsPageTableAddress);\r
     AsmWriteCr3 ((UINTN)AcpiS3Context->S3NvsPageTableAddress);\r
   }\r
 \r
     AsmWriteCr3 ((UINTN)AcpiS3Context->S3NvsPageTableAddress);\r
   }\r
 \r
@@ -712,6 +758,12 @@ S3ResumeExecuteBootScript (
     // \r
     IdtBuffer = AllocatePages (EFI_SIZE_TO_PAGES((IdtDescriptor->Limit + 1) + 16));\r
     ASSERT (IdtBuffer != NULL);\r
     // \r
     IdtBuffer = AllocatePages (EFI_SIZE_TO_PAGES((IdtDescriptor->Limit + 1) + 16));\r
     ASSERT (IdtBuffer != NULL);\r
+    //\r
+    // Additional 16 bytes allocated to save IA32 IDT descriptor and Pei Service Table Pointer\r
+    // IA32 IDT descriptor will be used to setup IA32 IDT table for 32-bit Framework Boot Script code\r
+    // \r
+    ZeroMem (IdtBuffer, 16);\r
+    AsmReadIdtr ((IA32_DESCRIPTOR *)IdtBuffer);\r
     CopyMem ((VOID*)((UINT8*)IdtBuffer + 16),(VOID*)(IdtDescriptor->Base), (IdtDescriptor->Limit + 1));\r
     IdtDescriptor->Base = (UINTN)((UINT8*)IdtBuffer + 16);\r
     *(UINTN*)(IdtDescriptor->Base - sizeof(UINTN)) = (UINTN)GetPeiServicesTablePointer ();\r
     CopyMem ((VOID*)((UINT8*)IdtBuffer + 16),(VOID*)(IdtDescriptor->Base), (IdtDescriptor->Limit + 1));\r
     IdtDescriptor->Base = (UINTN)((UINT8*)IdtBuffer + 16);\r
     *(UINTN*)(IdtDescriptor->Base - sizeof(UINTN)) = (UINTN)GetPeiServicesTablePointer ();\r
@@ -736,6 +788,8 @@ S3ResumeExecuteBootScript (
   //\r
   AsmReadIdtr (&PeiS3ResumeState->Idtr);\r
 \r
   //\r
   AsmReadIdtr (&PeiS3ResumeState->Idtr);\r
 \r
+  PERF_START (NULL, "ScriptExec", NULL, 0);\r
+\r
   if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
     //\r
     // X64 S3 Resume\r
   if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
     //\r
     // X64 S3 Resume\r
@@ -811,7 +865,6 @@ S3RestoreConfig2 (
   PEI_SMM_ACCESS_PPI                            *SmmAccess;\r
   UINTN                                         Index;\r
   ACPI_S3_CONTEXT                               *AcpiS3Context;\r
   PEI_SMM_ACCESS_PPI                            *SmmAccess;\r
   UINTN                                         Index;\r
   ACPI_S3_CONTEXT                               *AcpiS3Context;\r
-  EFI_PEI_READ_ONLY_VARIABLE2_PPI               *VariableServices;\r
   EFI_PHYSICAL_ADDRESS                          TempEfiBootScriptExecutorVariable;\r
   EFI_PHYSICAL_ADDRESS                          TempAcpiS3Context;\r
   BOOT_SCRIPT_EXECUTOR_VARIABLE                 *EfiBootScriptExecutorVariable;\r
   EFI_PHYSICAL_ADDRESS                          TempEfiBootScriptExecutorVariable;\r
   EFI_PHYSICAL_ADDRESS                          TempAcpiS3Context;\r
   BOOT_SCRIPT_EXECUTOR_VARIABLE                 *EfiBootScriptExecutorVariable;\r
@@ -819,29 +872,10 @@ S3RestoreConfig2 (
   EFI_SMRAM_DESCRIPTOR                          *SmramDescriptor;\r
   SMM_S3_RESUME_STATE                           *SmmS3ResumeState;\r
   VOID                                          *GuidHob;\r
   EFI_SMRAM_DESCRIPTOR                          *SmramDescriptor;\r
   SMM_S3_RESUME_STATE                           *SmmS3ResumeState;\r
   VOID                                          *GuidHob;\r
+  BOOLEAN                                       Build4GPageTableOnly;\r
 \r
   DEBUG ((EFI_D_ERROR, "Enter S3 PEIM\r\n"));\r
 \r
 \r
   DEBUG ((EFI_D_ERROR, "Enter S3 PEIM\r\n"));\r
 \r
-  Status = PeiServicesLocatePpi (\r
-                            &gPeiSmmAccessPpiGuid,\r
-                            0,\r
-                            NULL,\r
-                            (VOID **) &SmmAccess\r
-                            );\r
-  for (Index = 0; !EFI_ERROR (Status); Index++) {\r
-    Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);\r
-  }\r
-\r
-  Status = PeiServicesLocatePpi (\r
-                            &gEfiPeiReadOnlyVariable2PpiGuid,\r
-                            0,\r
-                            NULL,\r
-                            (VOID **) &VariableServices\r
-                            );\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-\r
   VarSize = sizeof (EFI_PHYSICAL_ADDRESS);\r
   Status = RestoreLockBox (\r
              &gEfiAcpiVariableGuid,\r
   VarSize = sizeof (EFI_PHYSICAL_ADDRESS);\r
   Status = RestoreLockBox (\r
              &gEfiAcpiVariableGuid,\r
@@ -896,11 +930,33 @@ S3RestoreConfig2 (
     CpuDeadLoop ();\r
   }\r
 \r
     CpuDeadLoop ();\r
   }\r
 \r
+  if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
+    //\r
+    // Need reconstruct page table here, since we do not trust ACPINvs.\r
+    //\r
+    if (IsLongModeWakingVector (AcpiS3Context)) {\r
+      Build4GPageTableOnly = FALSE;\r
+    } else {\r
+      Build4GPageTableOnly = TRUE;\r
+    }\r
+    RestoreS3PageTables ((UINTN)AcpiS3Context->S3NvsPageTableAddress, Build4GPageTableOnly);\r
+  }\r
+\r
   //\r
   // Attempt to use content from SMRAM first\r
   //\r
   GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);\r
   if (GuidHob != NULL) {\r
   //\r
   // Attempt to use content from SMRAM first\r
   //\r
   GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);\r
   if (GuidHob != NULL) {\r
+    Status = PeiServicesLocatePpi (\r
+                              &gPeiSmmAccessPpiGuid,\r
+                              0,\r
+                              NULL,\r
+                              (VOID **) &SmmAccess\r
+                              );\r
+    for (Index = 0; !EFI_ERROR (Status); Index++) {\r
+      Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);\r
+    }\r
+\r
     SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);\r
     SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart;\r
 \r
     SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);\r
     SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart;\r
 \r