2 The logic to process capsule.
4 Caution: This module requires additional review when modified.
5 This driver will have external input - capsule image.
6 This external input must be validated carefully to avoid security issue like
7 buffer overflow, integer overflow.
9 CapsuleDataCoalesce() will do basic validation before coalesce capsule data
12 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
13 Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
14 SPDX-License-Identifier: BSD-2-Clause-Patent
21 #include <Guid/CapsuleVendor.h>
23 #include <Library/BaseMemoryLib.h>
24 #include <Library/DebugLib.h>
25 #include <Library/PrintLib.h>
26 #include <Library/BaseLib.h>
28 #include "CommonHeader.h"
30 #define MIN_COALESCE_ADDR (1024 * 1024)
33 Given a pointer to the capsule block list, info on the available system
34 memory, and the size of a buffer, find a free block of memory where a
35 buffer of the given size can be copied to safely.
37 @param BlockList Pointer to head of capsule block descriptors
38 @param MemBase Pointer to the base of memory in which we want to find free space
39 @param MemSize The size of the block of memory pointed to by MemBase
40 @param DataSize How big a free block we want to find
42 @return A pointer to a memory block of at least DataSize that lies somewhere
43 between MemBase and (MemBase + MemSize). The memory pointed to does not
44 contain any of the capsule block descriptors or capsule blocks pointed to
50 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockList
,
57 The capsule block descriptors may be fragmented and spread all over memory.
58 To simplify the coalescing of capsule blocks, first coalesce all the
59 capsule block descriptors low in memory.
61 The descriptors passed in can be fragmented throughout memory. Here
62 they are relocated into memory to turn them into a contiguous (null
65 @param PeiServices pointer to PEI services table
66 @param BlockList pointer to the capsule block descriptors
67 @param NumDescriptors number of capsule data block descriptors, whose Length is non-zero.
68 @param MemBase base of system memory in which we can work
69 @param MemSize size of the system memory pointed to by MemBase
71 @retval NULL could not relocate the descriptors
72 @retval Pointer to the base of the successfully-relocated block descriptors.
75 EFI_CAPSULE_BLOCK_DESCRIPTOR
*
76 RelocateBlockDescriptors (
77 IN EFI_PEI_SERVICES
**PeiServices
,
78 IN EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockList
,
79 IN UINTN NumDescriptors
,
85 Check every capsule header.
87 @param CapsuleHeader The pointer to EFI_CAPSULE_HEADER
89 @retval FALSE Capsule is OK
90 @retval TRUE Capsule is corrupted
95 IN EFI_CAPSULE_HEADER
*CapsuleHeader
99 Determine if two buffers overlap in memory.
101 @param Buff1 pointer to first buffer
102 @param Size1 size of Buff1
103 @param Buff2 pointer to second buffer
104 @param Size2 size of Buff2
106 @retval TRUE Buffers overlap in memory.
107 @retval FALSE Buffer doesn't overlap.
119 Given a pointer to a capsule block descriptor, traverse the list to figure
120 out how many legitimate descriptors there are, and how big the capsule it
123 @param Desc Pointer to the capsule block descriptors
124 @param NumDescriptors Optional pointer to where to return the number of capsule data descriptors, whose Length is non-zero.
125 @param CapsuleSize Optional pointer to where to return the capsule image size
126 @param CapsuleNumber Optional pointer to where to return the number of capsule
128 @retval EFI_NOT_FOUND No descriptors containing data in the list
129 @retval EFI_SUCCESS Return data is valid
134 IN EFI_CAPSULE_BLOCK_DESCRIPTOR
*Desc
,
135 IN OUT UINTN
*NumDescriptors OPTIONAL
,
136 IN OUT UINTN
*CapsuleSize OPTIONAL
,
137 IN OUT UINTN
*CapsuleNumber OPTIONAL
141 Given a pointer to the capsule block list, info on the available system
142 memory, and the size of a buffer, find a free block of memory where a
143 buffer of the given size can be copied to safely.
145 @param BlockList Pointer to head of capsule block descriptors
146 @param MemBase Pointer to the base of memory in which we want to find free space
147 @param MemSize The size of the block of memory pointed to by MemBase
148 @param DataSize How big a free block we want to find
150 @return A pointer to a memory block of at least DataSize that lies somewhere
151 between MemBase and (MemBase + MemSize). The memory pointed to does not
152 contain any of the capsule block descriptors or capsule blocks pointed to
158 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockList
,
165 EFI_CAPSULE_BLOCK_DESCRIPTOR
*CurrDesc
;
166 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempDesc
;
171 // Need at least enough to copy the data to at the end of the buffer, so
172 // say the end is less the data size for easy comparisons here.
174 MemEnd
= MemBase
+ MemSize
- DataSize
;
175 CurrDesc
= BlockList
;
177 // Go through all the descriptor blocks and see if any obstruct the range
179 while (CurrDesc
!= NULL
) {
181 // Get the size of this block list and see if it's in the way
185 Size
= sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
);
186 while (TempDesc
->Length
!= 0) {
187 Size
+= sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
);
191 if (IsOverlapped (MemBase
, DataSize
, (UINT8
*)CurrDesc
, Size
)) {
193 // Set our new base to the end of this block list and start all over
195 MemBase
= (UINT8
*)CurrDesc
+ Size
;
196 CurrDesc
= BlockList
;
197 if (MemBase
> MemEnd
) {
205 // Now go through all the blocks and make sure none are in the way
207 while ((CurrDesc
->Length
!= 0) && (!Failed
)) {
208 if (IsOverlapped (MemBase
, DataSize
, (UINT8
*)(UINTN
)CurrDesc
->Union
.DataBlock
, (UINTN
)CurrDesc
->Length
)) {
210 // Set our new base to the end of this block and start all over
213 MemBase
= (UINT8
*)((UINTN
)CurrDesc
->Union
.DataBlock
) + CurrDesc
->Length
;
214 CurrDesc
= BlockList
;
215 if (MemBase
> MemEnd
) {
224 // Normal continuation -- jump to next block descriptor list
227 CurrDesc
= (EFI_CAPSULE_BLOCK_DESCRIPTOR
*)(UINTN
)CurrDesc
->Union
.ContinuationPointer
;
235 Validate capsule by MemoryResource.
237 @param MemoryResource Pointer to the buffer of memory resource descriptor.
238 @param Address Address to be validated.
239 @param Size Size to be validated.
241 @retval TRUE No memory resource descriptor reported in HOB list before capsule Coalesce,
242 or it is valid in one MemoryResource.
243 FALSE It is not in any MemoryResource.
247 ValidateCapsuleByMemoryResource (
248 IN MEMORY_RESOURCE_DESCRIPTOR
*MemoryResource
,
249 IN EFI_PHYSICAL_ADDRESS Address
,
258 if (Size
> MAX_ADDRESS
) {
259 DEBUG ((DEBUG_ERROR
, "ERROR: Size(0x%lx) > MAX_ADDRESS\n", Size
));
266 if (Address
> (MAX_ADDRESS
- Size
)) {
267 DEBUG ((DEBUG_ERROR
, "ERROR: Address(0x%lx) > (MAX_ADDRESS - Size(0x%lx))\n", Address
, Size
));
271 if (MemoryResource
== NULL
) {
273 // No memory resource descriptor reported in HOB list before capsule Coalesce.
278 for (Index
= 0; MemoryResource
[Index
].ResourceLength
!= 0; Index
++) {
279 if ((Address
>= MemoryResource
[Index
].PhysicalStart
) &&
280 ((Address
+ Size
) <= (MemoryResource
[Index
].PhysicalStart
+ MemoryResource
[Index
].ResourceLength
)))
284 "Address(0x%lx) Size(0x%lx) in MemoryResource[0x%x] - Start(0x%lx) Length(0x%lx)\n",
288 MemoryResource
[Index
].PhysicalStart
,
289 MemoryResource
[Index
].ResourceLength
295 DEBUG ((DEBUG_ERROR
, "ERROR: Address(0x%lx) Size(0x%lx) not in any MemoryResource\n", Address
, Size
));
300 Check the integrity of the capsule descriptors.
302 @param BlockList Pointer to the capsule descriptors
303 @param MemoryResource Pointer to the buffer of memory resource descriptor.
305 @retval NULL BlockList is not valid.
306 @retval LastBlockDesc Last one Block in BlockList
309 EFI_CAPSULE_BLOCK_DESCRIPTOR
*
310 ValidateCapsuleIntegrity (
311 IN EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockList
,
312 IN MEMORY_RESOURCE_DESCRIPTOR
*MemoryResource
315 EFI_CAPSULE_HEADER
*CapsuleHeader
;
318 EFI_CAPSULE_BLOCK_DESCRIPTOR
*Ptr
;
320 DEBUG ((DEBUG_INFO
, "ValidateCapsuleIntegrity\n"));
323 // Go through the list to look for inconsistencies. Check for:
324 // * misaligned block descriptors.
325 // * The first capsule header guid
326 // * The first capsule header flag
327 // * The first capsule header HeaderSize
328 // * Below check will be done in ValidateCapsuleByMemoryResource()
329 // Length > MAX_ADDRESS
330 // Ptr + sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR) > MAX_ADDRESS
331 // DataBlock + Length > MAX_ADDRESS
337 if (!ValidateCapsuleByMemoryResource (MemoryResource
, (EFI_PHYSICAL_ADDRESS
)(UINTN
)Ptr
, sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
))) {
341 DEBUG ((DEBUG_INFO
, "Ptr - 0x%p\n", Ptr
));
342 DEBUG ((DEBUG_INFO
, "Ptr->Length - 0x%lx\n", Ptr
->Length
));
343 DEBUG ((DEBUG_INFO
, "Ptr->Union - 0x%lx\n", Ptr
->Union
.ContinuationPointer
));
344 while ((Ptr
->Length
!= 0) || (Ptr
->Union
.ContinuationPointer
!= (EFI_PHYSICAL_ADDRESS
)(UINTN
)NULL
)) {
346 // Make sure the descriptor is aligned at UINT64 in memory
348 if ((UINTN
)Ptr
& (sizeof (UINT64
) - 1)) {
349 DEBUG ((DEBUG_ERROR
, "ERROR: BlockList address failed alignment check\n"));
353 if (Ptr
->Length
== 0) {
355 // Descriptor points to another list of block descriptors somewhere
358 Ptr
= (EFI_CAPSULE_BLOCK_DESCRIPTOR
*)(UINTN
)Ptr
->Union
.ContinuationPointer
;
359 if (!ValidateCapsuleByMemoryResource (MemoryResource
, (EFI_PHYSICAL_ADDRESS
)(UINTN
)Ptr
, sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
))) {
363 DEBUG ((DEBUG_INFO
, "Ptr(C) - 0x%p\n", Ptr
));
364 DEBUG ((DEBUG_INFO
, "Ptr->Length - 0x%lx\n", Ptr
->Length
));
365 DEBUG ((DEBUG_INFO
, "Ptr->Union - 0x%lx\n", Ptr
->Union
.ContinuationPointer
));
367 if (!ValidateCapsuleByMemoryResource (MemoryResource
, Ptr
->Union
.DataBlock
, Ptr
->Length
)) {
372 // To enhance the reliability of check-up, the first capsule's header is checked here.
373 // More reliabilities check-up will do later.
375 if (CapsuleSize
== 0) {
377 // Move to the first capsule to check its header.
379 CapsuleHeader
= (EFI_CAPSULE_HEADER
*)((UINTN
)Ptr
->Union
.DataBlock
);
383 if (Ptr
->Length
< sizeof (EFI_CAPSULE_HEADER
)) {
384 DEBUG ((DEBUG_ERROR
, "ERROR: Ptr->Length(0x%lx) < sizeof(EFI_CAPSULE_HEADER)\n", Ptr
->Length
));
389 // Make sure HeaderSize field is valid
391 if (CapsuleHeader
->HeaderSize
> CapsuleHeader
->CapsuleImageSize
) {
392 DEBUG ((DEBUG_ERROR
, "ERROR: CapsuleHeader->HeaderSize(0x%x) > CapsuleHeader->CapsuleImageSize(0x%x)\n", CapsuleHeader
->HeaderSize
, CapsuleHeader
->CapsuleImageSize
));
396 if (IsCapsuleCorrupted (CapsuleHeader
)) {
401 CapsuleSize
= CapsuleHeader
->CapsuleImageSize
;
404 if (CapsuleSize
>= Ptr
->Length
) {
405 CapsuleSize
= CapsuleSize
- Ptr
->Length
;
407 DEBUG ((DEBUG_ERROR
, "ERROR: CapsuleSize(0x%lx) < Ptr->Length(0x%lx)\n", CapsuleSize
, Ptr
->Length
));
415 // Move to next BLOCK descriptor
418 if (!ValidateCapsuleByMemoryResource (MemoryResource
, (EFI_PHYSICAL_ADDRESS
)(UINTN
)Ptr
, sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
))) {
422 DEBUG ((DEBUG_INFO
, "Ptr(B) - 0x%p\n", Ptr
));
423 DEBUG ((DEBUG_INFO
, "Ptr->Length - 0x%lx\n", Ptr
->Length
));
424 DEBUG ((DEBUG_INFO
, "Ptr->Union - 0x%lx\n", Ptr
->Union
.ContinuationPointer
));
428 if (CapsuleCount
== 0) {
430 // No any capsule is found in BlockList
432 DEBUG ((DEBUG_ERROR
, "ERROR: CapsuleCount(0x%x) == 0\n", CapsuleCount
));
436 if (CapsuleSize
!= 0) {
438 // Capsule data is incomplete.
440 DEBUG ((DEBUG_ERROR
, "ERROR: CapsuleSize(0x%lx) != 0\n", CapsuleSize
));
448 The capsule block descriptors may be fragmented and spread all over memory.
449 To simplify the coalescing of capsule blocks, first coalesce all the
450 capsule block descriptors low in memory.
452 The descriptors passed in can be fragmented throughout memory. Here
453 they are relocated into memory to turn them into a contiguous (null
456 @param PeiServices pointer to PEI services table
457 @param BlockList pointer to the capsule block descriptors
458 @param NumDescriptors number of capsule data block descriptors, whose Length is non-zero.
459 @param MemBase base of system memory in which we can work
460 @param MemSize size of the system memory pointed to by MemBase
462 @retval NULL could not relocate the descriptors
463 @retval Pointer to the base of the successfully-relocated block descriptors.
466 EFI_CAPSULE_BLOCK_DESCRIPTOR
*
467 RelocateBlockDescriptors (
468 IN EFI_PEI_SERVICES
**PeiServices
,
469 IN EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockList
,
470 IN UINTN NumDescriptors
,
475 EFI_CAPSULE_BLOCK_DESCRIPTOR
*NewBlockList
;
476 EFI_CAPSULE_BLOCK_DESCRIPTOR
*CurrBlockDescHead
;
477 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockDesc
;
478 EFI_CAPSULE_BLOCK_DESCRIPTOR
*PrevBlockDescTail
;
484 // Get the info on the blocks and descriptors. Since we're going to move
485 // the descriptors low in memory, adjust the base/size values accordingly here.
486 // NumDescriptors is the number of legit data descriptors, so add one for
487 // a terminator. (Already done by caller, no check is needed.)
490 BufferSize
= NumDescriptors
* sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
);
491 NewBlockList
= (EFI_CAPSULE_BLOCK_DESCRIPTOR
*)MemBase
;
492 if (MemSize
< BufferSize
) {
496 MemSize
-= BufferSize
;
497 MemBase
+= BufferSize
;
499 // Go through all the blocks and make sure none are in the way
501 TempBlockDesc
= BlockList
;
502 while (TempBlockDesc
->Union
.ContinuationPointer
!= (EFI_PHYSICAL_ADDRESS
)(UINTN
)NULL
) {
503 if (TempBlockDesc
->Length
== 0) {
505 // Next block of descriptors
507 TempBlockDesc
= (EFI_CAPSULE_BLOCK_DESCRIPTOR
*)(UINTN
)TempBlockDesc
->Union
.ContinuationPointer
;
510 // If the capsule data pointed to by this descriptor is in the way,
514 (UINT8
*)NewBlockList
,
516 (UINT8
*)(UINTN
)TempBlockDesc
->Union
.DataBlock
,
517 (UINTN
)TempBlockDesc
->Length
521 // Relocate the block
523 RelocBuffer
= FindFreeMem (BlockList
, MemBase
, MemSize
, (UINTN
)TempBlockDesc
->Length
);
524 if (RelocBuffer
== NULL
) {
528 CopyMem ((VOID
*)RelocBuffer
, (VOID
*)(UINTN
)TempBlockDesc
->Union
.DataBlock
, (UINTN
)TempBlockDesc
->Length
);
529 DEBUG ((DEBUG_INFO
, "Capsule relocate descriptors from/to/size 0x%lX 0x%lX 0x%lX\n", TempBlockDesc
->Union
.DataBlock
, (UINT64
)(UINTN
)RelocBuffer
, TempBlockDesc
->Length
));
530 TempBlockDesc
->Union
.DataBlock
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)RelocBuffer
;
538 // Now go through all the block descriptors to make sure that they're not
539 // in the memory region we want to copy them to.
541 CurrBlockDescHead
= BlockList
;
542 PrevBlockDescTail
= NULL
;
543 while ((CurrBlockDescHead
!= NULL
) && (CurrBlockDescHead
->Union
.ContinuationPointer
!= (EFI_PHYSICAL_ADDRESS
)(UINTN
)NULL
)) {
545 // Get the size of this list then see if it overlaps our low region
547 TempBlockDesc
= CurrBlockDescHead
;
548 BlockListSize
= sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
);
549 while (TempBlockDesc
->Length
!= 0) {
550 BlockListSize
+= sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
);
555 (UINT8
*)NewBlockList
,
557 (UINT8
*)CurrBlockDescHead
,
562 // Overlaps, so move it out of the way
564 RelocBuffer
= FindFreeMem (BlockList
, MemBase
, MemSize
, BlockListSize
);
565 if (RelocBuffer
== NULL
) {
569 CopyMem ((VOID
*)RelocBuffer
, (VOID
*)CurrBlockDescHead
, BlockListSize
);
570 DEBUG ((DEBUG_INFO
, "Capsule reloc descriptor block #2\n"));
572 // Point the previous block's next point to this copied version. If
573 // the tail pointer is null, then this is the first descriptor block.
575 if (PrevBlockDescTail
== NULL
) {
576 BlockList
= (EFI_CAPSULE_BLOCK_DESCRIPTOR
*)RelocBuffer
;
578 PrevBlockDescTail
->Union
.DataBlock
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)RelocBuffer
;
583 // Save our new tail and jump to the next block list
585 PrevBlockDescTail
= TempBlockDesc
;
586 CurrBlockDescHead
= (EFI_CAPSULE_BLOCK_DESCRIPTOR
*)(UINTN
)TempBlockDesc
->Union
.ContinuationPointer
;
590 // Cleared out low memory. Now copy the descriptors down there.
592 TempBlockDesc
= BlockList
;
593 CurrBlockDescHead
= NewBlockList
;
594 while ((TempBlockDesc
!= NULL
) && (TempBlockDesc
->Union
.ContinuationPointer
!= (EFI_PHYSICAL_ADDRESS
)(UINTN
)NULL
)) {
595 if (TempBlockDesc
->Length
!= 0) {
596 CurrBlockDescHead
->Union
.DataBlock
= TempBlockDesc
->Union
.DataBlock
;
597 CurrBlockDescHead
->Length
= TempBlockDesc
->Length
;
601 TempBlockDesc
= (EFI_CAPSULE_BLOCK_DESCRIPTOR
*)(UINTN
)TempBlockDesc
->Union
.ContinuationPointer
;
608 CurrBlockDescHead
->Union
.ContinuationPointer
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)NULL
;
609 CurrBlockDescHead
->Length
= 0;
614 Determine if two buffers overlap in memory.
616 @param Buff1 pointer to first buffer
617 @param Size1 size of Buff1
618 @param Buff2 pointer to second buffer
619 @param Size2 size of Buff2
621 @retval TRUE Buffers overlap in memory.
622 @retval FALSE Buffer doesn't overlap.
634 // If buff1's end is less than the start of buff2, then it's ok.
635 // Also, if buff1's start is beyond buff2's end, then it's ok.
637 if (((Buff1
+ Size1
) <= Buff2
) || (Buff1
>= (Buff2
+ Size2
))) {
645 Given a pointer to a capsule block descriptor, traverse the list to figure
646 out how many legitimate descriptors there are, and how big the capsule it
649 @param Desc Pointer to the capsule block descriptors
650 @param NumDescriptors Optional pointer to where to return the number of capsule data descriptors, whose Length is non-zero.
651 @param CapsuleSize Optional pointer to where to return the capsule image size
652 @param CapsuleNumber Optional pointer to where to return the number of capsule
654 @retval EFI_NOT_FOUND No descriptors containing data in the list
655 @retval EFI_SUCCESS Return data is valid
660 IN EFI_CAPSULE_BLOCK_DESCRIPTOR
*Desc
,
661 IN OUT UINTN
*NumDescriptors OPTIONAL
,
662 IN OUT UINTN
*CapsuleSize OPTIONAL
,
663 IN OUT UINTN
*CapsuleNumber OPTIONAL
669 UINTN ThisCapsuleImageSize
;
670 EFI_CAPSULE_HEADER
*CapsuleHeader
;
672 DEBUG ((DEBUG_INFO
, "GetCapsuleInfo enter\n"));
674 ASSERT (Desc
!= NULL
);
679 ThisCapsuleImageSize
= 0;
681 while (Desc
->Union
.ContinuationPointer
!= (EFI_PHYSICAL_ADDRESS
)(UINTN
)NULL
) {
682 if (Desc
->Length
== 0) {
684 // Descriptor points to another list of block descriptors somewhere
686 Desc
= (EFI_CAPSULE_BLOCK_DESCRIPTOR
*)(UINTN
)Desc
->Union
.ContinuationPointer
;
690 // It is needed, because ValidateCapsuleIntegrity() only validate one individual capsule Size.
691 // While here we need check all capsules size.
693 if (Desc
->Length
>= (MAX_ADDRESS
- Size
)) {
694 DEBUG ((DEBUG_ERROR
, "ERROR: Desc->Length(0x%lx) >= (MAX_ADDRESS - Size(0x%x))\n", Desc
->Length
, Size
));
695 return EFI_OUT_OF_RESOURCES
;
698 Size
+= (UINTN
)Desc
->Length
;
702 // See if this is first capsule's header
704 if (ThisCapsuleImageSize
== 0) {
705 CapsuleHeader
= (EFI_CAPSULE_HEADER
*)((UINTN
)Desc
->Union
.DataBlock
);
707 // This has been checked in ValidateCapsuleIntegrity()
710 ThisCapsuleImageSize
= CapsuleHeader
->CapsuleImageSize
;
714 // This has been checked in ValidateCapsuleIntegrity()
716 ASSERT (ThisCapsuleImageSize
>= Desc
->Length
);
717 ThisCapsuleImageSize
= (UINTN
)(ThisCapsuleImageSize
- Desc
->Length
);
727 // If no descriptors, then fail
730 DEBUG ((DEBUG_ERROR
, "ERROR: Count == 0\n"));
731 return EFI_NOT_FOUND
;
735 // checked in ValidateCapsuleIntegrity()
737 ASSERT (ThisCapsuleImageSize
== 0);
739 if (NumDescriptors
!= NULL
) {
740 *NumDescriptors
= Count
;
743 if (CapsuleSize
!= NULL
) {
747 if (CapsuleNumber
!= NULL
) {
748 *CapsuleNumber
= Number
;
755 Check every capsule header.
757 @param CapsuleHeader The pointer to EFI_CAPSULE_HEADER
759 @retval FALSE Capsule is OK
760 @retval TRUE Capsule is corrupted
765 IN EFI_CAPSULE_HEADER
*CapsuleHeader
769 // A capsule to be updated across a system reset should contain CAPSULE_FLAGS_PERSIST_ACROSS_RESET.
771 if ((CapsuleHeader
->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) == 0) {
776 // Make sure the flags combination is supported by the platform.
778 if ((CapsuleHeader
->Flags
& (CAPSULE_FLAGS_PERSIST_ACROSS_RESET
| CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE
)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE
) {
782 if ((CapsuleHeader
->Flags
& (CAPSULE_FLAGS_PERSIST_ACROSS_RESET
| CAPSULE_FLAGS_INITIATE_RESET
)) == CAPSULE_FLAGS_INITIATE_RESET
) {
790 Try to verify the integrity of a capsule test pattern before the
791 capsule gets coalesced. This can be useful in narrowing down
792 where capsule data corruption occurs.
794 The test pattern mode fills in memory with a counting UINT32 value.
795 If the capsule is not divided up in a multiple of 4-byte blocks, then
796 things get messy doing the check. Therefore there are some cases
797 here where we just give up and skip the pre-coalesce check.
799 @param PeiServices PEI services table
800 @param Desc Pointer to capsule descriptors
803 CapsuleTestPatternPreCoalesce (
804 IN EFI_PEI_SERVICES
**PeiServices
,
805 IN EFI_CAPSULE_BLOCK_DESCRIPTOR
*Desc
812 DEBUG ((DEBUG_INFO
, "CapsuleTestPatternPreCoalesce\n"));
815 // Find first data descriptor
817 while ((Desc
->Length
== 0) && (Desc
->Union
.ContinuationPointer
!= (EFI_PHYSICAL_ADDRESS
)(UINTN
)NULL
)) {
818 Desc
= (EFI_CAPSULE_BLOCK_DESCRIPTOR
*)(UINTN
)Desc
->Union
.ContinuationPointer
;
821 if (Desc
->Union
.ContinuationPointer
== 0) {
826 // First one better be long enough to at least hold the test signature
828 if (Desc
->Length
< sizeof (UINT32
)) {
829 DEBUG ((DEBUG_INFO
, "Capsule test pattern pre-coalesce punted #1\n"));
833 TestPtr
= (UINT32
*)(UINTN
)Desc
->Union
.DataBlock
;
837 if (*TestPtr
!= 0x54534554) {
842 TestSize
= (UINT32
)Desc
->Length
- 2 * sizeof (UINT32
);
844 // Skip over the signature and the size fields in the pattern data header
848 if ((TestSize
& 0x03) != 0) {
849 DEBUG ((DEBUG_INFO
, "Capsule test pattern pre-coalesce punted #2\n"));
853 while (TestSize
> 0) {
854 if (*TestPtr
!= TestCounter
) {
855 DEBUG ((DEBUG_INFO
, "Capsule test pattern pre-coalesce failed data corruption check\n"));
859 TestSize
-= sizeof (UINT32
);
865 while ((Desc
->Length
== 0) && (Desc
->Union
.ContinuationPointer
!= (EFI_PHYSICAL_ADDRESS
)(UINTN
)NULL
)) {
866 Desc
= (EFI_CAPSULE_BLOCK_DESCRIPTOR
*)(UINTN
)Desc
->Union
.ContinuationPointer
;
869 if (Desc
->Union
.ContinuationPointer
== (EFI_PHYSICAL_ADDRESS
)(UINTN
)NULL
) {
873 TestSize
= (UINT32
)Desc
->Length
;
874 TestPtr
= (UINT32
*)(UINTN
)Desc
->Union
.DataBlock
;
879 Checks for the presence of capsule descriptors.
880 Get capsule descriptors from variable CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
882 @param BlockListBuffer Pointer to the buffer of capsule descriptors variables
883 @param MemoryResource Pointer to the buffer of memory resource descriptor.
884 @param BlockDescriptorList Pointer to the capsule descriptors list
886 @retval EFI_SUCCESS a valid capsule is present
887 @retval EFI_NOT_FOUND if a valid capsule is not present
890 BuildCapsuleDescriptors (
891 IN EFI_PHYSICAL_ADDRESS
*BlockListBuffer
,
892 IN MEMORY_RESOURCE_DESCRIPTOR
*MemoryResource
,
893 OUT EFI_CAPSULE_BLOCK_DESCRIPTOR
**BlockDescriptorList
897 EFI_CAPSULE_BLOCK_DESCRIPTOR
*LastBlock
;
898 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlock
;
899 EFI_CAPSULE_BLOCK_DESCRIPTOR
*HeadBlock
;
901 DEBUG ((DEBUG_INFO
, "BuildCapsuleDescriptors enter\n"));
908 while (BlockListBuffer
[Index
] != 0) {
910 // Test integrity of descriptors.
912 if (BlockListBuffer
[Index
] < MAX_ADDRESS
) {
913 TempBlock
= ValidateCapsuleIntegrity ((EFI_CAPSULE_BLOCK_DESCRIPTOR
*)(UINTN
)BlockListBuffer
[Index
], MemoryResource
);
914 if (TempBlock
!= NULL
) {
915 if (LastBlock
== NULL
) {
916 LastBlock
= TempBlock
;
919 // Return the base of the block descriptors
921 HeadBlock
= (EFI_CAPSULE_BLOCK_DESCRIPTOR
*)(UINTN
)BlockListBuffer
[Index
];
924 // Combine the different BlockList into single BlockList.
926 LastBlock
->Union
.DataBlock
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)BlockListBuffer
[Index
];
927 LastBlock
->Length
= 0;
928 LastBlock
= TempBlock
;
932 DEBUG ((DEBUG_ERROR
, "ERROR: BlockListBuffer[Index](0x%lx) < MAX_ADDRESS\n", BlockListBuffer
[Index
]));
938 if (HeadBlock
!= NULL
) {
939 *BlockDescriptorList
= HeadBlock
;
943 return EFI_NOT_FOUND
;
947 The function to coalesce a fragmented capsule in memory.
949 Memory Map for coalesced capsule:
950 MemBase + ---->+---------------------------+<-----------+
951 MemSize | ------------------------- | |
952 | | Capsule [Num-1] | | |
953 | ------------------------- | |
954 | | ................ | | |
955 | ------------------------- | |
956 | | Capsule [1] | | |
957 | ------------------------- | |
958 | | Capsule [0] | | |
959 | ------------------------- | |
961 CapsuleImageBase-->+---------------------------+
962 | ------------------------- | |
963 | | CapsuleOffset[Num-1] | | |
964 | ------------------------- | |
965 | | ................ | | CapsuleSize
966 | ------------------------- | |
967 | | CapsuleOffset[1] | | |
968 | ------------------------- | |
969 | | CapsuleOffset[0] | | |
970 |---------------------------| |
971 | | CapsuleNumber | | |
972 | ------------------------- | |
973 | | CapsuleAllImageSize | | |
974 | ------------------------- | |
976 DestPtr ---->+---------------------------+<-----------+
978 | FreeMem | FreeMemSize
980 FreeMemBase --->+---------------------------+<-----------+
982 +---------------------------+
983 | BlockDescriptor n |
984 +---------------------------+
985 | ................. |
986 +---------------------------+
987 | BlockDescriptor 1 |
988 +---------------------------+
989 | BlockDescriptor 0 |
990 +---------------------------+
991 | PrivateDataDesc 0 |
992 MemBase ---->+---------------------------+<----- BlockList
994 Caution: This function may receive untrusted input.
995 The capsule data is external input, so this routine will do basic validation before
996 coalesce capsule data into memory.
998 @param PeiServices General purpose services available to every PEIM.
999 @param BlockListBuffer Pointer to the buffer of Capsule Descriptor Variables.
1000 @param MemoryResource Pointer to the buffer of memory resource descriptor.
1001 @param MemoryBase Pointer to the base of a block of memory that we can walk
1002 all over while trying to coalesce our buffers.
1003 On output, this variable will hold the base address of
1004 a coalesced capsule.
1005 @param MemorySize Size of the memory region pointed to by MemoryBase.
1006 On output, this variable will contain the size of the
1009 @retval EFI_NOT_FOUND If we could not find the capsule descriptors.
1011 @retval EFI_BUFFER_TOO_SMALL
1012 If we could not coalesce the capsule in the memory
1013 region provided to us.
1015 @retval EFI_SUCCESS Processed the capsule successfully.
1019 CapsuleDataCoalesce (
1020 IN EFI_PEI_SERVICES
**PeiServices
,
1021 IN EFI_PHYSICAL_ADDRESS
*BlockListBuffer
,
1022 IN MEMORY_RESOURCE_DESCRIPTOR
*MemoryResource
,
1023 IN OUT VOID
**MemoryBase
,
1024 IN OUT UINTN
*MemorySize
1027 VOID
*NewCapsuleBase
;
1028 VOID
*CapsuleImageBase
;
1036 UINT64 CapsuleImageSize
;
1038 UINTN CapsuleNumber
;
1039 UINTN DescriptorsSize
;
1041 UINTN NumDescriptors
;
1042 BOOLEAN CapsuleBeginFlag
;
1044 EFI_CAPSULE_HEADER
*CapsuleHeader
;
1045 EFI_CAPSULE_PEIM_PRIVATE_DATA PrivateData
;
1046 EFI_CAPSULE_PEIM_PRIVATE_DATA
*PrivateDataPtr
;
1047 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockList
;
1048 EFI_CAPSULE_BLOCK_DESCRIPTOR
*CurrentBlockDesc
;
1049 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockDesc
;
1050 EFI_CAPSULE_BLOCK_DESCRIPTOR PrivateDataDesc
[2];
1052 DEBUG ((DEBUG_INFO
, "CapsuleDataCoalesce enter\n"));
1057 CapsuleImageSize
= 0;
1058 PrivateDataPtr
= NULL
;
1059 CapsuleHeader
= NULL
;
1060 CapsuleBeginFlag
= TRUE
;
1065 // Build capsule descriptors list
1067 Status
= BuildCapsuleDescriptors (BlockListBuffer
, MemoryResource
, &BlockList
);
1068 if (EFI_ERROR (Status
)) {
1073 CapsuleTestPatternPreCoalesce (PeiServices
, BlockList
);
1077 // Get the size of our descriptors and the capsule size. GetCapsuleInfo()
1078 // returns the number of descriptors that actually point to data, so add
1079 // one for a terminator. Do that below.
1081 Status
= GetCapsuleInfo (BlockList
, &NumDescriptors
, &CapsuleSize
, &CapsuleNumber
);
1082 if (EFI_ERROR (Status
)) {
1086 DEBUG ((DEBUG_INFO
, "CapsuleSize - 0x%x\n", CapsuleSize
));
1087 DEBUG ((DEBUG_INFO
, "CapsuleNumber - 0x%x\n", CapsuleNumber
));
1088 DEBUG ((DEBUG_INFO
, "NumDescriptors - 0x%x\n", NumDescriptors
));
1089 if ((CapsuleSize
== 0) || (NumDescriptors
== 0) || (CapsuleNumber
== 0)) {
1090 return EFI_NOT_FOUND
;
1093 if (CapsuleNumber
- 1 >= (MAX_ADDRESS
- (sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA
) + sizeof (UINT64
))) / sizeof (UINT64
)) {
1094 DEBUG ((DEBUG_ERROR
, "ERROR: CapsuleNumber - 0x%x\n", CapsuleNumber
));
1095 return EFI_BUFFER_TOO_SMALL
;
1099 // Initialize our local copy of private data. When we're done, we'll create a
1100 // descriptor for it as well so that it can be put into free memory without
1101 // trashing anything.
1103 PrivateData
.Signature
= EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE
;
1104 PrivateData
.CapsuleAllImageSize
= (UINT64
)CapsuleSize
;
1105 PrivateData
.CapsuleNumber
= (UINT64
)CapsuleNumber
;
1106 PrivateData
.CapsuleOffset
[0] = 0;
1108 // NOTE: Only data in sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) is valid, CapsuleOffset field is uninitialized at this moment.
1109 // The code sets partial length here for Descriptor.Length check, but later it will use full length to reserve those PrivateData region.
1111 PrivateDataDesc
[0].Union
.DataBlock
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&PrivateData
;
1112 PrivateDataDesc
[0].Length
= sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA
);
1113 PrivateDataDesc
[1].Union
.DataBlock
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)BlockList
;
1114 PrivateDataDesc
[1].Length
= 0;
1116 // Add PrivateDataDesc[0] in beginning, as it is new descriptor. PrivateDataDesc[1] is NOT needed.
1117 // In addition, one NULL terminator is added in the end. See RelocateBlockDescriptors().
1119 NumDescriptors
+= 2;
1123 if (CapsuleSize
>= (MAX_ADDRESS
- (sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA
) + (CapsuleNumber
- 1) * sizeof (UINT64
) + sizeof (UINT64
)))) {
1124 DEBUG ((DEBUG_ERROR
, "ERROR: CapsuleSize - 0x%x\n", CapsuleSize
));
1125 return EFI_BUFFER_TOO_SMALL
;
1129 // Need add sizeof(UINT64) for PrivateData alignment
1131 CapsuleSize
+= sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA
) + (CapsuleNumber
- 1) * sizeof (UINT64
) + sizeof (UINT64
);
1132 BlockList
= PrivateDataDesc
;
1136 if (NumDescriptors
>= (MAX_ADDRESS
/ sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
))) {
1137 DEBUG ((DEBUG_ERROR
, "ERROR: NumDescriptors - 0x%x\n", NumDescriptors
));
1138 return EFI_BUFFER_TOO_SMALL
;
1141 DescriptorsSize
= NumDescriptors
* sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
);
1145 if (DescriptorsSize
>= (MAX_ADDRESS
- CapsuleSize
)) {
1146 DEBUG ((DEBUG_ERROR
, "ERROR: DescriptorsSize - 0x%lx, CapsuleSize - 0x%lx\n", (UINT64
)DescriptorsSize
, (UINT64
)CapsuleSize
));
1147 return EFI_BUFFER_TOO_SMALL
;
1151 // Don't go below some min address. If the base is below it,
1152 // then move it up and adjust the size accordingly.
1154 DEBUG ((DEBUG_INFO
, "Capsule Memory range from 0x%8X to 0x%8X\n", (UINTN
)*MemoryBase
, (UINTN
)*MemoryBase
+ *MemorySize
));
1155 if ((UINTN
)*MemoryBase
< (UINTN
)MIN_COALESCE_ADDR
) {
1156 if (((UINTN
)*MemoryBase
+ *MemorySize
) < (UINTN
)MIN_COALESCE_ADDR
) {
1157 DEBUG ((DEBUG_ERROR
, "ERROR: *MemoryBase + *MemorySize - 0x%x\n", (UINTN
)*MemoryBase
+ *MemorySize
));
1158 return EFI_BUFFER_TOO_SMALL
;
1160 *MemorySize
= *MemorySize
- ((UINTN
)MIN_COALESCE_ADDR
- (UINTN
)*MemoryBase
);
1161 *MemoryBase
= (VOID
*)(UINTN
)MIN_COALESCE_ADDR
;
1165 if (*MemorySize
<= (CapsuleSize
+ DescriptorsSize
)) {
1166 DEBUG ((DEBUG_ERROR
, "ERROR: CapsuleSize + DescriptorsSize - 0x%x\n", CapsuleSize
+ DescriptorsSize
));
1167 return EFI_BUFFER_TOO_SMALL
;
1170 FreeMemBase
= *MemoryBase
;
1171 FreeMemSize
= *MemorySize
;
1172 DEBUG ((DEBUG_INFO
, "Capsule Free Memory from 0x%8X to 0x%8X\n", (UINTN
)FreeMemBase
, (UINTN
)FreeMemBase
+ FreeMemSize
));
1175 // Relocate all the block descriptors to low memory to make further
1176 // processing easier.
1178 BlockList
= RelocateBlockDescriptors (PeiServices
, BlockList
, NumDescriptors
, FreeMemBase
, FreeMemSize
);
1179 if (BlockList
== NULL
) {
1181 // Not enough room to relocate the descriptors
1183 return EFI_BUFFER_TOO_SMALL
;
1187 // Take the top of memory for the capsule. UINT64 align up.
1189 DestPtr
= FreeMemBase
+ FreeMemSize
- CapsuleSize
;
1190 DestPtr
= (UINT8
*)(((UINTN
)DestPtr
+ sizeof (UINT64
) - 1) & ~(sizeof (UINT64
) - 1));
1191 FreeMemBase
= (UINT8
*)BlockList
+ DescriptorsSize
;
1192 FreeMemSize
= (UINTN
)DestPtr
- (UINTN
)FreeMemBase
;
1193 NewCapsuleBase
= (VOID
*)DestPtr
;
1194 CapsuleImageBase
= (UINT8
*)NewCapsuleBase
+ sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA
) + (CapsuleNumber
- 1) * sizeof (UINT64
);
1196 PrivateDataPtr
= (EFI_CAPSULE_PEIM_PRIVATE_DATA
*)NewCapsuleBase
;
1199 // Move all the blocks to the top (high) of memory.
1200 // Relocate all the obstructing blocks. Note that the block descriptors
1201 // were coalesced when they were relocated, so we can just ++ the pointer.
1203 CurrentBlockDesc
= BlockList
;
1204 while ((CurrentBlockDesc
->Length
!= 0) || (CurrentBlockDesc
->Union
.ContinuationPointer
!= (EFI_PHYSICAL_ADDRESS
)(UINTN
)NULL
)) {
1205 if (CapsuleTimes
== 0) {
1207 // The first entry is the block descriptor for EFI_CAPSULE_PEIM_PRIVATE_DATA.
1208 // CapsuleOffset field is uninitialized at this time. No need copy it, but need to reserve for future use.
1210 ASSERT (CurrentBlockDesc
->Union
.DataBlock
== (UINT64
)(UINTN
)&PrivateData
);
1211 DestLength
= sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA
) + (CapsuleNumber
- 1) * sizeof (UINT64
);
1213 DestLength
= (UINTN
)CurrentBlockDesc
->Length
;
1217 // See if any of the remaining capsule blocks are in the way
1219 TempBlockDesc
= CurrentBlockDesc
;
1220 while (TempBlockDesc
->Length
!= 0) {
1222 // Is this block in the way of where we want to copy the current descriptor to?
1227 (UINT8
*)(UINTN
)TempBlockDesc
->Union
.DataBlock
,
1228 (UINTN
)TempBlockDesc
->Length
1232 // Relocate the block
1234 RelocPtr
= FindFreeMem (BlockList
, FreeMemBase
, FreeMemSize
, (UINTN
)TempBlockDesc
->Length
);
1235 if (RelocPtr
== NULL
) {
1236 return EFI_BUFFER_TOO_SMALL
;
1239 CopyMem ((VOID
*)RelocPtr
, (VOID
*)(UINTN
)TempBlockDesc
->Union
.DataBlock
, (UINTN
)TempBlockDesc
->Length
);
1242 "Capsule reloc data block from 0x%8X to 0x%8X with size 0x%8X\n",
1243 (UINTN
)TempBlockDesc
->Union
.DataBlock
,
1245 (UINTN
)TempBlockDesc
->Length
1248 TempBlockDesc
->Union
.DataBlock
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)RelocPtr
;
1258 // Ok, we made it through. Copy the block.
1259 // we just support greping one capsule from the lists of block descs list.
1263 // Skip the first block descriptor that filled with EFI_CAPSULE_PEIM_PRIVATE_DATA
1265 if (CapsuleTimes
> 1) {
1267 // For every capsule entry point, check its header to determine whether to relocate it.
1268 // If it is invalid, skip it and move on to the next capsule. If it is valid, relocate it.
1270 if (CapsuleBeginFlag
) {
1271 CapsuleBeginFlag
= FALSE
;
1272 CapsuleHeader
= (EFI_CAPSULE_HEADER
*)(UINTN
)CurrentBlockDesc
->Union
.DataBlock
;
1273 SizeLeft
= CapsuleHeader
->CapsuleImageSize
;
1276 // No more check here is needed, because IsCapsuleCorrupted() already in ValidateCapsuleIntegrity()
1278 ASSERT (CapsuleIndex
< CapsuleNumber
);
1281 // Relocate this capsule
1283 CapsuleImageSize
+= SizeLeft
;
1285 // Cache the begin offset of this capsule
1287 ASSERT (PrivateDataPtr
->Signature
== EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE
);
1288 ASSERT ((UINTN
)DestPtr
>= (UINTN
)CapsuleImageBase
);
1289 PrivateDataPtr
->CapsuleOffset
[CapsuleIndex
++] = (UINTN
)DestPtr
- (UINTN
)CapsuleImageBase
;
1293 // Below ASSERT is checked in ValidateCapsuleIntegrity()
1295 ASSERT (CurrentBlockDesc
->Length
<= SizeLeft
);
1297 CopyMem ((VOID
*)DestPtr
, (VOID
*)(UINTN
)(CurrentBlockDesc
->Union
.DataBlock
), (UINTN
)CurrentBlockDesc
->Length
);
1300 "Capsule coalesce block no.0x%lX from 0x%lX to 0x%lX with size 0x%lX\n",
1301 (UINT64
)CapsuleTimes
,
1302 CurrentBlockDesc
->Union
.DataBlock
,
1303 (UINT64
)(UINTN
)DestPtr
,
1304 CurrentBlockDesc
->Length
1306 DestPtr
+= CurrentBlockDesc
->Length
;
1307 SizeLeft
-= CurrentBlockDesc
->Length
;
1309 if (SizeLeft
== 0) {
1311 // Here is the end of the current capsule image.
1313 CapsuleBeginFlag
= TRUE
;
1317 // The first entry is the block descriptor for EFI_CAPSULE_PEIM_PRIVATE_DATA.
1318 // CapsuleOffset field is uninitialized at this time. No need copy it, but need to reserve for future use.
1320 ASSERT (CurrentBlockDesc
->Length
== sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA
));
1321 ASSERT ((UINTN
)DestPtr
== (UINTN
)NewCapsuleBase
);
1322 CopyMem ((VOID
*)DestPtr
, (VOID
*)(UINTN
)CurrentBlockDesc
->Union
.DataBlock
, (UINTN
)CurrentBlockDesc
->Length
);
1323 DestPtr
+= sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA
) + (CapsuleNumber
- 1) * sizeof (UINT64
);
1327 // Walk through the block descriptor list.
1333 // We return the base of memory we want reserved, and the size.
1334 // The memory peim should handle it appropriately from there.
1336 *MemorySize
= (UINTN
)CapsuleSize
;
1337 *MemoryBase
= (VOID
*)NewCapsuleBase
;
1339 ASSERT (PrivateDataPtr
->Signature
== EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE
);
1340 ASSERT (PrivateDataPtr
->CapsuleAllImageSize
== CapsuleImageSize
);
1341 ASSERT (PrivateDataPtr
->CapsuleNumber
== CapsuleIndex
);