diff options
author | li-elvin <li-elvin@6f19259b-4bc3-4df7-8a09-765794883524> | 2011-09-02 11:34:35 +0000 |
---|---|---|
committer | li-elvin <li-elvin@6f19259b-4bc3-4df7-8a09-765794883524> | 2011-09-02 11:34:35 +0000 |
commit | ab7017fe2bf2c1944090d347e7853e087d8641e8 (patch) | |
tree | d7cd1ecb4d6cdf3784a139c33d1d7f1e615674a6 /MdeModulePkg/Universal/CapsuleRuntimeDxe/X64 | |
parent | 4ff7e37b4f7e336a8ecb7080b8f48eef4b52d396 (diff) | |
download | edk2-ab7017fe2bf2c1944090d347e7853e087d8641e8.zip edk2-ab7017fe2bf2c1944090d347e7853e087d8641e8.tar.gz edk2-ab7017fe2bf2c1944090d347e7853e087d8641e8.tar.bz2 |
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/X64')
-rw-r--r-- | MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c b/MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c new file mode 100644 index 0000000..0cfc352 --- /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
+ );
+ }
+}
|