X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FUniversal%2FCapsulePei%2FUefiCapsule.c;h=36b04e34064b1caec15d86b4fffb23e9bb6532af;hp=6b934c9e3c91408b39b41d50eb8fecef2a6effd0;hb=9d510e61fceee7b92955ef9a3c20343752d8ce3f;hpb=09d469952352f53df741a903a3f154360f38b8ca diff --git a/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c b/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c index 6b934c9e3c..36b04e3406 100644 --- a/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c +++ b/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c @@ -1,16 +1,10 @@ /** @file Capsule update PEIM for UEFI2.0 -Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2017, AMD Incorporated. All rights reserved.
-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. +SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -41,25 +35,21 @@ GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR mGdt = { (UINTN) mGdtEntries }; + /** - Calculate the total size of page table. - - @return The size of page table. - - + The function will check if 1G page is supported. + + @retval TRUE 1G page is supported. + @retval FALSE 1G page is not supported. + **/ -UINTN -CalculatePageTableSize ( +BOOLEAN +IsPage1GSupport ( VOID ) { UINT32 RegEax; UINT32 RegEdx; - UINTN TotalPagesNum; - UINT8 PhysicalAddressBits; - VOID *Hob; - UINT32 NumberOfPml4EntriesNeeded; - UINT32 NumberOfPdpEntriesNeeded; BOOLEAN Page1GSupport; Page1GSupport = FALSE; @@ -73,29 +63,34 @@ CalculatePageTableSize ( } } - // - // Get physical address bits supported. - // - Hob = GetFirstHob (EFI_HOB_TYPE_CPU); - if (Hob != NULL) { - PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace; - } else { - AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); - if (RegEax >= 0x80000008) { - AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); - PhysicalAddressBits = (UINT8) RegEax; - } else { - PhysicalAddressBits = 36; - } - } + return Page1GSupport; +} + +/** + Calculate the total size of page table. + + @param[in] Page1GSupport 1G page support or not. + + @return The size of page table. + +**/ +UINTN +CalculatePageTableSize ( + IN BOOLEAN Page1GSupport + ) +{ + UINTN ExtraPageTablePages; + UINTN TotalPagesNum; + UINT8 PhysicalAddressBits; + UINT32 NumberOfPml4EntriesNeeded; + UINT32 NumberOfPdpEntriesNeeded; // - // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses. + // Create 4G page table by default, + // and let PF handler to handle > 4G request. // - ASSERT (PhysicalAddressBits <= 52); - if (PhysicalAddressBits > 48) { - PhysicalAddressBits = 48; - } + PhysicalAddressBits = 32; + ExtraPageTablePages = EXTRA_PAGE_TABLE_PAGES; // // Calculate the table entries needed. @@ -113,24 +108,25 @@ CalculatePageTableSize ( } else { TotalPagesNum = NumberOfPml4EntriesNeeded + 1; } + TotalPagesNum += ExtraPageTablePages; return EFI_PAGES_TO_SIZE (TotalPagesNum); } /** Allocates and fills in the Page Directory and Page Table Entries to - establish a 1:1 Virtual to Physical mapping. + establish a 4G page table. - @param[in] PageTablesAddress The base address of page table. + @param[in] PageTablesAddress The base address of page table. + @param[in] Page1GSupport 1G page support or not. **/ VOID -CreateIdentityMappingPageTables ( - IN EFI_PHYSICAL_ADDRESS PageTablesAddress +Create4GPageTables ( + IN EFI_PHYSICAL_ADDRESS PageTablesAddress, + IN BOOLEAN Page1GSupport ) -{ - UINT32 RegEax; - UINT32 RegEdx; +{ UINT8 PhysicalAddressBits; EFI_PHYSICAL_ADDRESS PageAddress; UINTN IndexOfPml4Entries; @@ -143,42 +139,19 @@ CreateIdentityMappingPageTables ( PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry; PAGE_TABLE_ENTRY *PageDirectoryEntry; UINTN BigPageAddress; - VOID *Hob; - BOOLEAN Page1GSupport; PAGE_TABLE_1G_ENTRY *PageDirectory1GEntry; - - Page1GSupport = FALSE; - AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); - if (RegEax >= 0x80000001) { - AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx); - if ((RegEdx & BIT26) != 0) { - Page1GSupport = TRUE; - } - } + UINT64 AddressEncMask; // - // Get physical address bits supported. + // Make sure AddressEncMask is contained to smallest supported address field. // - Hob = GetFirstHob (EFI_HOB_TYPE_CPU); - if (Hob != NULL) { - PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace; - } else { - AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); - if (RegEax >= 0x80000008) { - AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); - PhysicalAddressBits = (UINT8) RegEax; - } else { - PhysicalAddressBits = 36; - } - } + AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64; // - // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses. + // Create 4G page table by default, + // and let PF handler to handle > 4G request. // - ASSERT (PhysicalAddressBits <= 52); - if (PhysicalAddressBits > 48) { - PhysicalAddressBits = 48; - } + PhysicalAddressBits = 32; // // Calculate the table entries needed. @@ -192,7 +165,7 @@ CreateIdentityMappingPageTables ( } // - // Pre-allocate big pages to avoid later allocations. + // Pre-allocate big pages to avoid later allocations. // BigPageAddress = (UINTN) PageTablesAddress; @@ -215,18 +188,18 @@ CreateIdentityMappingPageTables ( // // Make a PML4 Entry // - PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry; + PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry | AddressEncMask; PageMapLevel4Entry->Bits.ReadWrite = 1; PageMapLevel4Entry->Bits.Present = 1; if (Page1GSupport) { PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry; - + for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) { // // Fill in the Page Directory entries // - PageDirectory1GEntry->Uint64 = (UINT64)PageAddress; + PageDirectory1GEntry->Uint64 = (UINT64)PageAddress | AddressEncMask; PageDirectory1GEntry->Bits.ReadWrite = 1; PageDirectory1GEntry->Bits.Present = 1; PageDirectory1GEntry->Bits.MustBe1 = 1; @@ -236,14 +209,14 @@ CreateIdentityMappingPageTables ( // // 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 += SIZE_4KB; // // Fill in a Page Directory Pointer Entries // - PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry; + PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry | AddressEncMask; PageDirectoryPointerEntry->Bits.ReadWrite = 1; PageDirectoryPointerEntry->Bits.Present = 1; @@ -251,7 +224,7 @@ CreateIdentityMappingPageTables ( // // Fill in the Page Directory entries // - PageDirectoryEntry->Uint64 = (UINT64)PageAddress; + PageDirectoryEntry->Uint64 = (UINT64)PageAddress | AddressEncMask; PageDirectoryEntry->Bits.ReadWrite = 1; PageDirectoryEntry->Bits.Present = 1; PageDirectoryEntry->Bits.MustBe1 = 1; @@ -290,20 +263,20 @@ 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); } @@ -335,10 +308,10 @@ Thunk32To64 ( if (SetJumpFlag == 0) { // - // Build Page Tables for all physical memory processor supports + // Build 4G Page Tables. // - CreateIdentityMappingPageTables (PageTableAddress); - + Create4GPageTables (PageTableAddress, Context->Page1GSupport); + // // Create 64-bit GDT // @@ -349,6 +322,14 @@ Thunk32To64 ( // AsmWriteCr3 ((UINTN) PageTableAddress); + DEBUG (( + DEBUG_INFO, + "%a() Stack Base: 0x%lx, Stack Size: 0x%lx\n", + __FUNCTION__, + Context->StackBufferBase, + Context->StackBufferLength + )); + // // Disable interrupt of Debug timer, since the IDT table cannot work in long mode // @@ -364,7 +345,7 @@ Thunk32To64 ( Context->StackBufferBase + Context->StackBufferLength ); } - + // // Convert to 32-bit Status and return // @@ -372,7 +353,7 @@ Thunk32To64 ( if ((UINTN) ReturnContext->ReturnStatus != 0) { Status = ENCODE_ERROR ((UINTN) ReturnContext->ReturnStatus); } - + return Status; } @@ -382,6 +363,7 @@ Thunk32To64 ( @param LongModeBuffer The context of long mode. @param CoalesceEntry Entry of coalesce image. @param BlockListAddr Address of block list. + @param MemoryResource Pointer to the buffer of memory resource descriptor. @param MemoryBase Base of memory range. @param MemorySize Size of memory range. @@ -394,6 +376,7 @@ ModeSwitch ( IN EFI_CAPSULE_LONG_MODE_BUFFER *LongModeBuffer, IN COALESCE_ENTRY CoalesceEntry, IN EFI_PHYSICAL_ADDRESS BlockListAddr, + IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource, IN OUT VOID **MemoryBase, IN OUT UINTN *MemorySize ) @@ -407,25 +390,28 @@ ModeSwitch ( BASE_LIBRARY_JUMP_BUFFER JumpBuffer; EFI_PHYSICAL_ADDRESS ReservedRangeBase; EFI_PHYSICAL_ADDRESS ReservedRangeEnd; + BOOLEAN Page1GSupport; 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; + Page1GSupport = IsPage1GSupport (); + // - // Merge memory range reserved for stack and page table + // Merge memory range reserved for stack and page table // if (LongModeBuffer->StackBaseAddress < LongModeBuffer->PageTableAddress) { ReservedRangeBase = LongModeBuffer->StackBaseAddress; - ReservedRangeEnd = LongModeBuffer->PageTableAddress + CalculatePageTableSize (); + ReservedRangeEnd = LongModeBuffer->PageTableAddress + CalculatePageTableSize (Page1GSupport); } 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. @@ -444,8 +430,8 @@ ModeSwitch ( } else { MemorySize64 = (UINT64)(UINTN)(ReservedRangeBase - MemoryBase64); } - } - + } + // // Initialize context jumping to 64-bit enviroment // @@ -454,8 +440,11 @@ ModeSwitch ( Context.StackBufferLength = LongModeBuffer->StackSize; Context.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)CoalesceEntry; Context.BlockListAddr = BlockListAddr; + Context.MemoryResource = (EFI_PHYSICAL_ADDRESS)(UINTN)MemoryResource; Context.MemoryBase64Ptr = (EFI_PHYSICAL_ADDRESS)(UINTN)&MemoryBase64; Context.MemorySize64Ptr = (EFI_PHYSICAL_ADDRESS)(UINTN)&MemorySize64; + Context.Page1GSupport = Page1GSupport; + Context.AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64; // // Prepare data for return back @@ -466,14 +455,14 @@ ModeSwitch ( // 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; @@ -529,7 +518,7 @@ FindCapsuleCoalesceImage ( &AuthenticationState ); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "Unable to find PE32 section in CapsuleRelocate image ffs %r!\n", Status)); + DEBUG ((EFI_D_ERROR, "Unable to find PE32 section in CapsuleX64 image ffs %r!\n", Status)); return Status; } *CoalesceImageMachineType = PeCoffLoaderGetMachineType ((VOID *) (UINTN) CoalesceImageAddress); @@ -542,8 +531,265 @@ FindCapsuleCoalesceImage ( return Status; } +/** + Gets the reserved long mode buffer. + + @param LongModeBuffer Pointer to the long mode buffer for output. + + @retval EFI_SUCCESS Long mode buffer successfully retrieved. + @retval Others Variable storing long mode buffer not found. + +**/ +EFI_STATUS +GetLongModeContext ( + OUT EFI_CAPSULE_LONG_MODE_BUFFER *LongModeBuffer + ) +{ + EFI_STATUS Status; + UINTN Size; + EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices; + + 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)); + } + return Status; +} #endif +#if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64) +/** + Get physical address bits. + + @return Physical address bits. + +**/ +UINT8 +GetPhysicalAddressBits ( + VOID + ) +{ + UINT32 RegEax; + UINT8 PhysicalAddressBits; + VOID *Hob; + + // + // Get physical address bits supported. + // + Hob = GetFirstHob (EFI_HOB_TYPE_CPU); + if (Hob != NULL) { + PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace; + } else { + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); + if (RegEax >= 0x80000008) { + AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); + PhysicalAddressBits = (UINT8) RegEax; + } else { + PhysicalAddressBits = 36; + } + } + + // + // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses. + // + ASSERT (PhysicalAddressBits <= 52); + if (PhysicalAddressBits > 48) { + PhysicalAddressBits = 48; + } + + return PhysicalAddressBits; +} +#endif + +/** + Sort memory resource entries based upon PhysicalStart, from low to high. + + @param[in, out] MemoryResource A pointer to the memory resource entry buffer. + +**/ +VOID +SortMemoryResourceDescriptor ( + IN OUT MEMORY_RESOURCE_DESCRIPTOR *MemoryResource + ) +{ + MEMORY_RESOURCE_DESCRIPTOR *MemoryResourceEntry; + MEMORY_RESOURCE_DESCRIPTOR *NextMemoryResourceEntry; + MEMORY_RESOURCE_DESCRIPTOR TempMemoryResource; + + MemoryResourceEntry = MemoryResource; + NextMemoryResourceEntry = MemoryResource + 1; + while (MemoryResourceEntry->ResourceLength != 0) { + while (NextMemoryResourceEntry->ResourceLength != 0) { + if (MemoryResourceEntry->PhysicalStart > NextMemoryResourceEntry->PhysicalStart) { + CopyMem (&TempMemoryResource, MemoryResourceEntry, sizeof (MEMORY_RESOURCE_DESCRIPTOR)); + CopyMem (MemoryResourceEntry, NextMemoryResourceEntry, sizeof (MEMORY_RESOURCE_DESCRIPTOR)); + CopyMem (NextMemoryResourceEntry, &TempMemoryResource, sizeof (MEMORY_RESOURCE_DESCRIPTOR)); + } + + NextMemoryResourceEntry = NextMemoryResourceEntry + 1; + } + + MemoryResourceEntry = MemoryResourceEntry + 1; + NextMemoryResourceEntry = MemoryResourceEntry + 1; + } +} + +/** + Merge continous memory resource entries. + + @param[in, out] MemoryResource A pointer to the memory resource entry buffer. + +**/ +VOID +MergeMemoryResourceDescriptor ( + IN OUT MEMORY_RESOURCE_DESCRIPTOR *MemoryResource + ) +{ + MEMORY_RESOURCE_DESCRIPTOR *MemoryResourceEntry; + MEMORY_RESOURCE_DESCRIPTOR *NewMemoryResourceEntry; + MEMORY_RESOURCE_DESCRIPTOR *NextMemoryResourceEntry; + MEMORY_RESOURCE_DESCRIPTOR *MemoryResourceEnd; + + MemoryResourceEntry = MemoryResource; + NewMemoryResourceEntry = MemoryResource; + while (MemoryResourceEntry->ResourceLength != 0) { + CopyMem (NewMemoryResourceEntry, MemoryResourceEntry, sizeof (MEMORY_RESOURCE_DESCRIPTOR)); + NextMemoryResourceEntry = MemoryResourceEntry + 1; + + while ((NextMemoryResourceEntry->ResourceLength != 0) && + (NextMemoryResourceEntry->PhysicalStart == (MemoryResourceEntry->PhysicalStart + MemoryResourceEntry->ResourceLength))) { + MemoryResourceEntry->ResourceLength += NextMemoryResourceEntry->ResourceLength; + if (NewMemoryResourceEntry != MemoryResourceEntry) { + NewMemoryResourceEntry->ResourceLength += NextMemoryResourceEntry->ResourceLength; + } + + NextMemoryResourceEntry = NextMemoryResourceEntry + 1; + } + + MemoryResourceEntry = NextMemoryResourceEntry; + NewMemoryResourceEntry = NewMemoryResourceEntry + 1; + } + + // + // Set NULL terminate memory resource descriptor after merging. + // + MemoryResourceEnd = NewMemoryResourceEntry; + ZeroMem (MemoryResourceEnd, sizeof (MEMORY_RESOURCE_DESCRIPTOR)); +} + +/** + Build memory resource descriptor from resource descriptor in HOB list. + + @return Pointer to the buffer of memory resource descriptor. + NULL if no memory resource descriptor reported in HOB list + before capsule Coalesce. + +**/ +MEMORY_RESOURCE_DESCRIPTOR * +BuildMemoryResourceDescriptor ( + VOID + ) +{ + EFI_PEI_HOB_POINTERS Hob; + UINTN Index; + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor; + MEMORY_RESOURCE_DESCRIPTOR *MemoryResource; + EFI_STATUS Status; + + // + // Get the count of memory resource descriptor. + // + Index = 0; + Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR); + while (Hob.Raw != NULL) { + ResourceDescriptor = (EFI_HOB_RESOURCE_DESCRIPTOR *) Hob.Raw; + if (ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) { + Index++; + } + Hob.Raw = GET_NEXT_HOB (Hob); + Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw); + } + + if (Index == 0) { + DEBUG ((EFI_D_INFO | EFI_D_WARN, "No memory resource descriptor reported in HOB list before capsule Coalesce\n")); +#if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64) + // + // Allocate memory to hold memory resource descriptor, + // include extra one NULL terminate memory resource descriptor. + // + Status = PeiServicesAllocatePool ((1 + 1) * sizeof (MEMORY_RESOURCE_DESCRIPTOR), (VOID **) &MemoryResource); + ASSERT_EFI_ERROR (Status); + ZeroMem (MemoryResource, (1 + 1) * sizeof (MEMORY_RESOURCE_DESCRIPTOR)); + + MemoryResource[0].PhysicalStart = 0; + MemoryResource[0].ResourceLength = LShiftU64 (1, GetPhysicalAddressBits ()); + DEBUG ((EFI_D_INFO, "MemoryResource[0x0] - Start(0x%0lx) Length(0x%0lx)\n", + MemoryResource[0x0].PhysicalStart, MemoryResource[0x0].ResourceLength)); + return MemoryResource; +#else + return NULL; +#endif + } + + // + // Allocate memory to hold memory resource descriptor, + // include extra one NULL terminate memory resource descriptor. + // + Status = PeiServicesAllocatePool ((Index + 1) * sizeof (MEMORY_RESOURCE_DESCRIPTOR), (VOID **) &MemoryResource); + ASSERT_EFI_ERROR (Status); + ZeroMem (MemoryResource, (Index + 1) * sizeof (MEMORY_RESOURCE_DESCRIPTOR)); + + // + // Get the content of memory resource descriptor. + // + Index = 0; + Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR); + while (Hob.Raw != NULL) { + ResourceDescriptor = (EFI_HOB_RESOURCE_DESCRIPTOR *) Hob.Raw; + if (ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) { + DEBUG ((EFI_D_INFO, "MemoryResource[0x%x] - Start(0x%0lx) Length(0x%0lx)\n", + Index, ResourceDescriptor->PhysicalStart, ResourceDescriptor->ResourceLength)); + MemoryResource[Index].PhysicalStart = ResourceDescriptor->PhysicalStart; + MemoryResource[Index].ResourceLength = ResourceDescriptor->ResourceLength; + Index++; + } + Hob.Raw = GET_NEXT_HOB (Hob); + Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw); + } + + SortMemoryResourceDescriptor (MemoryResource); + MergeMemoryResourceDescriptor (MemoryResource); + + DEBUG ((DEBUG_INFO, "Dump MemoryResource[] after sorted and merged\n")); + for (Index = 0; MemoryResource[Index].ResourceLength != 0; Index++) { + DEBUG (( + DEBUG_INFO, + " MemoryResource[0x%x] - Start(0x%0lx) Length(0x%0lx)\n", + Index, + MemoryResource[Index].PhysicalStart, + MemoryResource[Index].ResourceLength + )); + } + + return MemoryResource; +} + /** Checks for the presence of capsule descriptors. Get capsule descriptors from variable CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2... @@ -575,7 +821,7 @@ GetCapsuleDescriptors ( CapsuleVarName[0] = 0; ValidIndex = 0; CapsuleDataPtr64 = 0; - + Status = PeiServicesLocatePpi ( &gEfiPeiReadOnlyVariable2PpiGuid, 0, @@ -583,7 +829,7 @@ GetCapsuleDescriptors ( (VOID **) &PPIVariableServices ); if (Status == EFI_SUCCESS) { - StrCpy (CapsuleVarName, EFI_CAPSULE_VARIABLE_NAME); + StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16), EFI_CAPSULE_VARIABLE_NAME); TempVarName = CapsuleVarName + StrLen (CapsuleVarName); Size = sizeof (CapsuleDataPtr64); while (1) { @@ -600,7 +846,7 @@ GetCapsuleDescriptors ( (VOID *) &CapsuleDataPtr64 ); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "Capsule -- capsule variable not set\n")); + DEBUG ((DEBUG_INFO, "Capsule -- capsule variable not set\n")); return EFI_NOT_FOUND; } // @@ -614,7 +860,13 @@ GetCapsuleDescriptors ( return EFI_SUCCESS; } } else { - UnicodeValueToString (TempVarName, 0, Index, 0); + UnicodeValueToStringS ( + TempVarName, + sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName), + 0, + Index, + 0 + ); Status = PPIVariableServices->GetVariable ( PPIVariableServices, CapsuleVarName, @@ -626,7 +878,7 @@ GetCapsuleDescriptors ( if (EFI_ERROR (Status)) { break; } - + // // If this BlockList has been linked before, skip this variable // @@ -642,7 +894,7 @@ GetCapsuleDescriptors ( continue; } } - + // // Cache BlockList which has been processed // @@ -650,49 +902,8 @@ GetCapsuleDescriptors ( Index ++; } } - - return EFI_SUCCESS; -} - -/** - Gets the reserved long mode buffer. - - @param LongModeBuffer Pointer to the long mode buffer for output. - - @retval EFI_SUCCESS Long mode buffer successfully retrieved. - @retval Others Variable storing long mode buffer not found. - -**/ -EFI_STATUS -GetLongModeContext ( - OUT EFI_CAPSULE_LONG_MODE_BUFFER *LongModeBuffer - ) -{ - EFI_STATUS Status; - UINTN Size; - EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices; - - 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)); - } - return Status; + return EFI_SUCCESS; } /** @@ -731,11 +942,12 @@ CapsuleCoalesce ( UINTN VariableCount; CHAR16 CapsuleVarName[30]; CHAR16 *TempVarName; - EFI_PHYSICAL_ADDRESS CapsuleDataPtr64; + EFI_PHYSICAL_ADDRESS CapsuleDataPtr64; EFI_STATUS Status; EFI_BOOT_MODE BootMode; EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices; EFI_PHYSICAL_ADDRESS *VariableArrayAddress; + MEMORY_RESOURCE_DESCRIPTOR *MemoryResource; #ifdef MDE_CPU_IA32 UINT16 CoalesceImageMachineType; EFI_PHYSICAL_ADDRESS CoalesceImageEntryPoint; @@ -754,11 +966,11 @@ CapsuleCoalesce ( // Status = PeiServicesGetBootMode (&BootMode); if (EFI_ERROR (Status) || (BootMode != BOOT_ON_FLASH_UPDATE)) { - DEBUG ((EFI_D_ERROR, "Boot mode is not correct for capsule update path.\n")); + DEBUG ((EFI_D_ERROR, "Boot mode is not correct for capsule update path.\n")); Status = EFI_NOT_FOUND; goto Done; } - + // // User may set the same ScatterGatherList with several different variables, // so cache all ScatterGatherList for check later. @@ -773,11 +985,17 @@ CapsuleCoalesce ( goto Done; } Size = sizeof (CapsuleDataPtr64); - StrCpy (CapsuleVarName, EFI_CAPSULE_VARIABLE_NAME); + StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16), EFI_CAPSULE_VARIABLE_NAME); TempVarName = CapsuleVarName + StrLen (CapsuleVarName); while (TRUE) { if (Index > 0) { - UnicodeValueToString (TempVarName, 0, Index, 0); + UnicodeValueToStringS ( + TempVarName, + sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName), + 0, + Index, + 0 + ); } Status = PPIVariableServices->GetVariable ( PPIVariableServices, @@ -797,9 +1015,9 @@ CapsuleCoalesce ( VariableCount++; Index++; } - + DEBUG ((EFI_D_INFO,"Capsule variable count = %d\n", VariableCount)); - + // // The last entry is the end flag. // @@ -812,9 +1030,9 @@ CapsuleCoalesce ( DEBUG ((EFI_D_ERROR, "AllocatePages Failed!, Status = %x\n", 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. @@ -825,6 +1043,8 @@ CapsuleCoalesce ( goto Done; } + MemoryResource = BuildMemoryResourceDescriptor (); + #ifdef MDE_CPU_IA32 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { // @@ -837,11 +1057,11 @@ CapsuleCoalesce ( CoalesceImageEntryPoint = 0; Status = GetLongModeContext (&LongModeBuffer); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "Fail to find the variables for long mode context!\n")); + DEBUG ((EFI_D_ERROR, "Fail to find the variable for long mode context!\n")); Status = EFI_NOT_FOUND; goto Done; } - + 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")); @@ -850,26 +1070,26 @@ CapsuleCoalesce ( } ASSERT (CoalesceImageEntryPoint != 0); CoalesceEntry = (COALESCE_ENTRY) (UINTN) CoalesceImageEntryPoint; - Status = ModeSwitch (&LongModeBuffer, CoalesceEntry, (EFI_PHYSICAL_ADDRESS)(UINTN)VariableArrayAddress, MemoryBase, MemorySize); + Status = ModeSwitch (&LongModeBuffer, CoalesceEntry, (EFI_PHYSICAL_ADDRESS)(UINTN)VariableArrayAddress, MemoryResource, MemoryBase, MemorySize); } else { // // Capsule is processed in IA32 mode. // - Status = CapsuleDataCoalesce (PeiServices, (EFI_PHYSICAL_ADDRESS *)(UINTN)VariableArrayAddress, MemoryBase, MemorySize); + Status = CapsuleDataCoalesce (PeiServices, (EFI_PHYSICAL_ADDRESS *)(UINTN)VariableArrayAddress, MemoryResource, MemoryBase, MemorySize); } #else // // Process capsule directly. // - Status = CapsuleDataCoalesce (PeiServices, (EFI_PHYSICAL_ADDRESS *)(UINTN)VariableArrayAddress, MemoryBase, MemorySize); + Status = CapsuleDataCoalesce (PeiServices, (EFI_PHYSICAL_ADDRESS *)(UINTN)VariableArrayAddress, MemoryResource, MemoryBase, MemorySize); #endif - + DEBUG ((EFI_D_INFO, "Capsule Coalesce Status = %r!\n", Status)); 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 ( @@ -902,9 +1122,9 @@ CheckCapsuleUpdate ( return Status; } /** - This function will look at a capsule and determine if it's a test pattern. + This function will look at a capsule and determine if it's a test pattern. If it is, then it will verify it and emit an error message if corruption is detected. - + @param PeiServices Standard pei services pointer @param CapsuleBase Base address of coalesced capsule, which is preceeded by private data. Very implementation specific. @@ -993,7 +1213,7 @@ CreateState ( UINT32 Index; EFI_PHYSICAL_ADDRESS BaseAddress; UINT64 Length; - + PrivateData = (EFI_CAPSULE_PEIM_PRIVATE_DATA *) CapsuleBase; if (PrivateData->Signature != EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE) { return EFI_VOLUME_CORRUPTED; @@ -1031,7 +1251,7 @@ CreateState ( CopyMem ((VOID *) (UINTN) NewBuffer, (VOID *) (UINTN) ((UINT8 *)PrivateData + sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64)), Size); // // Check for test data pattern. If it is the test pattern, then we'll - // test it ans still create the HOB so that it can be used to verify + // test it and still create the HOB so that it can be used to verify // that capsules don't get corrupted all the way into BDS. BDS will // still try to turn it into a firmware volume, but will think it's // corrupted so nothing will happen. @@ -1049,7 +1269,7 @@ CreateState ( BuildCvHob (BaseAddress, Length); } - + return EFI_SUCCESS; }