/** @file\r
Capsule update PEIM for UEFI2.0\r
\r
-Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>\r
\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions\r
-of the BSD License which accompanies this distribution. The\r
-full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
(UINTN) mGdtEntries\r
};\r
\r
+\r
/**\r
The function will check if 1G page is supported.\r
\r
IN EFI_PHYSICAL_ADDRESS PageTablesAddress,\r
IN BOOLEAN Page1GSupport\r
)\r
-{ \r
+{\r
UINT8 PhysicalAddressBits;\r
EFI_PHYSICAL_ADDRESS PageAddress;\r
UINTN IndexOfPml4Entries;\r
PAGE_TABLE_ENTRY *PageDirectoryEntry;\r
UINTN BigPageAddress;\r
PAGE_TABLE_1G_ENTRY *PageDirectory1GEntry;\r
+ UINT64 AddressEncMask;\r
+\r
+ //\r
+ // Make sure AddressEncMask is contained to smallest supported address field.\r
+ //\r
+ AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;\r
\r
//\r
// Create 4G page table by default,\r
}\r
\r
//\r
- // Pre-allocate big pages to avoid later allocations. \r
+ // Pre-allocate big pages to avoid later allocations.\r
//\r
BigPageAddress = (UINTN) PageTablesAddress;\r
\r
//\r
// Make a PML4 Entry\r
//\r
- PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry;\r
+ PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry | AddressEncMask;\r
PageMapLevel4Entry->Bits.ReadWrite = 1;\r
PageMapLevel4Entry->Bits.Present = 1;\r
\r
if (Page1GSupport) {\r
PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;\r
- \r
+\r
for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {\r
//\r
// Fill in the Page Directory entries\r
//\r
- PageDirectory1GEntry->Uint64 = (UINT64)PageAddress;\r
+ PageDirectory1GEntry->Uint64 = (UINT64)PageAddress | AddressEncMask;\r
PageDirectory1GEntry->Bits.ReadWrite = 1;\r
PageDirectory1GEntry->Bits.Present = 1;\r
PageDirectory1GEntry->Bits.MustBe1 = 1;\r
//\r
// Each Directory Pointer entries points to a page of Page Directory entires.\r
// So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.\r
- // \r
+ //\r
PageDirectoryEntry = (VOID *) BigPageAddress;\r
BigPageAddress += SIZE_4KB;\r
\r
//\r
// Fill in a Page Directory Pointer Entries\r
//\r
- PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry;\r
+ PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry | AddressEncMask;\r
PageDirectoryPointerEntry->Bits.ReadWrite = 1;\r
PageDirectoryPointerEntry->Bits.Present = 1;\r
\r
//\r
// Fill in the Page Directory entries\r
//\r
- PageDirectoryEntry->Uint64 = (UINT64)PageAddress;\r
+ PageDirectoryEntry->Uint64 = (UINT64)PageAddress | AddressEncMask;\r
PageDirectoryEntry->Bits.ReadWrite = 1;\r
PageDirectoryEntry->Bits.Present = 1;\r
PageDirectoryEntry->Bits.MustBe1 = 1;\r
//\r
AsmWriteCr3 ((UINTN) PageTableAddress);\r
\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "%a() Stack Base: 0x%lx, Stack Size: 0x%lx\n",\r
+ __FUNCTION__,\r
+ Context->StackBufferBase,\r
+ Context->StackBufferLength\r
+ ));\r
+\r
//\r
// Disable interrupt of Debug timer, since the IDT table cannot work in long mode\r
//\r
if ((UINTN) ReturnContext->ReturnStatus != 0) {\r
Status = ENCODE_ERROR ((UINTN) ReturnContext->ReturnStatus);\r
}\r
- \r
+\r
return Status;\r
}\r
\r
\r
ZeroMem (&Context, sizeof (SWITCH_32_TO_64_CONTEXT));\r
ZeroMem (&ReturnContext, sizeof (SWITCH_64_TO_32_CONTEXT));\r
- \r
+\r
MemoryBase64 = (UINT64) (UINTN) *MemoryBase;\r
MemorySize64 = (UINT64) (UINTN) *MemorySize;\r
MemoryEnd64 = MemoryBase64 + MemorySize64;\r
Page1GSupport = IsPage1GSupport ();\r
\r
//\r
- // Merge memory range reserved for stack and page table \r
+ // Merge memory range reserved for stack and page table\r
//\r
if (LongModeBuffer->StackBaseAddress < LongModeBuffer->PageTableAddress) {\r
ReservedRangeBase = LongModeBuffer->StackBaseAddress;\r
Context.MemoryBase64Ptr = (EFI_PHYSICAL_ADDRESS)(UINTN)&MemoryBase64;\r
Context.MemorySize64Ptr = (EFI_PHYSICAL_ADDRESS)(UINTN)&MemorySize64;\r
Context.Page1GSupport = Page1GSupport;\r
+ Context.AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;\r
\r
//\r
// Prepare data for return back\r
// Will save the return status of processing capsule\r
//\r
ReturnContext.ReturnStatus = 0;\r
- \r
+\r
//\r
// Save original GDT\r
//\r
AsmReadGdtr ((IA32_DESCRIPTOR *)&ReturnContext.Gdtr);\r
- \r
+\r
Status = Thunk32To64 (LongModeBuffer->PageTableAddress, &Context, &ReturnContext);\r
- \r
+\r
if (!EFI_ERROR (Status)) {\r
*MemoryBase = (VOID *) (UINTN) MemoryBase64;\r
*MemorySize = (UINTN) MemorySize64;\r
}\r
#endif\r
\r
+/**\r
+ Sort memory resource entries based upon PhysicalStart, from low to high.\r
+\r
+ @param[in, out] MemoryResource A pointer to the memory resource entry buffer.\r
+\r
+**/\r
+VOID\r
+SortMemoryResourceDescriptor (\r
+ IN OUT MEMORY_RESOURCE_DESCRIPTOR *MemoryResource\r
+ )\r
+{\r
+ MEMORY_RESOURCE_DESCRIPTOR *MemoryResourceEntry;\r
+ MEMORY_RESOURCE_DESCRIPTOR *NextMemoryResourceEntry;\r
+ MEMORY_RESOURCE_DESCRIPTOR TempMemoryResource;\r
+\r
+ MemoryResourceEntry = MemoryResource;\r
+ NextMemoryResourceEntry = MemoryResource + 1;\r
+ while (MemoryResourceEntry->ResourceLength != 0) {\r
+ while (NextMemoryResourceEntry->ResourceLength != 0) {\r
+ if (MemoryResourceEntry->PhysicalStart > NextMemoryResourceEntry->PhysicalStart) {\r
+ CopyMem (&TempMemoryResource, MemoryResourceEntry, sizeof (MEMORY_RESOURCE_DESCRIPTOR));\r
+ CopyMem (MemoryResourceEntry, NextMemoryResourceEntry, sizeof (MEMORY_RESOURCE_DESCRIPTOR));\r
+ CopyMem (NextMemoryResourceEntry, &TempMemoryResource, sizeof (MEMORY_RESOURCE_DESCRIPTOR));\r
+ }\r
+\r
+ NextMemoryResourceEntry = NextMemoryResourceEntry + 1;\r
+ }\r
+\r
+ MemoryResourceEntry = MemoryResourceEntry + 1;\r
+ NextMemoryResourceEntry = MemoryResourceEntry + 1;\r
+ }\r
+}\r
+\r
+/**\r
+ Merge continous memory resource entries.\r
+\r
+ @param[in, out] MemoryResource A pointer to the memory resource entry buffer.\r
+\r
+**/\r
+VOID\r
+MergeMemoryResourceDescriptor (\r
+ IN OUT MEMORY_RESOURCE_DESCRIPTOR *MemoryResource\r
+ )\r
+{\r
+ MEMORY_RESOURCE_DESCRIPTOR *MemoryResourceEntry;\r
+ MEMORY_RESOURCE_DESCRIPTOR *NewMemoryResourceEntry;\r
+ MEMORY_RESOURCE_DESCRIPTOR *NextMemoryResourceEntry;\r
+ MEMORY_RESOURCE_DESCRIPTOR *MemoryResourceEnd;\r
+\r
+ MemoryResourceEntry = MemoryResource;\r
+ NewMemoryResourceEntry = MemoryResource;\r
+ while (MemoryResourceEntry->ResourceLength != 0) {\r
+ CopyMem (NewMemoryResourceEntry, MemoryResourceEntry, sizeof (MEMORY_RESOURCE_DESCRIPTOR));\r
+ NextMemoryResourceEntry = MemoryResourceEntry + 1;\r
+\r
+ while ((NextMemoryResourceEntry->ResourceLength != 0) &&\r
+ (NextMemoryResourceEntry->PhysicalStart == (MemoryResourceEntry->PhysicalStart + MemoryResourceEntry->ResourceLength))) {\r
+ MemoryResourceEntry->ResourceLength += NextMemoryResourceEntry->ResourceLength;\r
+ if (NewMemoryResourceEntry != MemoryResourceEntry) {\r
+ NewMemoryResourceEntry->ResourceLength += NextMemoryResourceEntry->ResourceLength;\r
+ }\r
+\r
+ NextMemoryResourceEntry = NextMemoryResourceEntry + 1;\r
+ }\r
+\r
+ MemoryResourceEntry = NextMemoryResourceEntry;\r
+ NewMemoryResourceEntry = NewMemoryResourceEntry + 1;\r
+ }\r
+\r
+ //\r
+ // Set NULL terminate memory resource descriptor after merging.\r
+ //\r
+ MemoryResourceEnd = NewMemoryResourceEntry;\r
+ ZeroMem (MemoryResourceEnd, sizeof (MEMORY_RESOURCE_DESCRIPTOR));\r
+}\r
+\r
/**\r
Build memory resource descriptor from resource descriptor in HOB list.\r
\r
Status = PeiServicesAllocatePool ((1 + 1) * sizeof (MEMORY_RESOURCE_DESCRIPTOR), (VOID **) &MemoryResource);\r
ASSERT_EFI_ERROR (Status);\r
ZeroMem (MemoryResource, (1 + 1) * sizeof (MEMORY_RESOURCE_DESCRIPTOR));\r
- \r
+\r
MemoryResource[0].PhysicalStart = 0;\r
MemoryResource[0].ResourceLength = LShiftU64 (1, GetPhysicalAddressBits ());\r
DEBUG ((EFI_D_INFO, "MemoryResource[0x0] - Start(0x%0lx) Length(0x%0lx)\n",\r
Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);\r
}\r
\r
+ SortMemoryResourceDescriptor (MemoryResource);\r
+ MergeMemoryResourceDescriptor (MemoryResource);\r
+\r
+ DEBUG ((DEBUG_INFO, "Dump MemoryResource[] after sorted and merged\n"));\r
+ for (Index = 0; MemoryResource[Index].ResourceLength != 0; Index++) {\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ " MemoryResource[0x%x] - Start(0x%0lx) Length(0x%0lx)\n",\r
+ Index,\r
+ MemoryResource[Index].PhysicalStart,\r
+ MemoryResource[Index].ResourceLength\r
+ ));\r
+ }\r
+\r
return MemoryResource;\r
}\r
\r
CapsuleVarName[0] = 0;\r
ValidIndex = 0;\r
CapsuleDataPtr64 = 0;\r
- \r
+\r
Status = PeiServicesLocatePpi (\r
&gEfiPeiReadOnlyVariable2PpiGuid,\r
0,\r
(VOID *) &CapsuleDataPtr64\r
);\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "Capsule -- capsule variable not set\n"));\r
+ DEBUG ((DEBUG_INFO, "Capsule -- capsule variable not set\n"));\r
return EFI_NOT_FOUND;\r
}\r
//\r
return EFI_SUCCESS;\r
}\r
} else {\r
- UnicodeValueToString (TempVarName, 0, Index, 0);\r
+ UnicodeValueToStringS (\r
+ TempVarName,\r
+ sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName),\r
+ 0,\r
+ Index,\r
+ 0\r
+ );\r
Status = PPIVariableServices->GetVariable (\r
PPIVariableServices,\r
CapsuleVarName,\r
if (EFI_ERROR (Status)) {\r
break;\r
}\r
- \r
+\r
//\r
// If this BlockList has been linked before, skip this variable\r
//\r
continue;\r
}\r
}\r
- \r
+\r
//\r
// Cache BlockList which has been processed\r
//\r
Index ++;\r
}\r
}\r
- \r
+\r
return EFI_SUCCESS;\r
}\r
\r
UINTN VariableCount;\r
CHAR16 CapsuleVarName[30];\r
CHAR16 *TempVarName;\r
- EFI_PHYSICAL_ADDRESS CapsuleDataPtr64; \r
+ EFI_PHYSICAL_ADDRESS CapsuleDataPtr64;\r
EFI_STATUS Status;\r
EFI_BOOT_MODE BootMode;\r
EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices;\r
//\r
Status = PeiServicesGetBootMode (&BootMode);\r
if (EFI_ERROR (Status) || (BootMode != BOOT_ON_FLASH_UPDATE)) {\r
- DEBUG ((EFI_D_ERROR, "Boot mode is not correct for capsule update path.\n")); \r
+ DEBUG ((EFI_D_ERROR, "Boot mode is not correct for capsule update path.\n"));\r
Status = EFI_NOT_FOUND;\r
goto Done;\r
}\r
- \r
+\r
//\r
// User may set the same ScatterGatherList with several different variables,\r
// so cache all ScatterGatherList for check later.\r
TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
while (TRUE) {\r
if (Index > 0) {\r
- UnicodeValueToString (TempVarName, 0, Index, 0);\r
+ UnicodeValueToStringS (\r
+ TempVarName,\r
+ sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName),\r
+ 0,\r
+ Index,\r
+ 0\r
+ );\r
}\r
Status = PPIVariableServices->GetVariable (\r
PPIVariableServices,\r
VariableCount++;\r
Index++;\r
}\r
- \r
+\r
DEBUG ((EFI_D_INFO,"Capsule variable count = %d\n", VariableCount));\r
- \r
+\r
//\r
// The last entry is the end flag.\r
//\r
DEBUG ((EFI_D_ERROR, "AllocatePages Failed!, Status = %x\n", Status));\r
goto Done;\r
}\r
- \r
+\r
ZeroMem (VariableArrayAddress, (VariableCount + 1) * sizeof (EFI_PHYSICAL_ADDRESS));\r
- \r
+\r
//\r
// Find out if we actually have a capsule.\r
// GetCapsuleDescriptors depends on variable PPI, so it should run in 32-bit environment.\r
Status = EFI_NOT_FOUND;\r
goto Done;\r
}\r
- \r
+\r
Status = FindCapsuleCoalesceImage (&CoalesceImageEntryPoint, &CoalesceImageMachineType);\r
if ((EFI_ERROR (Status)) || (CoalesceImageMachineType != EFI_IMAGE_MACHINE_X64)) {\r
DEBUG ((EFI_D_ERROR, "Fail to find CapsuleX64 module in FV!\n"));\r
//\r
Status = CapsuleDataCoalesce (PeiServices, (EFI_PHYSICAL_ADDRESS *)(UINTN)VariableArrayAddress, MemoryResource, MemoryBase, MemorySize);\r
#endif\r
- \r
+\r
DEBUG ((EFI_D_INFO, "Capsule Coalesce Status = %r!\n", Status));\r
\r
if (Status == EFI_BUFFER_TOO_SMALL) {\r
DEBUG ((EFI_D_ERROR, "There is not enough memory to process capsule!\n"));\r
}\r
- \r
+\r
if (Status == EFI_NOT_FOUND) {\r
DEBUG ((EFI_D_ERROR, "Fail to parse capsule descriptor in memory!\n"));\r
REPORT_STATUS_CODE (\r
return Status;\r
}\r
/**\r
- This function will look at a capsule and determine if it's a test pattern. \r
+ This function will look at a capsule and determine if it's a test pattern.\r
If it is, then it will verify it and emit an error message if corruption is detected.\r
- \r
+\r
@param PeiServices Standard pei services pointer\r
@param CapsuleBase Base address of coalesced capsule, which is preceeded\r
by private data. Very implementation specific.\r
UINT32 Index;\r
EFI_PHYSICAL_ADDRESS BaseAddress;\r
UINT64 Length;\r
- \r
+\r
PrivateData = (EFI_CAPSULE_PEIM_PRIVATE_DATA *) CapsuleBase;\r
if (PrivateData->Signature != EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE) {\r
return EFI_VOLUME_CORRUPTED;\r
\r
BuildCvHob (BaseAddress, Length);\r
}\r
- \r
+\r
return EFI_SUCCESS;\r
}\r
\r