]> git.proxmox.com Git - mirror_edk2.git/commitdiff
1. CapsuleLongModeBuffer variable should not have EFI_VARIABLE_RUNTIME_ACCESS attribute.
authorElvin Li <elvin.li@intel.com>
Tue, 26 Aug 2014 12:26:32 +0000 (12:26 +0000)
committerli-elvin <li-elvin@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 26 Aug 2014 12:26:32 +0000 (12:26 +0000)
2. CapsuleLongModeBuffer variable should be set to Read-Only.  It should not be changed by someone else.
3. Introduce a new PCD PcdIdentifyMappingPageTablePtr to share the same range of page table between AcpiS3 and Capsule.
4. Capsule stack size is allocated from PcdCapsulePeiLongModeStackSize.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Elvin Li <elvin.li@intel.com>
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15909 6f19259b-4bc3-4df7-8a09-765794883524

MdeModulePkg/MdeModulePkg.dec
MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c

index 7fec666c79fe1ce40a5855764b7e95b4a579df3e..30912c152194ab3c6cc7633b6cce6ea13165eefd 100644 (file)
   #  default value is set to Zero. And the PCD is assumed ONLY to be accessed in DxeS3BootScriptLib Library.\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptTablePrivateSmmDataPtr|0x0|UINT64|0x00030001\r
 \r
+  ## This dynamic PCD hold an address to point to the memory of page table. The page table establishes a 1:1 \r
+  #  Virtual to Physical mapping according to the processor physical address bits.\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdIdentifyMappingPageTablePtr|0x0|UINT64|0x00030002\r
index 7767e68345d66b60720eed2c0d557be42085650d..66c438ca63498fbc69681009a45425180f0ce3f1 100644 (file)
@@ -5,7 +5,7 @@
 #  It installs the Capsule Architectural Protocol defined in PI1.0a to signify \r
 #  the capsule runtime services are ready.\r
 #  \r
-#  Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
+#  Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
 #  This program and the accompanying materials\r
 #  are licensed and made available under the terms and conditions of the BSD License\r
 #  which accompanies this distribution.  The full text of the license may be found at\r
@@ -73,7 +73,9 @@
   gEfiCapsuleArchProtocolGuid                   ## PRODUCED\r
 \r
 [Protocols.X64]\r
-  gEfiDxeSmmReadyToLockProtocolGuid             # ALWAYS_CONSUMED\r
+  ## UNDEFINED ## NOTIFY\r
+  ## SOMETIMES_CONSUMES\r
+  gEdkiiVariableLockProtocolGuid\r
 \r
 [FeaturePcd]\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdSupportUpdateCapsuleReset\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxSizePopulateCapsule || gEfiMdeModulePkgTokenSpaceGuid.PcdSupportUpdateCapsuleReset  ## Populate Image requires reset support.\r
 \r
 [Pcd.X64]\r
+  ## SOMETIMES_CONSUMES\r
+  ## SOMETIMES_PRODUCES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdIdentifyMappingPageTablePtr\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdCapsulePeiLongModeStackSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable                ## SOMETIMES_CONSUMES\r
 \r
 [Depex]\r
   gEfiVariableWriteArchProtocolGuid             ## Depends on variable write functionality to produce capsule data variable\r
index 0cfc352ac0e865115affaa484640d2689333d6e9..a5c7c48eeefe4e4c09550a20337f2170f1943b7b 100644 (file)
@@ -2,7 +2,7 @@
   Create the variable to save the base address of page table and stack\r
   for transferring into long mode in IA32 capsule PEI.\r
 \r
-Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -17,6 +17,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 #include <Protocol/Capsule.h>\r
 #include <Protocol/DxeSmmReadyToLock.h>\r
+#include <Protocol/VariableLock.h>\r
 \r
 #include <Guid/CapsuleVendor.h>\r
 #include <Guid/AcpiS3Context.h>\r
@@ -70,83 +71,85 @@ AllocateAcpiNvsMemoryBelow4G (
 }\r
 \r
 /**\r
-  DxeSmmReadyToLock Protocol notification event handler.\r
-  We reuse S3 ACPI NVS reserved memory to do capsule process\r
-  after reset.\r
+  Register callback function upon VariableLockProtocol\r
+  to lock EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to avoid malicious code to update it.\r
 \r
   @param[in] Event    Event whose notification function is being invoked.\r
   @param[in] Context  Pointer to the notification function's context.\r
 **/\r
 VOID\r
 EFIAPI\r
