]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume.c
UefiCpuPkg: INF/DEC file updates to EDK II packages
[mirror_edk2.git] / UefiCpuPkg / Universal / Acpi / S3Resume2Pei / S3Resume.c
index 07d83cc87529e4a550b341a89d93fa1891444e96..aa1c8032915879eae905b4bfc0dbecb1b938f6d8 100644 (file)
@@ -1,10 +1,10 @@
 /** @file\r
-  This module produces the EFI_PEI_S3_RESUME_PPI.\r
+  This module produces the EFI_PEI_S3_RESUME2_PPI.\r
   This module works with StandAloneBootScriptExecutor to S3 resume to OS.\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 - 2012, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2006 - 2014, 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
 #include <Library/LockBoxLib.h>\r
 #include <IndustryStandard/Acpi.h>\r
 \r
+/**\r
+  This macro aligns the address of a variable with auto storage\r
+  duration down to CPU_STACK_ALIGNMENT.\r
+\r
+  Since the stack grows downward, the result preserves more of the\r
+  stack than the original address (or the same amount), not less.\r
+**/\r
+#define STACK_ALIGN_DOWN(Ptr) \\r
+          ((UINTN)(Ptr) & ~(UINTN)(CPU_STACK_ALIGNMENT - 1))\r
+\r
 #pragma pack(1)\r
 typedef union {\r
   struct {\r
@@ -193,6 +203,18 @@ S3RestoreConfig2 (
   IN EFI_PEI_S3_RESUME2_PPI  *This\r
   );\r
 \r
+/**\r
+  Set data segment selectors value including DS/ES/FS/GS/SS.\r
+\r
+  @param[in]  SelectorValue      Segment selector value to be set.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AsmSetDataSelectors (\r
+  IN UINT16   SelectorValue\r
+  );\r
+\r
 //\r
 // Globals\r
 //\r
@@ -232,6 +254,8 @@ GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = {
 /* 0x40 */  {{0,      0,  0,  0,    0,  0,  0,  0,    0,  0, 0,  0,  0}},\r
 };\r
 \r
+#define DATA_SEGEMENT_SELECTOR        0x18\r
+\r
 //\r
 // IA32 Gdt register\r
 //\r
@@ -343,6 +367,7 @@ WriteToOsS3PerformanceData (
         AsciiSPrint (PerfData->Token, PERF_TOKEN_LENGTH, "0x%11p", Handle);\r
       } else {\r
         AsciiStrnCpy (PerfData->Token, Token, PERF_TOKEN_LENGTH);\r
+        PerfData->Token[PERF_TOKEN_LENGTH] = '\0';\r
       }\r
       if (StartTicker == 1) {\r
         StartTicker = StartValue;\r
@@ -427,6 +452,22 @@ S3ResumeBootOs (
   //\r
   AsmWriteIdtr (&PeiS3ResumeState->Idtr);\r
 \r
+  if (PeiS3ResumeState->ReturnStatus != EFI_SUCCESS) {\r
+    //\r
+    // Report Status code that boot script execution is failed\r
+    //\r
+    REPORT_STATUS_CODE (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_BOOT_SCRIPT_ERROR)\r
+      );\r
+  }\r
+\r
+  //\r
+  // NOTE: Because Debug Timer interrupt and system interrupts will be disabled \r
+  // in BootScriptExecuteDxe, the rest code in S3ResumeBootOs() cannot be halted\r
+  // by soft debugger.\r
+  //\r
+\r
   PERF_END (NULL, "ScriptExec", NULL, 0);\r
 \r
   //\r
@@ -443,6 +484,13 @@ S3ResumeBootOs (
   if ((Facs == NULL) ||\r
       (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ||\r
       ((Facs->FirmwareWakingVector == 0) && (Facs->XFirmwareWakingVector == 0)) ) {\r
+    //\r
+    // Report Status code that no valid vector is found\r
+    //\r
+    REPORT_STATUS_CODE (\r
+      EFI_ERROR_CODE | EFI_ERROR_MAJOR,\r
+      (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_OS_WAKE_ERROR)\r
+      );\r
     CpuDeadLoop ();\r
     return ;\r
   }\r
@@ -484,8 +532,17 @@ S3ResumeBootOs (
           (UINT64)(UINTN)TempStackTop\r
           );\r
       } else {\r
+        //\r
+        // Report Status code that no valid waking vector is found\r
+        //\r
+        REPORT_STATUS_CODE (\r
+          EFI_ERROR_CODE | EFI_ERROR_MAJOR,\r
+          (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_OS_WAKE_ERROR)\r
+          );\r
         DEBUG (( EFI_D_ERROR, "Unsupported for 32bit DXE transfer to 64bit OS waking vector!\r\n"));\r
         ASSERT (FALSE);\r
+        CpuDeadLoop ();\r
+        return ;\r
       }\r
     } else {\r
       //\r
@@ -507,6 +564,14 @@ S3ResumeBootOs (
     AsmTransferControl (Facs->FirmwareWakingVector, 0x0);\r
   }\r
 \r
+  //\r
+  // Report Status code the failure of S3Resume\r
+  //\r
+  REPORT_STATUS_CODE (\r
+    EFI_ERROR_CODE | EFI_ERROR_MAJOR,\r
+    (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_OS_WAKE_ERROR)\r
+    );\r
+\r
   //\r
   // Never run to here\r
   //\r
@@ -701,6 +766,7 @@ S3ResumeExecuteBootScript (
   IA32_DESCRIPTOR            *IdtDescriptor;\r
   VOID                       *IdtBuffer;\r
   PEI_S3_RESUME_STATE        *PeiS3ResumeState;\r
+  BOOLEAN                    InterruptStatus;\r
 \r
   DEBUG ((EFI_D_ERROR, "S3ResumeExecuteBootScript()\n"));\r
 \r
@@ -769,10 +835,19 @@ S3ResumeExecuteBootScript (
     *(UINTN*)(IdtDescriptor->Base - sizeof(UINTN)) = (UINTN)GetPeiServicesTablePointer ();\r
   }\r
 \r
+  InterruptStatus = SaveAndDisableInterrupts ();\r
   //\r
   // Need to make sure the GDT is loaded with values that support long mode and real mode.\r
   //\r
   AsmWriteGdtr (&mGdt);\r
+  //\r
+  // update segment selectors per the new GDT.\r
+  //\r
+  AsmSetDataSelectors (DATA_SEGEMENT_SELECTOR);\r
+  //\r
+  // Restore interrupt state.\r
+  //\r
+  SetInterruptState (InterruptStatus);\r
 \r
   //\r
   // Prepare data for return back\r
@@ -782,11 +857,16 @@ S3ResumeExecuteBootScript (
   DEBUG (( EFI_D_ERROR, "PeiS3ResumeState - %x\r\n", PeiS3ResumeState));\r
   PeiS3ResumeState->ReturnCs           = 0x10;\r
   PeiS3ResumeState->ReturnEntryPoint   = (EFI_PHYSICAL_ADDRESS)(UINTN)S3ResumeBootOs;\r
-  PeiS3ResumeState->ReturnStackPointer = (EFI_PHYSICAL_ADDRESS)(UINTN)&Status;\r
+  PeiS3ResumeState->ReturnStackPointer = (EFI_PHYSICAL_ADDRESS)STACK_ALIGN_DOWN (&Status);\r
   //\r
   // Save IDT\r
   //\r
   AsmReadIdtr (&PeiS3ResumeState->Idtr);\r
+  \r
+  //\r
+  // Report Status Code to indicate S3 boot script execution\r
+  //\r
+  REPORT_STATUS_CODE (EFI_PROGRESS_CODE, EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_S3_BOOT_SCRIPT);\r
 \r
   PERF_START (NULL, "ScriptExec", NULL, 0);\r
 \r
@@ -873,6 +953,7 @@ S3RestoreConfig2 (
   SMM_S3_RESUME_STATE                           *SmmS3ResumeState;\r
   VOID                                          *GuidHob;\r
   BOOLEAN                                       Build4GPageTableOnly;\r
+  BOOLEAN                                       InterruptStatus;\r
 \r
   TempAcpiS3Context = 0;\r
   TempEfiBootScriptExecutorVariable = 0;\r
@@ -918,8 +999,11 @@ S3RestoreConfig2 (
   DEBUG (( EFI_D_ERROR, "AcpiS3Context = %x\n", AcpiS3Context));\r
   DEBUG (( EFI_D_ERROR, "Waking Vector = %x\n", ((EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable)))->FirmwareWakingVector));\r
   DEBUG (( EFI_D_ERROR, "AcpiS3Context->AcpiFacsTable = %x\n", AcpiS3Context->AcpiFacsTable));\r
+  DEBUG (( EFI_D_ERROR, "AcpiS3Context->IdtrProfile = %x\n", AcpiS3Context->IdtrProfile));  \r
   DEBUG (( EFI_D_ERROR, "AcpiS3Context->S3NvsPageTableAddress = %x\n", AcpiS3Context->S3NvsPageTableAddress));\r
   DEBUG (( EFI_D_ERROR, "AcpiS3Context->S3DebugBufferAddress = %x\n", AcpiS3Context->S3DebugBufferAddress));\r
+  DEBUG (( EFI_D_ERROR, "AcpiS3Context->BootScriptStackBase = %x\n", AcpiS3Context->BootScriptStackBase));\r
+  DEBUG (( EFI_D_ERROR, "AcpiS3Context->BootScriptStackSize = %x\n", AcpiS3Context->BootScriptStackSize));\r
   DEBUG (( EFI_D_ERROR, "EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint = %x\n", EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint));\r
 \r
   //\r
@@ -968,7 +1052,7 @@ S3RestoreConfig2 (
     SmmS3ResumeState->ReturnEntryPoint   = (EFI_PHYSICAL_ADDRESS)(UINTN)S3ResumeExecuteBootScript;\r
     SmmS3ResumeState->ReturnContext1     = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context;\r
     SmmS3ResumeState->ReturnContext2     = (EFI_PHYSICAL_ADDRESS)(UINTN)EfiBootScriptExecutorVariable;\r
-    SmmS3ResumeState->ReturnStackPointer = (EFI_PHYSICAL_ADDRESS)(UINTN)&Status;\r
+    SmmS3ResumeState->ReturnStackPointer = (EFI_PHYSICAL_ADDRESS)STACK_ALIGN_DOWN (&Status);\r
 \r
     DEBUG (( EFI_D_ERROR, "SMM S3 Signature                = %x\n", SmmS3ResumeState->Signature));\r
     DEBUG (( EFI_D_ERROR, "SMM S3 Stack Base               = %x\n", SmmS3ResumeState->SmmS3StackBase));\r
@@ -984,11 +1068,6 @@ S3RestoreConfig2 (
     DEBUG (( EFI_D_ERROR, "SMM S3 Return Stack Pointer     = %x\n", SmmS3ResumeState->ReturnStackPointer));\r
     DEBUG (( EFI_D_ERROR, "SMM S3 Smst                     = %x\n", SmmS3ResumeState->Smst));\r
 \r
-    //\r
-    // Disable interrupt of Debug timer.\r
-    //\r
-    SaveAndSetDebugTimerInterrupt (FALSE);\r
-\r
     if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_32) {\r
       SwitchStack (\r
         (SWITCH_STACK_ENTRY_POINT)(UINTN)SmmS3ResumeState->SmmS3ResumeEntryPoint,\r
@@ -1002,11 +1081,29 @@ S3RestoreConfig2 (
       // Switch to long mode to complete resume.\r
       //\r
 \r
+      InterruptStatus = SaveAndDisableInterrupts ();\r
       //\r
       // Need to make sure the GDT is loaded with values that support long mode and real mode.\r
       //\r
       AsmWriteGdtr (&mGdt);\r
+      //\r
+      // update segment selectors per the new GDT.\r
+      //      \r
+      AsmSetDataSelectors (DATA_SEGEMENT_SELECTOR);\r
+      //\r
+      // Restore interrupt state.\r
+      //\r
+      SetInterruptState (InterruptStatus);\r
+\r
       AsmWriteCr3 ((UINTN)SmmS3ResumeState->SmmS3Cr3);\r
+\r
+      //\r
+      // Disable interrupt of Debug timer, since IDT table cannot work in long mode.\r
+      // NOTE: On x64 platforms, because DisablePaging64() will disable interrupts,\r
+      // the code in S3ResumeExecuteBootScript() cannot be halted by soft debugger.\r
+      //\r
+      SaveAndSetDebugTimerInterrupt (FALSE);\r
+\r
       AsmEnablePaging64 (\r
         0x38,\r
         SmmS3ResumeState->SmmS3ResumeEntryPoint,\r