summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Universal/CapsulePei
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/CapsulePei
parent4ff7e37b4f7e336a8ecb7080b8f48eef4b52d396 (diff)
downloadedk2-platforms-ab7017fe2bf2c1944090d347e7853e087d8641e8.tar.xz
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/CapsulePei')
-rw-r--r--MdeModulePkg/Universal/CapsulePei/Capsule.h72
-rw-r--r--MdeModulePkg/Universal/CapsulePei/CapsulePei.inf11
-rw-r--r--MdeModulePkg/Universal/CapsulePei/CapsuleX64.inf48
-rw-r--r--MdeModulePkg/Universal/CapsulePei/Common/CapsuleCoalesce.c1104
-rw-r--r--MdeModulePkg/Universal/CapsulePei/Common/CommonHeader.h84
-rw-r--r--MdeModulePkg/Universal/CapsulePei/UefiCapsule.c1360
-rw-r--r--MdeModulePkg/Universal/CapsulePei/X64/X64Entry.c66
7 files changed, 1899 insertions, 846 deletions
diff --git a/MdeModulePkg/Universal/CapsulePei/Capsule.h b/MdeModulePkg/Universal/CapsulePei/Capsule.h
index 2a042f288d..8d8658a0c1 100644
--- a/MdeModulePkg/Universal/CapsulePei/Capsule.h
+++ b/MdeModulePkg/Universal/CapsulePei/Capsule.h
@@ -20,7 +20,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Uefi/UefiSpec.h>
#include <Ppi/Capsule.h>
-
+#include <Ppi/LoadFile.h>
#include <Ppi/ReadOnlyVariable2.h>
#include <Guid/CapsuleVendor.h>
@@ -31,25 +31,71 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Library/HobLib.h>
#include <Library/PeiServicesTablePointerLib.h>
#include <Library/PrintLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/PcdLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <IndustryStandard/PeImage.h>
+#include "Common/CommonHeader.h"
+
+#pragma pack(1)
//
-// We want to avoid using memory at 0 for coalescing, so set a
-// min address.
+// Page-Map Level-4 Offset (PML4) and
+// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB
//
-#define MIN_COALESCE_ADDR 0x100000
-#define MAX_SUPPORT_CAPSULE_NUM 50
+
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
+ UINT64 Reserved:1; // Reserved
+ UINT64 MustBeZero:2; // Must Be Zero
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PageTableBaseAddress:40; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // No Execute bit
+ } Bits;
+ UINT64 Uint64;
+} PAGE_MAP_AND_DIRECTORY_POINTER;
//
-// This capsule PEIM puts its private data at the start of the
-// coalesced capsule. Here's the structure definition.
+// Page Table Entry 2MB
//
-#define EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('C', 'a', 'p', 'D')
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
+ UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page
+ UINT64 MustBe1:1; // Must be 1
+ UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PAT:1; //
+ UINT64 MustBeZero:8; // Must be zero;
+ UINT64 PageTableBaseAddress:31; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution
+ } Bits;
+ UINT64 Uint64;
+} PAGE_TABLE_ENTRY;
-typedef struct {
- UINT32 Signature;
- UINTN CapsuleSize;
-} EFI_CAPSULE_PEIM_PRIVATE_DATA;
+#pragma pack()
-#define CAPSULE_TEST_SIGNATURE SIGNATURE_32('T', 'E', 'S', 'T')
+typedef
+EFI_STATUS
+(*COALESCE_ENTRY) (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,
+ IN OUT VOID **MemoryBase,
+ IN OUT UINTN *MemorySize
+ );
#endif
diff --git a/MdeModulePkg/Universal/CapsulePei/CapsulePei.inf b/MdeModulePkg/Universal/CapsulePei/CapsulePei.inf
index c66e7720ca..2599cdbcd1 100644
--- a/MdeModulePkg/Universal/CapsulePei/CapsulePei.inf
+++ b/MdeModulePkg/Universal/CapsulePei/CapsulePei.inf
@@ -3,7 +3,7 @@
#
# Capsule update module supports EFI and UEFI.
#
-# 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
@@ -34,6 +34,7 @@
[Sources]
UefiCapsule.c
Capsule.h
+ Common/CapsuleCoalesce.c
[Packages]
MdePkg/MdePkg.dec
@@ -48,6 +49,10 @@
DebugLib
PeiServicesTablePointerLib
PrintLib
+ PeCoffLib
+ PeCoffGetEntryPointLib
+ PcdLib
+ ReportStatusCodeLib
[Guids]
gEfiCapsuleVendorGuid # ALWAYS_CONSUMED
@@ -56,7 +61,11 @@
[Ppis]
gEfiPeiReadOnlyVariable2PpiGuid # PPI ALWAYS_CONSUMED
gPeiCapsulePpiGuid # PPI ALWAYS_CONSUMED
+ gEfiPeiLoadFilePpiGuid # PPI ALWAYS_CONSUMED
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleCoalesceFile
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode
[Depex]
gEfiPeiReadOnlyVariable2PpiGuid
diff --git a/MdeModulePkg/Universal/CapsulePei/CapsuleX64.inf b/MdeModulePkg/Universal/CapsulePei/CapsuleX64.inf
new file mode 100644
index 0000000000..b12d3e57e4
--- /dev/null
+++ b/MdeModulePkg/Universal/CapsulePei/CapsuleX64.inf
@@ -0,0 +1,48 @@
+## @file
+# Component description file for CapsuleX64 module.
+#
+# The X64 entrypoint to process capsule in long mode.
+# This module is built as X64.
+#
+# 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.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CapsuleX64
+ FILE_GUID = F7FDE4A6-294C-493c-B50F-9734553BB757
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = X64
+#
+
+[Sources]
+ X64/X64Entry.c
+ Common/CapsuleCoalesce.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+
+[Depex]
+ FALSE
+
+
diff --git a/MdeModulePkg/Universal/CapsulePei/Common/CapsuleCoalesce.c b/MdeModulePkg/Universal/CapsulePei/Common/CapsuleCoalesce.c
new file mode 100644
index 0000000000..76c719a54e
--- /dev/null
+++ b/MdeModulePkg/Universal/CapsulePei/Common/CapsuleCoalesce.c
@@ -0,0 +1,1104 @@
+/** @file
+ The logic to process capsule.
+
+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 <PiPei.h>
+
+#include <Guid/CapsuleVendor.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PrintLib.h>
+#include <Library/BaseLib.h>
+
+#define MIN_COALESCE_ADDR (1024 * 1024)
+#define MAX_SUPPORT_CAPSULE_NUM 50
+
+#define EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('C', 'a', 'p', 'D')
+
+typedef struct {
+ UINT32 Signature;
+ UINT32 CapsuleSize;
+} EFI_CAPSULE_PEIM_PRIVATE_DATA;
+
+/**
+ Given a pointer to the capsule block list, info on the available system
+ memory, and the size of a buffer, find a free block of memory where a
+ buffer of the given size can be copied to safely.
+
+ @param BlockList Pointer to head of capsule block descriptors
+ @param MemBase Pointer to the base of memory in which we want to find free space
+ @param MemSize The size of the block of memory pointed to by MemBase
+ @param DataSize How big a free block we want to find
+
+ @return A pointer to a memory block of at least DataSize that lies somewhere
+ between MemBase and (MemBase + MemSize). The memory pointed to does not
+ contain any of the capsule block descriptors or capsule blocks pointed to
+ by the BlockList.
+
+**/
+UINT8 *
+FindFreeMem (
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,
+ UINT8 *MemBase,
+ UINTN MemSize,
+ UINTN DataSize
+ );
+
+/**
+ Check the integrity of the capsule descriptors.
+
+ @param BlockList Pointer to the capsule descriptors
+
+ @retval NULL BlockList is not valid.
+ @retval LastBlockDesc Last one Block in BlockList
+
+**/
+EFI_CAPSULE_BLOCK_DESCRIPTOR *
+ValidateCapsuleIntegrity (
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList
+ );
+
+/**
+ The capsule block descriptors may be fragmented and spread all over memory.
+ To simplify the coalescing of capsule blocks, first coalesce all the
+ capsule block descriptors low in memory.
+
+ The descriptors passed in can be fragmented throughout memory. Here
+ they are relocated into memory to turn them into a contiguous (null
+ terminated) array.
+
+ @param PeiServices pointer to PEI services table
+ @param BlockList pointer to the capsule block descriptors
+ @param MemBase base of system memory in which we can work
+ @param MemSize size of the system memory pointed to by MemBase
+
+ @retval NULL could not relocate the descriptors
+ @retval Pointer to the base of the successfully-relocated block descriptors.
+
+**/
+EFI_CAPSULE_BLOCK_DESCRIPTOR *
+RelocateBlockDescriptors (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,
+ IN UINT8 *MemBase,
+ IN UINTN MemSize
+ );
+
+/**
+ Check every capsule header.
+
+ @param CapsuleHeader The pointer to EFI_CAPSULE_HEADER
+
+ @retval FALSE Capsule is OK
+ @retval TRUE Capsule is corrupted
+
+**/
+BOOLEAN
+IsCapsuleCorrupted (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ );
+
+/**
+ Determine if two buffers overlap in memory.
+
+ @param Buff1 pointer to first buffer
+ @param Size1 size of Buff1
+ @param Buff2 pointer to second buffer
+ @param Size2 size of Buff2
+
+ @retval TRUE Buffers overlap in memory.
+ @retval FALSE Buffer doesn't overlap.
+
+**/
+BOOLEAN
+IsOverlapped (
+ UINT8 *Buff1,
+ UINTN Size1,
+ UINT8 *Buff2,
+ UINTN Size2
+ );
+
+/**
+ Given a pointer to a capsule block descriptor, traverse the list to figure
+ out how many legitimate descriptors there are, and how big the capsule it
+ refers to is.
+
+ @param Desc Pointer to the capsule block descriptors
+ NumDescriptors - optional pointer to where to return the number of descriptors
+ CapsuleSize - optional pointer to where to return the capsule size
+ @param NumDescriptors Optional pointer to where to return the number of descriptors
+ @param CapsuleSize Optional pointer to where to return the capsule size
+
+ @retval EFI_NOT_FOUND No descriptors containing data in the list
+ @retval EFI_SUCCESS Return data is valid
+
+**/
+EFI_STATUS
+GetCapsuleInfo (
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc,
+ IN OUT UINTN *NumDescriptors OPTIONAL,
+ IN OUT UINTN *CapsuleSize OPTIONAL
+ );
+
+/**
+ Given a pointer to the capsule block list, info on the available system
+ memory, and the size of a buffer, find a free block of memory where a
+ buffer of the given size can be copied to safely.
+
+ @param BlockList Pointer to head of capsule block descriptors
+ @param MemBase Pointer to the base of memory in which we want to find free space
+ @param MemSize The size of the block of memory pointed to by MemBase
+ @param DataSize How big a free block we want to find
+
+ @return A pointer to a memory block of at least DataSize that lies somewhere
+ between MemBase and (MemBase + MemSize). The memory pointed to does not
+ contain any of the capsule block descriptors or capsule blocks pointed to
+ by the BlockList.
+
+**/
+UINT8 *
+FindFreeMem (
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,
+ UINT8 *MemBase,
+ UINTN MemSize,
+ UINTN DataSize
+ )
+{
+ UINTN Size;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrDesc;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempDesc;
+ UINT8 *MemEnd;
+ BOOLEAN Failed;
+
+ //
+ // Need at least enough to copy the data to at the end of the buffer, so
+ // say the end is less the data size for easy comparisons here.
+ //
+ MemEnd = MemBase + MemSize - DataSize;
+ CurrDesc = BlockList;
+ //
+ // Go through all the descriptor blocks and see if any obstruct the range
+ //
+ while (CurrDesc != NULL) {
+ //
+ // Get the size of this block list and see if it's in the way
+ //
+ Failed = FALSE;
+ TempDesc = CurrDesc;
+ Size = sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
+ while (TempDesc->Length != 0) {
+ Size += sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
+ TempDesc++;
+ }
+
+ if (IsOverlapped (MemBase, DataSize, (UINT8 *) CurrDesc, Size)) {
+ //
+ // Set our new base to the end of this block list and start all over
+ //
+ MemBase = (UINT8 *) CurrDesc + Size;
+ CurrDesc = BlockList;
+ if (MemBase > MemEnd) {
+ return NULL;
+ }
+
+ Failed = TRUE;
+ }
+ //
+ // Now go through all the blocks and make sure none are in the way
+ //
+ while ((CurrDesc->Length != 0) && (!Failed)) {
+ if (IsOverlapped (MemBase, DataSize, (UINT8 *) (UINTN) CurrDesc->Union.DataBlock, (UINTN) CurrDesc->Length)) {
+ //
+ // Set our new base to the end of this block and start all over
+ //
+ Failed = TRUE;
+ MemBase = (UINT8 *) ((UINTN) CurrDesc->Union.DataBlock) + CurrDesc->Length;
+ CurrDesc = BlockList;
+ if (MemBase > MemEnd) {
+ return NULL;
+ }
+ }
+ CurrDesc++;
+ }
+ //
+ // Normal continuation -- jump to next block descriptor list
+ //
+ if (!Failed) {
+ CurrDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) CurrDesc->Union.ContinuationPointer;
+ }
+ }
+ return MemBase;
+}
+
+/**
+ Check the integrity of the capsule descriptors.
+
+ @param BlockList Pointer to the capsule descriptors
+
+ @retval NULL BlockList is not valid.
+ @retval LastBlockDesc Last one Block in BlockList
+
+**/
+EFI_CAPSULE_BLOCK_DESCRIPTOR *
+ValidateCapsuleIntegrity (
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList
+ )
+{
+ EFI_CAPSULE_HEADER *CapsuleHeader;
+ UINT64 CapsuleSize;
+ UINT32 CapsuleCount;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *Ptr;
+
+ //
+ // Go through the list to look for inconsistencies. Check for:
+ // * misaligned block descriptors.
+ // * The first capsule header guid
+ // * The first capsule header flag
+ // * Data + Length < Data (wrap)
+ CapsuleSize = 0;
+ CapsuleCount = 0;
+ Ptr = BlockList;
+ while ((Ptr->Length != 0) || (Ptr->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {
+ //
+ // Make sure the descriptor is aligned at UINT64 in memory
+ //
+ if ((UINTN) Ptr & 0x07) {
+ DEBUG ((EFI_D_ERROR, "BlockList address failed alignment check\n"));
+ return NULL;
+ }
+
+ if (Ptr->Length == 0) {
+ //
+ // Descriptor points to another list of block descriptors somewhere
+ // else.
+ //
+ Ptr = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Ptr->Union.ContinuationPointer;
+ } else {
+ //
+ //To enhance the reliability of check-up, the first capsule's header is checked here.
+ //More reliabilities check-up will do later.
+ //
+ if (CapsuleSize == 0) {
+ //
+ //Move to the first capsule to check its header.
+ //
+ CapsuleHeader = (EFI_CAPSULE_HEADER*)((UINTN)Ptr->Union.DataBlock);
+ if (IsCapsuleCorrupted (CapsuleHeader)) {
+ return NULL;
+ }
+ CapsuleCount ++;
+ CapsuleSize = CapsuleHeader->CapsuleImageSize;
+ } else {
+ if (CapsuleSize >= Ptr->Length) {
+ CapsuleSize = CapsuleSize - Ptr->Length;
+ } else {
+ CapsuleSize = 0;
+ }
+ }
+ //
+ // Move to next BLOCK descriptor
+ //
+ Ptr++;
+ }
+ }
+
+ if (CapsuleCount == 0) {
+ //
+ // No any capsule is found in BlockList.
+ //
+ return NULL;
+ }
+
+ return Ptr;
+}
+
+/**
+ The capsule block descriptors may be fragmented and spread all over memory.
+ To simplify the coalescing of capsule blocks, first coalesce all the
+ capsule block descriptors low in memory.
+
+ The descriptors passed in can be fragmented throughout memory. Here
+ they are relocated into memory to turn them into a contiguous (null
+ terminated) array.
+
+ @param PeiServices pointer to PEI services table
+ @param BlockList pointer to the capsule block descriptors
+ @param MemBase base of system memory in which we can work
+ @param MemSize size of the system memory pointed to by MemBase
+
+ @retval NULL could not relocate the descriptors
+ @retval Pointer to the base of the successfully-relocated block descriptors.
+
+**/
+EFI_CAPSULE_BLOCK_DESCRIPTOR *
+RelocateBlockDescriptors (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,
+ IN UINT8 *MemBase,
+ IN UINTN MemSize
+ )
+{
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *NewBlockList;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrBlockDescHead;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockDesc;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *PrevBlockDescTail;
+ UINTN NumDescriptors;
+ UINTN BufferSize;
+ UINT8 *RelocBuffer;
+ UINTN BlockListSize;
+ //
+ // Get the info on the blocks and descriptors. Since we're going to move
+ // the descriptors low in memory, adjust the base/size values accordingly here.
+ // GetCapsuleInfo() returns the number of legit descriptors, so add one for
+ // a terminator.
+ //
+ if (GetCapsuleInfo (BlockList, &NumDescriptors, NULL) != EFI_SUCCESS) {
+ return NULL;
+ }
+
+ NumDescriptors++;
+ BufferSize = NumDescriptors * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
+ NewBlockList = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) MemBase;
+ if (MemSize < BufferSize) {
+ return NULL;
+ }
+
+ MemSize -= BufferSize;
+ MemBase += BufferSize;
+ //
+ // Go through all the blocks and make sure none are in the way
+ //
+ TempBlockDesc = BlockList;
+ while (TempBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) {
+ if (TempBlockDesc->Length == 0) {
+ //
+ // Next block of descriptors
+ //
+ TempBlockDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer;
+ } else {
+ //
+ // If the capsule data pointed to by this descriptor is in the way,
+ // move it.
+ //
+ if (IsOverlapped (
+ (UINT8 *) NewBlockList,
+ BufferSize,
+ (UINT8 *) (UINTN) TempBlockDesc->Union.DataBlock,
+ (UINTN) TempBlockDesc->Length
+ )) {
+ //
+ // Relocate the block
+ //
+ RelocBuffer = FindFreeMem (BlockList, MemBase, MemSize, (UINTN) TempBlockDesc->Length);
+ if (RelocBuffer == NULL) {
+ return NULL;
+ }
+
+ CopyMem ((VOID *) RelocBuffer, (VOID *) (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) TempBlockDesc->Length);
+ TempBlockDesc->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocBuffer;
+
+ DEBUG ((EFI_D_INFO, "Capsule relocate descriptors from/to/size 0x%X 0x%X 0x%X\n", (UINT32)(UINTN)TempBlockDesc->Union.DataBlock, (UINT32)(UINTN)RelocBuffer, (UINT32)(UINTN)TempBlockDesc->Length));
+ }
+ }
+ TempBlockDesc++;
+ }
+ //
+ // Now go through all the block descriptors to make sure that they're not
+ // in the memory region we want to copy them to.
+ //
+ CurrBlockDescHead = BlockList;
+ PrevBlockDescTail = NULL;
+ while ((CurrBlockDescHead != NULL) && (CurrBlockDescHead->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {
+ //
+ // Get the size of this list then see if it overlaps our low region
+ //
+ TempBlockDesc = CurrBlockDescHead;
+ BlockListSize = sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
+ while (TempBlockDesc->Length != 0) {
+ BlockListSize += sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
+ TempBlockDesc++;
+ }
+
+ if (IsOverlapped (
+ (UINT8 *) NewBlockList,
+ BufferSize,
+ (UINT8 *) CurrBlockDescHead,
+ BlockListSize
+ )) {
+ //
+ // Overlaps, so move it out of the way
+ //
+ RelocBuffer = FindFreeMem (BlockList, MemBase, MemSize, BlockListSize);
+ if (RelocBuffer == NULL) {
+ return NULL;
+ }
+ CopyMem ((VOID *) RelocBuffer, (VOID *) CurrBlockDescHead, BlockListSize);
+ DEBUG ((EFI_D_INFO, "Capsule reloc descriptor block #2\n"));
+ //
+ // Point the previous block's next point to this copied version. If
+ // the tail pointer is null, then this is the first descriptor block.
+ //
+ if (PrevBlockDescTail == NULL) {
+ BlockList = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) RelocBuffer;
+ } else {
+ PrevBlockDescTail->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocBuffer;
+ }
+ }
+ //
+ // Save our new tail and jump to the next block list
+ //
+ PrevBlockDescTail = TempBlockDesc;
+ CurrBlockDescHead = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer;
+ }
+ //
+ // Cleared out low memory. Now copy the descriptors down there.
+ //
+ TempBlockDesc = BlockList;
+ CurrBlockDescHead = NewBlockList;
+ while ((TempBlockDesc != NULL) && (TempBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {
+ if (TempBlockDesc->Length != 0) {
+ CurrBlockDescHead->Union.DataBlock = TempBlockDesc->Union.DataBlock;
+ CurrBlockDescHead->Length = TempBlockDesc->Length;
+ CurrBlockDescHead++;
+ TempBlockDesc++;
+ } else {
+ TempBlockDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer;
+ }
+ }
+ //
+ // Null terminate
+ //
+ CurrBlockDescHead->Union.ContinuationPointer = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL;
+ CurrBlockDescHead->Length = 0;
+ return NewBlockList;
+}
+
+/**
+ Determine if two buffers overlap in memory.
+
+ @param Buff1 pointer to first buffer
+ @param Size1 size of Buff1
+ @param Buff2 pointer to second buffer
+ @param Size2 size of Buff2
+
+ @retval TRUE Buffers overlap in memory.
+ @retval FALSE Buffer doesn't overlap.
+
+**/
+BOOLEAN
+IsOverlapped (
+ UINT8 *Buff1,
+ UINTN Size1,
+ UINT8 *Buff2,
+ UINTN Size2
+ )
+{
+ //
+ // If buff1's end is less than the start of buff2, then it's ok.
+ // Also, if buff1's start is beyond buff2's end, then it's ok.
+ //
+ if (((Buff1 + Size1) <= Buff2) || (Buff1 >= (Buff2 + Size2))) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Given a pointer to a capsule block descriptor, traverse the list to figure
+ out how many legitimate descriptors there are, and how big the capsule it
+ refers to is.
+
+ @param Desc Pointer to the capsule block descriptors
+ NumDescriptors - optional pointer to where to return the number of descriptors
+ CapsuleSize - optional pointer to where to return the capsule size
+ @param NumDescriptors Optional pointer to where to return the number of descriptors
+ @param CapsuleSize Optional pointer to where to return the capsule size
+
+ @retval EFI_NOT_FOUND No descriptors containing data in the list
+ @retval EFI_SUCCESS Return data is valid
+
+**/
+EFI_STATUS
+GetCapsuleInfo (
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc,
+ IN OUT UINTN *NumDescriptors OPTIONAL,
+ IN OUT UINTN *CapsuleSize OPTIONAL
+ )
+{
+ UINTN Count;
+ UINTN Size;
+
+ Count = 0;
+ Size = 0;
+
+ while (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) {
+ if (Desc->Length == 0) {
+ //
+ // Descriptor points to another list of block descriptors somewhere
+ //
+ Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer;
+ } else {
+ Size += (UINTN) Desc->Length;
+ Count++;
+ Desc++;
+ }
+ }
+ //
+ // If no descriptors, then fail
+ //
+ if (Count == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (NumDescriptors != NULL) {
+ *NumDescriptors = Count;
+ }
+
+ if (CapsuleSize != NULL) {
+ *CapsuleSize = Size;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check every capsule header.
+
+ @param CapsuleHeader The pointer to EFI_CAPSULE_HEADER
+
+ @retval FALSE Capsule is OK
+ @retval TRUE Capsule is corrupted
+
+**/
+BOOLEAN
+IsCapsuleCorrupted (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ //
+ //A capsule to be updated across a system reset should contain CAPSULE_FLAGS_PERSIST_ACROSS_RESET.
+ //
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) == 0) {
+ return TRUE;
+ }
+ //
+ //Make sure the flags combination is supported by the platform.
+ //
+ if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {
+ return TRUE;
+ }
+ if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Try to verify the integrity of a capsule test pattern before the
+ capsule gets coalesced. This can be useful in narrowing down
+ where capsule data corruption occurs.
+
+ The test pattern mode fills in memory with a counting UINT32 value.
+ If the capsule is not divided up in a multiple of 4-byte blocks, then
+ things get messy doing the check. Therefore there are some cases
+ here where we just give up and skip the pre-coalesce check.
+
+ @param PeiServices PEI services table
+ @param Desc Pointer to capsule descriptors
+**/
+VOID
+CapsuleTestPatternPreCoalesce (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc
+ )
+{
+ UINT32 *TestPtr;
+ UINT32 TestCounter;
+ UINT32 TestSize;
+ //
+ // Find first data descriptor
+ //
+ while ((Desc->Length == 0) && (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {
+ Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer;
+ }
+
+ if (Desc->Union.ContinuationPointer == 0) {
+ return ;
+ }
+ //
+ // First one better be long enough to at least hold the test signature
+ //
+ if (Desc->Length < sizeof (UINT32)) {
+ DEBUG ((EFI_D_INFO, "Capsule test pattern pre-coalesce punted #1\n"));
+ return ;
+ }
+
+ TestPtr = (UINT32 *) (UINTN) Desc->Union.DataBlock;
+ //
+ // 0x54534554 "TEST"
+ //
+ if (*TestPtr != 0x54534554) {
+ return ;
+ }
+
+ TestCounter = 0;
+ TestSize = (UINT32) Desc->Length - 2 * sizeof (UINT32);
+ //
+ // Skip over the signature and the size fields in the pattern data header
+ //
+ TestPtr += 2;
+ while (1) {
+ if ((TestSize & 0x03) != 0) {
+ DEBUG ((EFI_D_INFO, "Capsule test pattern pre-coalesce punted #2\n"));
+ return ;
+ }
+
+ while (TestSize > 0) {
+ if (*TestPtr != TestCounter) {
+ DEBUG ((EFI_D_INFO, "Capsule test pattern pre-coalesce failed data corruption check\n"));
+ return ;
+ }
+
+ TestSize -= sizeof (UINT32);
+ TestCounter++;
+ TestPtr++;
+ }
+ Desc++;
+ while ((Desc->Length == 0) && (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {
+ Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer;
+ }
+
+ if (Desc->Union.ContinuationPointer == (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) {
+ return ;
+ }
+ TestSize = (UINT32) Desc->Length;
+ TestPtr = (UINT32 *) (UINTN) Desc->Union.DataBlock;
+ }
+}
+
+/**
+ Checks for the presence of capsule descriptors.
+ Get capsule descriptors from variable CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
+
+ @param BlockListBuffer Pointer to the buffer of capsule descriptors variables
+ @param BlockDescriptorList Pointer to the capsule descriptors list
+
+ @retval EFI_SUCCESS a valid capsule is present
+ @retval EFI_NOT_FOUND if a valid capsule is not present
+**/
+EFI_STATUS
+BuildCapsuleDescriptors (
+ IN EFI_PHYSICAL_ADDRESS *BlockListBuffer,
+ OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptorList
+ )
+{
+ UINTN Index;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *LastBlock;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlock;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *HeadBlock;
+
+ LastBlock = NULL;
+ HeadBlock = NULL;
+ TempBlock = NULL;
+ Index = 0;
+
+ while (BlockListBuffer[Index] != 0) {
+ if (Index == 0) {
+ //
+ // For the first Capsule Image, test integrity of descriptors.
+ //
+ LastBlock = ValidateCapsuleIntegrity ((EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)BlockListBuffer[Index]);
+ if (LastBlock == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Return the base of the block descriptors
+ //
+ HeadBlock = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)BlockListBuffer[Index];
+ } else {
+ //
+ // Test integrity of descriptors.
+ //
+ TempBlock = ValidateCapsuleIntegrity ((EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)BlockListBuffer[Index]);
+ if (TempBlock == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Combine the different BlockList into single BlockList.
+ //
+ LastBlock->Union.DataBlock = (EFI_PHYSICAL_ADDRESS)(UINTN)BlockListBuffer[Index];
+ LastBlock->Length = 0;
+ LastBlock = TempBlock;
+ }
+ Index ++;
+ }
+
+ if (HeadBlock != NULL) {
+ *BlockDescriptorList = HeadBlock;
+ return EFI_SUCCESS;
+ }
+ return EFI_NOT_FOUND;
+}
+
+/**
+ The function to coalesce a fragmented capsule in memory.
+
+ Memory Map for coalesced capsule:
+ MemBase + ---->+---------------------------+<-----------+
+ MemSize | CapsuleOffset[49] | |
+ +---------------------------+ |
+ | ................ | |
+ +---------------------------+ |
+ | CapsuleOffset[2] | |
+ +---------------------------+ |
+ | CapsuleOffset[1] | |
+ +---------------------------+ |
+ | CapsuleOffset[0] | CapsuleSize
+ +---------------------------+ |
+ | CapsuleNumber | |
+ +---------------------------+ |
+ | | |
+ | | |
+ | Capsule Image | |
+ | | |
+ | | |
+ +---------------------------+ |
+ | PrivateData | |
+ DestPtr ----> +---------------------------+<-----------+
+ | | |
+ | FreeMem | FreeMemSize
+ | | |
+ FreeMemBase --->+---------------------------+<-----------+
+ | Terminator |
+ +---------------------------+
+ | BlockDescriptor n |
+ +---------------------------+
+ | ................. |
+ +---------------------------+
+ | BlockDescriptor 1 |
+ +---------------------------+
+ | BlockDescriptor 0 |
+ +---------------------------+
+ | PrivateDataDesc 0 |
+ MemBase ---->+---------------------------+<----- BlockList
+
+ @param PeiServices General purpose services available to every PEIM.
+ @param BlockListBuffer Point to the buffer of Capsule Descriptor Variables.
+ @param MemoryBase Pointer to the base of a block of memory that we can walk
+ all over while trying to coalesce our buffers.
+ On output, this variable will hold the base address of
+ a coalesced capsule.
+ @param MemorySize Size of the memory region pointed to by MemoryBase.
+ On output, this variable will contain the size of the
+ coalesced capsule.
+
+ @retval EFI_NOT_FOUND If we could not find the capsule descriptors.
+
+ @retval EFI_BUFFER_TOO_SMALL
+ If we could not coalesce the capsule in the memory
+ region provided to us.
+
+ @retval EFI_SUCCESS Processed the capsule successfully.
+**/
+EFI_STATUS
+EFIAPI
+CapsuleDataCoalesce (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PHYSICAL_ADDRESS *BlockListBuffer,
+ IN OUT VOID **MemoryBase,
+ IN OUT UINTN *MemorySize
+ )
+{
+ VOID *NewCapsuleBase;
+ VOID *DataPtr;
+ UINT8 CapsuleIndex;
+ UINT8 *FreeMemBase;
+ UINT8 *DestPtr;
+ UINT8 *RelocPtr;
+ UINT32 CapsuleOffset[MAX_SUPPORT_CAPSULE_NUM];
+ UINT32 *AddDataPtr;
+ UINT32 CapsuleTimes;
+ UINT64 SizeLeft;
+ UINT64 CapsuleImageSize;
+ UINTN CapsuleSize;
+ UINTN DescriptorsSize;
+ UINTN FreeMemSize;
+ UINTN NumDescriptors;
+ BOOLEAN IsCorrupted;
+ BOOLEAN CapsuleBeginFlag;
+ EFI_STATUS Status;
+ EFI_CAPSULE_HEADER *CapsuleHeader;
+ EFI_CAPSULE_PEIM_PRIVATE_DATA PrivateData;
+ EFI_CAPSULE_PEIM_PRIVATE_DATA *PrivateDataPtr;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrentBlockDesc;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockDesc;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR PrivateDataDesc[2];
+
+ CapsuleIndex = 0;
+ SizeLeft = 0;
+ CapsuleTimes = 0;
+ CapsuleImageSize = 0;
+ PrivateDataPtr = NULL;
+ AddDataPtr = NULL;
+ CapsuleHeader = NULL;
+ CapsuleBeginFlag = TRUE;
+ IsCorrupted = TRUE;
+ CapsuleSize = 0;
+ NumDescriptors = 0;
+
+ //
+ // Build capsule descriptors list
+ //
+ Status = BuildCapsuleDescriptors (BlockListBuffer, &BlockList);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG_CODE (
+ CapsuleTestPatternPreCoalesce (PeiServices, BlockList);
+ );
+
+ //
+ // Get the size of our descriptors and the capsule size. GetCapsuleInfo()
+ // returns the number of descriptors that actually point to data, so add
+ // one for a terminator. Do that below.
+ //
+ GetCapsuleInfo (BlockList, &NumDescriptors, &CapsuleSize);
+ if ((CapsuleSize == 0) || (NumDescriptors == 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Initialize our local copy of private data. When we're done, we'll create a
+ // descriptor for it as well so that it can be put into free memory without
+ // trashing anything.
+ //
+ PrivateData.Signature = EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE;
+ PrivateData.CapsuleSize = (UINT32) CapsuleSize;
+ PrivateDataDesc[0].Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) &PrivateData;
+ PrivateDataDesc[0].Length = sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA);
+ PrivateDataDesc[1].Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) BlockList;
+ PrivateDataDesc[1].Length = 0;
+ //
+ // In addition to PrivateDataDesc[1:0], one terminator is added
+ // See below RelocateBlockDescriptors()
+ //
+ NumDescriptors += 3;
+ CapsuleSize += sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + sizeof(CapsuleOffset) + sizeof(UINT32);
+ BlockList = PrivateDataDesc;
+ DescriptorsSize = NumDescriptors * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
+
+ //
+ // Don't go below some min address. If the base is below it,
+ // then move it up and adjust the size accordingly.
+ //
+ DEBUG ((EFI_D_INFO, "Capsule Memory range from 0x%8X to 0x%8X\n", (UINTN) *MemoryBase, (UINTN)*MemoryBase + *MemorySize));
+ if ((UINTN)*MemoryBase < (UINTN) MIN_COALESCE_ADDR) {
+ if (((UINTN)*MemoryBase + *MemorySize) < (UINTN) MIN_COALESCE_ADDR) {
+ return EFI_BUFFER_TOO_SMALL;
+ } else {
+ *MemorySize = *MemorySize - ((UINTN) MIN_COALESCE_ADDR - (UINTN) *MemoryBase);
+ *MemoryBase = (VOID *) (UINTN) MIN_COALESCE_ADDR;
+ }
+ }
+
+ if (*MemorySize <= (CapsuleSize + DescriptorsSize)) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ FreeMemBase = *MemoryBase;
+ FreeMemSize = *MemorySize;
+ DEBUG ((EFI_D_INFO, "Capsule Free Memory from 0x%8X to 0x%8X\n", (UINTN) FreeMemBase, (UINTN) FreeMemBase + FreeMemSize));
+
+ //
+ // Relocate all the block descriptors to low memory to make further
+ // processing easier.
+ //
+ BlockList = RelocateBlockDescriptors (PeiServices, BlockList, FreeMemBase, FreeMemSize);
+ if (BlockList == NULL) {
+ //
+ // Not enough room to relocate the descriptors
+ //
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Take the top of memory for the capsule. Naturally align.
+ //
+ DestPtr = FreeMemBase + FreeMemSize - CapsuleSize;
+ DestPtr = (UINT8 *) ((UINTN) DestPtr &~ (UINTN) (sizeof (UINTN) - 1));
+ FreeMemBase = (UINT8 *) BlockList + DescriptorsSize;
+ FreeMemSize = FreeMemSize - DescriptorsSize - CapsuleSize;
+ NewCapsuleBase = (VOID *) DestPtr;
+
+ //
+ // Move all the blocks to the top (high) of memory.
+ // Relocate all the obstructing blocks. Note that the block descriptors
+ // were coalesced when they were relocated, so we can just ++ the pointer.
+ //
+ CurrentBlockDesc = BlockList;
+ while ((CurrentBlockDesc->Length != 0) || (CurrentBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {
+ //
+ // See if any of the remaining capsule blocks are in the way
+ //
+ TempBlockDesc = CurrentBlockDesc;
+ while (TempBlockDesc->Length != 0) {
+ //
+ // Is this block in the way of where we want to copy the current descriptor to?
+ //
+ if (IsOverlapped (
+ (UINT8 *) DestPtr,
+ (UINTN) CurrentBlockDesc->Length,
+ (UINT8 *) (UINTN) TempBlockDesc->Union.DataBlock,
+ (UINTN) TempBlockDesc->Length
+ )) {
+ //
+ // Relocate the block
+ //
+ RelocPtr = FindFreeMem (BlockList, FreeMemBase, FreeMemSize, (UINTN) TempBlockDesc->Length);
+ if (RelocPtr == NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ CopyMem ((VOID *) RelocPtr, (VOID *) (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) TempBlockDesc->Length);
+ DEBUG ((EFI_D_INFO, "Capsule reloc data block from 0x%8X to 0x%8X with size 0x%8X\n",
+ (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) RelocPtr, (UINTN) TempBlockDesc->Length));
+
+ TempBlockDesc->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocPtr;
+ }
+ //
+ // Next descriptor
+ //
+ TempBlockDesc++;
+ }
+ //
+ // Ok, we made it through. Copy the block.
+ // we just support greping one capsule from the lists of block descs list.
+ //
+ CapsuleTimes ++;
+ //
+ //Skip the first block descriptor that filled with EFI_CAPSULE_PEIM_PRIVATE_DATA
+ //
+ if (CapsuleTimes > 1) {
+ //
+ //For every capsule entry point, check its header to determine whether to relocate it.
+ //If it is invalid, skip it and move on to the next capsule. If it is valid, relocate it.
+ //
+ if (CapsuleBeginFlag) {
+ CapsuleBeginFlag = FALSE;
+ CapsuleHeader = (EFI_CAPSULE_HEADER*)(UINTN)CurrentBlockDesc->Union.DataBlock;
+ SizeLeft = CapsuleHeader->CapsuleImageSize;
+ if (!IsCapsuleCorrupted (CapsuleHeader)) {
+
+ if (CapsuleIndex > (MAX_SUPPORT_CAPSULE_NUM - 1)) {
+ DEBUG ((EFI_D_ERROR, "Capsule number exceeds the max number of %d!\n", MAX_SUPPORT_CAPSULE_NUM));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Relocate this valid capsule
+ //
+ IsCorrupted = FALSE;
+ CapsuleImageSize += SizeLeft;
+ CopyMem ((VOID *) DestPtr, (VOID *) (UINTN) CurrentBlockDesc->Union.DataBlock, (UINTN) CurrentBlockDesc->Length);
+ DEBUG ((EFI_D_INFO, "Capsule coalesce block no.0x%8X from 0x%8lX to 0x%8lX with size 0x%8X\n",CapsuleTimes,
+ (UINTN)CurrentBlockDesc->Union.DataBlock, (UINTN)DestPtr, (UINTN)CurrentBlockDesc->Length));
+ //
+ // Cache the begin offset of this capsule
+ //
+ CapsuleOffset[CapsuleIndex++] = (UINT32) (UINTN) DestPtr - (UINT32)(UINTN)NewCapsuleBase - (UINT32)sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA);
+ DestPtr += CurrentBlockDesc->Length;
+ }
+ //
+ // If the current block length is greater than or equal to SizeLeft, this is the
+ // start of the next capsule
+ //
+ if (CurrentBlockDesc->Length < SizeLeft) {
+ SizeLeft -= CurrentBlockDesc->Length;
+ } else {
+ //
+ // Start the next cycle
+ //
+ SizeLeft = 0;
+ IsCorrupted = TRUE;
+ CapsuleBeginFlag = TRUE;
+ }
+ } else {
+ //
+ //Go on relocating the current capule image.
+ //
+ if (CurrentBlockDesc->Length < SizeLeft) {
+ if (!IsCorrupted) {
+ CopyMem ((VOID *) DestPtr, (VOID *) (UINTN) (CurrentBlockDesc->Union.DataBlock), (UINTN)CurrentBlockDesc->Length);
+ DEBUG ((EFI_D_INFO, "Capsule coalesce block no.0x%8X from 0x%8lX to 0x%8lX with size 0x%8X\n",CapsuleTimes,
+ (UINTN)CurrentBlockDesc->Union.DataBlock, (UINTN)DestPtr, (UINTN)CurrentBlockDesc->Length));
+ DestPtr += CurrentBlockDesc->Length;
+ }
+ SizeLeft -= CurrentBlockDesc->Length;
+ } else {
+ //
+ //Here is the end of the current capsule image.
+ //
+ if (!IsCorrupted) {
+ CopyMem ((VOID *) DestPtr, (VOID *)(UINTN)(CurrentBlockDesc->Union.DataBlock), (UINTN)CurrentBlockDesc->Length);
+ DEBUG ((EFI_D_INFO, "Capsule coalesce block no.0x%8X from 0x%8lX to 0x%8lX with size 0x%8X\n",CapsuleTimes,
+ (UINTN)CurrentBlockDesc->Union.DataBlock, (UINTN)DestPtr, (UINTN)CurrentBlockDesc->Length));
+ DestPtr += CurrentBlockDesc->Length;
+ }
+ //
+ // Start the next cycle
+ //
+ SizeLeft = 0;
+ IsCorrupted = TRUE;
+ CapsuleBeginFlag = TRUE;
+ }
+ }
+ } else {
+ //
+ //The first entry is the block descriptor for EFI_CAPSULE_PEIM_PRIVATE_DATA.
+ //
+ CopyMem ((VOID *) DestPtr, (VOID *) (UINTN) CurrentBlockDesc->Union.DataBlock, (UINTN) CurrentBlockDesc->Length);
+ DestPtr += CurrentBlockDesc->Length;
+ }
+ //
+ //Walk through the block descriptor list.
+ //
+ CurrentBlockDesc++;
+ }
+ //
+ // We return the base of memory we want reserved, and the size.
+ // The memory peim should handle it appropriately from there.
+ //
+ *MemorySize = (UINTN) CapsuleImageSize;
+ *MemoryBase = (VOID *) NewCapsuleBase;
+
+ //
+ //Append the offsets of mutiply capsules to the continous buffer
+ //
+ DataPtr = (VOID*)((UINTN)NewCapsuleBase + sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA) + (UINTN)CapsuleImageSize);
+ AddDataPtr = (UINT32*)(((UINTN) DataPtr + sizeof(UINT32) - 1) &~ (UINT32) (sizeof (UINT32) - 1));
+
+ *AddDataPtr++ = CapsuleIndex;
+
+ CopyMem (AddDataPtr, &CapsuleOffset[0], sizeof (UINT32) * CapsuleIndex);
+
+ PrivateDataPtr = (EFI_CAPSULE_PEIM_PRIVATE_DATA *) NewCapsuleBase;
+ PrivateDataPtr->CapsuleSize = (UINT32) CapsuleImageSize;
+
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Universal/CapsulePei/Common/CommonHeader.h b/MdeModulePkg/Universal/CapsulePei/Common/CommonHeader.h
new file mode 100644
index 0000000000..5c0aa3068c
--- /dev/null
+++ b/MdeModulePkg/Universal/CapsulePei/Common/CommonHeader.h
@@ -0,0 +1,84 @@
+/** @file
+ Common header file.
+
+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.
+
+**/
+
+#ifndef _CAPSULE_THUNK_32_TO_64_
+#define _CAPSULE_THUNK_32_TO_64_
+
+#include <Uefi.h>
+#include "PiPei.h"
+
+//
+// This capsule PEIM puts its private data at the start of the
+// coalesced capsule. Here's the structure definition.
+//
+#define EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('C', 'a', 'p', 'D')
+
+typedef struct {
+ UINT32 Signature;
+ UINTN CapsuleSize;
+} EFI_CAPSULE_PEIM_PRIVATE_DATA;
+
+#define CAPSULE_TEST_SIGNATURE SIGNATURE_32('T', 'E', 'S', 'T')
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS EntryPoint;
+ EFI_PHYSICAL_ADDRESS StackBufferBase;
+ UINT64 StackBufferLength;
+ EFI_PHYSICAL_ADDRESS JumpBuffer;
+ EFI_PHYSICAL_ADDRESS BlockListAddr;
+ EFI_PHYSICAL_ADDRESS MemoryBase64Ptr;
+ EFI_PHYSICAL_ADDRESS MemorySize64Ptr;
+} SWITCH_32_TO_64_CONTEXT;
+
+typedef struct {
+ UINT16 ReturnCs;
+ EFI_PHYSICAL_ADDRESS ReturnEntryPoint;
+ UINT64 ReturnStatus;
+ IA32_DESCRIPTOR Gdtr;
+} SWITCH_64_TO_32_CONTEXT;
+
+/**
+ The function to coalesce a fragmented capsule in memory.
+
+ @param PeiServices General purpose services available to every PEIM.
+ @param BlockListBuffer Point to the buffer of Capsule Descriptor Variables.
+ @param MemoryBase Pointer to the base of a block of memory that we can walk
+ all over while trying to coalesce our buffers.
+ On output, this variable will hold the base address of
+ a coalesced capsule.
+ @param MemorySize Size of the memory region pointed to by MemoryBase.
+ On output, this variable will contain the size of the
+ coalesced capsule.
+
+ @retval EFI_NOT_FOUND if we can't determine the boot mode
+ if the boot mode is not flash-update
+ if we could not find the capsule descriptors
+
+ @retval EFI_BUFFER_TOO_SMALL
+ if we could not coalesce the capsule in the memory
+ region provided to us
+
+ @retval EFI_SUCCESS if there's no capsule, or if we processed the
+ capsule successfully.
+**/
+EFI_STATUS
+EFIAPI
+CapsuleDataCoalesce (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN IN EFI_PHYSICAL_ADDRESS *BlockListBuffer,
+ IN OUT VOID **MemoryBase,
+ IN OUT UINTN *MemorySize
+ );
+
+#endif
diff --git a/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c b/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c
index 7c10a3c568..5598755d46 100644
--- a/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c
+++ b/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c
@@ -16,136 +16,420 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "Capsule.h"
-EFI_PHYSICAL_ADDRESS *mBufferAddress;
-
-/**
- Check every capsule header.
-
- @param CapsuleHeader The pointer to EFI_CAPSULE_HEADER
+//
+// Global Descriptor Table (GDT)
+//
+GLOBAL_REMOVE_IF_UNREFERENCED IA32_SEGMENT_DESCRIPTOR mGdtEntries[] = {
+/* selector { Global Segment Descriptor } */
+/* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //null descriptor
+/* 0x08 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear data segment descriptor
+/* 0x10 */ {{0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear code segment descriptor
+/* 0x18 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
+/* 0x20 */ {{0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system code segment descriptor
+/* 0x28 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
+/* 0x30 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
+/* 0x38 */ {{0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 1, 0, 1, 0}}, //system code segment descriptor
+/* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
+};
- @retval FALSE Capsule is OK
- @retval TRUE Capsule is corrupted
+//
+// IA32 Gdt register
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR mGdt = {
+ sizeof (mGdtEntries) - 1,
+ (UINTN) mGdtEntries
+ };
+/**
+ Calculate the total size of page table.
+
+ @return The size of page table.
+
+
**/
-BOOLEAN
-IsCapsuleCorrupted (
- IN EFI_CAPSULE_HEADER *CapsuleHeader
+UINTN
+CalculatePageTableSize (
+ VOID
)
{
+ UINTN TotalPagesNum;
+ UINT8 PhysicalAddressBits;
+ VOID *Hob;
+ UINT32 NumberOfPml4EntriesNeeded;
+ UINT32 NumberOfPdpEntriesNeeded;
+
//
- //A capsule to be updated across a system reset should contain CAPSULE_FLAGS_PERSIST_ACROSS_RESET.
+ // Get physical address bits supported from CPU HOB.
//
- if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) == 0) {
- return TRUE;
+ PhysicalAddressBits = 36;
+
+ Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
+ if (Hob != NULL) {
+ PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
}
+
//
- //Make sure the flags combination is supported by the platform.
+ // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
//
- if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {
- return TRUE;
+ ASSERT (PhysicalAddressBits <= 52);
+ if (PhysicalAddressBits > 48) {
+ PhysicalAddressBits = 48;
}
- if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) {
- return TRUE;
+
+ //
+ // Calculate the table entries needed.
+ //
+ if (PhysicalAddressBits <= 39 ) {
+ NumberOfPml4EntriesNeeded = 1;
+ NumberOfPdpEntriesNeeded = 1 << (PhysicalAddressBits - 30);
+ } else {
+ NumberOfPml4EntriesNeeded = 1 << (PhysicalAddressBits - 39);
+ NumberOfPdpEntriesNeeded = 512;
}
- return FALSE;
+ TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;
+
+ return EFI_PAGES_TO_SIZE (TotalPagesNum);
}
/**
- Check the integrity of the capsule descriptors.
-
- @param BlockList Pointer to the capsule descriptors
+ Allocates and fills in the Page Directory and Page Table Entries to
+ establish a 1:1 Virtual to Physical mapping.
- @retval NULL BlockList is not valid.
- @retval LastBlockDesc Last one Block in BlockList
+ @param[in] PageTablesAddress The base address of page table.
**/
-EFI_CAPSULE_BLOCK_DESCRIPTOR *
-ValidateCapsuleIntegrity (
- IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList
+VOID
+CreateIdentityMappingPageTables (
+ IN EFI_PHYSICAL_ADDRESS PageTablesAddress
)
-{
- EFI_CAPSULE_HEADER *CapsuleHeader;
- UINT64 CapsuleSize;
- UINT32 CapsuleCount;
- EFI_CAPSULE_BLOCK_DESCRIPTOR *Ptr;
-
- //
- // Go through the list to look for inconsistencies. Check for:
- // * misaligned block descriptors.
- // * The first capsule header guid
- // * The first capsule header flag
- // * Data + Length < Data (wrap)
- CapsuleSize = 0;
- CapsuleCount = 0;
- Ptr = BlockList;
- while ((Ptr->Length != 0) || (Ptr->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {
+{
+ UINT8 PhysicalAddressBits;
+ EFI_PHYSICAL_ADDRESS PageAddress;
+ UINTN IndexOfPml4Entries;
+ UINTN IndexOfPdpEntries;
+ UINTN IndexOfPageDirectoryEntries;
+ UINT32 NumberOfPml4EntriesNeeded;
+ UINT32 NumberOfPdpEntriesNeeded;
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry;
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageMap;
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry;
+ PAGE_TABLE_ENTRY *PageDirectoryEntry;
+ UINTN BigPageAddress;
+ VOID *Hob;
+
+ //
+ // 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 the table entries needed.
+ //
+ if (PhysicalAddressBits <= 39 ) {
+ NumberOfPml4EntriesNeeded = 1;
+ NumberOfPdpEntriesNeeded = 1 << (PhysicalAddressBits - 30);
+ } else {
+ NumberOfPml4EntriesNeeded = 1 << (PhysicalAddressBits - 39);
+ NumberOfPdpEntriesNeeded = 512;
+ }
+
+ //
+ // Pre-allocate big pages to avoid later allocations.
+ //
+ BigPageAddress = (UINTN) PageTablesAddress;
+
+ //
+ // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
+ //
+ PageMap = (VOID *) BigPageAddress;
+ BigPageAddress += EFI_PAGE_SIZE;
+
+ PageMapLevel4Entry = PageMap;
+ PageAddress = 0;
+ for (IndexOfPml4Entries = 0; IndexOfPml4Entries < NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) {
//
- // Make sure the descriptor is aligned at UINT64 in memory
+ // Each PML4 entry points to a page of Page Directory Pointer entires.
+ // So lets allocate space for them and fill them in in the IndexOfPdpEntries loop.
//
- if ((UINTN) Ptr & 0x07) {
- DEBUG ((EFI_D_ERROR, "BlockList address failed alignment check\n"));
- return NULL;
- }
+ PageDirectoryPointerEntry = (VOID *) BigPageAddress;
+ BigPageAddress += EFI_PAGE_SIZE;
- if (Ptr->Length == 0) {
- //
- // Descriptor points to another list of block descriptors somewhere
- // else.
+ //
+ // Make a PML4 Entry
+ //
+ PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry;
+ PageMapLevel4Entry->Bits.ReadWrite = 1;
+ PageMapLevel4Entry->Bits.Present = 1;
+
+ for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
//
- Ptr = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Ptr->Union.ContinuationPointer;
- } else {
+ // Each Directory Pointer entries points to a page of Page Directory entires.
+ // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.
+ //
+ PageDirectoryEntry = (VOID *) BigPageAddress;
+ BigPageAddress += EFI_PAGE_SIZE;
+
//
- //To enhance the reliability of check-up, the first capsule's header is checked here.
- //More reliabilities check-up will do later.
+ // Fill in a Page Directory Pointer Entries
//
- if (CapsuleSize == 0) {
+ PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry;
+ PageDirectoryPointerEntry->Bits.ReadWrite = 1;
+ PageDirectoryPointerEntry->Bits.Present = 1;
+
+ for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += 0x200000) {
//
- //Move to the first capsule to check its header.
+ // Fill in the Page Directory entries
//
- CapsuleHeader = (EFI_CAPSULE_HEADER*)((UINTN)Ptr->Union.DataBlock);
- if (IsCapsuleCorrupted (CapsuleHeader)) {
- return NULL;
- }
- CapsuleCount ++;
- CapsuleSize = CapsuleHeader->CapsuleImageSize;
- } else {
- if (CapsuleSize >= Ptr->Length) {
- CapsuleSize = CapsuleSize - Ptr->Length;
- } else {
- CapsuleSize = 0;
- }
+ PageDirectoryEntry->Uint64 = (UINT64)PageAddress;
+ PageDirectoryEntry->Bits.ReadWrite = 1;
+ PageDirectoryEntry->Bits.Present = 1;
+ PageDirectoryEntry->Bits.MustBe1 = 1;
+
}
- //
- // Move to next BLOCK descriptor
- //
- Ptr++;
}
}
- if (CapsuleCount == 0) {
+ //
+ // For the PML4 entries we are not using fill in a null entry.
+ // For now we just copy the first entry.
+ //
+ for (; IndexOfPml4Entries < 512; IndexOfPml4Entries++, PageMapLevel4Entry++) {
+ CopyMem (
+ PageMapLevel4Entry,
+ PageMap,
+ sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)
+ );
+ }
+}
+
+/**
+ Return function from long mode to 32-bit mode.
+
+ @param EntrypointContext Context for mode switching
+ @param ReturnContext Context for mode switching
+
+**/
+VOID
+ReturnFunction (
+ SWITCH_32_TO_64_CONTEXT *EntrypointContext,
+ SWITCH_64_TO_32_CONTEXT *ReturnContext
+ )
+{
+ //
+ // Restore original GDT
+ //
+ AsmWriteGdtr (&ReturnContext->Gdtr);
+
+ //
+ // return to original caller
+ //
+ LongJump ((BASE_LIBRARY_JUMP_BUFFER *)(UINTN)EntrypointContext->JumpBuffer, 1);
+
+ //
+ // never be here
+ //
+ ASSERT (FALSE);
+}
+
+/**
+ Thunk function from 32-bit protection mode to long mode.
+
+ @param PageTableAddress Page table base address
+ @param Context Context for mode switching
+ @param ReturnContext Context for mode switching
+
+ @retval EFI_SUCCESS Function successfully executed.
+
+**/
+EFI_STATUS
+Thunk32To64 (
+ EFI_PHYSICAL_ADDRESS PageTableAddress,
+ SWITCH_32_TO_64_CONTEXT *Context,
+ SWITCH_64_TO_32_CONTEXT *ReturnContext
+ )
+{
+ UINTN SetJumpFlag;
+ EFI_STATUS Status;
+
+ //
+ // Save return address, LongJump will return here then
+ //
+ SetJumpFlag = SetJump ((BASE_LIBRARY_JUMP_BUFFER *) (UINTN) Context->JumpBuffer);
+
+ if (SetJumpFlag == 0) {
+
//
- // No any capsule is found in BlockList.
+ // Build Page Tables for all physical memory processor supports
//
- return NULL;
- }
+ CreateIdentityMappingPageTables (PageTableAddress);
+
+ //
+ // Create 64-bit GDT
+ //
+ AsmWriteGdtr (&mGdt);
+
+ //
+ // Write CR3
+ //
+ AsmWriteCr3 ((UINTN) PageTableAddress);
- return Ptr;
+ //
+ // Transfer to long mode
+ //
+ AsmEnablePaging64 (
+ 0x38,
+ (UINT64) Context->EntryPoint,
+ (UINT64)(UINTN) Context,
+ (UINT64)(UINTN) ReturnContext,
+ Context->StackBufferBase + Context->StackBufferLength
+ );
+ }
+
+ //
+ // Convert to 32-bit Status and return
+ //
+ Status = EFI_SUCCESS;
+ if ((UINTN) ReturnContext->ReturnStatus != 0) {
+ Status = ENCODE_ERROR ((UINTN) ReturnContext->ReturnStatus);
+ }
+
+ return Status;
}
+/**
+ If in 32 bit protection mode, and coalesce image is of X64, switch to long mode.
+
+ @param LongModeBuffer The context of long mode.
+ @param CoalesceEntry Entry of coalesce image.
+ @param BlockListAddr Address of block list.
+ @param MemoryBase Base of memory range.
+ @param MemorySize Size of memory range.
+
+ @retval EFI_SUCCESS Successfully switched to long mode and execute coalesce.
+ @retval Others Failed to execute coalesce in long mode.
+
+**/
+EFI_STATUS
+ModeSwitch (
+ IN EFI_CAPSULE_LONG_MODE_BUFFER *LongModeBuffer,
+ IN COALESCE_ENTRY CoalesceEntry,
+ IN EFI_PHYSICAL_ADDRESS BlockListAddr,
+ IN OUT VOID **MemoryBase,
+ IN OUT UINTN *MemorySize
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS MemoryBase64;
+ UINT64 MemorySize64;
+ EFI_PHYSICAL_ADDRESS MemoryEnd64;
+ SWITCH_32_TO_64_CONTEXT Context;
+ SWITCH_64_TO_32_CONTEXT ReturnContext;
+ BASE_LIBRARY_JUMP_BUFFER JumpBuffer;
+ EFI_PHYSICAL_ADDRESS ReservedRangeBase;
+ EFI_PHYSICAL_ADDRESS ReservedRangeEnd;
+
+ ZeroMem (&Context, sizeof (SWITCH_32_TO_64_CONTEXT));
+ ZeroMem (&ReturnContext, sizeof (SWITCH_64_TO_32_CONTEXT));
+
+ MemoryBase64 = (UINT64) (UINTN) *MemoryBase;
+ MemorySize64 = (UINT64) (UINTN) *MemorySize;
+ MemoryEnd64 = MemoryBase64 + MemorySize64;
+
+ //
+ // Merge memory range reserved for stack and page table
+ //
+ if (LongModeBuffer->StackBaseAddress < LongModeBuffer->PageTableAddress) {
+ ReservedRangeBase = LongModeBuffer->StackBaseAddress;
+ ReservedRangeEnd = LongModeBuffer->PageTableAddress + CalculatePageTableSize ();
+ } else {
+ ReservedRangeBase = LongModeBuffer->PageTableAddress;
+ ReservedRangeEnd = LongModeBuffer->StackBaseAddress + LongModeBuffer->StackSize;
+ }
+
+ //
+ // Check if memory range reserved is overlap with MemoryBase ~ MemoryBase + MemorySize.
+ // If they are overlapped, get a larger range to process capsule data.
+ //
+ if (ReservedRangeBase <= MemoryBase64) {
+ if (ReservedRangeEnd < MemoryEnd64) {
+ MemoryBase64 = ReservedRangeEnd;
+ } else {
+ DEBUG ((EFI_D_ERROR, "Memory is not enough to process capsule!\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else if (ReservedRangeBase < MemoryEnd64) {
+ if (ReservedRangeEnd < MemoryEnd64 &&
+ ReservedRangeBase - MemoryBase64 < MemoryEnd64 - ReservedRangeEnd) {
+ MemoryBase64 = ReservedRangeEnd;
+ } else {
+ MemorySize64 = (UINT64)(UINTN)(ReservedRangeBase - MemoryBase64);
+ }
+ }
+
+ //
+ // Initialize context jumping to 64-bit enviroment
+ //
+ Context.JumpBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)&JumpBuffer;
+ Context.StackBufferBase = LongModeBuffer->StackBaseAddress;
+ Context.StackBufferLength = LongModeBuffer->StackSize;
+ Context.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)CoalesceEntry;
+ Context.BlockListAddr = BlockListAddr;
+ Context.MemoryBase64Ptr = (EFI_PHYSICAL_ADDRESS)(UINTN)&MemoryBase64;
+ Context.MemorySize64Ptr = (EFI_PHYSICAL_ADDRESS)(UINTN)&MemorySize64;
+
+ //
+ // Prepare data for return back
+ //
+ ReturnContext.ReturnCs = 0x10;
+ ReturnContext.ReturnEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)ReturnFunction;
+ //
+ // Will save the return status of processing capsule
+ //
+ ReturnContext.ReturnStatus = 0;
+
+ //
+ // Save original GDT
+ //
+ AsmReadGdtr ((IA32_DESCRIPTOR *)&ReturnContext.Gdtr);
+
+ Status = Thunk32To64 (LongModeBuffer->PageTableAddress, &Context, &ReturnContext);
+
+ if (!EFI_ERROR (Status)) {
+ *MemoryBase = (VOID *) (UINTN) MemoryBase64;
+ *MemorySize = (UINTN) MemorySize64;
+ }
+
+ return Status;
+
+}
/**
Checks for the presence of capsule descriptors.
Get capsule descriptors from variable CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
+ and save to DescriptorBuffer.
- @param BlockList Pointer to the capsule descriptors
+ @param DescriptorBuffer Pointer to the capsule descriptors
@retval EFI_SUCCESS a valid capsule is present
@retval EFI_NOT_FOUND if a valid capsule is not present
**/
EFI_STATUS
GetCapsuleDescriptors (
- IN OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockList OPTIONAL
+ IN EFI_PHYSICAL_ADDRESS *DescriptorBuffer
)
{
EFI_STATUS Status;
@@ -157,14 +441,8 @@ GetCapsuleDescriptors (
CHAR16 CapsuleVarName[30];
CHAR16 *TempVarName;
EFI_PHYSICAL_ADDRESS CapsuleDataPtr64;
- EFI_CAPSULE_BLOCK_DESCRIPTOR *LastBlock;
- EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlock;
- EFI_CAPSULE_BLOCK_DESCRIPTOR *HeadBlock;
EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices;
- LastBlock = NULL;
- HeadBlock = NULL;
- TempBlock = NULL;
Index = 0;
TempVarName = NULL;
CapsuleVarName[0] = 0;
@@ -204,20 +482,9 @@ GetCapsuleDescriptors (
// pointer is null. In that case, return success since we know that the
// variable is set.
//
- if (BlockList == NULL) {
+ if (DescriptorBuffer == NULL) {
return EFI_SUCCESS;
}
- //
- // Test integrity of descriptors.
- //
- LastBlock = ValidateCapsuleIntegrity ((EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)CapsuleDataPtr64);
- if (LastBlock == NULL) {
- return EFI_NOT_FOUND;
- }
- //
- // Return the base of the block descriptors
- //
- HeadBlock = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)CapsuleDataPtr64;
} else {
UnicodeValueToString (TempVarName, 0, Index, 0);
Status = PPIVariableServices->GetVariable (
@@ -237,7 +504,7 @@ GetCapsuleDescriptors (
//
Flag = FALSE;
for (TempIndex = 0; TempIndex < ValidIndex; TempIndex++) {
- if (mBufferAddress[TempIndex] == CapsuleDataPtr64) {
+ if (DescriptorBuffer[TempIndex] == CapsuleDataPtr64) {
Flag = TRUE;
break;
}
@@ -246,500 +513,122 @@ GetCapsuleDescriptors (
Index ++;
continue;
}
-
- //
- // Test integrity of descriptors.
- //
- TempBlock = ValidateCapsuleIntegrity ((EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)CapsuleDataPtr64);
- if (TempBlock == NULL) {
- return EFI_NOT_FOUND;
- }
- //
- // Combine the different BlockList into single BlockList.
- //
- LastBlock->Union.DataBlock = CapsuleDataPtr64;
- LastBlock->Length = 0;
- LastBlock = TempBlock;
}
//
// Cache BlockList which has been processed
//
- mBufferAddress[ValidIndex++] = CapsuleDataPtr64;
+ DescriptorBuffer[ValidIndex++] = CapsuleDataPtr64;
Index ++;
}
}
- if (HeadBlock != NULL) {
- *BlockList = HeadBlock;
- return EFI_SUCCESS;
- }
- return EFI_NOT_FOUND;
-}
-
-/**
- Given a pointer to a capsule block descriptor, traverse the list to figure
- out how many legitimate descriptors there are, and how big the capsule it
- refers to is.
-
- @param Desc Pointer to the capsule block descriptors
- NumDescriptors - optional pointer to where to return the number of descriptors
- CapsuleSize - optional pointer to where to return the capsule size
- @param NumDescriptors Optional pointer to where to return the number of descriptors
- @param CapsuleSize Optional pointer to where to return the capsule size
-
- @retval EFI_NOT_FOUND No descriptors containing data in the list
- @retval EFI_SUCCESS Return data is valid
-**/
-EFI_STATUS
-GetCapsuleInfo (
- IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc,
- IN OUT UINTN *NumDescriptors OPTIONAL,
- IN OUT UINTN *CapsuleSize OPTIONAL
- )
-{
- UINTN Count;
- UINTN Size;
-
- ASSERT (Desc != NULL);
-
- Count = 0;
- Size = 0;
-
- while (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) {
- if (Desc->Length == 0) {
- //
- // Descriptor points to another list of block descriptors somewhere
- //
- Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer;
- } else {
- Size += (UINTN) Desc->Length;
- Count++;
- Desc++;
- }
- }
- //
- // If no descriptors, then fail
- //
- if (Count == 0) {
- return EFI_NOT_FOUND;
- }
-
- if (NumDescriptors != NULL) {
- *NumDescriptors = Count;
- }
-
- if (CapsuleSize != NULL) {
- *CapsuleSize = Size;
- }
-
return EFI_SUCCESS;
}
-
-/**
- Try to verify the integrity of a capsule test pattern before the
- capsule gets coalesced. This can be useful in narrowing down
- where capsule data corruption occurs.
-
- The test pattern mode fills in memory with a counting UINT32 value.
- If the capsule is not divided up in a multiple of 4-byte blocks, then
- things get messy doing the check. Therefore there are some cases
- here where we just give up and skip the pre-coalesce check.
-
- @param PeiServices PEI services table
- @param Desc Pointer to capsule descriptors
-**/
-VOID
-CapsuleTestPatternPreCoalesce (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc
- )
-{
- UINT32 *TestPtr;
- UINT32 TestCounter;
- UINT32 TestSize;
- //
- // Find first data descriptor
- //
- while ((Desc->Length == 0) && (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {
- Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer;
- }
-
- if (Desc->Union.ContinuationPointer == 0) {
- return ;
- }
- //
- // First one better be long enough to at least hold the test signature
- //
- if (Desc->Length < sizeof (UINT32)) {
- DEBUG ((EFI_D_INFO, "Capsule test pattern pre-coalesce punted #1\n"));
- return ;
- }
-
- TestPtr = (UINT32 *) (UINTN) Desc->Union.DataBlock;
- if (*TestPtr != CAPSULE_TEST_SIGNATURE) {
- return ;
- }
-
- TestCounter = 0;
- TestSize = (UINT32) Desc->Length - 2 * sizeof (UINT32);
- //
- // Skip over the signature and the size fields in the pattern data header
- //
- TestPtr += 2;
- while (1) {
- if ((TestSize & 0x03) != 0) {
- DEBUG ((EFI_D_INFO, "Capsule test pattern pre-coalesce punted #2\n"));
- return ;
- }
-
- while (TestSize > 0) {
- if (*TestPtr != TestCounter) {
- DEBUG ((EFI_D_INFO, "Capsule test pattern pre-coalesce failed data corruption check\n"));
- return ;
- }
-
- TestSize -= sizeof (UINT32);
- TestCounter++;
- TestPtr++;
- }
- Desc++;
- while ((Desc->Length == 0) && (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {
- Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer;
- }
-
- if (Desc->Union.ContinuationPointer == (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) {
- return ;
- }
- TestSize = (UINT32) Desc->Length;
- TestPtr = (UINT32 *) (UINTN) Desc->Union.DataBlock;
- }
-}
-
-
/**
- Determine if two buffers overlap in memory.
-
- @param Buff1 pointer to first buffer
- @param Size1 size of Buff1
- @param Buff2 pointer to second buffer
- @param Size2 size of Buff2
+ Locates the coalesce image entry point, and detects its machine type.
- @retval TRUE Buffers overlap in memory.
- @retval FALSE Buffer doesn't overlap.
-**/
-BOOLEAN
-IsOverlapped (
- UINT8 *Buff1,
- UINTN Size1,
- UINT8 *Buff2,
- UINTN Size2
- )
-{
- //
- // If buff1's end is less than the start of buff2, then it's ok.
- // Also, if buff1's start is beyond buff2's end, then it's ok.
- //
- if (((Buff1 + Size1) <= Buff2) || (Buff1 >= (Buff2 + Size2))) {
- return FALSE;
- }
+ @param CoalesceImageEntryPoint Pointer to coalesce image entry point for output.
+ @param CoalesceImageMachineType Pointer to machine type of coalesce image.
- return TRUE;
-}
+ @retval EFI_SUCCESS Coalesce image successfully located.
+ @retval Others Failed to locate the coalesce image.
-/**
- Given a pointer to the capsule block list, info on the available system
- memory, and the size of a buffer, find a free block of memory where a
- buffer of the given size can be copied to safely.
-
- @param BlockList Pointer to head of capsule block descriptors
- @param MemBase Pointer to the base of memory in which we want to find free space
- @param MemSize The size of the block of memory pointed to by MemBase
- @param DataSize How big a free block we want to find
-
- @return A pointer to a memory block of at least DataSize that lies somewhere
- between MemBase and (MemBase + MemSize). The memory pointed to does not
- contain any of the capsule block descriptors or capsule blocks pointed to
- by the BlockList.
**/
-UINT8 *
-FindFreeMem (
- EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,
- UINT8 *MemBase,
- UINTN MemSize,
- UINTN DataSize
+EFI_STATUS
+FindCapsuleCoalesceImage (
+ OUT EFI_PHYSICAL_ADDRESS *CoalesceImageEntryPoint,
+ OUT UINT16 *CoalesceImageMachineType
)
{
- UINTN Size;
- EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrDesc;
- EFI_CAPSULE_BLOCK_DESCRIPTOR *TempDesc;
- UINT8 *MemEnd;
- BOOLEAN Failed;
-
- //
- // Need at least enough to copy the data to at the end of the buffer, so
- // say the end is less the data size for easy comparisons here.
- //
- MemEnd = MemBase + MemSize - DataSize;
- CurrDesc = BlockList;
- //
- // Go through all the descriptor blocks and see if any obstruct the range
- //
- while (CurrDesc != NULL) {
- //
- // Get the size of this block list and see if it's in the way
- //
- Failed = FALSE;
- TempDesc = CurrDesc;
- Size = sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
- while (TempDesc->Length != 0) {
- Size += sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
- TempDesc++;
- }
+ EFI_STATUS Status;
+ UINTN Instance;
+ EFI_PEI_LOAD_FILE_PPI *LoadFile;
+ EFI_PEI_FV_HANDLE VolumeHandle;
+ EFI_PEI_FILE_HANDLE FileHandle;
+ EFI_PHYSICAL_ADDRESS CoalesceImageAddress;
+ UINT64 CoalesceImageSize;
+ UINT32 AuthenticationState;
- if (IsOverlapped (MemBase, DataSize, (UINT8 *) CurrDesc, Size)) {
- //
- // Set our new base to the end of this block list and start all over
- //
- MemBase = (UINT8 *) CurrDesc + Size;
- CurrDesc = BlockList;
- if (MemBase > MemEnd) {
- return NULL;
- }
+ Instance = 0;
- Failed = TRUE;
+ while (TRUE) {
+ Status = PeiServicesFfsFindNextVolume (Instance++, &VolumeHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
}
- //
- // Now go through all the blocks and make sure none are in the way
- //
- while ((CurrDesc->Length != 0) && (!Failed)) {
- if (IsOverlapped (MemBase, DataSize, (UINT8 *) (UINTN) CurrDesc->Union.DataBlock, (UINTN) CurrDesc->Length)) {
- //
- // Set our new base to the end of this block and start all over
- //
- Failed = TRUE;
- MemBase = (UINT8 *) ((UINTN) CurrDesc->Union.DataBlock) + CurrDesc->Length;
- CurrDesc = BlockList;
- if (MemBase > MemEnd) {
- return NULL;
- }
+ Status = PeiServicesFfsFindFileByName (PcdGetPtr(PcdCapsuleCoalesceFile), VolumeHandle, &FileHandle);
+ if (!EFI_ERROR (Status)) {
+ Status = PeiServicesLocatePpi (&gEfiPeiLoadFilePpiGuid, 0, NULL, (VOID **) &LoadFile);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = LoadFile->LoadFile (
+ LoadFile,
+ FileHandle,
+ &CoalesceImageAddress,
+ &CoalesceImageSize,
+ CoalesceImageEntryPoint,
+ &AuthenticationState
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Unable to find PE32 section in CapsuleRelocate image ffs %r!\n", Status));
+ return Status;
}
- CurrDesc++;
- }
- //
- // Normal continuation -- jump to next block descriptor list
- //
- if (!Failed) {
- CurrDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) CurrDesc->Union.ContinuationPointer;
+ *CoalesceImageMachineType = PeCoffLoaderGetMachineType ((VOID *) (UINTN) CoalesceImageAddress);
+ break;
+ } else {
+ continue;
}
}
- return MemBase;
+
+ return Status;
}
/**
- The capsule block descriptors may be fragmented and spread all over memory.
- To simplify the coalescing of capsule blocks, first coalesce all the
- capsule block descriptors low in memory.
+ Gets the reserved long mode buffer.
- The descriptors passed in can be fragmented throughout memory. Here
- they are relocated into memory to turn them into a contiguous (null
- terminated) array.
+ @param LongModeBuffer Pointer to the long mode buffer for output.
- @param PeiServices pointer to PEI services table
- @param BlockList pointer to the capsule block descriptors
- @param MemBase base of system memory in which we can work
- @param MemSize size of the system memory pointed to by MemBase
+ @retval EFI_SUCCESS Long mode buffer successfully retrieved.
+ @retval Others Variable storing long mode buffer not found.
- @retval NULL could not relocate the descriptors
- @retval Pointer to the base of the successfully-relocated block descriptors.
**/
-EFI_CAPSULE_BLOCK_DESCRIPTOR *
-RelocateBlockDescriptors (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,
- IN UINT8 *MemBase,
- IN UINTN MemSize
+EFI_STATUS
+GetLongModeContext (
+ OUT EFI_CAPSULE_LONG_MODE_BUFFER *LongModeBuffer
)
{
- EFI_CAPSULE_BLOCK_DESCRIPTOR *NewBlockList;
- EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrBlockDescHead;
- EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockDesc;
- EFI_CAPSULE_BLOCK_DESCRIPTOR *PrevBlockDescTail;
- UINTN NumDescriptors;
- UINTN BufferSize;
- UINT8 *RelocBuffer;
- UINTN BlockListSize;
- //
- // Get the info on the blocks and descriptors. Since we're going to move
- // the descriptors low in memory, adjust the base/size values accordingly here.
- // GetCapsuleInfo() returns the number of legit descriptors, so add one for
- // a terminator.
- //
- if (GetCapsuleInfo (BlockList, &NumDescriptors, NULL) != EFI_SUCCESS) {
- return NULL;
- }
-
- NumDescriptors++;
- BufferSize = NumDescriptors * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
- NewBlockList = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) MemBase;
- if (MemSize < BufferSize) {
- return NULL;
- }
-
- MemSize -= BufferSize;
- MemBase += BufferSize;
- //
- // Go through all the blocks and make sure none are in the way
- //
- TempBlockDesc = BlockList;
- while (TempBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) {
- if (TempBlockDesc->Length == 0) {
- //
- // Next block of descriptors
- //
- TempBlockDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer;
- } else {
- //
- // If the capsule data pointed to by this descriptor is in the way,
- // move it.
- //
- if (IsOverlapped (
- (UINT8 *) NewBlockList,
- BufferSize,
- (UINT8 *) (UINTN) TempBlockDesc->Union.DataBlock,
- (UINTN) TempBlockDesc->Length
- )) {
- //
- // Relocate the block
- //
- RelocBuffer = FindFreeMem (BlockList, MemBase, MemSize, (UINTN) TempBlockDesc->Length);
- if (RelocBuffer == NULL) {
- return NULL;
- }
-
- CopyMem ((VOID *) RelocBuffer, (VOID *) (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) TempBlockDesc->Length);
- TempBlockDesc->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocBuffer;
-
- DEBUG ((EFI_D_INFO, "Capsule relocate descriptors from/to/size 0x%X 0x%X 0x%X\n", (UINT32)(UINTN)TempBlockDesc->Union.DataBlock, (UINT32)(UINTN)RelocBuffer, (UINT32)(UINTN)TempBlockDesc->Length));
- }
- }
- TempBlockDesc++;
- }
- //
- // Now go through all the block descriptors to make sure that they're not
- // in the memory region we want to copy them to.
- //
- CurrBlockDescHead = BlockList;
- PrevBlockDescTail = NULL;
- while ((CurrBlockDescHead != NULL) && (CurrBlockDescHead->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {
- //
- // Get the size of this list then see if it overlaps our low region
- //
- TempBlockDesc = CurrBlockDescHead;
- BlockListSize = sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
- while (TempBlockDesc->Length != 0) {
- BlockListSize += sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
- TempBlockDesc++;
- }
+ EFI_STATUS Status;
+ UINTN Size;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices;
- if (IsOverlapped (
- (UINT8 *) NewBlockList,
- BufferSize,
- (UINT8 *) CurrBlockDescHead,
- BlockListSize
- )) {
- //
- // Overlaps, so move it out of the way
- //
- RelocBuffer = FindFreeMem (BlockList, MemBase, MemSize, BlockListSize);
- if (RelocBuffer == NULL) {
- return NULL;
- }
- CopyMem ((VOID *) RelocBuffer, (VOID *) CurrBlockDescHead, BlockListSize);
- DEBUG ((EFI_D_INFO, "Capsule reloc descriptor block #2\n"));
- //
- // Point the previous block's next point to this copied version. If
- // the tail pointer is null, then this is the first descriptor block.
- //
- if (PrevBlockDescTail == NULL) {
- BlockList = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) RelocBuffer;
- } else {
- PrevBlockDescTail->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocBuffer;
- }
- }
- //
- // Save our new tail and jump to the next block list
- //
- PrevBlockDescTail = TempBlockDesc;
- CurrBlockDescHead = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer;
- }
- //
- // Cleared out low memory. Now copy the descriptors down there.
- //
- TempBlockDesc = BlockList;
- CurrBlockDescHead = NewBlockList;
- while ((TempBlockDesc != NULL) && (TempBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {
- if (TempBlockDesc->Length != 0) {
- CurrBlockDescHead->Union.DataBlock = TempBlockDesc->Union.DataBlock;
- CurrBlockDescHead->Length = TempBlockDesc->Length;
- CurrBlockDescHead++;
- TempBlockDesc++;
- } else {
- TempBlockDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer;
- }
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiReadOnlyVariable2PpiGuid,
+ 0,
+ NULL,
+ (VOID **) &PPIVariableServices
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Size = sizeof (EFI_CAPSULE_LONG_MODE_BUFFER);
+ Status = PPIVariableServices->GetVariable (
+ PPIVariableServices,
+ EFI_CAPSULE_LONG_MODE_BUFFER_NAME,
+ &gEfiCapsuleVendorGuid,
+ NULL,
+ &Size,
+ LongModeBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG (( EFI_D_ERROR, "Error Get LongModeBuffer variable %r!\n", Status));
}
- //
- // Null terminate
- //
- CurrBlockDescHead->Union.ContinuationPointer = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL;
- CurrBlockDescHead->Length = 0;
- return NewBlockList;
+ return Status;
}
/**
Capsule PPI service to coalesce a fragmented capsule in memory.
- Memory Map for coalesced capsule:
- MemBase + ---->+---------------------------+<-----------+
- MemSize | CapsuleOffset[49] | |
- +---------------------------+ |
- | ................ | |
- +---------------------------+ |
- | CapsuleOffset[2] | |
- +---------------------------+ |
- | CapsuleOffset[1] | |
- +---------------------------+ |
- | CapsuleOffset[0] | CapsuleSize
- +---------------------------+ |
- | CapsuleNumber | |
- +---------------------------+ |
- | | |
- | | |
- | Capsule Image | |
- | | |
- | | |
- +---------------------------+ |
- | PrivateData | |
- DestPtr ----> +---------------------------+<-----------+
- | | |
- | FreeMem | FreeMemSize
- | | |
- FreeMemBase --->+---------------------------+<-----------+
- | Terminator |
- +---------------------------+
- | BlockDescriptor n |
- +---------------------------+
- | ................. |
- +---------------------------+
- | BlockDescriptor 1 |
- +---------------------------+
- | BlockDescriptor 0 |
- +---------------------------+
- | PrivateDataDesc 0 |
- MemBase ---->+---------------------------+<----- BlockList
-
-
@param PeiServices General purpose services available to every PEIM.
@param MemoryBase Pointer to the base of a block of memory that we can walk
all over while trying to coalesce our buffers.
@@ -768,54 +657,26 @@ CapsuleCoalesce (
IN OUT UINTN *MemorySize
)
{
- VOID *NewCapsuleBase;
- VOID *DataPtr;
- UINT8 CapsuleIndex;
- UINT8 *FreeMemBase;
- UINT8 *DestPtr;
- UINT8 *RelocPtr;
- UINT32 CapsuleOffset[MAX_SUPPORT_CAPSULE_NUM];
- UINT32 *AddDataPtr;
- UINT32 CapsuleTimes;
- UINT64 SizeLeft;
- UINT64 CapsuleImageSize;
- UINTN CapsuleSize;
- UINTN DescriptorsSize;
- UINTN FreeMemSize;
- UINTN NumDescriptors;
- UINTN Index;
- UINTN Size;
- UINTN VariableCount;
- CHAR16 CapsuleVarName[30];
- CHAR16 *TempVarName;
- EFI_PHYSICAL_ADDRESS CapsuleDataPtr64;
- BOOLEAN IsCorrupted;
- BOOLEAN CapsuleBeginFlag;
- EFI_STATUS Status;
- EFI_BOOT_MODE BootMode;
- EFI_CAPSULE_HEADER *CapsuleHeader;
- EFI_CAPSULE_PEIM_PRIVATE_DATA PrivateData;
- EFI_CAPSULE_PEIM_PRIVATE_DATA *PrivateDataPtr;
- EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList;
- EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrentBlockDesc;
- EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockDesc;
- EFI_CAPSULE_BLOCK_DESCRIPTOR PrivateDataDesc[2];
- EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices;
-
- CapsuleIndex = 0;
- SizeLeft = 0;
- CapsuleTimes = 0;
- CapsuleImageSize = 0;
- PrivateDataPtr = NULL;
- AddDataPtr = NULL;
- CapsuleHeader = NULL;
- CapsuleBeginFlag = TRUE;
- IsCorrupted = TRUE;
- CapsuleSize = 0;
- NumDescriptors = 0;
- Index = 0;
- VariableCount = 0;
- CapsuleVarName[0] = 0;
+ UINTN Index;
+ UINTN Size;
+ UINTN VariableCount;
+ CHAR16 CapsuleVarName[30];
+ CHAR16 *TempVarName;
+ EFI_PHYSICAL_ADDRESS CapsuleDataPtr64;
+ EFI_STATUS Status;
+ EFI_BOOT_MODE BootMode;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices;
+ EFI_PHYSICAL_ADDRESS *VariableArrayAddress;
+#ifdef MDE_CPU_IA32
+ UINT16 CoalesceImageMachineType;
+ EFI_PHYSICAL_ADDRESS CoalesceImageEntryPoint;
+ COALESCE_ENTRY CoalesceEntry;
+ EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer;
+#endif
+
+ Index = 0;
+ VariableCount = 0;
+ CapsuleVarName[0] = 0;
//
// Someone should have already ascertained the boot mode. If it's not
@@ -823,7 +684,9 @@ CapsuleCoalesce (
//
Status = PeiServicesGetBootMode (&BootMode);
if (EFI_ERROR (Status) || (BootMode != BOOT_ON_FLASH_UPDATE)) {
- return EFI_NOT_FOUND;
+ DEBUG ((EFI_D_ERROR, "Boot mode is not correct for capsule update path.\n"));
+ Status = EFI_NOT_FOUND;
+ goto Done;
}
//
@@ -837,7 +700,7 @@ CapsuleCoalesce (
(VOID **) &PPIVariableServices
);
if (EFI_ERROR (Status)) {
- return Status;
+ goto Done;
}
Size = sizeof (CapsuleDataPtr64);
StrCpy (CapsuleVarName, EFI_CAPSULE_VARIABLE_NAME);
@@ -858,264 +721,94 @@ CapsuleCoalesce (
//
// There is no capsule variables, quit
//
- DEBUG ((EFI_D_ERROR,"Capsule variable Index = %d\n", Index));
+ DEBUG ((EFI_D_INFO,"Capsule variable Index = %d\n", Index));
break;
}
VariableCount++;
Index++;
}
- DEBUG ((EFI_D_ERROR,"Capsule variable count = %d\n", VariableCount));
+ DEBUG ((EFI_D_INFO,"Capsule variable count = %d\n", VariableCount));
+ //
+ // The last entry is the end flag.
+ //
Status = PeiServicesAllocatePool (
- VariableCount * sizeof (EFI_PHYSICAL_ADDRESS),
- (VOID **)&mBufferAddress
+ (VariableCount + 1) * sizeof (EFI_PHYSICAL_ADDRESS),
+ (VOID **)&VariableArrayAddress
);
if (Status != EFI_SUCCESS) {
DEBUG ((EFI_D_ERROR, "AllocatePages Failed!, Status = %x\n", Status));
- return Status;
+ goto Done;
}
+ ZeroMem (VariableArrayAddress, (VariableCount + 1) * sizeof (EFI_PHYSICAL_ADDRESS));
+
//
// Find out if we actually have a capsule.
+ // GetCapsuleDescriptors depends on variable PPI, so it should run in 32-bit environment.
//
- Status = GetCapsuleDescriptors (&BlockList);
+ Status = GetCapsuleDescriptors (VariableArrayAddress);
if (EFI_ERROR (Status)) {
- return Status;
- }
-
- DEBUG_CODE (
- CapsuleTestPatternPreCoalesce (PeiServices, BlockList);
- );
-
- //
- // Get the size of our descriptors and the capsule size. GetCapsuleInfo()
- // returns the number of descriptors that actually point to data, so add
- // one for a terminator. Do that below.
- //
- GetCapsuleInfo (BlockList, &NumDescriptors, &CapsuleSize);
- if ((CapsuleSize == 0) || (NumDescriptors == 0)) {
- return EFI_NOT_FOUND;
- }
-
- //
- // Initialize our local copy of private data. When we're done, we'll create a
- // descriptor for it as well so that it can be put into free memory without
- // trashing anything.
- //
- PrivateData.Signature = EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE;
- PrivateData.CapsuleSize = CapsuleSize;
- PrivateDataDesc[0].Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) &PrivateData;
- PrivateDataDesc[0].Length = sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA);
- PrivateDataDesc[1].Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) BlockList;
- PrivateDataDesc[1].Length = 0;
- //
- // In addition to PrivateDataDesc[1:0], one terminator is added
- // See below RelocateBlockDescriptors()
- //
- NumDescriptors += 3;
- CapsuleSize += sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + sizeof(CapsuleOffset) + sizeof(UINT32);
- BlockList = PrivateDataDesc;
- DescriptorsSize = NumDescriptors * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
-
- //
- // Don't go below some min address. If the base is below it,
- // then move it up and adjust the size accordingly.
- //
- DEBUG ((EFI_D_INFO, "Capsule Memory range from 0x%8X to 0x%8X\n", (UINTN) *MemoryBase, (UINTN)*MemoryBase + *MemorySize));
- if ((UINTN)*MemoryBase < (UINTN) MIN_COALESCE_ADDR) {
- if (((UINTN)*MemoryBase + *MemorySize) < (UINTN) MIN_COALESCE_ADDR) {
- return EFI_BUFFER_TOO_SMALL;
- } else {
- *MemorySize = *MemorySize - ((UINTN) MIN_COALESCE_ADDR - (UINTN) *MemoryBase);
- *MemoryBase = (VOID *) (UINTN) MIN_COALESCE_ADDR;
- }
- }
-
- if (*MemorySize <= (CapsuleSize + DescriptorsSize)) {
- return EFI_BUFFER_TOO_SMALL;
+ DEBUG ((EFI_D_ERROR, "Fail to find capsule variables.\n"));
+ goto Done;
}
- FreeMemBase = *MemoryBase;
- FreeMemSize = *MemorySize;
- DEBUG ((EFI_D_INFO, "Capsule Free Memory from 0x%8X to 0x%8X\n", (UINTN) FreeMemBase, (UINTN) FreeMemBase + FreeMemSize));
-
- //
- // Relocate all the block descriptors to low memory to make further
- // processing easier.
- //
- BlockList = RelocateBlockDescriptors (PeiServices, BlockList, FreeMemBase, FreeMemSize);
- if (BlockList == NULL) {
+#ifdef MDE_CPU_IA32
+ if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
//
- // Not enough room to relocate the descriptors
+ // Switch to 64-bit mode to process capsule data when:
+ // 1. When DXE phase is 64-bit
+ // 2. When the buffer for 64-bit transition exists
+ // 3. When Capsule X64 image is built in BIOS image
+ // In 64-bit mode, we can process capsule data above 4GB.
//
- return EFI_BUFFER_TOO_SMALL;
- }
-
- //
- // Take the top of memory for the capsule. Naturally align.
- //
- DestPtr = FreeMemBase + FreeMemSize - CapsuleSize;
- DestPtr = (UINT8 *) ((UINTN) DestPtr &~ (UINTN) (sizeof (UINTN) - 1));
- FreeMemBase = (UINT8 *) BlockList + DescriptorsSize;
- FreeMemSize = FreeMemSize - DescriptorsSize - CapsuleSize;
- NewCapsuleBase = (VOID *) DestPtr;
-
- //
- // Move all the blocks to the top (high) of memory.
- // Relocate all the obstructing blocks. Note that the block descriptors
- // were coalesced when they were relocated, so we can just ++ the pointer.
- //
- CurrentBlockDesc = BlockList;
- while ((CurrentBlockDesc->Length != 0) || (CurrentBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {
- //
- // See if any of the remaining capsule blocks are in the way
- //
- TempBlockDesc = CurrentBlockDesc;
- while (TempBlockDesc->Length != 0) {
- //
- // Is this block in the way of where we want to copy the current descriptor to?
- //
- if (IsOverlapped (
- (UINT8 *) DestPtr,
- (UINTN) CurrentBlockDesc->Length,
- (UINT8 *) (UINTN) TempBlockDesc->Union.DataBlock,
- (UINTN) TempBlockDesc->Length
- )) {
- //
- // Relocate the block
- //
- RelocPtr = FindFreeMem (BlockList, FreeMemBase, FreeMemSize, (UINTN) TempBlockDesc->Length);
- if (RelocPtr == NULL) {
- return EFI_BUFFER_TOO_SMALL;
- }
-
- CopyMem ((VOID *) RelocPtr, (VOID *) (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) TempBlockDesc->Length);
- DEBUG ((EFI_D_INFO, "Capsule reloc data block from 0x%8X to 0x%8X with size 0x%8X\n",
- (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) RelocPtr, (UINTN) TempBlockDesc->Length));
-
- TempBlockDesc->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocPtr;
- }
- //
- // Next descriptor
- //
- TempBlockDesc++;
+ CoalesceImageEntryPoint = 0;
+ Status = GetLongModeContext (&LongModeBuffer);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Fail to find the variables for long mode context!\n"));
+ Status = EFI_NOT_FOUND;
+ goto Done;
}
- //
- // Ok, we made it through. Copy the block.
- // we just support greping one capsule from the lists of block descs list.
- //
- CapsuleTimes ++;
- //
- //Skip the first block descriptor that filled with EFI_CAPSULE_PEIM_PRIVATE_DATA
- //
- if (CapsuleTimes > 1) {
- //
- //For every capsule entry point, check its header to determine whether to relocate it.
- //If it is invalid, skip it and move on to the next capsule. If it is valid, relocate it.
- //
- if (CapsuleBeginFlag) {
- CapsuleBeginFlag = FALSE;
- CapsuleHeader = (EFI_CAPSULE_HEADER*)(UINTN)CurrentBlockDesc->Union.DataBlock;
- SizeLeft = CapsuleHeader->CapsuleImageSize;
- if (!IsCapsuleCorrupted (CapsuleHeader)) {
-
- if (CapsuleIndex > (MAX_SUPPORT_CAPSULE_NUM - 1)) {
- DEBUG ((EFI_D_ERROR, "Capsule number exceeds the max number of %d!\n", MAX_SUPPORT_CAPSULE_NUM));
- return EFI_BUFFER_TOO_SMALL;
- }
-
- //
- // Relocate this valid capsule
- //
- IsCorrupted = FALSE;
- CapsuleImageSize += SizeLeft;
- CopyMem ((VOID *) DestPtr, (VOID *) (UINTN) CurrentBlockDesc->Union.DataBlock, (UINTN) CurrentBlockDesc->Length);
- DEBUG ((EFI_D_INFO, "Capsule coalesce block no.0x%8X from 0x%8X to 0x%8X with size 0x%8X\n",CapsuleTimes,
- (UINTN)CurrentBlockDesc->Union.DataBlock, (UINTN)DestPtr, (UINTN)CurrentBlockDesc->Length));
- //
- // Cache the begin offset of this capsule
- //
- CapsuleOffset[CapsuleIndex++] = (UINT32) (UINTN) DestPtr - (UINT32)(UINTN)NewCapsuleBase - (UINT32)sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA);
- DestPtr += CurrentBlockDesc->Length;
- }
- //
- // If the current block length is greater than or equal to SizeLeft, this is the
- // start of the next capsule
- //
- if (CurrentBlockDesc->Length < SizeLeft) {
- SizeLeft -= CurrentBlockDesc->Length;
- } else {
- //
- // Start the next cycle
- //
- SizeLeft = 0;
- IsCorrupted = TRUE;
- CapsuleBeginFlag = TRUE;
- }
- } else {
- //
- //Go on relocating the current capule image.
- //
- if (CurrentBlockDesc->Length < SizeLeft) {
- if (!IsCorrupted) {
- CopyMem ((VOID *) DestPtr, (VOID *) (UINTN) (CurrentBlockDesc->Union.DataBlock), (UINTN)CurrentBlockDesc->Length);
- DEBUG ((EFI_D_INFO, "Capsule coalesce block no.0x%8X from 0x%8X to 0x%8X with size 0x%8X\n",CapsuleTimes,
- (UINTN)CurrentBlockDesc->Union.DataBlock, (UINTN)DestPtr, (UINTN)CurrentBlockDesc->Length));
- DestPtr += CurrentBlockDesc->Length;
- }
- SizeLeft -= CurrentBlockDesc->Length;
- } else {
- //
- //Here is the end of the current capsule image.
- //
- if (!IsCorrupted) {
- CopyMem ((VOID *) DestPtr, (VOID *)(UINTN)(CurrentBlockDesc->Union.DataBlock), (UINTN)CurrentBlockDesc->Length);
- DEBUG ((EFI_D_INFO, "Capsule coalesce block no.0x%8X from 0x%8X to 0x%8X with size 0x%8X\n",CapsuleTimes,
- (UINTN)CurrentBlockDesc->Union.DataBlock, (UINTN)DestPtr, (UINTN)CurrentBlockDesc->Length));
- DestPtr += CurrentBlockDesc->Length;
- }
- //
- // Start the next cycle
- //
- SizeLeft = 0;
- IsCorrupted = TRUE;
- CapsuleBeginFlag = TRUE;
- }
- }
- } else {
- //
- //The first entry is the block descriptor for EFI_CAPSULE_PEIM_PRIVATE_DATA.
- //
- CopyMem ((VOID *) DestPtr, (VOID *) (UINTN) CurrentBlockDesc->Union.DataBlock, (UINTN) CurrentBlockDesc->Length);
- DestPtr += CurrentBlockDesc->Length;
+
+ Status = FindCapsuleCoalesceImage (&CoalesceImageEntryPoint, &CoalesceImageMachineType);
+ if ((EFI_ERROR (Status)) || (CoalesceImageMachineType != EFI_IMAGE_MACHINE_X64)) {
+ DEBUG ((EFI_D_ERROR, "Fail to find CapsuleX64 module in FV!\n"));
+ Status = EFI_NOT_FOUND;
+ goto Done;
}
+ ASSERT (CoalesceImageEntryPoint != 0);
+ CoalesceEntry = (COALESCE_ENTRY) (UINTN) CoalesceImageEntryPoint;
+ Status = ModeSwitch (&LongModeBuffer, CoalesceEntry, (EFI_PHYSICAL_ADDRESS)(UINTN)VariableArrayAddress, MemoryBase, MemorySize);
+ } else {
//
- //Walk through the block descriptor list.
+ // Capsule is processed in IA32 mode.
//
- CurrentBlockDesc++;
+ Status = CapsuleDataCoalesce (PeiServices, (EFI_PHYSICAL_ADDRESS *)(UINTN)VariableArrayAddress, MemoryBase, MemorySize);
}
+#else
//
- // We return the base of memory we want reserved, and the size.
- // The memory peim should handle it appropriately from there.
+ // Process capsule directly.
//
- *MemorySize = (UINTN) CapsuleImageSize;
- *MemoryBase = (VOID *) NewCapsuleBase;
-
- //
- //Append the offsets of mutiply capsules to the continous buffer
- //
- DataPtr = (VOID*)((UINTN)NewCapsuleBase + sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA) + (UINTN)CapsuleImageSize);
- AddDataPtr = (UINT32*)(((UINTN) DataPtr + sizeof(UINT32) - 1) &~ (UINT32) (sizeof (UINT32) - 1));
-
- *AddDataPtr++ = CapsuleIndex;
-
- CopyMem (AddDataPtr, &CapsuleOffset[0], sizeof (UINT32) * CapsuleIndex);
+ Status = CapsuleDataCoalesce (PeiServices, (EFI_PHYSICAL_ADDRESS *)(UINTN)VariableArrayAddress, MemoryBase, MemorySize);
+#endif
+
+ DEBUG ((EFI_D_INFO, "Capsule Coalesce Status = %r!\n", Status));
- PrivateDataPtr = (EFI_CAPSULE_PEIM_PRIVATE_DATA *) NewCapsuleBase;
- PrivateDataPtr->CapsuleSize = (UINTN)CapsuleImageSize;
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ DEBUG ((EFI_D_ERROR, "There is not enough memory to process capsule!\n"));
+ }
+
+ if (Status == EFI_NOT_FOUND) {
+ DEBUG ((EFI_D_ERROR, "Fail to parse capsule descriptor in memory!\n"));
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MAJOR,
+ (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_INVALID_CAPSULE_DESCRIPTOR)
+ );
+ }
+Done:
return Status;
}
@@ -1168,7 +861,10 @@ CapsuleTestPattern (
// is, then test it now.
//
TestPtr = (UINT32 *) CapsuleBase;
- if (*TestPtr == CAPSULE_TEST_SIGNATURE) {
+ //
+ // 0x54534554 "TEST"
+ //
+ if (*TestPtr == 0x54534554) {
RetValue = TRUE;
DEBUG ((EFI_D_INFO, "Capsule test pattern mode activated...\n"));
TestSize = TestPtr[1] / sizeof (UINT32);
diff --git a/MdeModulePkg/Universal/CapsulePei/X64/X64Entry.c b/MdeModulePkg/Universal/CapsulePei/X64/X64Entry.c
new file mode 100644
index 0000000000..c64fe1017c
--- /dev/null
+++ b/MdeModulePkg/Universal/CapsulePei/X64/X64Entry.c
@@ -0,0 +1,66 @@
+/** @file
+ The X64 entrypoint is used to process capsule in long mode.
+
+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 <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include "CommonHeader.h"
+
+/**
+ The X64 entrypoint is used to process capsule in long mode then
+ return to 32-bit protected mode.
+
+ @param EntrypointContext Pointer to the context of long mode.
+ @param ReturnContext Pointer to the context of 32-bit protected mode.
+
+ @retval This function should never return actually.
+
+**/
+EFI_STATUS
+EFIAPI
+_ModuleEntryPoint (
+ SWITCH_32_TO_64_CONTEXT *EntrypointContext,
+ SWITCH_64_TO_32_CONTEXT *ReturnContext
+)
+{
+ EFI_STATUS Status;
+
+ //
+ // Call CapsuleDataCoalesce to process capsule.
+ //
+ Status = CapsuleDataCoalesce (
+ NULL,
+ (EFI_PHYSICAL_ADDRESS *) (UINTN) EntrypointContext->BlockListAddr,
+ (VOID **) (UINTN) EntrypointContext->MemoryBase64Ptr,
+ (UINTN *) (UINTN) EntrypointContext->MemorySize64Ptr
+ );
+
+ ReturnContext->ReturnStatus = Status;
+
+ //
+ // Finish to coalesce capsule, and return to 32-bit mode.
+ //
+ AsmDisablePaging64 (
+ ReturnContext->ReturnCs,
+ (UINT32) ReturnContext->ReturnEntryPoint,
+ (UINT32) (UINTN) EntrypointContext,
+ (UINT32) (UINTN) ReturnContext,
+ (UINT32) (EntrypointContext->StackBufferBase + EntrypointContext->StackBufferLength)
+ );
+
+ //
+ // Should never be here.
+ //
+ ASSERT (FALSE);
+ return EFI_SUCCESS;
+} \ No newline at end of file