TianoCore EDK2 master
Loading...
Searching...
No Matches
CapsuleCoalesce.c
Go to the documentation of this file.
1
18#include <Uefi.h>
19#include <PiPei.h>
20
21#include <Guid/CapsuleVendor.h>
22
24#include <Library/DebugLib.h>
25#include <Library/PrintLib.h>
26#include <Library/BaseLib.h>
27
28#include "CommonHeader.h"
29
30#define MIN_COALESCE_ADDR (1024 * 1024)
31
48UINT8 *
51 UINT8 *MemBase,
52 UINTN MemSize,
53 UINTN DataSize
54 );
55
77 IN EFI_PEI_SERVICES **PeiServices,
79 IN UINTN NumDescriptors,
80 IN UINT8 *MemBase,
81 IN UINTN MemSize
82 );
83
93BOOLEAN
95 IN EFI_CAPSULE_HEADER *CapsuleHeader
96 );
97
110BOOLEAN
112 UINT8 *Buff1,
113 UINTN Size1,
114 UINT8 *Buff2,
115 UINTN Size2
116 );
117
135 IN OUT UINTN *NumDescriptors OPTIONAL,
136 IN OUT UINTN *CapsuleSize OPTIONAL,
137 IN OUT UINTN *CapsuleNumber OPTIONAL
138 );
139
156UINT8 *
159 UINT8 *MemBase,
160 UINTN MemSize,
161 UINTN DataSize
162 )
163{
164 UINTN Size;
167 UINT8 *MemEnd;
168 BOOLEAN Failed;
169
170 //
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.
173 //
174 MemEnd = MemBase + MemSize - DataSize;
175 CurrDesc = BlockList;
176 //
177 // Go through all the descriptor blocks and see if any obstruct the range
178 //
179 while (CurrDesc != NULL) {
180 //
181 // Get the size of this block list and see if it's in the way
182 //
183 Failed = FALSE;
184 TempDesc = CurrDesc;
185 Size = sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
186 while (TempDesc->Length != 0) {
187 Size += sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
188 TempDesc++;
189 }
190
191 if (IsOverlapped (MemBase, DataSize, (UINT8 *)CurrDesc, Size)) {
192 //
193 // Set our new base to the end of this block list and start all over
194 //
195 MemBase = (UINT8 *)CurrDesc + Size;
196 CurrDesc = BlockList;
197 if (MemBase > MemEnd) {
198 return NULL;
199 }
200
201 Failed = TRUE;
202 }
203
204 //
205 // Now go through all the blocks and make sure none are in the way
206 //
207 while ((CurrDesc->Length != 0) && (!Failed)) {
208 if (IsOverlapped (MemBase, DataSize, (UINT8 *)(UINTN)CurrDesc->Union.DataBlock, (UINTN)CurrDesc->Length)) {
209 //
210 // Set our new base to the end of this block and start all over
211 //
212 Failed = TRUE;
213 MemBase = (UINT8 *)((UINTN)CurrDesc->Union.DataBlock) + CurrDesc->Length;
214 CurrDesc = BlockList;
215 if (MemBase > MemEnd) {
216 return NULL;
217 }
218 }
219
220 CurrDesc++;
221 }
222
223 //
224 // Normal continuation -- jump to next block descriptor list
225 //
226 if (!Failed) {
227 CurrDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)CurrDesc->Union.ContinuationPointer;
228 }
229 }
230
231 return MemBase;
232}
233
246BOOLEAN
248 IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource,
249 IN EFI_PHYSICAL_ADDRESS Address,
250 IN UINT64 Size
251 )
252{
253 UINTN Index;
254
255 //
256 // Sanity Check
257 //
258 if (Size > MAX_ADDRESS) {
259 DEBUG ((DEBUG_ERROR, "ERROR: Size(0x%lx) > MAX_ADDRESS\n", Size));
260 return FALSE;
261 }
262
263 //
264 // Sanity Check
265 //
266 if (Address > (MAX_ADDRESS - Size)) {
267 DEBUG ((DEBUG_ERROR, "ERROR: Address(0x%lx) > (MAX_ADDRESS - Size(0x%lx))\n", Address, Size));
268 return FALSE;
269 }
270
271 if (MemoryResource == NULL) {
272 //
273 // No memory resource descriptor reported in HOB list before capsule Coalesce.
274 //
275 return TRUE;
276 }
277
278 for (Index = 0; MemoryResource[Index].ResourceLength != 0; Index++) {
279 if ((Address >= MemoryResource[Index].PhysicalStart) &&
280 ((Address + Size) <= (MemoryResource[Index].PhysicalStart + MemoryResource[Index].ResourceLength)))
281 {
282 DEBUG ((
283 DEBUG_INFO,
284 "Address(0x%lx) Size(0x%lx) in MemoryResource[0x%x] - Start(0x%lx) Length(0x%lx)\n",
285 Address,
286 Size,
287 Index,
288 MemoryResource[Index].PhysicalStart,
289 MemoryResource[Index].ResourceLength
290 ));
291 return TRUE;
292 }
293 }
294
295 DEBUG ((DEBUG_ERROR, "ERROR: Address(0x%lx) Size(0x%lx) not in any MemoryResource\n", Address, Size));
296 return FALSE;
297}
298
312 IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource
313 )
314{
315 EFI_CAPSULE_HEADER *CapsuleHeader;
316 UINT64 CapsuleSize;
317 UINTN CapsuleCount;
319
320 DEBUG ((DEBUG_INFO, "ValidateCapsuleIntegrity\n"));
321
322 //
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
332 //
333 CapsuleSize = 0;
334 CapsuleCount = 0;
335 Ptr = BlockList;
336
338 return NULL;
339 }
340
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)) {
345 //
346 // Make sure the descriptor is aligned at UINT64 in memory
347 //
348 if ((UINTN)Ptr & (sizeof (UINT64) - 1)) {
349 DEBUG ((DEBUG_ERROR, "ERROR: BlockList address failed alignment check\n"));
350 return NULL;
351 }
352
353 if (Ptr->Length == 0) {
354 //
355 // Descriptor points to another list of block descriptors somewhere
356 // else.
357 //
360 return NULL;
361 }
362
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));
366 } else {
367 if (!ValidateCapsuleByMemoryResource (MemoryResource, Ptr->Union.DataBlock, Ptr->Length)) {
368 return NULL;
369 }
370
371 //
372 // To enhance the reliability of check-up, the first capsule's header is checked here.
373 // More reliabilities check-up will do later.
374 //
375 if (CapsuleSize == 0) {
376 //
377 // Move to the first capsule to check its header.
378 //
379 CapsuleHeader = (EFI_CAPSULE_HEADER *)((UINTN)Ptr->Union.DataBlock);
380 //
381 // Sanity check
382 //
383 if (Ptr->Length < sizeof (EFI_CAPSULE_HEADER)) {
384 DEBUG ((DEBUG_ERROR, "ERROR: Ptr->Length(0x%lx) < sizeof(EFI_CAPSULE_HEADER)\n", Ptr->Length));
385 return NULL;
386 }
387
388 //
389 // Make sure HeaderSize field is valid
390 //
391 if (CapsuleHeader->HeaderSize > CapsuleHeader->CapsuleImageSize) {
392 DEBUG ((DEBUG_ERROR, "ERROR: CapsuleHeader->HeaderSize(0x%x) > CapsuleHeader->CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));
393 return NULL;
394 }
395
396 if (IsCapsuleCorrupted (CapsuleHeader)) {
397 return NULL;
398 }
399
400 CapsuleCount++;
401 CapsuleSize = CapsuleHeader->CapsuleImageSize;
402 }
403
404 if (CapsuleSize >= Ptr->Length) {
405 CapsuleSize = CapsuleSize - Ptr->Length;
406 } else {
407 DEBUG ((DEBUG_ERROR, "ERROR: CapsuleSize(0x%lx) < Ptr->Length(0x%lx)\n", CapsuleSize, Ptr->Length));
408 //
409 // Sanity check
410 //
411 return NULL;
412 }
413
414 //
415 // Move to next BLOCK descriptor
416 //
417 Ptr++;
419 return NULL;
420 }
421
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));
425 }
426 }
427
428 if (CapsuleCount == 0) {
429 //
430 // No any capsule is found in BlockList
431 //
432 DEBUG ((DEBUG_ERROR, "ERROR: CapsuleCount(0x%x) == 0\n", CapsuleCount));
433 return NULL;
434 }
435
436 if (CapsuleSize != 0) {
437 //
438 // Capsule data is incomplete.
439 //
440 DEBUG ((DEBUG_ERROR, "ERROR: CapsuleSize(0x%lx) != 0\n", CapsuleSize));
441 return NULL;
442 }
443
444 return Ptr;
445}
446
468 IN EFI_PEI_SERVICES **PeiServices,
470 IN UINTN NumDescriptors,
471 IN UINT8 *MemBase,
472 IN UINTN MemSize
473 )
474{
475 EFI_CAPSULE_BLOCK_DESCRIPTOR *NewBlockList;
476 EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrBlockDescHead;
477 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockDesc;
478 EFI_CAPSULE_BLOCK_DESCRIPTOR *PrevBlockDescTail;
479 UINTN BufferSize;
480 UINT8 *RelocBuffer;
481 UINTN BlockListSize;
482
483 //
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.)
488 //
489
490 BufferSize = NumDescriptors * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
491 NewBlockList = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)MemBase;
492 if (MemSize < BufferSize) {
493 return NULL;
494 }
495
496 MemSize -= BufferSize;
497 MemBase += BufferSize;
498 //
499 // Go through all the blocks and make sure none are in the way
500 //
501 TempBlockDesc = BlockList;
502 while (TempBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS)(UINTN)NULL) {
503 if (TempBlockDesc->Length == 0) {
504 //
505 // Next block of descriptors
506 //
507 TempBlockDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)TempBlockDesc->Union.ContinuationPointer;
508 } else {
509 //
510 // If the capsule data pointed to by this descriptor is in the way,
511 // move it.
512 //
513 if (IsOverlapped (
514 (UINT8 *)NewBlockList,
515 BufferSize,
516 (UINT8 *)(UINTN)TempBlockDesc->Union.DataBlock,
517 (UINTN)TempBlockDesc->Length
518 ))
519 {
520 //
521 // Relocate the block
522 //
523 RelocBuffer = FindFreeMem (BlockList, MemBase, MemSize, (UINTN)TempBlockDesc->Length);
524 if (RelocBuffer == NULL) {
525 return NULL;
526 }
527
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;
531 }
532
533 TempBlockDesc++;
534 }
535 }
536
537 //
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.
540 //
541 CurrBlockDescHead = BlockList;
542 PrevBlockDescTail = NULL;
543 while ((CurrBlockDescHead != NULL) && (CurrBlockDescHead->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS)(UINTN)NULL)) {
544 //
545 // Get the size of this list then see if it overlaps our low region
546 //
547 TempBlockDesc = CurrBlockDescHead;
548 BlockListSize = sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
549 while (TempBlockDesc->Length != 0) {
550 BlockListSize += sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
551 TempBlockDesc++;
552 }
553
554 if (IsOverlapped (
555 (UINT8 *)NewBlockList,
556 BufferSize,
557 (UINT8 *)CurrBlockDescHead,
558 BlockListSize
559 ))
560 {
561 //
562 // Overlaps, so move it out of the way
563 //
564 RelocBuffer = FindFreeMem (BlockList, MemBase, MemSize, BlockListSize);
565 if (RelocBuffer == NULL) {
566 return NULL;
567 }
568
569 CopyMem ((VOID *)RelocBuffer, (VOID *)CurrBlockDescHead, BlockListSize);
570 DEBUG ((DEBUG_INFO, "Capsule reloc descriptor block #2\n"));
571 //
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.
574 //
575 if (PrevBlockDescTail == NULL) {
576 BlockList = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)RelocBuffer;
577 } else {
578 PrevBlockDescTail->Union.DataBlock = (EFI_PHYSICAL_ADDRESS)(UINTN)RelocBuffer;
579 }
580 }
581
582 //
583 // Save our new tail and jump to the next block list
584 //
585 PrevBlockDescTail = TempBlockDesc;
586 CurrBlockDescHead = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)TempBlockDesc->Union.ContinuationPointer;
587 }
588
589 //
590 // Cleared out low memory. Now copy the descriptors down there.
591 //
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;
598 CurrBlockDescHead++;
599 TempBlockDesc++;
600 } else {
601 TempBlockDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)TempBlockDesc->Union.ContinuationPointer;
602 }
603 }
604
605 //
606 // Null terminate
607 //
608 CurrBlockDescHead->Union.ContinuationPointer = (EFI_PHYSICAL_ADDRESS)(UINTN)NULL;
609 CurrBlockDescHead->Length = 0;
610 return NewBlockList;
611}
612
625BOOLEAN
627 UINT8 *Buff1,
628 UINTN Size1,
629 UINT8 *Buff2,
630 UINTN Size2
631 )
632{
633 //
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.
636 //
637 if (((Buff1 + Size1) <= Buff2) || (Buff1 >= (Buff2 + Size2))) {
638 return FALSE;
639 }
640
641 return TRUE;
642}
643
661 IN OUT UINTN *NumDescriptors OPTIONAL,
662 IN OUT UINTN *CapsuleSize OPTIONAL,
663 IN OUT UINTN *CapsuleNumber OPTIONAL
664 )
665{
666 UINTN Count;
667 UINTN Size;
668 UINTN Number;
669 UINTN ThisCapsuleImageSize;
670 EFI_CAPSULE_HEADER *CapsuleHeader;
671
672 DEBUG ((DEBUG_INFO, "GetCapsuleInfo enter\n"));
673
674 ASSERT (Desc != NULL);
675
676 Count = 0;
677 Size = 0;
678 Number = 0;
679 ThisCapsuleImageSize = 0;
680
681 while (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS)(UINTN)NULL) {
682 if (Desc->Length == 0) {
683 //
684 // Descriptor points to another list of block descriptors somewhere
685 //
686 Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)Desc->Union.ContinuationPointer;
687 } else {
688 //
689 // Sanity Check
690 // It is needed, because ValidateCapsuleIntegrity() only validate one individual capsule Size.
691 // While here we need check all capsules size.
692 //
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;
696 }
697
698 Size += (UINTN)Desc->Length;
699 Count++;
700
701 //
702 // See if this is first capsule's header
703 //
704 if (ThisCapsuleImageSize == 0) {
705 CapsuleHeader = (EFI_CAPSULE_HEADER *)((UINTN)Desc->Union.DataBlock);
706 //
707 // This has been checked in ValidateCapsuleIntegrity()
708 //
709 Number++;
710 ThisCapsuleImageSize = CapsuleHeader->CapsuleImageSize;
711 }
712
713 //
714 // This has been checked in ValidateCapsuleIntegrity()
715 //
716 ASSERT (ThisCapsuleImageSize >= Desc->Length);
717 ThisCapsuleImageSize = (UINTN)(ThisCapsuleImageSize - Desc->Length);
718
719 //
720 // Move to next
721 //
722 Desc++;
723 }
724 }
725
726 //
727 // If no descriptors, then fail
728 //
729 if (Count == 0) {
730 DEBUG ((DEBUG_ERROR, "ERROR: Count == 0\n"));
731 return EFI_NOT_FOUND;
732 }
733
734 //
735 // checked in ValidateCapsuleIntegrity()
736 //
737 ASSERT (ThisCapsuleImageSize == 0);
738
739 if (NumDescriptors != NULL) {
740 *NumDescriptors = Count;
741 }
742
743 if (CapsuleSize != NULL) {
744 *CapsuleSize = Size;
745 }
746
747 if (CapsuleNumber != NULL) {
748 *CapsuleNumber = Number;
749 }
750
751 return EFI_SUCCESS;
752}
753
763BOOLEAN
765 IN EFI_CAPSULE_HEADER *CapsuleHeader
766 )
767{
768 //
769 // A capsule to be updated across a system reset should contain CAPSULE_FLAGS_PERSIST_ACROSS_RESET.
770 //
771 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) == 0) {
772 return TRUE;
773 }
774
775 //
776 // Make sure the flags combination is supported by the platform.
777 //
778 if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {
779 return TRUE;
780 }
781
782 if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) {
783 return TRUE;
784 }
785
786 return FALSE;
787}
788
802VOID
804 IN EFI_PEI_SERVICES **PeiServices,
806 )
807{
808 UINT32 *TestPtr;
809 UINT32 TestCounter;
810 UINT32 TestSize;
811
812 DEBUG ((DEBUG_INFO, "CapsuleTestPatternPreCoalesce\n"));
813
814 //
815 // Find first data descriptor
816 //
817 while ((Desc->Length == 0) && (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS)(UINTN)NULL)) {
818 Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)Desc->Union.ContinuationPointer;
819 }
820
821 if (Desc->Union.ContinuationPointer == 0) {
822 return;
823 }
824
825 //
826 // First one better be long enough to at least hold the test signature
827 //
828 if (Desc->Length < sizeof (UINT32)) {
829 DEBUG ((DEBUG_INFO, "Capsule test pattern pre-coalesce punted #1\n"));
830 return;
831 }
832
833 TestPtr = (UINT32 *)(UINTN)Desc->Union.DataBlock;
834 //
835 // 0x54534554 "TEST"
836 //
837 if (*TestPtr != 0x54534554) {
838 return;
839 }
840
841 TestCounter = 0;
842 TestSize = (UINT32)Desc->Length - 2 * sizeof (UINT32);
843 //
844 // Skip over the signature and the size fields in the pattern data header
845 //
846 TestPtr += 2;
847 while (1) {
848 if ((TestSize & 0x03) != 0) {
849 DEBUG ((DEBUG_INFO, "Capsule test pattern pre-coalesce punted #2\n"));
850 return;
851 }
852
853 while (TestSize > 0) {
854 if (*TestPtr != TestCounter) {
855 DEBUG ((DEBUG_INFO, "Capsule test pattern pre-coalesce failed data corruption check\n"));
856 return;
857 }
858
859 TestSize -= sizeof (UINT32);
860 TestCounter++;
861 TestPtr++;
862 }
863
864 Desc++;
865 while ((Desc->Length == 0) && (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS)(UINTN)NULL)) {
866 Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)Desc->Union.ContinuationPointer;
867 }
868
869 if (Desc->Union.ContinuationPointer == (EFI_PHYSICAL_ADDRESS)(UINTN)NULL) {
870 return;
871 }
872
873 TestSize = (UINT32)Desc->Length;
874 TestPtr = (UINT32 *)(UINTN)Desc->Union.DataBlock;
875 }
876}
877
891 IN EFI_PHYSICAL_ADDRESS *BlockListBuffer,
892 IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource,
893 OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptorList
894 )
895{
896 UINTN Index;
900
901 DEBUG ((DEBUG_INFO, "BuildCapsuleDescriptors enter\n"));
902
903 LastBlock = NULL;
904 HeadBlock = NULL;
905 TempBlock = NULL;
906 Index = 0;
907
908 while (BlockListBuffer[Index] != 0) {
909 //
910 // Test integrity of descriptors.
911 //
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;
917
918 //
919 // Return the base of the block descriptors
920 //
921 HeadBlock = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)BlockListBuffer[Index];
922 } else {
923 //
924 // Combine the different BlockList into single BlockList.
925 //
926 LastBlock->Union.DataBlock = (EFI_PHYSICAL_ADDRESS)(UINTN)BlockListBuffer[Index];
927 LastBlock->Length = 0;
928 LastBlock = TempBlock;
929 }
930 }
931 } else {
932 DEBUG ((DEBUG_ERROR, "ERROR: BlockListBuffer[Index](0x%lx) < MAX_ADDRESS\n", BlockListBuffer[Index]));
933 }
934
935 Index++;
936 }
937
938 if (HeadBlock != NULL) {
939 *BlockDescriptorList = HeadBlock;
940 return EFI_SUCCESS;
941 }
942
943 return EFI_NOT_FOUND;
944}
945
1018EFIAPI
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
1025 )
1026{
1027 VOID *NewCapsuleBase;
1028 VOID *CapsuleImageBase;
1029 UINTN CapsuleIndex;
1030 UINT8 *FreeMemBase;
1031 UINT8 *DestPtr;
1032 UINTN DestLength;
1033 UINT8 *RelocPtr;
1034 UINTN CapsuleTimes;
1035 UINT64 SizeLeft;
1036 UINT64 CapsuleImageSize;
1037 UINTN CapsuleSize;
1038 UINTN CapsuleNumber;
1039 UINTN DescriptorsSize;
1040 UINTN FreeMemSize;
1041 UINTN NumDescriptors;
1042 BOOLEAN CapsuleBeginFlag;
1043 EFI_STATUS Status;
1044 EFI_CAPSULE_HEADER *CapsuleHeader;
1046 EFI_CAPSULE_PEIM_PRIVATE_DATA *PrivateDataPtr;
1048 EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrentBlockDesc;
1049 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockDesc;
1050 EFI_CAPSULE_BLOCK_DESCRIPTOR PrivateDataDesc[2];
1051
1052 DEBUG ((DEBUG_INFO, "CapsuleDataCoalesce enter\n"));
1053
1054 CapsuleIndex = 0;
1055 SizeLeft = 0;
1056 CapsuleTimes = 0;
1057 CapsuleImageSize = 0;
1058 PrivateDataPtr = NULL;
1059 CapsuleHeader = NULL;
1060 CapsuleBeginFlag = TRUE;
1061 CapsuleSize = 0;
1062 NumDescriptors = 0;
1063
1064 //
1065 // Build capsule descriptors list
1066 //
1067 Status = BuildCapsuleDescriptors (BlockListBuffer, MemoryResource, &BlockList);
1068 if (EFI_ERROR (Status)) {
1069 return Status;
1070 }
1071
1072 DEBUG_CODE (
1073 CapsuleTestPatternPreCoalesce (PeiServices, BlockList);
1074 );
1075
1076 //
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.
1080 //
1081 Status = GetCapsuleInfo (BlockList, &NumDescriptors, &CapsuleSize, &CapsuleNumber);
1082 if (EFI_ERROR (Status)) {
1083 return Status;
1084 }
1085
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;
1091 }
1092
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;
1096 }
1097
1098 //
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.
1102 //
1103 PrivateData.Signature = EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE;
1104 PrivateData.CapsuleAllImageSize = (UINT64)CapsuleSize;
1105 PrivateData.CapsuleNumber = (UINT64)CapsuleNumber;
1106 PrivateData.CapsuleOffset[0] = 0;
1107 //
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.
1110 //
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;
1115 //
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().
1118 //
1119 NumDescriptors += 2;
1120 //
1121 // Sanity check
1122 //
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;
1126 }
1127
1128 //
1129 // Need add sizeof(UINT64) for PrivateData alignment
1130 //
1131 CapsuleSize += sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof (UINT64) + sizeof (UINT64);
1132 BlockList = PrivateDataDesc;
1133 //
1134 // Sanity check
1135 //
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;
1139 }
1140
1141 DescriptorsSize = NumDescriptors * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
1142 //
1143 // Sanity check
1144 //
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;
1148 }
1149
1150 //
1151 // Don't go below some min address. If the base is below it,
1152 // then move it up and adjust the size accordingly.
1153 //
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;
1159 } else {
1160 *MemorySize = *MemorySize - ((UINTN)MIN_COALESCE_ADDR - (UINTN)*MemoryBase);
1161 *MemoryBase = (VOID *)(UINTN)MIN_COALESCE_ADDR;
1162 }
1163 }
1164
1165 if (*MemorySize <= (CapsuleSize + DescriptorsSize)) {
1166 DEBUG ((DEBUG_ERROR, "ERROR: CapsuleSize + DescriptorsSize - 0x%x\n", CapsuleSize + DescriptorsSize));
1167 return EFI_BUFFER_TOO_SMALL;
1168 }
1169
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));
1173
1174 //
1175 // Relocate all the block descriptors to low memory to make further
1176 // processing easier.
1177 //
1178 BlockList = RelocateBlockDescriptors (PeiServices, BlockList, NumDescriptors, FreeMemBase, FreeMemSize);
1179 if (BlockList == NULL) {
1180 //
1181 // Not enough room to relocate the descriptors
1182 //
1183 return EFI_BUFFER_TOO_SMALL;
1184 }
1185
1186 //
1187 // Take the top of memory for the capsule. UINT64 align up.
1188 //
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);
1195
1196 PrivateDataPtr = (EFI_CAPSULE_PEIM_PRIVATE_DATA *)NewCapsuleBase;
1197
1198 //
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.
1202 //
1203 CurrentBlockDesc = BlockList;
1204 while ((CurrentBlockDesc->Length != 0) || (CurrentBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS)(UINTN)NULL)) {
1205 if (CapsuleTimes == 0) {
1206 //
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.
1209 //
1210 ASSERT (CurrentBlockDesc->Union.DataBlock == (UINT64)(UINTN)&PrivateData);
1211 DestLength = sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof (UINT64);
1212 } else {
1213 DestLength = (UINTN)CurrentBlockDesc->Length;
1214 }
1215
1216 //
1217 // See if any of the remaining capsule blocks are in the way
1218 //
1219 TempBlockDesc = CurrentBlockDesc;
1220 while (TempBlockDesc->Length != 0) {
1221 //
1222 // Is this block in the way of where we want to copy the current descriptor to?
1223 //
1224 if (IsOverlapped (
1225 (UINT8 *)DestPtr,
1226 (UINTN)DestLength,
1227 (UINT8 *)(UINTN)TempBlockDesc->Union.DataBlock,
1228 (UINTN)TempBlockDesc->Length
1229 ))
1230 {
1231 //
1232 // Relocate the block
1233 //
1234 RelocPtr = FindFreeMem (BlockList, FreeMemBase, FreeMemSize, (UINTN)TempBlockDesc->Length);
1235 if (RelocPtr == NULL) {
1236 return EFI_BUFFER_TOO_SMALL;
1237 }
1238
1239 CopyMem ((VOID *)RelocPtr, (VOID *)(UINTN)TempBlockDesc->Union.DataBlock, (UINTN)TempBlockDesc->Length);
1240 DEBUG ((
1241 DEBUG_INFO,
1242 "Capsule reloc data block from 0x%8X to 0x%8X with size 0x%8X\n",
1243 (UINTN)TempBlockDesc->Union.DataBlock,
1244 (UINTN)RelocPtr,
1245 (UINTN)TempBlockDesc->Length
1246 ));
1247
1248 TempBlockDesc->Union.DataBlock = (EFI_PHYSICAL_ADDRESS)(UINTN)RelocPtr;
1249 }
1250
1251 //
1252 // Next descriptor
1253 //
1254 TempBlockDesc++;
1255 }
1256
1257 //
1258 // Ok, we made it through. Copy the block.
1259 // we just support greping one capsule from the lists of block descs list.
1260 //
1261 CapsuleTimes++;
1262 //
1263 // Skip the first block descriptor that filled with EFI_CAPSULE_PEIM_PRIVATE_DATA
1264 //
1265 if (CapsuleTimes > 1) {
1266 //
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.
1269 //
1270 if (CapsuleBeginFlag) {
1271 CapsuleBeginFlag = FALSE;
1272 CapsuleHeader = (EFI_CAPSULE_HEADER *)(UINTN)CurrentBlockDesc->Union.DataBlock;
1273 SizeLeft = CapsuleHeader->CapsuleImageSize;
1274
1275 //
1276 // No more check here is needed, because IsCapsuleCorrupted() already in ValidateCapsuleIntegrity()
1277 //
1278 ASSERT (CapsuleIndex < CapsuleNumber);
1279
1280 //
1281 // Relocate this capsule
1282 //
1283 CapsuleImageSize += SizeLeft;
1284 //
1285 // Cache the begin offset of this capsule
1286 //
1287 ASSERT (PrivateDataPtr->Signature == EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE);
1288 ASSERT ((UINTN)DestPtr >= (UINTN)CapsuleImageBase);
1289 PrivateDataPtr->CapsuleOffset[CapsuleIndex++] = (UINTN)DestPtr - (UINTN)CapsuleImageBase;
1290 }
1291
1292 //
1293 // Below ASSERT is checked in ValidateCapsuleIntegrity()
1294 //
1295 ASSERT (CurrentBlockDesc->Length <= SizeLeft);
1296
1297 CopyMem ((VOID *)DestPtr, (VOID *)(UINTN)(CurrentBlockDesc->Union.DataBlock), (UINTN)CurrentBlockDesc->Length);
1298 DEBUG ((
1299 DEBUG_INFO,
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
1305 ));
1306 DestPtr += CurrentBlockDesc->Length;
1307 SizeLeft -= CurrentBlockDesc->Length;
1308
1309 if (SizeLeft == 0) {
1310 //
1311 // Here is the end of the current capsule image.
1312 //
1313 CapsuleBeginFlag = TRUE;
1314 }
1315 } else {
1316 //
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.
1319 //
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);
1324 }
1325
1326 //
1327 // Walk through the block descriptor list.
1328 //
1329 CurrentBlockDesc++;
1330 }
1331
1332 //
1333 // We return the base of memory we want reserved, and the size.
1334 // The memory peim should handle it appropriately from there.
1335 //
1336 *MemorySize = (UINTN)CapsuleSize;
1337 *MemoryBase = (VOID *)NewCapsuleBase;
1338
1339 ASSERT (PrivateDataPtr->Signature == EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE);
1340 ASSERT (PrivateDataPtr->CapsuleAllImageSize == CapsuleImageSize);
1341 ASSERT (PrivateDataPtr->CapsuleNumber == CapsuleIndex);
1342
1343 return EFI_SUCCESS;
1344}
UINT64 UINTN
#define MAX_ADDRESS
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
BOOLEAN ValidateCapsuleByMemoryResource(IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource, IN EFI_PHYSICAL_ADDRESS Address, IN UINT64 Size)
UINT8 * FindFreeMem(EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList, UINT8 *MemBase, UINTN MemSize, UINTN DataSize)
EFI_STATUS GetCapsuleInfo(IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc, IN OUT UINTN *NumDescriptors OPTIONAL, IN OUT UINTN *CapsuleSize OPTIONAL, IN OUT UINTN *CapsuleNumber OPTIONAL)
EFI_STATUS EFIAPI CapsuleDataCoalesce(IN EFI_PEI_SERVICES **PeiServices, IN EFI_PHYSICAL_ADDRESS *BlockListBuffer, IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource, IN OUT VOID **MemoryBase, IN OUT UINTN *MemorySize)
EFI_CAPSULE_BLOCK_DESCRIPTOR * RelocateBlockDescriptors(IN EFI_PEI_SERVICES **PeiServices, IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList, IN UINTN NumDescriptors, IN UINT8 *MemBase, IN UINTN MemSize)
BOOLEAN IsOverlapped(UINT8 *Buff1, UINTN Size1, UINT8 *Buff2, UINTN Size2)
EFI_STATUS BuildCapsuleDescriptors(IN EFI_PHYSICAL_ADDRESS *BlockListBuffer, IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource, OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptorList)
VOID CapsuleTestPatternPreCoalesce(IN EFI_PEI_SERVICES **PeiServices, IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc)
EFI_CAPSULE_BLOCK_DESCRIPTOR * ValidateCapsuleIntegrity(IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList, IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource)
BOOLEAN IsCapsuleCorrupted(IN EFI_CAPSULE_HEADER *CapsuleHeader)
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define DEBUG_CODE(Expression)
Definition: DebugLib.h:590
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_PHYSICAL_ADDRESS DataBlock
Definition: UefiSpec.h:1664
EFI_PHYSICAL_ADDRESS ContinuationPointer
Definition: UefiSpec.h:1671
UINT32 CapsuleImageSize
Definition: UefiSpec.h:1698