-DxeSmmReadyToLockNotification (\r
-  IN EFI_EVENT  Event,\r
-  IN VOID       *Context\r
+VariableLockCapsuleLongModeBufferVariable (\r
+  IN  EFI_EVENT                             Event,\r
+  IN  VOID                                  *Context\r
   )\r
 {\r
   EFI_STATUS                    Status;\r
-  VOID                          *DxeSmmReadyToLock;\r
-  UINTN                         VarSize;\r
-  EFI_PHYSICAL_ADDRESS          TempAcpiS3Context;\r
-  ACPI_S3_CONTEXT               *AcpiS3Context;\r
-  EFI_CAPSULE_LONG_MODE_BUFFER  LongModeBuffer;\r
-  UINTN                         TotalPagesNum;\r
-  UINT8                         PhysicalAddressBits;\r
-  VOID                          *Hob;\r
-  UINT32                        NumberOfPml4EntriesNeeded;\r
-  UINT32                        NumberOfPdpEntriesNeeded;\r
-  BOOLEAN                       LockBoxFound;\r
-\r
-  Status = gBS->LocateProtocol (\r
-                  &gEfiDxeSmmReadyToLockProtocolGuid,\r
-                  NULL,\r
-                  &DxeSmmReadyToLock\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    return ;\r
-  }\r
-\r
+  EDKII_VARIABLE_LOCK_PROTOCOL  *VariableLock;\r
   //\r
-  // Get the ACPI NVS pages reserved by AcpiS3Save\r
+  // Mark EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to read-only if the Variable Lock protocol exists\r
   //\r
-  LockBoxFound = FALSE;\r
-  VarSize = sizeof (EFI_PHYSICAL_ADDRESS);\r
-  Status = RestoreLockBox (\r
-             &gEfiAcpiVariableGuid,\r
-             &TempAcpiS3Context,\r
-             &VarSize\r
-             );\r
+  Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
   if (!EFI_ERROR (Status)) {\r
-    AcpiS3Context = (ACPI_S3_CONTEXT *)(UINTN)TempAcpiS3Context;\r
-    ASSERT (AcpiS3Context != NULL);\r
-    \r
-    Status = RestoreLockBox (\r
-               &gEfiAcpiS3ContextGuid,\r
-               NULL,\r
-               NULL\r
-               );\r
-    if (!EFI_ERROR (Status)) {\r
-      LongModeBuffer.PageTableAddress = AcpiS3Context->S3NvsPageTableAddress;\r
-      LongModeBuffer.StackBaseAddress = AcpiS3Context->BootScriptStackBase;\r
-      LongModeBuffer.StackSize        = AcpiS3Context->BootScriptStackSize;\r
-      LockBoxFound                    = TRUE;\r
-    }\r
+    Status = VariableLock->RequestToLock (VariableLock, EFI_CAPSULE_LONG_MODE_BUFFER_NAME, &gEfiCapsuleVendorGuid);\r
+    ASSERT_EFI_ERROR (Status);\r
   }\r
+}\r
+\r
+/**\r
+  1. Allocate NVS memory for capsule PEIM to establish a 1:1 Virtual to Physical mapping.\r
+  2. Allocate NVS memroy as a stack for capsule PEIM to transfer from 32-bit mdoe to 64-bit mode.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PrepareContextForCapsulePei (\r
+  VOID\r
+  )\r
+{\r
+  UINT32                                        RegEax;\r
+  UINT32                                        RegEdx;\r
+  UINTN                                         TotalPagesNum;\r
+  UINT8                                         PhysicalAddressBits;\r
+  VOID                                          *Hob;\r
+  UINT32                                        NumberOfPml4EntriesNeeded;\r
+  UINT32                                        NumberOfPdpEntriesNeeded;\r
+  BOOLEAN                                       Page1GSupport;\r
+  EFI_CAPSULE_LONG_MODE_BUFFER                  LongModeBuffer;\r
+  EFI_STATUS                                    Status;\r
+  VOID                                          *Registration;\r
   \r
-  if (!LockBoxFound) {\r
-    //\r
-    // Page table base address and stack base address can not be found in lock box,\r
-    // allocate both here. \r
-    //\r
+  LongModeBuffer.PageTableAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdIdentifyMappingPageTablePtr);\r
 \r
+  if (LongModeBuffer.PageTableAddress == 0x0) {\r
     //\r
-    // Get physical address bits supported from CPU HOB.\r
+    // Calculate the size of page table, allocate the memory, and set PcdIdentifyMappingPageTablePtr.\r
     //\r
-    PhysicalAddressBits = 36;\r
+    Page1GSupport = FALSE;\r
+    if (PcdGetBool(PcdUse1GPageTable)) {\r
+      AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+      if (RegEax >= 0x80000001) {\r
+        AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
+        if ((RegEdx & BIT26) != 0) {\r
+          Page1GSupport = TRUE;\r
+        }\r
+      }\r
+    }\r
     \r
+    //\r
+    // Get physical address bits supported.\r
+    //\r
     Hob = GetFirstHob (EFI_HOB_TYPE_CPU);\r
     if (Hob != NULL) {\r
       PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;\r
+    } else {\r
+      AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+      if (RegEax >= 0x80000008) {\r
+        AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
+        PhysicalAddressBits = (UINT8) RegEax;\r
+      } else {\r
+        PhysicalAddressBits = 36;\r
+      }\r
     }\r
     \r
     //\r
@@ -158,43 +161,57 @@ DxeSmmReadyToLockNotification (
     }\r
     \r
     //\r
-    // Calculate page table size and allocate memory for it.\r
+    // Calculate the table entries needed.\r
     //\r
     if (PhysicalAddressBits <= 39 ) {\r
       NumberOfPml4EntriesNeeded = 1;\r
-      NumberOfPdpEntriesNeeded =  1 << (PhysicalAddressBits - 30);\r
+      NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));\r
     } else {\r
-      NumberOfPml4EntriesNeeded = 1 << (PhysicalAddressBits - 39);\r
+      NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));\r
       NumberOfPdpEntriesNeeded = 512;\r
     }\r
     \r
-    TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;\r
+    if (!Page1GSupport) {\r
+      TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;\r
+    } else {\r
+      TotalPagesNum = NumberOfPml4EntriesNeeded + 1;\r
+    }\r
+    \r
     LongModeBuffer.PageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (EFI_PAGES_TO_SIZE (TotalPagesNum));\r
     ASSERT (LongModeBuffer.PageTableAddress != 0);\r
-    \r
-    //\r
-    // Allocate stack\r
-    //\r
-    LongModeBuffer.StackSize        = PcdGet32 (PcdCapsulePeiLongModeStackSize);\r
-    LongModeBuffer.StackBaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (PcdGet32 (PcdCapsulePeiLongModeStackSize));\r
-    ASSERT (LongModeBuffer.StackBaseAddress != 0);\r
+    PcdSet64 (PcdIdentifyMappingPageTablePtr, LongModeBuffer.PageTableAddress); \r
   }\r
-\r
+  \r
+  //\r
+  // Allocate stack\r
+  //\r
+  LongModeBuffer.StackSize        = PcdGet32 (PcdCapsulePeiLongModeStackSize);\r
+  LongModeBuffer.StackBaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (PcdGet32 (PcdCapsulePeiLongModeStackSize));\r
+  ASSERT (LongModeBuffer.StackBaseAddress != 0);  \r
+  \r
   Status = gRT->SetVariable (\r
                   EFI_CAPSULE_LONG_MODE_BUFFER_NAME,\r
                   &gEfiCapsuleVendorGuid,\r
-                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
                   sizeof (EFI_CAPSULE_LONG_MODE_BUFFER),\r
                   &LongModeBuffer\r
                   );\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
-  //\r
-  // Close event, so it will not be invoked again.\r
-  //\r
-  gBS->CloseEvent (Event);\r
-\r
-  return ;\r
+  if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Register callback function upon VariableLockProtocol\r
+      // to lock EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to avoid malicious code to update it.\r
+      //\r
+      EfiCreateProtocolNotifyEvent (\r
+        &gEdkiiVariableLockProtocolGuid,\r
+        TPL_CALLBACK,\r
+        VariableLockCapsuleLongModeBufferVariable,\r
+        NULL,\r
+        &Registration\r
+        );    \r
+  } else {\r
+      DEBUG ((EFI_D_ERROR, "FATAL ERROR: CapsuleLongModeBuffer cannot be saved: %r. Capsule in PEI may fail!\n", Status));\r
+      gBS->FreePages (LongModeBuffer.StackBaseAddress, EFI_SIZE_TO_PAGES (LongModeBuffer.StackSize));\r
+  }\r
 }\r
 \r
 /**\r
@@ -206,19 +223,10 @@ SaveLongModeContext (
   VOID\r
   )\r
 {\r
-  VOID        *Registration;\r
-  \r
   if ((FeaturePcdGet(PcdSupportUpdateCapsuleReset)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode))) {\r
     //\r
-    // Register event to get ACPI NVS pages reserved from lock box, these pages will be used by\r
-    // Capsule IA32 PEI to transfer to long mode to access capsule above 4GB.\r
+    // Allocate memory for Capsule IA32 PEIM, it will create page table to transfer to long mode to access capsule above 4GB.\r
     //\r
-    EfiCreateProtocolNotifyEvent (\r
-      &gEfiDxeSmmReadyToLockProtocolGuid,\r
-      TPL_CALLBACK,\r
-      DxeSmmReadyToLockNotification,\r
-      NULL,\r
-      &Registration\r
-      );\r
+    PrepareContextForCapsulePei ();\r
   }\r
 }\r