2 Capsule update PEIM for UEFI2.0
4 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions
8 of the BSD License which accompanies this distribution. The
9 full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 // Global Descriptor Table (GDT)
22 GLOBAL_REMOVE_IF_UNREFERENCED IA32_SEGMENT_DESCRIPTOR mGdtEntries
[] = {
23 /* selector { Global Segment Descriptor } */
24 /* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //null descriptor
25 /* 0x08 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear data segment descriptor
26 /* 0x10 */ {{0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear code segment descriptor
27 /* 0x18 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
28 /* 0x20 */ {{0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system code segment descriptor
29 /* 0x28 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
30 /* 0x30 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
31 /* 0x38 */ {{0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 1, 0, 1, 0}}, //system code segment descriptor
32 /* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
38 GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR mGdt
= {
39 sizeof (mGdtEntries
) - 1,
44 Calculate the total size of page table.
46 @return The size of page table.
51 CalculatePageTableSize (
56 UINT8 PhysicalAddressBits
;
58 UINT32 NumberOfPml4EntriesNeeded
;
59 UINT32 NumberOfPdpEntriesNeeded
;
62 // Get physical address bits supported from CPU HOB.
64 PhysicalAddressBits
= 36;
66 Hob
= GetFirstHob (EFI_HOB_TYPE_CPU
);
68 PhysicalAddressBits
= ((EFI_HOB_CPU
*) Hob
)->SizeOfMemorySpace
;
72 // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
74 ASSERT (PhysicalAddressBits
<= 52);
75 if (PhysicalAddressBits
> 48) {
76 PhysicalAddressBits
= 48;
80 // Calculate the table entries needed.
82 if (PhysicalAddressBits
<= 39 ) {
83 NumberOfPml4EntriesNeeded
= 1;
84 NumberOfPdpEntriesNeeded
= 1 << (PhysicalAddressBits
- 30);
86 NumberOfPml4EntriesNeeded
= 1 << (PhysicalAddressBits
- 39);
87 NumberOfPdpEntriesNeeded
= 512;
90 TotalPagesNum
= (NumberOfPdpEntriesNeeded
+ 1) * NumberOfPml4EntriesNeeded
+ 1;
92 return EFI_PAGES_TO_SIZE (TotalPagesNum
);
96 Allocates and fills in the Page Directory and Page Table Entries to
97 establish a 1:1 Virtual to Physical mapping.
99 @param[in] PageTablesAddress The base address of page table.
103 CreateIdentityMappingPageTables (
104 IN EFI_PHYSICAL_ADDRESS PageTablesAddress
107 UINT8 PhysicalAddressBits
;
108 EFI_PHYSICAL_ADDRESS PageAddress
;
109 UINTN IndexOfPml4Entries
;
110 UINTN IndexOfPdpEntries
;
111 UINTN IndexOfPageDirectoryEntries
;
112 UINT32 NumberOfPml4EntriesNeeded
;
113 UINT32 NumberOfPdpEntriesNeeded
;
114 PAGE_MAP_AND_DIRECTORY_POINTER
*PageMapLevel4Entry
;
115 PAGE_MAP_AND_DIRECTORY_POINTER
*PageMap
;
116 PAGE_MAP_AND_DIRECTORY_POINTER
*PageDirectoryPointerEntry
;
117 PAGE_TABLE_ENTRY
*PageDirectoryEntry
;
118 UINTN BigPageAddress
;
122 // Get physical address bits supported from CPU HOB.
124 PhysicalAddressBits
= 36;
126 Hob
= GetFirstHob (EFI_HOB_TYPE_CPU
);
128 PhysicalAddressBits
= ((EFI_HOB_CPU
*) Hob
)->SizeOfMemorySpace
;
132 // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
134 ASSERT (PhysicalAddressBits
<= 52);
135 if (PhysicalAddressBits
> 48) {
136 PhysicalAddressBits
= 48;
140 // Calculate the table entries needed.
142 if (PhysicalAddressBits
<= 39 ) {
143 NumberOfPml4EntriesNeeded
= 1;
144 NumberOfPdpEntriesNeeded
= 1 << (PhysicalAddressBits
- 30);
146 NumberOfPml4EntriesNeeded
= 1 << (PhysicalAddressBits
- 39);
147 NumberOfPdpEntriesNeeded
= 512;
151 // Pre-allocate big pages to avoid later allocations.
153 BigPageAddress
= (UINTN
) PageTablesAddress
;
156 // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
158 PageMap
= (VOID
*) BigPageAddress
;
159 BigPageAddress
+= EFI_PAGE_SIZE
;
161 PageMapLevel4Entry
= PageMap
;
163 for (IndexOfPml4Entries
= 0; IndexOfPml4Entries
< NumberOfPml4EntriesNeeded
; IndexOfPml4Entries
++, PageMapLevel4Entry
++) {
165 // Each PML4 entry points to a page of Page Directory Pointer entires.
166 // So lets allocate space for them and fill them in in the IndexOfPdpEntries loop.
168 PageDirectoryPointerEntry
= (VOID
*) BigPageAddress
;
169 BigPageAddress
+= EFI_PAGE_SIZE
;
174 PageMapLevel4Entry
->Uint64
= (UINT64
)(UINTN
)PageDirectoryPointerEntry
;
175 PageMapLevel4Entry
->Bits
.ReadWrite
= 1;
176 PageMapLevel4Entry
->Bits
.Present
= 1;
178 for (IndexOfPdpEntries
= 0; IndexOfPdpEntries
< NumberOfPdpEntriesNeeded
; IndexOfPdpEntries
++, PageDirectoryPointerEntry
++) {
180 // Each Directory Pointer entries points to a page of Page Directory entires.
181 // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.
183 PageDirectoryEntry
= (VOID
*) BigPageAddress
;
184 BigPageAddress
+= EFI_PAGE_SIZE
;
187 // Fill in a Page Directory Pointer Entries
189 PageDirectoryPointerEntry
->Uint64
= (UINT64
)(UINTN
)PageDirectoryEntry
;
190 PageDirectoryPointerEntry
->Bits
.ReadWrite
= 1;
191 PageDirectoryPointerEntry
->Bits
.Present
= 1;
193 for (IndexOfPageDirectoryEntries
= 0; IndexOfPageDirectoryEntries
< 512; IndexOfPageDirectoryEntries
++, PageDirectoryEntry
++, PageAddress
+= 0x200000) {
195 // Fill in the Page Directory entries
197 PageDirectoryEntry
->Uint64
= (UINT64
)PageAddress
;
198 PageDirectoryEntry
->Bits
.ReadWrite
= 1;
199 PageDirectoryEntry
->Bits
.Present
= 1;
200 PageDirectoryEntry
->Bits
.MustBe1
= 1;
207 // For the PML4 entries we are not using fill in a null entry.
208 // For now we just copy the first entry.
210 for (; IndexOfPml4Entries
< 512; IndexOfPml4Entries
++, PageMapLevel4Entry
++) {
214 sizeof (PAGE_MAP_AND_DIRECTORY_POINTER
)
220 Return function from long mode to 32-bit mode.
222 @param EntrypointContext Context for mode switching
223 @param ReturnContext Context for mode switching
228 SWITCH_32_TO_64_CONTEXT
*EntrypointContext
,
229 SWITCH_64_TO_32_CONTEXT
*ReturnContext
233 // Restore original GDT
235 AsmWriteGdtr (&ReturnContext
->Gdtr
);
238 // return to original caller
240 LongJump ((BASE_LIBRARY_JUMP_BUFFER
*)(UINTN
)EntrypointContext
->JumpBuffer
, 1);
249 Thunk function from 32-bit protection mode to long mode.
251 @param PageTableAddress Page table base address
252 @param Context Context for mode switching
253 @param ReturnContext Context for mode switching
255 @retval EFI_SUCCESS Function successfully executed.
260 EFI_PHYSICAL_ADDRESS PageTableAddress
,
261 SWITCH_32_TO_64_CONTEXT
*Context
,
262 SWITCH_64_TO_32_CONTEXT
*ReturnContext
269 // Save return address, LongJump will return here then
271 SetJumpFlag
= SetJump ((BASE_LIBRARY_JUMP_BUFFER
*) (UINTN
) Context
->JumpBuffer
);
273 if (SetJumpFlag
== 0) {
276 // Build Page Tables for all physical memory processor supports
278 CreateIdentityMappingPageTables (PageTableAddress
);
283 AsmWriteGdtr (&mGdt
);
288 AsmWriteCr3 ((UINTN
) PageTableAddress
);
291 // Transfer to long mode
295 (UINT64
) Context
->EntryPoint
,
296 (UINT64
)(UINTN
) Context
,
297 (UINT64
)(UINTN
) ReturnContext
,
298 Context
->StackBufferBase
+ Context
->StackBufferLength
303 // Convert to 32-bit Status and return
305 Status
= EFI_SUCCESS
;
306 if ((UINTN
) ReturnContext
->ReturnStatus
!= 0) {
307 Status
= ENCODE_ERROR ((UINTN
) ReturnContext
->ReturnStatus
);
314 If in 32 bit protection mode, and coalesce image is of X64, switch to long mode.
316 @param LongModeBuffer The context of long mode.
317 @param CoalesceEntry Entry of coalesce image.
318 @param BlockListAddr Address of block list.
319 @param MemoryBase Base of memory range.
320 @param MemorySize Size of memory range.
322 @retval EFI_SUCCESS Successfully switched to long mode and execute coalesce.
323 @retval Others Failed to execute coalesce in long mode.
328 IN EFI_CAPSULE_LONG_MODE_BUFFER
*LongModeBuffer
,
329 IN COALESCE_ENTRY CoalesceEntry
,
330 IN EFI_PHYSICAL_ADDRESS BlockListAddr
,
331 IN OUT VOID
**MemoryBase
,
332 IN OUT UINTN
*MemorySize
336 EFI_PHYSICAL_ADDRESS MemoryBase64
;
338 EFI_PHYSICAL_ADDRESS MemoryEnd64
;
339 SWITCH_32_TO_64_CONTEXT Context
;
340 SWITCH_64_TO_32_CONTEXT ReturnContext
;
341 BASE_LIBRARY_JUMP_BUFFER JumpBuffer
;
342 EFI_PHYSICAL_ADDRESS ReservedRangeBase
;
343 EFI_PHYSICAL_ADDRESS ReservedRangeEnd
;
345 ZeroMem (&Context
, sizeof (SWITCH_32_TO_64_CONTEXT
));
346 ZeroMem (&ReturnContext
, sizeof (SWITCH_64_TO_32_CONTEXT
));
348 MemoryBase64
= (UINT64
) (UINTN
) *MemoryBase
;
349 MemorySize64
= (UINT64
) (UINTN
) *MemorySize
;
350 MemoryEnd64
= MemoryBase64
+ MemorySize64
;
353 // Merge memory range reserved for stack and page table
355 if (LongModeBuffer
->StackBaseAddress
< LongModeBuffer
->PageTableAddress
) {
356 ReservedRangeBase
= LongModeBuffer
->StackBaseAddress
;
357 ReservedRangeEnd
= LongModeBuffer
->PageTableAddress
+ CalculatePageTableSize ();
359 ReservedRangeBase
= LongModeBuffer
->PageTableAddress
;
360 ReservedRangeEnd
= LongModeBuffer
->StackBaseAddress
+ LongModeBuffer
->StackSize
;
364 // Check if memory range reserved is overlap with MemoryBase ~ MemoryBase + MemorySize.
365 // If they are overlapped, get a larger range to process capsule data.
367 if (ReservedRangeBase
<= MemoryBase64
) {
368 if (ReservedRangeEnd
< MemoryEnd64
) {
369 MemoryBase64
= ReservedRangeEnd
;
371 DEBUG ((EFI_D_ERROR
, "Memory is not enough to process capsule!\n"));
372 return EFI_OUT_OF_RESOURCES
;
374 } else if (ReservedRangeBase
< MemoryEnd64
) {
375 if (ReservedRangeEnd
< MemoryEnd64
&&
376 ReservedRangeBase
- MemoryBase64
< MemoryEnd64
- ReservedRangeEnd
) {
377 MemoryBase64
= ReservedRangeEnd
;
379 MemorySize64
= (UINT64
)(UINTN
)(ReservedRangeBase
- MemoryBase64
);
384 // Initialize context jumping to 64-bit enviroment
386 Context
.JumpBuffer
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&JumpBuffer
;
387 Context
.StackBufferBase
= LongModeBuffer
->StackBaseAddress
;
388 Context
.StackBufferLength
= LongModeBuffer
->StackSize
;
389 Context
.EntryPoint
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)CoalesceEntry
;
390 Context
.BlockListAddr
= BlockListAddr
;
391 Context
.MemoryBase64Ptr
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&MemoryBase64
;
392 Context
.MemorySize64Ptr
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&MemorySize64
;
395 // Prepare data for return back
397 ReturnContext
.ReturnCs
= 0x10;
398 ReturnContext
.ReturnEntryPoint
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)ReturnFunction
;
400 // Will save the return status of processing capsule
402 ReturnContext
.ReturnStatus
= 0;
407 AsmReadGdtr ((IA32_DESCRIPTOR
*)&ReturnContext
.Gdtr
);
409 Status
= Thunk32To64 (LongModeBuffer
->PageTableAddress
, &Context
, &ReturnContext
);
411 if (!EFI_ERROR (Status
)) {
412 *MemoryBase
= (VOID
*) (UINTN
) MemoryBase64
;
413 *MemorySize
= (UINTN
) MemorySize64
;
421 Checks for the presence of capsule descriptors.
422 Get capsule descriptors from variable CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
423 and save to DescriptorBuffer.
425 @param DescriptorBuffer Pointer to the capsule descriptors
427 @retval EFI_SUCCESS a valid capsule is present
428 @retval EFI_NOT_FOUND if a valid capsule is not present
431 GetCapsuleDescriptors (
432 IN EFI_PHYSICAL_ADDRESS
*DescriptorBuffer
441 CHAR16 CapsuleVarName
[30];
443 EFI_PHYSICAL_ADDRESS CapsuleDataPtr64
;
444 EFI_PEI_READ_ONLY_VARIABLE2_PPI
*PPIVariableServices
;
448 CapsuleVarName
[0] = 0;
451 Status
= PeiServicesLocatePpi (
452 &gEfiPeiReadOnlyVariable2PpiGuid
,
455 (VOID
**) &PPIVariableServices
457 if (Status
== EFI_SUCCESS
) {
458 StrCpy (CapsuleVarName
, EFI_CAPSULE_VARIABLE_NAME
);
459 TempVarName
= CapsuleVarName
+ StrLen (CapsuleVarName
);
460 Size
= sizeof (CapsuleDataPtr64
);
464 // For the first Capsule Image
466 Status
= PPIVariableServices
->GetVariable (
469 &gEfiCapsuleVendorGuid
,
472 (VOID
*) &CapsuleDataPtr64
474 if (EFI_ERROR (Status
)) {
475 DEBUG ((EFI_D_ERROR
, "Capsule -- capsule variable not set\n"));
476 return EFI_NOT_FOUND
;
479 // We have a chicken/egg situation where the memory init code needs to
480 // know the boot mode prior to initializing memory. For this case, our
481 // validate function will fail. We can detect if this is the case if blocklist
482 // pointer is null. In that case, return success since we know that the
485 if (DescriptorBuffer
== NULL
) {
489 UnicodeValueToString (TempVarName
, 0, Index
, 0);
490 Status
= PPIVariableServices
->GetVariable (
493 &gEfiCapsuleVendorGuid
,
496 (VOID
*) &CapsuleDataPtr64
498 if (EFI_ERROR (Status
)) {
503 // If this BlockList has been linked before, skip this variable
506 for (TempIndex
= 0; TempIndex
< ValidIndex
; TempIndex
++) {
507 if (DescriptorBuffer
[TempIndex
] == CapsuleDataPtr64
) {
519 // Cache BlockList which has been processed
521 DescriptorBuffer
[ValidIndex
++] = CapsuleDataPtr64
;
530 Locates the coalesce image entry point, and detects its machine type.
532 @param CoalesceImageEntryPoint Pointer to coalesce image entry point for output.
533 @param CoalesceImageMachineType Pointer to machine type of coalesce image.
535 @retval EFI_SUCCESS Coalesce image successfully located.
536 @retval Others Failed to locate the coalesce image.
540 FindCapsuleCoalesceImage (
541 OUT EFI_PHYSICAL_ADDRESS
*CoalesceImageEntryPoint
,
542 OUT UINT16
*CoalesceImageMachineType
547 EFI_PEI_LOAD_FILE_PPI
*LoadFile
;
548 EFI_PEI_FV_HANDLE VolumeHandle
;
549 EFI_PEI_FILE_HANDLE FileHandle
;
550 EFI_PHYSICAL_ADDRESS CoalesceImageAddress
;
551 UINT64 CoalesceImageSize
;
552 UINT32 AuthenticationState
;
557 Status
= PeiServicesFfsFindNextVolume (Instance
++, &VolumeHandle
);
558 if (EFI_ERROR (Status
)) {
561 Status
= PeiServicesFfsFindFileByName (PcdGetPtr(PcdCapsuleCoalesceFile
), VolumeHandle
, &FileHandle
);
562 if (!EFI_ERROR (Status
)) {
563 Status
= PeiServicesLocatePpi (&gEfiPeiLoadFilePpiGuid
, 0, NULL
, (VOID
**) &LoadFile
);
564 ASSERT_EFI_ERROR (Status
);
566 Status
= LoadFile
->LoadFile (
569 &CoalesceImageAddress
,
571 CoalesceImageEntryPoint
,
574 if (EFI_ERROR (Status
)) {
575 DEBUG ((EFI_D_ERROR
, "Unable to find PE32 section in CapsuleRelocate image ffs %r!\n", Status
));
578 *CoalesceImageMachineType
= PeCoffLoaderGetMachineType ((VOID
*) (UINTN
) CoalesceImageAddress
);
589 Gets the reserved long mode buffer.
591 @param LongModeBuffer Pointer to the long mode buffer for output.
593 @retval EFI_SUCCESS Long mode buffer successfully retrieved.
594 @retval Others Variable storing long mode buffer not found.
599 OUT EFI_CAPSULE_LONG_MODE_BUFFER
*LongModeBuffer
604 EFI_PEI_READ_ONLY_VARIABLE2_PPI
*PPIVariableServices
;
606 Status
= PeiServicesLocatePpi (
607 &gEfiPeiReadOnlyVariable2PpiGuid
,
610 (VOID
**) &PPIVariableServices
612 ASSERT_EFI_ERROR (Status
);
614 Size
= sizeof (EFI_CAPSULE_LONG_MODE_BUFFER
);
615 Status
= PPIVariableServices
->GetVariable (
617 EFI_CAPSULE_LONG_MODE_BUFFER_NAME
,
618 &gEfiCapsuleVendorGuid
,
623 if (EFI_ERROR (Status
)) {
624 DEBUG (( EFI_D_ERROR
, "Error Get LongModeBuffer variable %r!\n", Status
));
630 Capsule PPI service to coalesce a fragmented capsule in memory.
632 @param PeiServices General purpose services available to every PEIM.
633 @param MemoryBase Pointer to the base of a block of memory that we can walk
634 all over while trying to coalesce our buffers.
635 On output, this variable will hold the base address of
637 @param MemorySize Size of the memory region pointed to by MemoryBase.
638 On output, this variable will contain the size of the
641 @retval EFI_NOT_FOUND if we can't determine the boot mode
642 if the boot mode is not flash-update
643 if we could not find the capsule descriptors
645 @retval EFI_BUFFER_TOO_SMALL
646 if we could not coalesce the capsule in the memory
647 region provided to us
649 @retval EFI_SUCCESS if there's no capsule, or if we processed the
650 capsule successfully.
655 IN EFI_PEI_SERVICES
**PeiServices
,
656 IN OUT VOID
**MemoryBase
,
657 IN OUT UINTN
*MemorySize
663 CHAR16 CapsuleVarName
[30];
665 EFI_PHYSICAL_ADDRESS CapsuleDataPtr64
;
667 EFI_BOOT_MODE BootMode
;
668 EFI_PEI_READ_ONLY_VARIABLE2_PPI
*PPIVariableServices
;
669 EFI_PHYSICAL_ADDRESS
*VariableArrayAddress
;
671 UINT16 CoalesceImageMachineType
;
672 EFI_PHYSICAL_ADDRESS CoalesceImageEntryPoint
;
673 COALESCE_ENTRY CoalesceEntry
;
674 EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer
;
679 CapsuleVarName
[0] = 0;
682 // Someone should have already ascertained the boot mode. If it's not
683 // capsule update, then return normally.
685 Status
= PeiServicesGetBootMode (&BootMode
);
686 if (EFI_ERROR (Status
) || (BootMode
!= BOOT_ON_FLASH_UPDATE
)) {
687 DEBUG ((EFI_D_ERROR
, "Boot mode is not correct for capsule update path.\n"));
688 Status
= EFI_NOT_FOUND
;
693 // User may set the same ScatterGatherList with several different variables,
694 // so cache all ScatterGatherList for check later.
696 Status
= PeiServicesLocatePpi (
697 &gEfiPeiReadOnlyVariable2PpiGuid
,
700 (VOID
**) &PPIVariableServices
702 if (EFI_ERROR (Status
)) {
705 Size
= sizeof (CapsuleDataPtr64
);
706 StrCpy (CapsuleVarName
, EFI_CAPSULE_VARIABLE_NAME
);
707 TempVarName
= CapsuleVarName
+ StrLen (CapsuleVarName
);
710 UnicodeValueToString (TempVarName
, 0, Index
, 0);
712 Status
= PPIVariableServices
->GetVariable (
715 &gEfiCapsuleVendorGuid
,
718 (VOID
*) &CapsuleDataPtr64
720 if (EFI_ERROR (Status
)) {
722 // There is no capsule variables, quit
724 DEBUG ((EFI_D_INFO
,"Capsule variable Index = %d\n", Index
));
731 DEBUG ((EFI_D_INFO
,"Capsule variable count = %d\n", VariableCount
));
734 // The last entry is the end flag.
736 Status
= PeiServicesAllocatePool (
737 (VariableCount
+ 1) * sizeof (EFI_PHYSICAL_ADDRESS
),
738 (VOID
**)&VariableArrayAddress
741 if (Status
!= EFI_SUCCESS
) {
742 DEBUG ((EFI_D_ERROR
, "AllocatePages Failed!, Status = %x\n", Status
));
746 ZeroMem (VariableArrayAddress
, (VariableCount
+ 1) * sizeof (EFI_PHYSICAL_ADDRESS
));
749 // Find out if we actually have a capsule.
750 // GetCapsuleDescriptors depends on variable PPI, so it should run in 32-bit environment.
752 Status
= GetCapsuleDescriptors (VariableArrayAddress
);
753 if (EFI_ERROR (Status
)) {
754 DEBUG ((EFI_D_ERROR
, "Fail to find capsule variables.\n"));
759 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode
)) {
761 // Switch to 64-bit mode to process capsule data when:
762 // 1. When DXE phase is 64-bit
763 // 2. When the buffer for 64-bit transition exists
764 // 3. When Capsule X64 image is built in BIOS image
765 // In 64-bit mode, we can process capsule data above 4GB.
767 CoalesceImageEntryPoint
= 0;
768 Status
= GetLongModeContext (&LongModeBuffer
);
769 if (EFI_ERROR (Status
)) {
770 DEBUG ((EFI_D_ERROR
, "Fail to find the variables for long mode context!\n"));
771 Status
= EFI_NOT_FOUND
;
775 Status
= FindCapsuleCoalesceImage (&CoalesceImageEntryPoint
, &CoalesceImageMachineType
);
776 if ((EFI_ERROR (Status
)) || (CoalesceImageMachineType
!= EFI_IMAGE_MACHINE_X64
)) {
777 DEBUG ((EFI_D_ERROR
, "Fail to find CapsuleX64 module in FV!\n"));
778 Status
= EFI_NOT_FOUND
;
781 ASSERT (CoalesceImageEntryPoint
!= 0);
782 CoalesceEntry
= (COALESCE_ENTRY
) (UINTN
) CoalesceImageEntryPoint
;
783 Status
= ModeSwitch (&LongModeBuffer
, CoalesceEntry
, (EFI_PHYSICAL_ADDRESS
)(UINTN
)VariableArrayAddress
, MemoryBase
, MemorySize
);
786 // Capsule is processed in IA32 mode.
788 Status
= CapsuleDataCoalesce (PeiServices
, (EFI_PHYSICAL_ADDRESS
*)(UINTN
)VariableArrayAddress
, MemoryBase
, MemorySize
);
792 // Process capsule directly.
794 Status
= CapsuleDataCoalesce (PeiServices
, (EFI_PHYSICAL_ADDRESS
*)(UINTN
)VariableArrayAddress
, MemoryBase
, MemorySize
);
797 DEBUG ((EFI_D_INFO
, "Capsule Coalesce Status = %r!\n", Status
));
799 if (Status
== EFI_BUFFER_TOO_SMALL
) {
800 DEBUG ((EFI_D_ERROR
, "There is not enough memory to process capsule!\n"));
803 if (Status
== EFI_NOT_FOUND
) {
804 DEBUG ((EFI_D_ERROR
, "Fail to parse capsule descriptor in memory!\n"));
806 EFI_ERROR_CODE
| EFI_ERROR_MAJOR
,
807 (EFI_SOFTWARE_PEI_MODULE
| EFI_SW_PEI_EC_INVALID_CAPSULE_DESCRIPTOR
)
816 Determine if we're in capsule update boot mode.
818 @param PeiServices PEI services table
820 @retval EFI_SUCCESS if we have a capsule available
821 @retval EFI_NOT_FOUND no capsule detected
827 IN EFI_PEI_SERVICES
**PeiServices
831 Status
= GetCapsuleDescriptors (NULL
);
835 This function will look at a capsule and determine if it's a test pattern.
836 If it is, then it will verify it and emit an error message if corruption is detected.
838 @param PeiServices Standard pei services pointer
839 @param CapsuleBase Base address of coalesced capsule, which is preceeded
840 by private data. Very implementation specific.
842 @retval TRUE Capsule image is the test image
843 @retval FALSE Capsule image is not the test image.
848 IN EFI_PEI_SERVICES
**PeiServices
,
860 // Look at the capsule data and determine if it's a test pattern. If it
861 // is, then test it now.
863 TestPtr
= (UINT32
*) CapsuleBase
;
867 if (*TestPtr
== 0x54534554) {
869 DEBUG ((EFI_D_INFO
, "Capsule test pattern mode activated...\n"));
870 TestSize
= TestPtr
[1] / sizeof (UINT32
);
872 // Skip over the signature and the size fields in the pattern data header
876 while (TestSize
> 0) {
877 if (*TestPtr
!= TestCounter
) {
878 DEBUG ((EFI_D_INFO
, "Capsule test pattern mode FAILED: BaseAddr/FailAddr 0x%X 0x%X\n", (UINT32
)(UINTN
)(EFI_CAPSULE_PEIM_PRIVATE_DATA
*)CapsuleBase
, (UINT32
)(UINTN
)TestPtr
));
887 DEBUG ((EFI_D_INFO
, "Capsule test pattern mode SUCCESS\n"));
894 Capsule PPI service that gets called after memory is available. The
895 capsule coalesce function, which must be called first, returns a base
896 address and size, which can be anything actually. Once the memory init
897 PEIM has discovered memory, then it should call this function and pass in
898 the base address and size returned by the coalesce function. Then this
899 function can create a capsule HOB and return.
901 @param PeiServices standard pei services pointer
902 @param CapsuleBase address returned by the capsule coalesce function. Most
903 likely this will actually be a pointer to private data.
904 @param CapsuleSize value returned by the capsule coalesce function.
906 @retval EFI_VOLUME_CORRUPTED CapsuleBase does not appear to point to a
908 @retval EFI_SUCCESS if all goes well.
913 IN EFI_PEI_SERVICES
**PeiServices
,
914 IN VOID
*CapsuleBase
,
919 EFI_CAPSULE_PEIM_PRIVATE_DATA
*PrivateData
;
921 EFI_PHYSICAL_ADDRESS NewBuffer
;
923 UINT32 CapsuleNumber
;
925 EFI_PHYSICAL_ADDRESS BaseAddress
;
930 PrivateData
= (EFI_CAPSULE_PEIM_PRIVATE_DATA
*) CapsuleBase
;
931 if (PrivateData
->Signature
!= EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE
) {
932 return EFI_VOLUME_CORRUPTED
;
935 // Capsule Number and Capsule Offset is in the tail of Capsule data.
937 Size
= (UINTN
) PrivateData
->CapsuleSize
;
938 DataPtr
= (UINT32
*)((UINTN
)CapsuleBase
+ (UINTN
)sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA
)+ Size
);
939 DataPtr
= (UINT32
*)(((UINTN
) DataPtr
+ sizeof(UINT32
) - 1) & ~(sizeof (UINT32
) - 1));
940 CapsuleNumber
= *DataPtr
++;
942 // Allocate the memory so that it gets preserved into DXE
944 Status
= PeiServicesAllocatePages (
945 EfiRuntimeServicesData
,
946 EFI_SIZE_TO_PAGES (Size
),
950 if (Status
!= EFI_SUCCESS
) {
951 DEBUG ((EFI_D_ERROR
, "AllocatePages Failed!\n"));
955 // Copy to our new buffer for DXE
957 DEBUG ((EFI_D_INFO
, "Capsule copy from 0x%8X to 0x%8X with size 0x%8X\n", (UINTN
) (PrivateData
+ 1), (UINTN
) NewBuffer
, Size
));
958 CopyMem ((VOID
*) (UINTN
) NewBuffer
, (VOID
*) (UINTN
) (PrivateData
+ 1), Size
);
960 // Check for test data pattern. If it is the test pattern, then we'll
961 // test it ans still create the HOB so that it can be used to verify
962 // that capsules don't get corrupted all the way into BDS. BDS will
963 // still try to turn it into a firmware volume, but will think it's
964 // corrupted so nothing will happen.
967 CapsuleTestPattern (PeiServices
, (VOID
*) (UINTN
) NewBuffer
);
971 // Build the UEFI Capsule Hob for each capsule image.
973 for (Index
= 0; Index
< CapsuleNumber
; Index
++) {
974 BaseAddress
= NewBuffer
+ DataPtr
[Index
];
975 Length
= ((EFI_CAPSULE_HEADER
*)((UINTN
) BaseAddress
))->CapsuleImageSize
;
977 BuildCvHob (BaseAddress
, Length
);
983 CONST PEI_CAPSULE_PPI mCapsulePpi
= {
989 CONST EFI_PEI_PPI_DESCRIPTOR mUefiPpiListCapsule
= {
990 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
992 (PEI_CAPSULE_PPI
*) &mCapsulePpi
996 Entry point function for the PEIM
998 @param FileHandle Handle of the file being invoked.
999 @param PeiServices Describes the list of possible PEI Services.
1001 @return EFI_SUCCESS If we installed our PPI
1007 IN EFI_PEI_FILE_HANDLE FileHandle
,
1008 IN CONST EFI_PEI_SERVICES
**PeiServices
1012 // Just produce our PPI
1014 return PeiServicesInstallPpi (&mUefiPpiListCapsule
);