/** @file\r
Capsule update PEIM for UEFI2.0\r
\r
-Copyright (c) 2006 - 2011, 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
(UINTN) mGdtEntries\r
};\r
\r
+\r
+/**\r
+ The function will check if 1G page is supported.\r
+\r
+ @retval TRUE 1G page is supported.\r
+ @retval FALSE 1G page is not supported.\r
+\r
+**/\r
+BOOLEAN\r
+IsPage1GSupport (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 RegEax;\r
+ UINT32 RegEdx;\r
+ BOOLEAN Page1GSupport;\r
+\r
+ Page1GSupport = FALSE;\r
+ if (PcdGetBool(PcdUse1GPageTable)) {\r
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+ if (RegEax >= 0x80000001) {\r
+ AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
+ if ((RegEdx & BIT26) != 0) {\r
+ Page1GSupport = TRUE;\r
+ }\r
+ }\r
+ }\r
+\r
+ return Page1GSupport;\r
+}\r
+\r
/**\r
Calculate the total size of page table.\r
- \r
+\r
+ @param[in] Page1GSupport 1G page support or not.\r
+\r
@return The size of page table.\r
- \r
- \r
+\r
**/\r
UINTN\r
CalculatePageTableSize (\r
- VOID\r
+ IN BOOLEAN Page1GSupport\r
)\r
{\r
+ UINTN ExtraPageTablePages;\r
UINTN TotalPagesNum;\r
UINT8 PhysicalAddressBits;\r
- VOID *Hob;\r
UINT32 NumberOfPml4EntriesNeeded;\r
UINT32 NumberOfPdpEntriesNeeded;\r
\r
//\r
- // Get physical address bits supported from CPU HOB.\r
+ // Create 4G page table by default,\r
+ // and let PF handler to handle > 4G request.\r
//\r
- PhysicalAddressBits = 36;\r
- \r
- Hob = GetFirstHob (EFI_HOB_TYPE_CPU);\r
- if (Hob != NULL) {\r
- PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;\r
- }\r
-\r
- //\r
- // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.\r
- //\r
- ASSERT (PhysicalAddressBits <= 52);\r
- if (PhysicalAddressBits > 48) {\r
- PhysicalAddressBits = 48;\r
- }\r
+ PhysicalAddressBits = 32;\r
+ ExtraPageTablePages = EXTRA_PAGE_TABLE_PAGES;\r
\r
//\r
// Calculate the table entries needed.\r
//\r
if (PhysicalAddressBits <= 39 ) {\r
NumberOfPml4EntriesNeeded = 1;\r
- NumberOfPdpEntriesNeeded = 1 << (PhysicalAddressBits - 30);\r
+ NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));\r
} else {\r
- NumberOfPml4EntriesNeeded = 1 << (PhysicalAddressBits - 39);\r
+ NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));\r
NumberOfPdpEntriesNeeded = 512;\r
}\r
\r
- TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;\r
+ if (!Page1GSupport) {\r
+ TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;\r
+ } else {\r
+ TotalPagesNum = NumberOfPml4EntriesNeeded + 1;\r
+ }\r
+ TotalPagesNum += ExtraPageTablePages;\r
\r
return EFI_PAGES_TO_SIZE (TotalPagesNum);\r
}\r
\r
/**\r
Allocates and fills in the Page Directory and Page Table Entries to\r
- establish a 1:1 Virtual to Physical mapping.\r
+ establish a 4G page table.\r
\r
- @param[in] PageTablesAddress The base address of page table.\r
+ @param[in] PageTablesAddress The base address of page table.\r
+ @param[in] Page1GSupport 1G page support or not.\r
\r
**/\r
VOID\r
-CreateIdentityMappingPageTables (\r
- IN EFI_PHYSICAL_ADDRESS PageTablesAddress\r
+Create4GPageTables (\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_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry;\r
PAGE_TABLE_ENTRY *PageDirectoryEntry;\r
UINTN BigPageAddress;\r
- VOID *Hob;\r
+ PAGE_TABLE_1G_ENTRY *PageDirectory1GEntry;\r
+ UINT64 AddressEncMask;\r
\r
//\r
- // Get physical address bits supported from CPU HOB.\r
+ // Make sure AddressEncMask is contained to smallest supported address field.\r
//\r
- PhysicalAddressBits = 36;\r
- \r
- Hob = GetFirstHob (EFI_HOB_TYPE_CPU);\r
- if (Hob != NULL) {\r
- PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;\r
- }\r
+ AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;\r
\r
//\r
- // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.\r
+ // Create 4G page table by default,\r
+ // and let PF handler to handle > 4G request.\r
//\r
- ASSERT (PhysicalAddressBits <= 52);\r
- if (PhysicalAddressBits > 48) {\r
- PhysicalAddressBits = 48;\r
- }\r
+ PhysicalAddressBits = 32;\r
\r
//\r
// Calculate the table entries needed.\r
//\r
if (PhysicalAddressBits <= 39 ) {\r
NumberOfPml4EntriesNeeded = 1;\r
- NumberOfPdpEntriesNeeded = 1 << (PhysicalAddressBits - 30);\r
+ NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));\r
} else {\r
- NumberOfPml4EntriesNeeded = 1 << (PhysicalAddressBits - 39);\r
+ NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));\r
NumberOfPdpEntriesNeeded = 512;\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
// By architecture only one PageMapLevel4 exists - so lets allocate storage for it.\r
//\r
PageMap = (VOID *) BigPageAddress;\r
- BigPageAddress += EFI_PAGE_SIZE;\r
+ BigPageAddress += SIZE_4KB;\r
\r
PageMapLevel4Entry = PageMap;\r
PageAddress = 0;\r
// So lets allocate space for them and fill them in in the IndexOfPdpEntries loop.\r
//\r
PageDirectoryPointerEntry = (VOID *) BigPageAddress;\r
- BigPageAddress += EFI_PAGE_SIZE;\r
+ BigPageAddress += SIZE_4KB;\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
- for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {\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
- PageDirectoryEntry = (VOID *) BigPageAddress;\r
- BigPageAddress += EFI_PAGE_SIZE;\r
-\r
- //\r
- // Fill in a Page Directory Pointer Entries\r
- //\r
- PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry;\r
- PageDirectoryPointerEntry->Bits.ReadWrite = 1;\r
- PageDirectoryPointerEntry->Bits.Present = 1;\r
+ if (Page1GSupport) {\r
+ PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;\r
\r
- for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += 0x200000) {\r
+ for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {\r
//\r
// Fill in the Page Directory entries\r
//\r
- PageDirectoryEntry->Uint64 = (UINT64)PageAddress;\r
- PageDirectoryEntry->Bits.ReadWrite = 1;\r
- PageDirectoryEntry->Bits.Present = 1;\r
- PageDirectoryEntry->Bits.MustBe1 = 1;\r
+ PageDirectory1GEntry->Uint64 = (UINT64)PageAddress | AddressEncMask;\r
+ PageDirectory1GEntry->Bits.ReadWrite = 1;\r
+ PageDirectory1GEntry->Bits.Present = 1;\r
+ PageDirectory1GEntry->Bits.MustBe1 = 1;\r
+ }\r
+ } else {\r
+ for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {\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
+ PageDirectoryEntry = (VOID *) BigPageAddress;\r
+ BigPageAddress += SIZE_4KB;\r
\r
+ //\r
+ // Fill in a Page Directory Pointer Entries\r
+ //\r
+ PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry | AddressEncMask;\r
+ PageDirectoryPointerEntry->Bits.ReadWrite = 1;\r
+ PageDirectoryPointerEntry->Bits.Present = 1;\r
+\r
+ for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {\r
+ //\r
+ // Fill in the Page Directory entries\r
+ //\r
+ PageDirectoryEntry->Uint64 = (UINT64)PageAddress | AddressEncMask;\r
+ PageDirectoryEntry->Bits.ReadWrite = 1;\r
+ PageDirectoryEntry->Bits.Present = 1;\r
+ PageDirectoryEntry->Bits.MustBe1 = 1;\r
+ }\r
+ }\r
+\r
+ for (; IndexOfPdpEntries < 512; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {\r
+ ZeroMem (\r
+ PageDirectoryPointerEntry,\r
+ sizeof(PAGE_MAP_AND_DIRECTORY_POINTER)\r
+ );\r
}\r
}\r
}\r
\r
//\r
// For the PML4 entries we are not using fill in a null entry.\r
- // For now we just copy the first entry.\r
//\r
for (; IndexOfPml4Entries < 512; IndexOfPml4Entries++, PageMapLevel4Entry++) {\r
- CopyMem (\r
- PageMapLevel4Entry,\r
- PageMap,\r
- sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)\r
- );\r
+ ZeroMem (\r
+ PageMapLevel4Entry,\r
+ sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)\r
+ );\r
}\r
}\r
\r
SWITCH_32_TO_64_CONTEXT *EntrypointContext,\r
SWITCH_64_TO_32_CONTEXT *ReturnContext\r
)\r
-{ \r
+{\r
//\r
// Restore original GDT\r
//\r
AsmWriteGdtr (&ReturnContext->Gdtr);\r
- \r
+\r
//\r
// return to original caller\r
//\r
LongJump ((BASE_LIBRARY_JUMP_BUFFER *)(UINTN)EntrypointContext->JumpBuffer, 1);\r
- \r
+\r
//\r
// never be here\r
- // \r
+ //\r
ASSERT (FALSE);\r
}\r
\r
if (SetJumpFlag == 0) {\r
\r
//\r
- // Build Page Tables for all physical memory processor supports\r
+ // Build 4G Page Tables.\r
//\r
- CreateIdentityMappingPageTables (PageTableAddress);\r
- \r
+ Create4GPageTables (PageTableAddress, Context->Page1GSupport);\r
+\r
//\r
// Create 64-bit GDT\r
//\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
+ SaveAndSetDebugTimerInterrupt (FALSE);\r
//\r
// Transfer to long mode\r
//\r
Context->StackBufferBase + Context->StackBufferLength\r
);\r
}\r
- \r
+\r
//\r
// Convert to 32-bit Status and return\r
//\r
if ((UINTN) ReturnContext->ReturnStatus != 0) {\r
Status = ENCODE_ERROR ((UINTN) ReturnContext->ReturnStatus);\r
}\r
- \r
+\r
return Status;\r
}\r
\r
@param LongModeBuffer The context of long mode.\r
@param CoalesceEntry Entry of coalesce image.\r
@param BlockListAddr Address of block list.\r
+ @param MemoryResource Pointer to the buffer of memory resource descriptor.\r
@param MemoryBase Base of memory range.\r
@param MemorySize Size of memory range.\r
\r
IN EFI_CAPSULE_LONG_MODE_BUFFER *LongModeBuffer,\r
IN COALESCE_ENTRY CoalesceEntry,\r
IN EFI_PHYSICAL_ADDRESS BlockListAddr,\r
+ IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource,\r
IN OUT VOID **MemoryBase,\r
IN OUT UINTN *MemorySize\r
)\r
BASE_LIBRARY_JUMP_BUFFER JumpBuffer;\r
EFI_PHYSICAL_ADDRESS ReservedRangeBase;\r
EFI_PHYSICAL_ADDRESS ReservedRangeEnd;\r
+ BOOLEAN Page1GSupport;\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
\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
- ReservedRangeEnd = LongModeBuffer->PageTableAddress + CalculatePageTableSize ();\r
+ ReservedRangeEnd = LongModeBuffer->PageTableAddress + CalculatePageTableSize (Page1GSupport);\r
} else {\r
ReservedRangeBase = LongModeBuffer->PageTableAddress;\r
ReservedRangeEnd = LongModeBuffer->StackBaseAddress + LongModeBuffer->StackSize;\r
}\r
- \r
+\r
//\r
// Check if memory range reserved is overlap with MemoryBase ~ MemoryBase + MemorySize.\r
// If they are overlapped, get a larger range to process capsule data.\r
} else {\r
MemorySize64 = (UINT64)(UINTN)(ReservedRangeBase - MemoryBase64);\r
}\r
- } \r
- \r
+ }\r
+\r
//\r
// Initialize context jumping to 64-bit enviroment\r
//\r
Context.StackBufferLength = LongModeBuffer->StackSize;\r
Context.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)CoalesceEntry;\r
Context.BlockListAddr = BlockListAddr;\r
+ Context.MemoryResource = (EFI_PHYSICAL_ADDRESS)(UINTN)MemoryResource;\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
&AuthenticationState\r
);\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "Unable to find PE32 section in CapsuleRelocate image ffs %r!\n", Status));\r
+ DEBUG ((EFI_D_ERROR, "Unable to find PE32 section in CapsuleX64 image ffs %r!\n", Status));\r
return Status;\r
}\r
*CoalesceImageMachineType = PeCoffLoaderGetMachineType ((VOID *) (UINTN) CoalesceImageAddress);\r
return Status;\r
}\r
\r
+/**\r
+ Gets the reserved long mode buffer.\r
+\r
+ @param LongModeBuffer Pointer to the long mode buffer for output.\r
+\r
+ @retval EFI_SUCCESS Long mode buffer successfully retrieved.\r
+ @retval Others Variable storing long mode buffer not found.\r
+\r
+**/\r
+EFI_STATUS\r
+GetLongModeContext (\r
+ OUT EFI_CAPSULE_LONG_MODE_BUFFER *LongModeBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Size;\r
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices;\r
+\r
+ Status = PeiServicesLocatePpi (\r
+ &gEfiPeiReadOnlyVariable2PpiGuid,\r
+ 0,\r
+ NULL,\r
+ (VOID **) &PPIVariableServices\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Size = sizeof (EFI_CAPSULE_LONG_MODE_BUFFER);\r
+ Status = PPIVariableServices->GetVariable (\r
+ PPIVariableServices,\r
+ EFI_CAPSULE_LONG_MODE_BUFFER_NAME,\r
+ &gEfiCapsuleVendorGuid,\r
+ NULL,\r
+ &Size,\r
+ LongModeBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG (( EFI_D_ERROR, "Error Get LongModeBuffer variable %r!\n", Status));\r
+ }\r
+ return Status;\r
+}\r
#endif\r
\r
+#if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64)\r
+/**\r
+ Get physical address bits.\r
+\r
+ @return Physical address bits.\r
+\r
+**/\r
+UINT8\r
+GetPhysicalAddressBits (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 RegEax;\r
+ UINT8 PhysicalAddressBits;\r
+ VOID *Hob;\r
+\r
+ //\r
+ // Get physical address bits supported.\r
+ //\r
+ Hob = GetFirstHob (EFI_HOB_TYPE_CPU);\r
+ if (Hob != NULL) {\r
+ PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;\r
+ } else {\r
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+ if (RegEax >= 0x80000008) {\r
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
+ PhysicalAddressBits = (UINT8) RegEax;\r
+ } else {\r
+ PhysicalAddressBits = 36;\r
+ }\r
+ }\r
+\r
+ //\r
+ // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.\r
+ //\r
+ ASSERT (PhysicalAddressBits <= 52);\r
+ if (PhysicalAddressBits > 48) {\r
+ PhysicalAddressBits = 48;\r
+ }\r
+\r
+ return PhysicalAddressBits;\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
+ @return Pointer to the buffer of memory resource descriptor.\r
+ NULL if no memory resource descriptor reported in HOB list\r
+ before capsule Coalesce.\r
+\r
+**/\r
+MEMORY_RESOURCE_DESCRIPTOR *\r
+BuildMemoryResourceDescriptor (\r
+ VOID\r
+ )\r
+{\r
+ EFI_PEI_HOB_POINTERS Hob;\r
+ UINTN Index;\r
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor;\r
+ MEMORY_RESOURCE_DESCRIPTOR *MemoryResource;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Get the count of memory resource descriptor.\r
+ //\r
+ Index = 0;\r
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);\r
+ while (Hob.Raw != NULL) {\r
+ ResourceDescriptor = (EFI_HOB_RESOURCE_DESCRIPTOR *) Hob.Raw;\r
+ if (ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {\r
+ Index++;\r
+ }\r
+ Hob.Raw = GET_NEXT_HOB (Hob);\r
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);\r
+ }\r
+\r
+ if (Index == 0) {\r
+ DEBUG ((EFI_D_INFO | EFI_D_WARN, "No memory resource descriptor reported in HOB list before capsule Coalesce\n"));\r
+#if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64)\r
+ //\r
+ // Allocate memory to hold memory resource descriptor,\r
+ // include extra one NULL terminate memory resource descriptor.\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
+ 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
+ MemoryResource[0x0].PhysicalStart, MemoryResource[0x0].ResourceLength));\r
+ return MemoryResource;\r
+#else\r
+ return NULL;\r
+#endif\r
+ }\r
+\r
+ //\r
+ // Allocate memory to hold memory resource descriptor,\r
+ // include extra one NULL terminate memory resource descriptor.\r
+ //\r
+ Status = PeiServicesAllocatePool ((Index + 1) * sizeof (MEMORY_RESOURCE_DESCRIPTOR), (VOID **) &MemoryResource);\r
+ ASSERT_EFI_ERROR (Status);\r
+ ZeroMem (MemoryResource, (Index + 1) * sizeof (MEMORY_RESOURCE_DESCRIPTOR));\r
+\r
+ //\r
+ // Get the content of memory resource descriptor.\r
+ //\r
+ Index = 0;\r
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);\r
+ while (Hob.Raw != NULL) {\r
+ ResourceDescriptor = (EFI_HOB_RESOURCE_DESCRIPTOR *) Hob.Raw;\r
+ if (ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {\r
+ DEBUG ((EFI_D_INFO, "MemoryResource[0x%x] - Start(0x%0lx) Length(0x%0lx)\n",\r
+ Index, ResourceDescriptor->PhysicalStart, ResourceDescriptor->ResourceLength));\r
+ MemoryResource[Index].PhysicalStart = ResourceDescriptor->PhysicalStart;\r
+ MemoryResource[Index].ResourceLength = ResourceDescriptor->ResourceLength;\r
+ Index++;\r
+ }\r
+ Hob.Raw = GET_NEXT_HOB (Hob);\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
/**\r
Checks for the presence of capsule descriptors.\r
Get capsule descriptors from variable CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...\r
TempVarName = NULL;\r
CapsuleVarName[0] = 0;\r
ValidIndex = 0;\r
- \r
+ CapsuleDataPtr64 = 0;\r
+\r
Status = PeiServicesLocatePpi (\r
&gEfiPeiReadOnlyVariable2PpiGuid,\r
0,\r
(VOID **) &PPIVariableServices\r
);\r
if (Status == EFI_SUCCESS) {\r
- StrCpy (CapsuleVarName, EFI_CAPSULE_VARIABLE_NAME);\r
+ StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16), EFI_CAPSULE_VARIABLE_NAME);\r
TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
Size = sizeof (CapsuleDataPtr64);\r
while (1) {\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
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Gets the reserved long mode buffer.\r
-\r
- @param LongModeBuffer Pointer to the long mode buffer for output.\r
-\r
- @retval EFI_SUCCESS Long mode buffer successfully retrieved.\r
- @retval Others Variable storing long mode buffer not found.\r
-\r
-**/\r
-EFI_STATUS\r
-GetLongModeContext (\r
- OUT EFI_CAPSULE_LONG_MODE_BUFFER *LongModeBuffer\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN Size;\r
- EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices;\r
-\r
- Status = PeiServicesLocatePpi (\r
- &gEfiPeiReadOnlyVariable2PpiGuid,\r
- 0,\r
- NULL,\r
- (VOID **) &PPIVariableServices\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
\r
- Size = sizeof (EFI_CAPSULE_LONG_MODE_BUFFER);\r
- Status = PPIVariableServices->GetVariable (\r
- PPIVariableServices,\r
- EFI_CAPSULE_LONG_MODE_BUFFER_NAME,\r
- &gEfiCapsuleVendorGuid,\r
- NULL,\r
- &Size,\r
- LongModeBuffer\r
- );\r
- if (EFI_ERROR (Status)) {\r
- DEBUG (( EFI_D_ERROR, "Error Get LongModeBuffer variable %r!\n", Status));\r
- }\r
- return Status;\r
+ return EFI_SUCCESS;\r
}\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
EFI_PHYSICAL_ADDRESS *VariableArrayAddress;\r
+ MEMORY_RESOURCE_DESCRIPTOR *MemoryResource;\r
#ifdef MDE_CPU_IA32\r
UINT16 CoalesceImageMachineType;\r
EFI_PHYSICAL_ADDRESS CoalesceImageEntryPoint;\r
Index = 0;\r
VariableCount = 0;\r
CapsuleVarName[0] = 0;\r
+ CapsuleDataPtr64 = 0;\r
\r
//\r
// Someone should have already ascertained the boot mode. If it's not\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
goto Done;\r
}\r
Size = sizeof (CapsuleDataPtr64);\r
- StrCpy (CapsuleVarName, EFI_CAPSULE_VARIABLE_NAME);\r
+ StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16), EFI_CAPSULE_VARIABLE_NAME);\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
goto Done;\r
}\r
\r
+ MemoryResource = BuildMemoryResourceDescriptor ();\r
+\r
#ifdef MDE_CPU_IA32\r
if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
//\r
CoalesceImageEntryPoint = 0;\r
Status = GetLongModeContext (&LongModeBuffer);\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "Fail to find the variables for long mode context!\n"));\r
+ DEBUG ((EFI_D_ERROR, "Fail to find the variable for long mode context!\n"));\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
ASSERT (CoalesceImageEntryPoint != 0);\r
CoalesceEntry = (COALESCE_ENTRY) (UINTN) CoalesceImageEntryPoint;\r
- Status = ModeSwitch (&LongModeBuffer, CoalesceEntry, (EFI_PHYSICAL_ADDRESS)(UINTN)VariableArrayAddress, MemoryBase, MemorySize);\r
+ Status = ModeSwitch (&LongModeBuffer, CoalesceEntry, (EFI_PHYSICAL_ADDRESS)(UINTN)VariableArrayAddress, MemoryResource, MemoryBase, MemorySize);\r
} else {\r
//\r
// Capsule is processed in IA32 mode.\r
//\r
- Status = CapsuleDataCoalesce (PeiServices, (EFI_PHYSICAL_ADDRESS *)(UINTN)VariableArrayAddress, MemoryBase, MemorySize);\r
+ Status = CapsuleDataCoalesce (PeiServices, (EFI_PHYSICAL_ADDRESS *)(UINTN)VariableArrayAddress, MemoryResource, MemoryBase, MemorySize);\r
}\r
#else\r
//\r
// Process capsule directly.\r
//\r
- Status = CapsuleDataCoalesce (PeiServices, (EFI_PHYSICAL_ADDRESS *)(UINTN)VariableArrayAddress, MemoryBase, MemorySize);\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
EFI_CAPSULE_PEIM_PRIVATE_DATA *PrivateData;\r
UINTN Size;\r
EFI_PHYSICAL_ADDRESS NewBuffer;\r
- UINT32 *DataPtr;\r
- UINT32 CapsuleNumber;\r
+ UINTN CapsuleNumber;\r
UINT32 Index;\r
EFI_PHYSICAL_ADDRESS BaseAddress;\r
UINT64 Length;\r
- \r
- DataPtr = NULL;\r
- CapsuleNumber = 0;\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
+ if (PrivateData->CapsuleAllImageSize >= MAX_ADDRESS) {\r
+ DEBUG ((EFI_D_ERROR, "CapsuleAllImageSize too big - 0x%lx\n", PrivateData->CapsuleAllImageSize));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ if (PrivateData->CapsuleNumber >= MAX_ADDRESS) {\r
+ DEBUG ((EFI_D_ERROR, "CapsuleNumber too big - 0x%lx\n", PrivateData->CapsuleNumber));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
//\r
// Capsule Number and Capsule Offset is in the tail of Capsule data.\r
//\r
- Size = (UINTN) PrivateData->CapsuleSize;\r
- DataPtr = (UINT32*)((UINTN)CapsuleBase + (UINTN)sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA)+ Size);\r
- DataPtr = (UINT32*)(((UINTN) DataPtr + sizeof(UINT32) - 1) & ~(sizeof (UINT32) - 1));\r
- CapsuleNumber = *DataPtr++;\r
+ Size = (UINTN)PrivateData->CapsuleAllImageSize;\r
+ CapsuleNumber = (UINTN)PrivateData->CapsuleNumber;\r
//\r
// Allocate the memory so that it gets preserved into DXE\r
//\r
//\r
// Copy to our new buffer for DXE\r
//\r
- DEBUG ((EFI_D_INFO, "Capsule copy from 0x%8X to 0x%8X with size 0x%8X\n", (UINTN) (PrivateData + 1), (UINTN) NewBuffer, Size));\r
- CopyMem ((VOID *) (UINTN) NewBuffer, (VOID *) (UINTN) (PrivateData + 1), Size);\r
+ DEBUG ((EFI_D_INFO, "Capsule copy from 0x%8X to 0x%8X with size 0x%8X\n", (UINTN)((UINT8 *)PrivateData + sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64)), (UINTN) NewBuffer, Size));\r
+ CopyMem ((VOID *) (UINTN) NewBuffer, (VOID *) (UINTN) ((UINT8 *)PrivateData + sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64)), Size);\r
//\r
// Check for test data pattern. If it is the test pattern, then we'll\r
- // test it ans still create the HOB so that it can be used to verify\r
+ // test it and still create the HOB so that it can be used to verify\r
// that capsules don't get corrupted all the way into BDS. BDS will\r
// still try to turn it into a firmware volume, but will think it's\r
// corrupted so nothing will happen.\r
// Build the UEFI Capsule Hob for each capsule image.\r
//\r
for (Index = 0; Index < CapsuleNumber; Index ++) {\r
- BaseAddress = NewBuffer + DataPtr[Index];\r
+ BaseAddress = NewBuffer + PrivateData->CapsuleOffset[Index];\r
Length = ((EFI_CAPSULE_HEADER *)((UINTN) BaseAddress))->CapsuleImageSize;\r
\r
BuildCvHob (BaseAddress, Length);\r
}\r
- \r
+\r
return EFI_SUCCESS;\r
}\r
\r
-CONST PEI_CAPSULE_PPI mCapsulePpi = {\r
+CONST EFI_PEI_CAPSULE_PPI mCapsulePpi = {\r
CapsuleCoalesce,\r
CheckCapsuleUpdate,\r
CreateState\r
\r
CONST EFI_PEI_PPI_DESCRIPTOR mUefiPpiListCapsule = {\r
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
- &gPeiCapsulePpiGuid,\r
- (PEI_CAPSULE_PPI *) &mCapsulePpi\r
+ &gEfiPeiCapsulePpiGuid,\r
+ (EFI_PEI_CAPSULE_PPI *) &mCapsulePpi\r
};\r
\r
/**\r