summaryrefslogtreecommitdiffstats
path: root/MdeModulePkg/Universal/CapsuleRuntimeDxe
diff options
context:
space:
mode:
authorli-elvin <li-elvin@6f19259b-4bc3-4df7-8a09-765794883524>2011-09-02 11:34:35 +0000
committerli-elvin <li-elvin@6f19259b-4bc3-4df7-8a09-765794883524>2011-09-02 11:34:35 +0000
commitab7017fe2bf2c1944090d347e7853e087d8641e8 (patch)
treed7cd1ecb4d6cdf3784a139c33d1d7f1e615674a6 /MdeModulePkg/Universal/CapsuleRuntimeDxe
parent4ff7e37b4f7e336a8ecb7080b8f48eef4b52d396 (diff)
downloadedk2-ab7017fe2bf2c1944090d347e7853e087d8641e8.tar.gz
edk2-ab7017fe2bf2c1944090d347e7853e087d8641e8.tar.bz2
edk2-ab7017fe2bf2c1944090d347e7853e087d8641e8.zip
Add capsule > 4GB support. When capsule data is put above 4GB, IA32 PEI transfers to long mode to get capsule data.
Signed-off-by: li-elvin Reviewed-by: lgao4, mdkinney git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12264 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'MdeModulePkg/Universal/CapsuleRuntimeDxe')
-rw-r--r--MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf25
-rw-r--r--MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.c20
-rw-r--r--MdeModulePkg/Universal/CapsuleRuntimeDxe/SaveLongModeContext.c27
-rw-r--r--MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c224
4 files changed, 295 insertions, 1 deletions
diff --git a/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf b/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
index 43388f55fc..e52b6a5f28 100644
--- a/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
+++ b/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
@@ -33,6 +33,12 @@
[Sources]
CapsuleService.c
+[Sources.Ia32, Sources.IPF, Sources.EBC, Sources.ARM]
+ SaveLongModeContext.c
+
+[Sources.X64]
+ X64/SaveLongModeContext.c
+
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
@@ -47,19 +53,38 @@
UefiRuntimeLib
BaseLib
PrintLib
+
+[LibraryClasses.X64]
+ LockBoxLib
+ UefiLib
+ BaseMemoryLib
+ HobLib
[Guids]
gEfiCapsuleVendorGuid ## SOMETIMES_PRODUCED (Process across reset capsule image) ## Variable:L"CapsuleUpdateData" for capsule updated data
+[Guids.X64]
+ gEfiAcpiVariableGuid # ALWAYS_CONSUMED
+ gEfiAcpiS3ContextGuid # ALWAYS_CONSUMED
+
[Protocols]
gEfiCapsuleArchProtocolGuid ## PRODUCED
+[Protocols.X64]
+ gEfiDxeSmmReadyToLockProtocolGuid # ALWAYS_CONSUMED
+
[FeaturePcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdSupportUpdateCapsuleReset
+[FeaturePcd.X64]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode
+
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdMaxSizeNonPopulateCapsule
gEfiMdeModulePkgTokenSpaceGuid.PcdMaxSizePopulateCapsule || gEfiMdeModulePkgTokenSpaceGuid.PcdSupportUpdateCapsuleReset ## Populate Image requires reset support.
+[Pcd.X64]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsulePeiLongModeStackSize
+
[Depex]
gEfiVariableWriteArchProtocolGuid ## Depends on variable write functionality to produce capsule data variable
diff --git a/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.c b/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.c
index 76b2a2a8fc..17f167c978 100644
--- a/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.c
+++ b/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.c
@@ -4,7 +4,7 @@
It installs the Capsule Architectural Protocol defined in PI1.0a to signify
the capsule runtime services are ready.
-Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@@ -41,6 +41,15 @@ EFI_HANDLE mNewHandle = NULL;
UINTN mTimes = 0;
/**
+ Create the variable to save the base address of page table and stack
+ for transferring into long mode in IA32 PEI.
+**/
+VOID
+SaveLongModeContext (
+ VOID
+ );
+
+/**
Passes capsules to the firmware with both virtual and physical mapping. Depending on the intended
consumption, the firmware may process the capsule immediately. If the payload should persist
across a system reset, the reset value returned from EFI_QueryCapsuleCapabilities must
@@ -334,6 +343,15 @@ CapsuleServiceInitialize (
EFI_STATUS Status;
//
+ // When PEI phase is IA32, DXE phase is X64, it is possible that capsule data are
+ // put above 4GB, so capsule PEI will transfer to long mode to get capsule data.
+ // The page table and stack is used to transfer processor mode from IA32 to long mode.
+ // Create the base address of page table and stack, and save them into variable.
+ // This is not needed when capsule with reset type is not supported.
+ //
+ SaveLongModeContext ();
+
+ //
// Install capsule runtime services into UEFI runtime service tables.
//
gRT->UpdateCapsule = UpdateCapsule;
diff --git a/MdeModulePkg/Universal/CapsuleRuntimeDxe/SaveLongModeContext.c b/MdeModulePkg/Universal/CapsuleRuntimeDxe/SaveLongModeContext.c
new file mode 100644
index 0000000000..72cea7956b
--- /dev/null
+++ b/MdeModulePkg/Universal/CapsuleRuntimeDxe/SaveLongModeContext.c
@@ -0,0 +1,27 @@
+/** @file
+ Create the NULL function to pass build in IA32/IPF/ARM/EBC.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+
+/**
+ Only when PEI is IA32 and DXE is X64, we need transfer to long mode in PEI
+ in order to process capsule data above 4GB. So create a NULL function here for
+ other cases.
+**/
+VOID
+SaveLongModeContext (
+ VOID
+ )
+{
+}
diff --git a/MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c b/MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c
new file mode 100644
index 0000000000..0cfc352ac0
--- /dev/null
+++ b/MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c
@@ -0,0 +1,224 @@
+/** @file
+ Create the variable to save the base address of page table and stack
+ for transferring into long mode in IA32 capsule PEI.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+
+#include <Protocol/Capsule.h>
+#include <Protocol/DxeSmmReadyToLock.h>
+
+#include <Guid/CapsuleVendor.h>
+#include <Guid/AcpiS3Context.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/BaseLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/HobLib.h>
+
+/**
+ Allocate EfiACPIMemoryNVS below 4G memory address.
+
+ This function allocates EfiACPIMemoryNVS below 4G memory address.
+
+ @param Size Size of memory to allocate.
+
+ @return Allocated address for output.
+
+**/
+VOID*
+AllocateAcpiNvsMemoryBelow4G (
+ IN UINTN Size
+ )
+{
+ UINTN Pages;
+ EFI_PHYSICAL_ADDRESS Address;
+ EFI_STATUS Status;
+ VOID* Buffer;
+
+ Pages = EFI_SIZE_TO_PAGES (Size);
+ Address = 0xffffffff;
+
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ Pages,
+ &Address
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Buffer = (VOID *) (UINTN) Address;
+ ZeroMem (Buffer, Size);
+
+ return Buffer;
+}
+
+/**
+ DxeSmmReadyToLock Protocol notification event handler.
+ We reuse S3 ACPI NVS reserved memory to do capsule process
+ after reset.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+**/
+VOID
+EFIAPI
+DxeSmmReadyToLockNotification (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *DxeSmmReadyToLock;
+ UINTN VarSize;
+ EFI_PHYSICAL_ADDRESS TempAcpiS3Context;
+ ACPI_S3_CONTEXT *AcpiS3Context;
+ EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer;
+ UINTN TotalPagesNum;
+ UINT8 PhysicalAddressBits;
+ VOID *Hob;
+ UINT32 NumberOfPml4EntriesNeeded;
+ UINT32 NumberOfPdpEntriesNeeded;
+ BOOLEAN LockBoxFound;
+
+ Status = gBS->LocateProtocol (
+ &gEfiDxeSmmReadyToLockProtocolGuid,
+ NULL,
+ &DxeSmmReadyToLock
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ //
+ // Get the ACPI NVS pages reserved by AcpiS3Save
+ //
+ LockBoxFound = FALSE;
+ VarSize = sizeof (EFI_PHYSICAL_ADDRESS);
+ Status = RestoreLockBox (
+ &gEfiAcpiVariableGuid,
+ &TempAcpiS3Context,
+ &VarSize
+ );
+ if (!EFI_ERROR (Status)) {
+ AcpiS3Context = (ACPI_S3_CONTEXT *)(UINTN)TempAcpiS3Context;
+ ASSERT (AcpiS3Context != NULL);
+
+ Status = RestoreLockBox (
+ &gEfiAcpiS3ContextGuid,
+ NULL,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ LongModeBuffer.PageTableAddress = AcpiS3Context->S3NvsPageTableAddress;
+ LongModeBuffer.StackBaseAddress = AcpiS3Context->BootScriptStackBase;
+ LongModeBuffer.StackSize = AcpiS3Context->BootScriptStackSize;
+ LockBoxFound = TRUE;
+ }
+ }
+
+ if (!LockBoxFound) {
+ //
+ // Page table base address and stack base address can not be found in lock box,
+ // allocate both here.
+ //
+
+ //
+ // Get physical address bits supported from CPU HOB.
+ //
+ PhysicalAddressBits = 36;
+
+ Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
+ if (Hob != NULL) {
+ PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
+ }
+
+ //
+ // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
+ //
+ ASSERT (PhysicalAddressBits <= 52);
+ if (PhysicalAddressBits > 48) {
+ PhysicalAddressBits = 48;
+ }
+
+ //
+ // Calculate page table size and allocate memory for it.
+ //
+ if (PhysicalAddressBits <= 39 ) {
+ NumberOfPml4EntriesNeeded = 1;
+ NumberOfPdpEntriesNeeded = 1 << (PhysicalAddressBits - 30);
+ } else {
+ NumberOfPml4EntriesNeeded = 1 << (PhysicalAddressBits - 39);
+ NumberOfPdpEntriesNeeded = 512;
+ }
+
+ TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;
+ LongModeBuffer.PageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (EFI_PAGES_TO_SIZE (TotalPagesNum));
+ ASSERT (LongModeBuffer.PageTableAddress != 0);
+
+ //
+ // Allocate stack
+ //
+ LongModeBuffer.StackSize = PcdGet32 (PcdCapsulePeiLongModeStackSize);
+ LongModeBuffer.StackBaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (PcdGet32 (PcdCapsulePeiLongModeStackSize));
+ ASSERT (LongModeBuffer.StackBaseAddress != 0);
+ }
+
+ Status = gRT->SetVariable (
+ EFI_CAPSULE_LONG_MODE_BUFFER_NAME,
+ &gEfiCapsuleVendorGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (EFI_CAPSULE_LONG_MODE_BUFFER),
+ &LongModeBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Close event, so it will not be invoked again.
+ //
+ gBS->CloseEvent (Event);
+
+ return ;
+}
+
+/**
+ Create the variable to save the base address of page table and stack
+ for transferring into long mode in IA32 capsule PEI.
+**/
+VOID
+SaveLongModeContext (
+ VOID
+ )
+{
+ VOID *Registration;
+
+ if ((FeaturePcdGet(PcdSupportUpdateCapsuleReset)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode))) {
+ //
+ // Register event to get ACPI NVS pages reserved from lock box, these pages will be used by
+ // Capsule IA32 PEI to transfer to long mode to access capsule above 4GB.
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gEfiDxeSmmReadyToLockProtocolGuid,
+ TPL_CALLBACK,
+ DxeSmmReadyToLockNotification,
+ NULL,
+ &Registration
+ );
+ }
+}