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.
21 // Global Descriptor Table (GDT)
23 GLOBAL_REMOVE_IF_UNREFERENCED IA32_SEGMENT_DESCRIPTOR mGdtEntries
[] = {
24 /* selector { Global Segment Descriptor } */
25 /* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //null descriptor
26 /* 0x08 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear data segment descriptor
27 /* 0x10 */ {{0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear code segment descriptor
28 /* 0x18 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
29 /* 0x20 */ {{0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system code segment descriptor
30 /* 0x28 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
31 /* 0x30 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
32 /* 0x38 */ {{0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 1, 0, 1, 0}}, //system code segment descriptor
33 /* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
39 GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR mGdt
= {
40 sizeof (mGdtEntries
) - 1,
45 Calculate the total size of page table.
47 @return The size of page table.
52 CalculatePageTableSize (
57 UINT8 PhysicalAddressBits
;
59 UINT32 NumberOfPml4EntriesNeeded
;
60 UINT32 NumberOfPdpEntriesNeeded
;
63 // Get physical address bits supported from CPU HOB.
65 PhysicalAddressBits
= 36;
67 Hob
= GetFirstHob (EFI_HOB_TYPE_CPU
);
69 PhysicalAddressBits
= ((EFI_HOB_CPU
*) Hob
)->SizeOfMemorySpace
;
73 // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
75 ASSERT (PhysicalAddressBits
<= 52);
76 if (PhysicalAddressBits
> 48) {
77 PhysicalAddressBits
= 48;
81 // Calculate the table entries needed.
83 if (PhysicalAddressBits
<= 39 ) {
84 NumberOfPml4EntriesNeeded
= 1;
85 NumberOfPdpEntriesNeeded
= 1 << (PhysicalAddressBits
- 30);
87 NumberOfPml4EntriesNeeded
= 1 << (PhysicalAddressBits
- 39);
88 NumberOfPdpEntriesNeeded
= 512;
91 TotalPagesNum
= (NumberOfPdpEntriesNeeded
+ 1) * NumberOfPml4EntriesNeeded
+ 1;
93 return EFI_PAGES_TO_SIZE (TotalPagesNum
);
97 Allocates and fills in the Page Directory and Page Table Entries to
98 establish a 1:1 Virtual to Physical mapping.
100 @param[in] PageTablesAddress The base address of page table.
104 CreateIdentityMappingPageTables (
105 IN EFI_PHYSICAL_ADDRESS PageTablesAddress
108 UINT8 PhysicalAddressBits
;
109 EFI_PHYSICAL_ADDRESS PageAddress
;
110 UINTN IndexOfPml4Entries
;
111 UINTN IndexOfPdpEntries
;
112 UINTN IndexOfPageDirectoryEntries
;
113 UINT32 NumberOfPml4EntriesNeeded
;
114 UINT32 NumberOfPdpEntriesNeeded
;
115 PAGE_MAP_AND_DIRECTORY_POINTER
*PageMapLevel4Entry
;
116 PAGE_MAP_AND_DIRECTORY_POINTER
*PageMap
;
117 PAGE_MAP_AND_DIRECTORY_POINTER
*PageDirectoryPointerEntry
;
118 PAGE_TABLE_ENTRY
*PageDirectoryEntry
;
119 UINTN BigPageAddress
;
123 // Get physical address bits supported from CPU HOB.
125 PhysicalAddressBits
= 36;
127 Hob
= GetFirstHob (EFI_HOB_TYPE_CPU
);
129 PhysicalAddressBits
= ((EFI_HOB_CPU
*) Hob
)->SizeOfMemorySpace
;
133 // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
135 ASSERT (PhysicalAddressBits
<= 52);
136 if (PhysicalAddressBits
> 48) {
137 PhysicalAddressBits
= 48;
141 // Calculate the table entries needed.
143 if (PhysicalAddressBits
<= 39 ) {
144 NumberOfPml4EntriesNeeded
= 1;
145 NumberOfPdpEntriesNeeded
= 1 << (PhysicalAddressBits
- 30);
147 NumberOfPml4EntriesNeeded
= 1 << (PhysicalAddressBits
- 39);
148 NumberOfPdpEntriesNeeded
= 512;
152 // Pre-allocate big pages to avoid later allocations.
154 BigPageAddress
= (UINTN
) PageTablesAddress
;
157 // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
159 PageMap
= (VOID
*) BigPageAddress
;
160 BigPageAddress
+= EFI_PAGE_SIZE
;
162 PageMapLevel4Entry
= PageMap
;
164 for (IndexOfPml4Entries
= 0; IndexOfPml4Entries
< NumberOfPml4EntriesNeeded
; IndexOfPml4Entries
++, PageMapLevel4Entry
++) {
166 // Each PML4 entry points to a page of Page Directory Pointer entires.
167 // So lets allocate space for them and fill them in in the IndexOfPdpEntries loop.
169 PageDirectoryPointerEntry
= (VOID
*) BigPageAddress
;
170 BigPageAddress
+= EFI_PAGE_SIZE
;
175 PageMapLevel4Entry
->Uint64
= (UINT64
)(UINTN
)PageDirectoryPointerEntry
;
176 PageMapLevel4Entry
->Bits
.ReadWrite
= 1;
177 PageMapLevel4Entry
->Bits
.Present
= 1;
179 for (IndexOfPdpEntries
= 0; IndexOfPdpEntries
< NumberOfPdpEntriesNeeded
; IndexOfPdpEntries
++, PageDirectoryPointerEntry
++) {
181 // Each Directory Pointer entries points to a page of Page Directory entires.
182 // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.
184 PageDirectoryEntry
= (VOID
*) BigPageAddress
;
185 BigPageAddress
+= EFI_PAGE_SIZE
;
188 // Fill in a Page Directory Pointer Entries
190 PageDirectoryPointerEntry
->Uint64
= (UINT64
)(UINTN
)PageDirectoryEntry
;
191 PageDirectoryPointerEntry
->Bits
.ReadWrite
= 1;
192 PageDirectoryPointerEntry
->Bits
.Present
= 1;
194 for (IndexOfPageDirectoryEntries
= 0; IndexOfPageDirectoryEntries
< 512; IndexOfPageDirectoryEntries
++, PageDirectoryEntry
++, PageAddress
+= 0x200000) {
196 // Fill in the Page Directory entries
198 PageDirectoryEntry
->Uint64
= (UINT64
)PageAddress
;
199 PageDirectoryEntry
->Bits
.ReadWrite
= 1;
200 PageDirectoryEntry
->Bits
.Present
= 1;
201 PageDirectoryEntry
->Bits
.MustBe1
= 1;
208 // For the PML4 entries we are not using fill in a null entry.
209 // For now we just copy the first entry.
211 for (; IndexOfPml4Entries
< 512; IndexOfPml4Entries
++, PageMapLevel4Entry
++) {
215 sizeof (PAGE_MAP_AND_DIRECTORY_POINTER
)
221 Return function from long mode to 32-bit mode.
223 @param EntrypointContext Context for mode switching
224 @param ReturnContext Context for mode switching
229 SWITCH_32_TO_64_CONTEXT
*EntrypointContext
,
230 SWITCH_64_TO_32_CONTEXT
*ReturnContext
234 // Restore original GDT
236 AsmWriteGdtr (&ReturnContext
->Gdtr
);
239 // return to original caller
241 LongJump ((BASE_LIBRARY_JUMP_BUFFER
*)(UINTN
)EntrypointContext
->JumpBuffer
, 1);
250 Thunk function from 32-bit protection mode to long mode.
252 @param PageTableAddress Page table base address
253 @param Context Context for mode switching
254 @param ReturnContext Context for mode switching
256 @retval EFI_SUCCESS Function successfully executed.
261 EFI_PHYSICAL_ADDRESS PageTableAddress
,
262 SWITCH_32_TO_64_CONTEXT
*Context
,
263 SWITCH_64_TO_32_CONTEXT
*ReturnContext
270 // Save return address, LongJump will return here then
272 SetJumpFlag
= SetJump ((BASE_LIBRARY_JUMP_BUFFER
*) (UINTN
) Context
->JumpBuffer
);
274 if (SetJumpFlag
== 0) {
277 // Build Page Tables for all physical memory processor supports
279 CreateIdentityMappingPageTables (PageTableAddress
);
284 AsmWriteGdtr (&mGdt
);
289 AsmWriteCr3 ((UINTN
) PageTableAddress
);
292 // Transfer to long mode
296 (UINT64
) Context
->EntryPoint
,
297 (UINT64
)(UINTN
) Context
,
298 (UINT64
)(UINTN
) ReturnContext
,
299 Context
->StackBufferBase
+ Context
->StackBufferLength
304 // Convert to 32-bit Status and return
306 Status
= EFI_SUCCESS
;
307 if ((UINTN
) ReturnContext
->ReturnStatus
!= 0) {
308 Status
= ENCODE_ERROR ((UINTN
) ReturnContext
->ReturnStatus
);
315 If in 32 bit protection mode, and coalesce image is of X64, switch to long mode.
317 @param LongModeBuffer The context of long mode.
318 @param CoalesceEntry Entry of coalesce image.
319 @param BlockListAddr Address of block list.
320 @param MemoryBase Base of memory range.
321 @param MemorySize Size of memory range.
323 @retval EFI_SUCCESS Successfully switched to long mode and execute coalesce.
324 @retval Others Failed to execute coalesce in long mode.
329 IN EFI_CAPSULE_LONG_MODE_BUFFER
*LongModeBuffer
,
330 IN COALESCE_ENTRY CoalesceEntry
,
331 IN EFI_PHYSICAL_ADDRESS BlockListAddr
,
332 IN OUT VOID
**MemoryBase
,
333 IN OUT UINTN
*MemorySize
337 EFI_PHYSICAL_ADDRESS MemoryBase64
;
339 EFI_PHYSICAL_ADDRESS MemoryEnd64
;
340 SWITCH_32_TO_64_CONTEXT Context
;
341 SWITCH_64_TO_32_CONTEXT ReturnContext
;
342 BASE_LIBRARY_JUMP_BUFFER JumpBuffer
;
343 EFI_PHYSICAL_ADDRESS ReservedRangeBase
;
344 EFI_PHYSICAL_ADDRESS ReservedRangeEnd
;
346 ZeroMem (&Context
, sizeof (SWITCH_32_TO_64_CONTEXT
));
347 ZeroMem (&ReturnContext
, sizeof (SWITCH_64_TO_32_CONTEXT
));
349 MemoryBase64
= (UINT64
) (UINTN
) *MemoryBase
;
350 MemorySize64
= (UINT64
) (UINTN
) *MemorySize
;
351 MemoryEnd64
= MemoryBase64
+ MemorySize64
;
354 // Merge memory range reserved for stack and page table
356 if (LongModeBuffer
->StackBaseAddress
< LongModeBuffer
->PageTableAddress
) {
357 ReservedRangeBase
= LongModeBuffer
->StackBaseAddress
;
358 ReservedRangeEnd
= LongModeBuffer
->PageTableAddress
+ CalculatePageTableSize ();
360 ReservedRangeBase
= LongModeBuffer
->PageTableAddress
;
361 ReservedRangeEnd
= LongModeBuffer
->StackBaseAddress
+ LongModeBuffer
->StackSize
;
365 // Check if memory range reserved is overlap with MemoryBase ~ MemoryBase + MemorySize.
366 // If they are overlapped, get a larger range to process capsule data.
368 if (ReservedRangeBase
<= MemoryBase64
) {
369 if (ReservedRangeEnd
< MemoryEnd64
) {
370 MemoryBase64
= ReservedRangeEnd
;
372 DEBUG ((EFI_D_ERROR
, "Memory is not enough to process capsule!\n"));
373 return EFI_OUT_OF_RESOURCES
;
375 } else if (ReservedRangeBase
< MemoryEnd64
) {
376 if (ReservedRangeEnd
< MemoryEnd64
&&
377 ReservedRangeBase
- MemoryBase64
< MemoryEnd64
- ReservedRangeEnd
) {
378 MemoryBase64
= ReservedRangeEnd
;
380 MemorySize64
= (UINT64
)(UINTN
)(ReservedRangeBase
- MemoryBase64
);
385 // Initialize context jumping to 64-bit enviroment
387 Context
.JumpBuffer
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&JumpBuffer
;
388 Context
.StackBufferBase
= LongModeBuffer
->StackBaseAddress
;
389 Context
.StackBufferLength
= LongModeBuffer
->StackSize
;
390 Context
.EntryPoint
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)CoalesceEntry
;
391 Context
.BlockListAddr
= BlockListAddr
;
392 Context
.MemoryBase64Ptr
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&MemoryBase64
;
393 Context
.MemorySize64Ptr
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&MemorySize64
;
396 // Prepare data for return back
398 ReturnContext
.ReturnCs
= 0x10;
399 ReturnContext
.ReturnEntryPoint
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)ReturnFunction
;
401 // Will save the return status of processing capsule
403 ReturnContext
.ReturnStatus
= 0;
408 AsmReadGdtr ((IA32_DESCRIPTOR
*)&ReturnContext
.Gdtr
);
410 Status
= Thunk32To64 (LongModeBuffer
->PageTableAddress
, &Context
, &ReturnContext
);
412 if (!EFI_ERROR (Status
)) {
413 *MemoryBase
= (VOID
*) (UINTN
) MemoryBase64
;
414 *MemorySize
= (UINTN
) MemorySize64
;
422 Locates the coalesce image entry point, and detects its machine type.
424 @param CoalesceImageEntryPoint Pointer to coalesce image entry point for output.
425 @param CoalesceImageMachineType Pointer to machine type of coalesce image.
427 @retval EFI_SUCCESS Coalesce image successfully located.
428 @retval Others Failed to locate the coalesce image.
432 FindCapsuleCoalesceImage (
433 OUT EFI_PHYSICAL_ADDRESS
*CoalesceImageEntryPoint
,
434 OUT UINT16
*CoalesceImageMachineType
439 EFI_PEI_LOAD_FILE_PPI
*LoadFile
;
440 EFI_PEI_FV_HANDLE VolumeHandle
;
441 EFI_PEI_FILE_HANDLE FileHandle
;
442 EFI_PHYSICAL_ADDRESS CoalesceImageAddress
;
443 UINT64 CoalesceImageSize
;
444 UINT32 AuthenticationState
;
449 Status
= PeiServicesFfsFindNextVolume (Instance
++, &VolumeHandle
);
450 if (EFI_ERROR (Status
)) {
453 Status
= PeiServicesFfsFindFileByName (PcdGetPtr(PcdCapsuleCoalesceFile
), VolumeHandle
, &FileHandle
);
454 if (!EFI_ERROR (Status
)) {
455 Status
= PeiServicesLocatePpi (&gEfiPeiLoadFilePpiGuid
, 0, NULL
, (VOID
**) &LoadFile
);
456 ASSERT_EFI_ERROR (Status
);
458 Status
= LoadFile
->LoadFile (
461 &CoalesceImageAddress
,
463 CoalesceImageEntryPoint
,
466 if (EFI_ERROR (Status
)) {
467 DEBUG ((EFI_D_ERROR
, "Unable to find PE32 section in CapsuleRelocate image ffs %r!\n", Status
));
470 *CoalesceImageMachineType
= PeCoffLoaderGetMachineType ((VOID
*) (UINTN
) CoalesceImageAddress
);
483 Checks for the presence of capsule descriptors.
484 Get capsule descriptors from variable CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
485 and save to DescriptorBuffer.
487 @param DescriptorBuffer Pointer to the capsule descriptors
489 @retval EFI_SUCCESS a valid capsule is present
490 @retval EFI_NOT_FOUND if a valid capsule is not present
493 GetCapsuleDescriptors (
494 IN EFI_PHYSICAL_ADDRESS
*DescriptorBuffer
503 CHAR16 CapsuleVarName
[30];
505 EFI_PHYSICAL_ADDRESS CapsuleDataPtr64
;
506 EFI_PEI_READ_ONLY_VARIABLE2_PPI
*PPIVariableServices
;
510 CapsuleVarName
[0] = 0;
513 Status
= PeiServicesLocatePpi (
514 &gEfiPeiReadOnlyVariable2PpiGuid
,
517 (VOID
**) &PPIVariableServices
519 if (Status
== EFI_SUCCESS
) {
520 StrCpy (CapsuleVarName
, EFI_CAPSULE_VARIABLE_NAME
);
521 TempVarName
= CapsuleVarName
+ StrLen (CapsuleVarName
);
522 Size
= sizeof (CapsuleDataPtr64
);
526 // For the first Capsule Image
528 Status
= PPIVariableServices
->GetVariable (
531 &gEfiCapsuleVendorGuid
,
534 (VOID
*) &CapsuleDataPtr64
536 if (EFI_ERROR (Status
)) {
537 DEBUG ((EFI_D_ERROR
, "Capsule -- capsule variable not set\n"));
538 return EFI_NOT_FOUND
;
541 // We have a chicken/egg situation where the memory init code needs to
542 // know the boot mode prior to initializing memory. For this case, our
543 // validate function will fail. We can detect if this is the case if blocklist
544 // pointer is null. In that case, return success since we know that the
547 if (DescriptorBuffer
== NULL
) {
551 UnicodeValueToString (TempVarName
, 0, Index
, 0);
552 Status
= PPIVariableServices
->GetVariable (
555 &gEfiCapsuleVendorGuid
,
558 (VOID
*) &CapsuleDataPtr64
560 if (EFI_ERROR (Status
)) {
565 // If this BlockList has been linked before, skip this variable
568 for (TempIndex
= 0; TempIndex
< ValidIndex
; TempIndex
++) {
569 if (DescriptorBuffer
[TempIndex
] == CapsuleDataPtr64
) {
581 // Cache BlockList which has been processed
583 DescriptorBuffer
[ValidIndex
++] = CapsuleDataPtr64
;
592 Gets the reserved long mode buffer.
594 @param LongModeBuffer Pointer to the long mode buffer for output.
596 @retval EFI_SUCCESS Long mode buffer successfully retrieved.
597 @retval Others Variable storing long mode buffer not found.
602 OUT EFI_CAPSULE_LONG_MODE_BUFFER
*LongModeBuffer
607 EFI_PEI_READ_ONLY_VARIABLE2_PPI
*PPIVariableServices
;
609 Status
= PeiServicesLocatePpi (
610 &gEfiPeiReadOnlyVariable2PpiGuid
,
613 (VOID
**) &PPIVariableServices
615 ASSERT_EFI_ERROR (Status
);
617 Size
= sizeof (EFI_CAPSULE_LONG_MODE_BUFFER
);
618 Status
= PPIVariableServices
->GetVariable (
620 EFI_CAPSULE_LONG_MODE_BUFFER_NAME
,
621 &gEfiCapsuleVendorGuid
,
626 if (EFI_ERROR (Status
)) {
627 DEBUG (( EFI_D_ERROR
, "Error Get LongModeBuffer variable %r!\n", Status
));
633 Capsule PPI service to coalesce a fragmented capsule in memory.
635 @param PeiServices General purpose services available to every PEIM.
636 @param MemoryBase Pointer to the base of a block of memory that we can walk
637 all over while trying to coalesce our buffers.
638 On output, this variable will hold the base address of
640 @param MemorySize Size of the memory region pointed to by MemoryBase.
641 On output, this variable will contain the size of the
644 @retval EFI_NOT_FOUND if we can't determine the boot mode
645 if the boot mode is not flash-update
646 if we could not find the capsule descriptors
648 @retval EFI_BUFFER_TOO_SMALL
649 if we could not coalesce the capsule in the memory
650 region provided to us
652 @retval EFI_SUCCESS if there's no capsule, or if we processed the
653 capsule successfully.
658 IN EFI_PEI_SERVICES
**PeiServices
,
659 IN OUT VOID
**MemoryBase
,
660 IN OUT UINTN
*MemorySize
666 CHAR16 CapsuleVarName
[30];
668 EFI_PHYSICAL_ADDRESS CapsuleDataPtr64
;
670 EFI_BOOT_MODE BootMode
;
671 EFI_PEI_READ_ONLY_VARIABLE2_PPI
*PPIVariableServices
;
672 EFI_PHYSICAL_ADDRESS
*VariableArrayAddress
;
674 UINT16 CoalesceImageMachineType
;
675 EFI_PHYSICAL_ADDRESS CoalesceImageEntryPoint
;
676 COALESCE_ENTRY CoalesceEntry
;
677 EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer
;
682 CapsuleVarName
[0] = 0;
685 // Someone should have already ascertained the boot mode. If it's not
686 // capsule update, then return normally.
688 Status
= PeiServicesGetBootMode (&BootMode
);
689 if (EFI_ERROR (Status
) || (BootMode
!= BOOT_ON_FLASH_UPDATE
)) {
690 DEBUG ((EFI_D_ERROR
, "Boot mode is not correct for capsule update path.\n"));
691 Status
= EFI_NOT_FOUND
;
696 // User may set the same ScatterGatherList with several different variables,
697 // so cache all ScatterGatherList for check later.
699 Status
= PeiServicesLocatePpi (
700 &gEfiPeiReadOnlyVariable2PpiGuid
,
703 (VOID
**) &PPIVariableServices
705 if (EFI_ERROR (Status
)) {
708 Size
= sizeof (CapsuleDataPtr64
);
709 StrCpy (CapsuleVarName
, EFI_CAPSULE_VARIABLE_NAME
);
710 TempVarName
= CapsuleVarName
+ StrLen (CapsuleVarName
);
713 UnicodeValueToString (TempVarName
, 0, Index
, 0);
715 Status
= PPIVariableServices
->GetVariable (
718 &gEfiCapsuleVendorGuid
,
721 (VOID
*) &CapsuleDataPtr64
723 if (EFI_ERROR (Status
)) {
725 // There is no capsule variables, quit
727 DEBUG ((EFI_D_INFO
,"Capsule variable Index = %d\n", Index
));
734 DEBUG ((EFI_D_INFO
,"Capsule variable count = %d\n", VariableCount
));
737 // The last entry is the end flag.
739 Status
= PeiServicesAllocatePool (
740 (VariableCount
+ 1) * sizeof (EFI_PHYSICAL_ADDRESS
),
741 (VOID
**)&VariableArrayAddress
744 if (Status
!= EFI_SUCCESS
) {
745 DEBUG ((EFI_D_ERROR
, "AllocatePages Failed!, Status = %x\n", Status
));
749 ZeroMem (VariableArrayAddress
, (VariableCount
+ 1) * sizeof (EFI_PHYSICAL_ADDRESS
));
752 // Find out if we actually have a capsule.
753 // GetCapsuleDescriptors depends on variable PPI, so it should run in 32-bit environment.
755 Status
= GetCapsuleDescriptors (VariableArrayAddress
);
756 if (EFI_ERROR (Status
)) {
757 DEBUG ((EFI_D_ERROR
, "Fail to find capsule variables.\n"));
762 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode
)) {
764 // Switch to 64-bit mode to process capsule data when:
765 // 1. When DXE phase is 64-bit
766 // 2. When the buffer for 64-bit transition exists
767 // 3. When Capsule X64 image is built in BIOS image
768 // In 64-bit mode, we can process capsule data above 4GB.
770 CoalesceImageEntryPoint
= 0;
771 Status
= GetLongModeContext (&LongModeBuffer
);
772 if (EFI_ERROR (Status
)) {
773 DEBUG ((EFI_D_ERROR
, "Fail to find the variables for long mode context!\n"));
774 Status
= EFI_NOT_FOUND
;
778 Status
= FindCapsuleCoalesceImage (&CoalesceImageEntryPoint
, &CoalesceImageMachineType
);
779 if ((EFI_ERROR (Status
)) || (CoalesceImageMachineType
!= EFI_IMAGE_MACHINE_X64
)) {
780 DEBUG ((EFI_D_ERROR
, "Fail to find CapsuleX64 module in FV!\n"));
781 Status
= EFI_NOT_FOUND
;
784 ASSERT (CoalesceImageEntryPoint
!= 0);
785 CoalesceEntry
= (COALESCE_ENTRY
) (UINTN
) CoalesceImageEntryPoint
;
786 Status
= ModeSwitch (&LongModeBuffer
, CoalesceEntry
, (EFI_PHYSICAL_ADDRESS
)(UINTN
)VariableArrayAddress
, MemoryBase
, MemorySize
);
789 // Capsule is processed in IA32 mode.
791 Status
= CapsuleDataCoalesce (PeiServices
, (EFI_PHYSICAL_ADDRESS
*)(UINTN
)VariableArrayAddress
, MemoryBase
, MemorySize
);
795 // Process capsule directly.
797 Status
= CapsuleDataCoalesce (PeiServices
, (EFI_PHYSICAL_ADDRESS
*)(UINTN
)VariableArrayAddress
, MemoryBase
, MemorySize
);
800 DEBUG ((EFI_D_INFO
, "Capsule Coalesce Status = %r!\n", Status
));
802 if (Status
== EFI_BUFFER_TOO_SMALL
) {
803 DEBUG ((EFI_D_ERROR
, "There is not enough memory to process capsule!\n"));
806 if (Status
== EFI_NOT_FOUND
) {
807 DEBUG ((EFI_D_ERROR
, "Fail to parse capsule descriptor in memory!\n"));
809 EFI_ERROR_CODE
| EFI_ERROR_MAJOR
,
810 (EFI_SOFTWARE_PEI_MODULE
| EFI_SW_PEI_EC_INVALID_CAPSULE_DESCRIPTOR
)
819 Determine if we're in capsule update boot mode.
821 @param PeiServices PEI services table
823 @retval EFI_SUCCESS if we have a capsule available
824 @retval EFI_NOT_FOUND no capsule detected
830 IN EFI_PEI_SERVICES
**PeiServices
834 Status
= GetCapsuleDescriptors (NULL
);
838 This function will look at a capsule and determine if it's a test pattern.
839 If it is, then it will verify it and emit an error message if corruption is detected.
841 @param PeiServices Standard pei services pointer
842 @param CapsuleBase Base address of coalesced capsule, which is preceeded
843 by private data. Very implementation specific.
845 @retval TRUE Capsule image is the test image
846 @retval FALSE Capsule image is not the test image.
851 IN EFI_PEI_SERVICES
**PeiServices
,
863 // Look at the capsule data and determine if it's a test pattern. If it
864 // is, then test it now.
866 TestPtr
= (UINT32
*) CapsuleBase
;
870 if (*TestPtr
== 0x54534554) {
872 DEBUG ((EFI_D_INFO
, "Capsule test pattern mode activated...\n"));
873 TestSize
= TestPtr
[1] / sizeof (UINT32
);
875 // Skip over the signature and the size fields in the pattern data header
879 while (TestSize
> 0) {
880 if (*TestPtr
!= TestCounter
) {
881 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
));
890 DEBUG ((EFI_D_INFO
, "Capsule test pattern mode SUCCESS\n"));
897 Capsule PPI service that gets called after memory is available. The
898 capsule coalesce function, which must be called first, returns a base
899 address and size, which can be anything actually. Once the memory init
900 PEIM has discovered memory, then it should call this function and pass in
901 the base address and size returned by the coalesce function. Then this
902 function can create a capsule HOB and return.
904 @param PeiServices standard pei services pointer
905 @param CapsuleBase address returned by the capsule coalesce function. Most
906 likely this will actually be a pointer to private data.
907 @param CapsuleSize value returned by the capsule coalesce function.
909 @retval EFI_VOLUME_CORRUPTED CapsuleBase does not appear to point to a
911 @retval EFI_SUCCESS if all goes well.
916 IN EFI_PEI_SERVICES
**PeiServices
,
917 IN VOID
*CapsuleBase
,
922 EFI_CAPSULE_PEIM_PRIVATE_DATA
*PrivateData
;
924 EFI_PHYSICAL_ADDRESS NewBuffer
;
926 UINT32 CapsuleNumber
;
928 EFI_PHYSICAL_ADDRESS BaseAddress
;
933 PrivateData
= (EFI_CAPSULE_PEIM_PRIVATE_DATA
*) CapsuleBase
;
934 if (PrivateData
->Signature
!= EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE
) {
935 return EFI_VOLUME_CORRUPTED
;
938 // Capsule Number and Capsule Offset is in the tail of Capsule data.
940 Size
= (UINTN
) PrivateData
->CapsuleSize
;
941 DataPtr
= (UINT32
*)((UINTN
)CapsuleBase
+ (UINTN
)sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA
)+ Size
);
942 DataPtr
= (UINT32
*)(((UINTN
) DataPtr
+ sizeof(UINT32
) - 1) & ~(sizeof (UINT32
) - 1));
943 CapsuleNumber
= *DataPtr
++;
945 // Allocate the memory so that it gets preserved into DXE
947 Status
= PeiServicesAllocatePages (
948 EfiRuntimeServicesData
,
949 EFI_SIZE_TO_PAGES (Size
),
953 if (Status
!= EFI_SUCCESS
) {
954 DEBUG ((EFI_D_ERROR
, "AllocatePages Failed!\n"));
958 // Copy to our new buffer for DXE
960 DEBUG ((EFI_D_INFO
, "Capsule copy from 0x%8X to 0x%8X with size 0x%8X\n", (UINTN
) (PrivateData
+ 1), (UINTN
) NewBuffer
, Size
));
961 CopyMem ((VOID
*) (UINTN
) NewBuffer
, (VOID
*) (UINTN
) (PrivateData
+ 1), Size
);
963 // Check for test data pattern. If it is the test pattern, then we'll
964 // test it ans still create the HOB so that it can be used to verify
965 // that capsules don't get corrupted all the way into BDS. BDS will
966 // still try to turn it into a firmware volume, but will think it's
967 // corrupted so nothing will happen.
970 CapsuleTestPattern (PeiServices
, (VOID
*) (UINTN
) NewBuffer
);
974 // Build the UEFI Capsule Hob for each capsule image.
976 for (Index
= 0; Index
< CapsuleNumber
; Index
++) {
977 BaseAddress
= NewBuffer
+ DataPtr
[Index
];
978 Length
= ((EFI_CAPSULE_HEADER
*)((UINTN
) BaseAddress
))->CapsuleImageSize
;
980 BuildCvHob (BaseAddress
, Length
);
986 CONST PEI_CAPSULE_PPI mCapsulePpi
= {
992 CONST EFI_PEI_PPI_DESCRIPTOR mUefiPpiListCapsule
= {
993 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
995 (PEI_CAPSULE_PPI
*) &mCapsulePpi
999 Entry point function for the PEIM
1001 @param FileHandle Handle of the file being invoked.
1002 @param PeiServices Describes the list of possible PEI Services.
1004 @return EFI_SUCCESS If we installed our PPI
1010 IN EFI_PEI_FILE_HANDLE FileHandle
,
1011 IN CONST EFI_PEI_SERVICES
**PeiServices
1015 // Just produce our PPI
1017 return PeiServicesInstallPpi (&mUefiPpiListCapsule
);