CapsuleCoalesce.c revision ff284c56a11a9a9b32777c91bc069093d5b5d8a9
1/** @file 2 The logic to process capsule. 3 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. 8 9 CapsuleDataCoalesce() will do basic validation before coalesce capsule data 10 into memory. 11 12Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR> 13This program and the accompanying materials 14are licensed and made available under the terms and conditions of the BSD License 15which accompanies this distribution. The full text of the license may be found at 16http://opensource.org/licenses/bsd-license.php 17 18THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 19WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 20 21**/ 22 23#include <Uefi.h> 24#include <PiPei.h> 25 26#include <Guid/CapsuleVendor.h> 27 28#include <Library/BaseMemoryLib.h> 29#include <Library/DebugLib.h> 30#include <Library/PrintLib.h> 31#include <Library/BaseLib.h> 32 33#include "CommonHeader.h" 34 35#define MIN_COALESCE_ADDR (1024 * 1024) 36 37/** 38 Given a pointer to the capsule block list, info on the available system 39 memory, and the size of a buffer, find a free block of memory where a 40 buffer of the given size can be copied to safely. 41 42 @param BlockList Pointer to head of capsule block descriptors 43 @param MemBase Pointer to the base of memory in which we want to find free space 44 @param MemSize The size of the block of memory pointed to by MemBase 45 @param DataSize How big a free block we want to find 46 47 @return A pointer to a memory block of at least DataSize that lies somewhere 48 between MemBase and (MemBase + MemSize). The memory pointed to does not 49 contain any of the capsule block descriptors or capsule blocks pointed to 50 by the BlockList. 51 52**/ 53UINT8 * 54FindFreeMem ( 55 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList, 56 UINT8 *MemBase, 57 UINTN MemSize, 58 UINTN DataSize 59 ); 60 61/** 62 Check the integrity of the capsule descriptors. 63 64 @param BlockList Pointer to the capsule descriptors 65 66 @retval NULL BlockList is not valid. 67 @retval LastBlockDesc Last one Block in BlockList 68 69**/ 70EFI_CAPSULE_BLOCK_DESCRIPTOR * 71ValidateCapsuleIntegrity ( 72 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList 73 ); 74 75/** 76 The capsule block descriptors may be fragmented and spread all over memory. 77 To simplify the coalescing of capsule blocks, first coalesce all the 78 capsule block descriptors low in memory. 79 80 The descriptors passed in can be fragmented throughout memory. Here 81 they are relocated into memory to turn them into a contiguous (null 82 terminated) array. 83 84 @param PeiServices pointer to PEI services table 85 @param BlockList pointer to the capsule block descriptors 86 @param NumDescriptors number of capsule data block descriptors, whose Length is non-zero. 87 @param MemBase base of system memory in which we can work 88 @param MemSize size of the system memory pointed to by MemBase 89 90 @retval NULL could not relocate the descriptors 91 @retval Pointer to the base of the successfully-relocated block descriptors. 92 93**/ 94EFI_CAPSULE_BLOCK_DESCRIPTOR * 95RelocateBlockDescriptors ( 96 IN EFI_PEI_SERVICES **PeiServices, 97 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList, 98 IN UINTN NumDescriptors, 99 IN UINT8 *MemBase, 100 IN UINTN MemSize 101 ); 102 103/** 104 Check every capsule header. 105 106 @param CapsuleHeader The pointer to EFI_CAPSULE_HEADER 107 108 @retval FALSE Capsule is OK 109 @retval TRUE Capsule is corrupted 110 111**/ 112BOOLEAN 113IsCapsuleCorrupted ( 114 IN EFI_CAPSULE_HEADER *CapsuleHeader 115 ); 116 117/** 118 Determine if two buffers overlap in memory. 119 120 @param Buff1 pointer to first buffer 121 @param Size1 size of Buff1 122 @param Buff2 pointer to second buffer 123 @param Size2 size of Buff2 124 125 @retval TRUE Buffers overlap in memory. 126 @retval FALSE Buffer doesn't overlap. 127 128**/ 129BOOLEAN 130IsOverlapped ( 131 UINT8 *Buff1, 132 UINTN Size1, 133 UINT8 *Buff2, 134 UINTN Size2 135 ); 136 137/** 138 Given a pointer to a capsule block descriptor, traverse the list to figure 139 out how many legitimate descriptors there are, and how big the capsule it 140 refers to is. 141 142 @param Desc Pointer to the capsule block descriptors 143 @param NumDescriptors Optional pointer to where to return the number of capsule data descriptors, whose Length is non-zero. 144 @param CapsuleSize Optional pointer to where to return the capsule image size 145 @param CapsuleNumber Optional pointer to where to return the number of capsule 146 147 @retval EFI_NOT_FOUND No descriptors containing data in the list 148 @retval EFI_SUCCESS Return data is valid 149 150**/ 151EFI_STATUS 152GetCapsuleInfo ( 153 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc, 154 IN OUT UINTN *NumDescriptors OPTIONAL, 155 IN OUT UINTN *CapsuleSize OPTIONAL, 156 IN OUT UINTN *CapsuleNumber OPTIONAL 157 ); 158 159/** 160 Given a pointer to the capsule block list, info on the available system 161 memory, and the size of a buffer, find a free block of memory where a 162 buffer of the given size can be copied to safely. 163 164 @param BlockList Pointer to head of capsule block descriptors 165 @param MemBase Pointer to the base of memory in which we want to find free space 166 @param MemSize The size of the block of memory pointed to by MemBase 167 @param DataSize How big a free block we want to find 168 169 @return A pointer to a memory block of at least DataSize that lies somewhere 170 between MemBase and (MemBase + MemSize). The memory pointed to does not 171 contain any of the capsule block descriptors or capsule blocks pointed to 172 by the BlockList. 173 174**/ 175UINT8 * 176FindFreeMem ( 177 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList, 178 UINT8 *MemBase, 179 UINTN MemSize, 180 UINTN DataSize 181 ) 182{ 183 UINTN Size; 184 EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrDesc; 185 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempDesc; 186 UINT8 *MemEnd; 187 BOOLEAN Failed; 188 189 // 190 // Need at least enough to copy the data to at the end of the buffer, so 191 // say the end is less the data size for easy comparisons here. 192 // 193 MemEnd = MemBase + MemSize - DataSize; 194 CurrDesc = BlockList; 195 // 196 // Go through all the descriptor blocks and see if any obstruct the range 197 // 198 while (CurrDesc != NULL) { 199 // 200 // Get the size of this block list and see if it's in the way 201 // 202 Failed = FALSE; 203 TempDesc = CurrDesc; 204 Size = sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR); 205 while (TempDesc->Length != 0) { 206 Size += sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR); 207 TempDesc++; 208 } 209 210 if (IsOverlapped (MemBase, DataSize, (UINT8 *) CurrDesc, Size)) { 211 // 212 // Set our new base to the end of this block list and start all over 213 // 214 MemBase = (UINT8 *) CurrDesc + Size; 215 CurrDesc = BlockList; 216 if (MemBase > MemEnd) { 217 return NULL; 218 } 219 220 Failed = TRUE; 221 } 222 // 223 // Now go through all the blocks and make sure none are in the way 224 // 225 while ((CurrDesc->Length != 0) && (!Failed)) { 226 if (IsOverlapped (MemBase, DataSize, (UINT8 *) (UINTN) CurrDesc->Union.DataBlock, (UINTN) CurrDesc->Length)) { 227 // 228 // Set our new base to the end of this block and start all over 229 // 230 Failed = TRUE; 231 MemBase = (UINT8 *) ((UINTN) CurrDesc->Union.DataBlock) + CurrDesc->Length; 232 CurrDesc = BlockList; 233 if (MemBase > MemEnd) { 234 return NULL; 235 } 236 } 237 CurrDesc++; 238 } 239 // 240 // Normal continuation -- jump to next block descriptor list 241 // 242 if (!Failed) { 243 CurrDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) CurrDesc->Union.ContinuationPointer; 244 } 245 } 246 return MemBase; 247} 248 249/** 250 Check the integrity of the capsule descriptors. 251 252 @param BlockList Pointer to the capsule descriptors 253 254 @retval NULL BlockList is not valid. 255 @retval LastBlockDesc Last one Block in BlockList 256 257**/ 258EFI_CAPSULE_BLOCK_DESCRIPTOR * 259ValidateCapsuleIntegrity ( 260 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList 261 ) 262{ 263 EFI_CAPSULE_HEADER *CapsuleHeader; 264 UINT64 CapsuleSize; 265 UINTN CapsuleCount; 266 EFI_CAPSULE_BLOCK_DESCRIPTOR *Ptr; 267 268 DEBUG ((EFI_D_INFO, "ValidateCapsuleIntegrity\n")); 269 270 // 271 // Go through the list to look for inconsistencies. Check for: 272 // * misaligned block descriptors. 273 // * The first capsule header guid 274 // * The first capsule header flag 275 // * The first capsule header HeaderSize 276 // * Length > MAX_ADDRESS 277 // * ContinuationPointer > MAX_ADDRESS 278 // * DataBlock + Length > MAX_ADDRESS 279 // 280 CapsuleSize = 0; 281 CapsuleCount = 0; 282 Ptr = BlockList; 283 284 DEBUG ((EFI_D_INFO, "Ptr - 0x%x\n", Ptr)); 285 DEBUG ((EFI_D_INFO, "Ptr->Length - 0x%x\n", Ptr->Length)); 286 DEBUG ((EFI_D_INFO, "Ptr->Union - 0x%x\n", Ptr->Union.ContinuationPointer)); 287 while ((Ptr->Length != 0) || (Ptr->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) { 288 // 289 // Make sure the descriptor is aligned at UINT64 in memory 290 // 291 if ((UINTN) Ptr & (sizeof(UINT64) - 1)) { 292 DEBUG ((EFI_D_ERROR, "ERROR: BlockList address failed alignment check\n")); 293 return NULL; 294 } 295 // 296 // Sanity Check 297 // 298 if (Ptr->Length > MAX_ADDRESS) { 299 DEBUG ((EFI_D_ERROR, "ERROR: Ptr->Length(0x%lx) > MAX_ADDRESS\n", Ptr->Length)); 300 return NULL; 301 } 302 303 if (Ptr->Length == 0) { 304 // 305 // Sanity Check 306 // 307 if (Ptr->Union.ContinuationPointer > MAX_ADDRESS) { 308 DEBUG ((EFI_D_ERROR, "ERROR: Ptr->Union.ContinuationPointer(0x%lx) > MAX_ADDRESS\n", Ptr->Union.ContinuationPointer)); 309 return NULL; 310 } 311 // 312 // Descriptor points to another list of block descriptors somewhere 313 // else. 314 // 315 Ptr = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Ptr->Union.ContinuationPointer; 316 DEBUG ((EFI_D_INFO, "Ptr(C) - 0x%x\n", Ptr)); 317 DEBUG ((EFI_D_INFO, "Ptr->Length - 0x%x\n", Ptr->Length)); 318 DEBUG ((EFI_D_INFO, "Ptr->Union - 0x%x\n", Ptr->Union.ContinuationPointer)); 319 } else { 320 // 321 // Sanity Check 322 // 323 if (Ptr->Union.DataBlock > (MAX_ADDRESS - (UINTN)Ptr->Length)) { 324 DEBUG ((EFI_D_ERROR, "ERROR: Ptr->Union.DataBlock(0x%lx) > (MAX_ADDRESS - (UINTN)Ptr->Length(0x%lx))\n", Ptr->Union.DataBlock, Ptr->Length)); 325 return NULL; 326 } 327 328 // 329 //To enhance the reliability of check-up, the first capsule's header is checked here. 330 //More reliabilities check-up will do later. 331 // 332 if (CapsuleSize == 0) { 333 // 334 //Move to the first capsule to check its header. 335 // 336 CapsuleHeader = (EFI_CAPSULE_HEADER*)((UINTN)Ptr->Union.DataBlock); 337 // 338 // Sanity check 339 // 340 if (Ptr->Length < sizeof(EFI_CAPSULE_HEADER)) { 341 DEBUG ((EFI_D_ERROR, "ERROR: Ptr->Length(0x%lx) < sizeof(EFI_CAPSULE_HEADER)\n", Ptr->Length)); 342 return NULL; 343 } 344 // 345 // Make sure HeaderSize field is valid 346 // 347 if (CapsuleHeader->HeaderSize > CapsuleHeader->CapsuleImageSize) { 348 DEBUG ((EFI_D_ERROR, "ERROR: CapsuleHeader->HeaderSize(0x%x) > CapsuleHeader->CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize)); 349 return NULL; 350 } 351 if (IsCapsuleCorrupted (CapsuleHeader)) { 352 return NULL; 353 } 354 CapsuleCount ++; 355 CapsuleSize = CapsuleHeader->CapsuleImageSize; 356 } 357 358 if (CapsuleSize >= Ptr->Length) { 359 CapsuleSize = CapsuleSize - Ptr->Length; 360 } else { 361 DEBUG ((EFI_D_ERROR, "ERROR: CapsuleSize(0x%lx) < Ptr->Length(0x%lx)\n", CapsuleSize, Ptr->Length)); 362 // 363 // Sanity check 364 // 365 return NULL; 366 } 367 368 // 369 // Move to next BLOCK descriptor 370 // 371 Ptr++; 372 DEBUG ((EFI_D_INFO, "Ptr(B) - 0x%x\n", Ptr)); 373 DEBUG ((EFI_D_INFO, "Ptr->Length - 0x%x\n", Ptr->Length)); 374 DEBUG ((EFI_D_INFO, "Ptr->Union - 0x%x\n", Ptr->Union.ContinuationPointer)); 375 } 376 } 377 378 if (CapsuleCount == 0) { 379 // 380 // No any capsule is found in BlockList 381 // 382 DEBUG ((EFI_D_ERROR, "ERROR: CapsuleCount(0x%x) == 0\n", CapsuleCount)); 383 return NULL; 384 } 385 386 if (CapsuleSize != 0) { 387 // 388 // Capsule data is incomplete. 389 // 390 DEBUG ((EFI_D_ERROR, "ERROR: CapsuleSize(0x%lx) != 0\n", CapsuleSize)); 391 return NULL; 392 } 393 394 return Ptr; 395} 396 397/** 398 The capsule block descriptors may be fragmented and spread all over memory. 399 To simplify the coalescing of capsule blocks, first coalesce all the 400 capsule block descriptors low in memory. 401 402 The descriptors passed in can be fragmented throughout memory. Here 403 they are relocated into memory to turn them into a contiguous (null 404 terminated) array. 405 406 @param PeiServices pointer to PEI services table 407 @param BlockList pointer to the capsule block descriptors 408 @param NumDescriptors number of capsule data block descriptors, whose Length is non-zero. 409 @param MemBase base of system memory in which we can work 410 @param MemSize size of the system memory pointed to by MemBase 411 412 @retval NULL could not relocate the descriptors 413 @retval Pointer to the base of the successfully-relocated block descriptors. 414 415**/ 416EFI_CAPSULE_BLOCK_DESCRIPTOR * 417RelocateBlockDescriptors ( 418 IN EFI_PEI_SERVICES **PeiServices, 419 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList, 420 IN UINTN NumDescriptors, 421 IN UINT8 *MemBase, 422 IN UINTN MemSize 423 ) 424{ 425 EFI_CAPSULE_BLOCK_DESCRIPTOR *NewBlockList; 426 EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrBlockDescHead; 427 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockDesc; 428 EFI_CAPSULE_BLOCK_DESCRIPTOR *PrevBlockDescTail; 429 UINTN BufferSize; 430 UINT8 *RelocBuffer; 431 UINTN BlockListSize; 432 433 // 434 // Get the info on the blocks and descriptors. Since we're going to move 435 // the descriptors low in memory, adjust the base/size values accordingly here. 436 // NumDescriptors is the number of legit data descriptors, so add one for 437 // a terminator. (Already done by caller, no check is needed.) 438 // 439 440 BufferSize = NumDescriptors * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR); 441 NewBlockList = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) MemBase; 442 if (MemSize < BufferSize) { 443 return NULL; 444 } 445 446 MemSize -= BufferSize; 447 MemBase += BufferSize; 448 // 449 // Go through all the blocks and make sure none are in the way 450 // 451 TempBlockDesc = BlockList; 452 while (TempBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) { 453 if (TempBlockDesc->Length == 0) { 454 // 455 // Next block of descriptors 456 // 457 TempBlockDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer; 458 } else { 459 // 460 // If the capsule data pointed to by this descriptor is in the way, 461 // move it. 462 // 463 if (IsOverlapped ( 464 (UINT8 *) NewBlockList, 465 BufferSize, 466 (UINT8 *) (UINTN) TempBlockDesc->Union.DataBlock, 467 (UINTN) TempBlockDesc->Length 468 )) { 469 // 470 // Relocate the block 471 // 472 RelocBuffer = FindFreeMem (BlockList, MemBase, MemSize, (UINTN) TempBlockDesc->Length); 473 if (RelocBuffer == NULL) { 474 return NULL; 475 } 476 477 CopyMem ((VOID *) RelocBuffer, (VOID *) (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) TempBlockDesc->Length); 478 DEBUG ((EFI_D_INFO, "Capsule relocate descriptors from/to/size 0x%lX 0x%lX 0x%lX\n", TempBlockDesc->Union.DataBlock, (UINT64)(UINTN)RelocBuffer, TempBlockDesc->Length)); 479 TempBlockDesc->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocBuffer; 480 } 481 TempBlockDesc++; 482 } 483 } 484 // 485 // Now go through all the block descriptors to make sure that they're not 486 // in the memory region we want to copy them to. 487 // 488 CurrBlockDescHead = BlockList; 489 PrevBlockDescTail = NULL; 490 while ((CurrBlockDescHead != NULL) && (CurrBlockDescHead->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) { 491 // 492 // Get the size of this list then see if it overlaps our low region 493 // 494 TempBlockDesc = CurrBlockDescHead; 495 BlockListSize = sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR); 496 while (TempBlockDesc->Length != 0) { 497 BlockListSize += sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR); 498 TempBlockDesc++; 499 } 500 501 if (IsOverlapped ( 502 (UINT8 *) NewBlockList, 503 BufferSize, 504 (UINT8 *) CurrBlockDescHead, 505 BlockListSize 506 )) { 507 // 508 // Overlaps, so move it out of the way 509 // 510 RelocBuffer = FindFreeMem (BlockList, MemBase, MemSize, BlockListSize); 511 if (RelocBuffer == NULL) { 512 return NULL; 513 } 514 CopyMem ((VOID *) RelocBuffer, (VOID *) CurrBlockDescHead, BlockListSize); 515 DEBUG ((EFI_D_INFO, "Capsule reloc descriptor block #2\n")); 516 // 517 // Point the previous block's next point to this copied version. If 518 // the tail pointer is null, then this is the first descriptor block. 519 // 520 if (PrevBlockDescTail == NULL) { 521 BlockList = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) RelocBuffer; 522 } else { 523 PrevBlockDescTail->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocBuffer; 524 } 525 } 526 // 527 // Save our new tail and jump to the next block list 528 // 529 PrevBlockDescTail = TempBlockDesc; 530 CurrBlockDescHead = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer; 531 } 532 // 533 // Cleared out low memory. Now copy the descriptors down there. 534 // 535 TempBlockDesc = BlockList; 536 CurrBlockDescHead = NewBlockList; 537 while ((TempBlockDesc != NULL) && (TempBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) { 538 if (TempBlockDesc->Length != 0) { 539 CurrBlockDescHead->Union.DataBlock = TempBlockDesc->Union.DataBlock; 540 CurrBlockDescHead->Length = TempBlockDesc->Length; 541 CurrBlockDescHead++; 542 TempBlockDesc++; 543 } else { 544 TempBlockDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer; 545 } 546 } 547 // 548 // Null terminate 549 // 550 CurrBlockDescHead->Union.ContinuationPointer = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL; 551 CurrBlockDescHead->Length = 0; 552 return NewBlockList; 553} 554 555/** 556 Determine if two buffers overlap in memory. 557 558 @param Buff1 pointer to first buffer 559 @param Size1 size of Buff1 560 @param Buff2 pointer to second buffer 561 @param Size2 size of Buff2 562 563 @retval TRUE Buffers overlap in memory. 564 @retval FALSE Buffer doesn't overlap. 565 566**/ 567BOOLEAN 568IsOverlapped ( 569 UINT8 *Buff1, 570 UINTN Size1, 571 UINT8 *Buff2, 572 UINTN Size2 573 ) 574{ 575 // 576 // If buff1's end is less than the start of buff2, then it's ok. 577 // Also, if buff1's start is beyond buff2's end, then it's ok. 578 // 579 if (((Buff1 + Size1) <= Buff2) || (Buff1 >= (Buff2 + Size2))) { 580 return FALSE; 581 } 582 583 return TRUE; 584} 585 586/** 587 Given a pointer to a capsule block descriptor, traverse the list to figure 588 out how many legitimate descriptors there are, and how big the capsule it 589 refers to is. 590 591 @param Desc Pointer to the capsule block descriptors 592 @param NumDescriptors Optional pointer to where to return the number of capsule data descriptors, whose Length is non-zero. 593 @param CapsuleSize Optional pointer to where to return the capsule image size 594 @param CapsuleNumber Optional pointer to where to return the number of capsule 595 596 @retval EFI_NOT_FOUND No descriptors containing data in the list 597 @retval EFI_SUCCESS Return data is valid 598 599**/ 600EFI_STATUS 601GetCapsuleInfo ( 602 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc, 603 IN OUT UINTN *NumDescriptors OPTIONAL, 604 IN OUT UINTN *CapsuleSize OPTIONAL, 605 IN OUT UINTN *CapsuleNumber OPTIONAL 606 ) 607{ 608 UINTN Count; 609 UINTN Size; 610 UINTN Number; 611 UINTN ThisCapsuleImageSize; 612 EFI_CAPSULE_HEADER *CapsuleHeader; 613 614 DEBUG ((EFI_D_INFO, "GetCapsuleInfo enter\n")); 615 616 ASSERT (Desc != NULL); 617 618 Count = 0; 619 Size = 0; 620 Number = 0; 621 ThisCapsuleImageSize = 0; 622 623 while (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) { 624 if (Desc->Length == 0) { 625 // 626 // Descriptor points to another list of block descriptors somewhere 627 // 628 Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer; 629 } else { 630 // 631 // Sanity Check 632 // It is needed, because ValidateCapsuleIntegrity() only validate one individual capsule Size. 633 // While here we need check all capsules size. 634 // 635 if (Desc->Length >= (MAX_ADDRESS - Size)) { 636 DEBUG ((EFI_D_ERROR, "ERROR: Desc->Length(0x%lx) >= (MAX_ADDRESS - Size(0x%x))\n", Desc->Length, Size)); 637 return EFI_OUT_OF_RESOURCES; 638 } 639 Size += (UINTN) Desc->Length; 640 Count++; 641 642 // 643 // See if this is first capsule's header 644 // 645 if (ThisCapsuleImageSize == 0) { 646 CapsuleHeader = (EFI_CAPSULE_HEADER*)((UINTN)Desc->Union.DataBlock); 647 // 648 // This has been checked in ValidateCapsuleIntegrity() 649 // 650 Number ++; 651 ThisCapsuleImageSize = CapsuleHeader->CapsuleImageSize; 652 } 653 654 // 655 // This has been checked in ValidateCapsuleIntegrity() 656 // 657 ASSERT (ThisCapsuleImageSize >= Desc->Length); 658 ThisCapsuleImageSize = (UINTN)(ThisCapsuleImageSize - Desc->Length); 659 660 // 661 // Move to next 662 // 663 Desc++; 664 } 665 } 666 // 667 // If no descriptors, then fail 668 // 669 if (Count == 0) { 670 DEBUG ((EFI_D_ERROR, "ERROR: Count == 0\n")); 671 return EFI_NOT_FOUND; 672 } 673 674 // 675 // checked in ValidateCapsuleIntegrity() 676 // 677 ASSERT (ThisCapsuleImageSize == 0); 678 679 if (NumDescriptors != NULL) { 680 *NumDescriptors = Count; 681 } 682 683 if (CapsuleSize != NULL) { 684 *CapsuleSize = Size; 685 } 686 687 if (CapsuleNumber != NULL) { 688 *CapsuleNumber = Number; 689 } 690 691 return EFI_SUCCESS; 692} 693 694/** 695 Check every capsule header. 696 697 @param CapsuleHeader The pointer to EFI_CAPSULE_HEADER 698 699 @retval FALSE Capsule is OK 700 @retval TRUE Capsule is corrupted 701 702**/ 703BOOLEAN 704IsCapsuleCorrupted ( 705 IN EFI_CAPSULE_HEADER *CapsuleHeader 706 ) 707{ 708 // 709 //A capsule to be updated across a system reset should contain CAPSULE_FLAGS_PERSIST_ACROSS_RESET. 710 // 711 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) == 0) { 712 return TRUE; 713 } 714 // 715 //Make sure the flags combination is supported by the platform. 716 // 717 if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) { 718 return TRUE; 719 } 720 if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) { 721 return TRUE; 722 } 723 724 return FALSE; 725} 726 727/** 728 Try to verify the integrity of a capsule test pattern before the 729 capsule gets coalesced. This can be useful in narrowing down 730 where capsule data corruption occurs. 731 732 The test pattern mode fills in memory with a counting UINT32 value. 733 If the capsule is not divided up in a multiple of 4-byte blocks, then 734 things get messy doing the check. Therefore there are some cases 735 here where we just give up and skip the pre-coalesce check. 736 737 @param PeiServices PEI services table 738 @param Desc Pointer to capsule descriptors 739**/ 740VOID 741CapsuleTestPatternPreCoalesce ( 742 IN EFI_PEI_SERVICES **PeiServices, 743 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc 744 ) 745{ 746 UINT32 *TestPtr; 747 UINT32 TestCounter; 748 UINT32 TestSize; 749 750 DEBUG ((EFI_D_INFO, "CapsuleTestPatternPreCoalesce\n")); 751 752 // 753 // Find first data descriptor 754 // 755 while ((Desc->Length == 0) && (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) { 756 Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer; 757 } 758 759 if (Desc->Union.ContinuationPointer == 0) { 760 return ; 761 } 762 // 763 // First one better be long enough to at least hold the test signature 764 // 765 if (Desc->Length < sizeof (UINT32)) { 766 DEBUG ((EFI_D_INFO, "Capsule test pattern pre-coalesce punted #1\n")); 767 return ; 768 } 769 770 TestPtr = (UINT32 *) (UINTN) Desc->Union.DataBlock; 771 // 772 // 0x54534554 "TEST" 773 // 774 if (*TestPtr != 0x54534554) { 775 return ; 776 } 777 778 TestCounter = 0; 779 TestSize = (UINT32) Desc->Length - 2 * sizeof (UINT32); 780 // 781 // Skip over the signature and the size fields in the pattern data header 782 // 783 TestPtr += 2; 784 while (1) { 785 if ((TestSize & 0x03) != 0) { 786 DEBUG ((EFI_D_INFO, "Capsule test pattern pre-coalesce punted #2\n")); 787 return ; 788 } 789 790 while (TestSize > 0) { 791 if (*TestPtr != TestCounter) { 792 DEBUG ((EFI_D_INFO, "Capsule test pattern pre-coalesce failed data corruption check\n")); 793 return ; 794 } 795 796 TestSize -= sizeof (UINT32); 797 TestCounter++; 798 TestPtr++; 799 } 800 Desc++; 801 while ((Desc->Length == 0) && (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) { 802 Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer; 803 } 804 805 if (Desc->Union.ContinuationPointer == (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) { 806 return ; 807 } 808 TestSize = (UINT32) Desc->Length; 809 TestPtr = (UINT32 *) (UINTN) Desc->Union.DataBlock; 810 } 811} 812 813/** 814 Checks for the presence of capsule descriptors. 815 Get capsule descriptors from variable CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2... 816 817 @param BlockListBuffer Pointer to the buffer of capsule descriptors variables 818 @param BlockDescriptorList Pointer to the capsule descriptors list 819 820 @retval EFI_SUCCESS a valid capsule is present 821 @retval EFI_NOT_FOUND if a valid capsule is not present 822**/ 823EFI_STATUS 824BuildCapsuleDescriptors ( 825 IN EFI_PHYSICAL_ADDRESS *BlockListBuffer, 826 OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptorList 827 ) 828{ 829 UINTN Index; 830 EFI_CAPSULE_BLOCK_DESCRIPTOR *LastBlock; 831 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlock; 832 EFI_CAPSULE_BLOCK_DESCRIPTOR *HeadBlock; 833 834 DEBUG ((EFI_D_INFO, "BuildCapsuleDescriptors enter\n")); 835 836 LastBlock = NULL; 837 HeadBlock = NULL; 838 TempBlock = NULL; 839 Index = 0; 840 841 while (BlockListBuffer[Index] != 0) { 842 // 843 // Test integrity of descriptors. 844 // 845 if (BlockListBuffer[Index] < MAX_ADDRESS) { 846 TempBlock = ValidateCapsuleIntegrity ((EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)BlockListBuffer[Index]); 847 if (TempBlock != NULL) { 848 if (LastBlock == NULL) { 849 LastBlock = TempBlock; 850 851 // 852 // Return the base of the block descriptors 853 // 854 HeadBlock = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)BlockListBuffer[Index]; 855 } else { 856 // 857 // Combine the different BlockList into single BlockList. 858 // 859 LastBlock->Union.DataBlock = (EFI_PHYSICAL_ADDRESS)(UINTN)BlockListBuffer[Index]; 860 LastBlock->Length = 0; 861 LastBlock = TempBlock; 862 } 863 } 864 } else { 865 DEBUG ((EFI_D_ERROR, "ERROR: BlockListBuffer[Index](0x%lx) < MAX_ADDRESS\n", BlockListBuffer[Index])); 866 } 867 Index ++; 868 } 869 870 if (HeadBlock != NULL) { 871 *BlockDescriptorList = HeadBlock; 872 return EFI_SUCCESS; 873 } 874 return EFI_NOT_FOUND; 875} 876 877/** 878 The function to coalesce a fragmented capsule in memory. 879 880 Memory Map for coalesced capsule: 881 MemBase + ---->+---------------------------+<-----------+ 882 MemSize | ------------------------- | | 883 | | Capsule [Num-1] | | | 884 | ------------------------- | | 885 | | ................ | | | 886 | ------------------------- | | 887 | | Capsule [1] | | | 888 | ------------------------- | | 889 | | Capsule [0] | | | 890 | ------------------------- | | 891 | Capsule Image | | 892CapsuleImageBase-->+---------------------------+ 893 | ------------------------- | | 894 | | CapsuleOffset[Num-1] | | | 895 | ------------------------- | | 896 | | ................ | | CapsuleSize 897 | ------------------------- | | 898 | | CapsuleOffset[1] | | | 899 | ------------------------- | | 900 | | CapsuleOffset[0] | | | 901 |---------------------------| | 902 | | CapsuleNumber | | | 903 | ------------------------- | | 904 | | CapsuleAllImageSize | | | 905 | ------------------------- | | 906 | PrivateData | | 907 DestPtr ---->+---------------------------+<-----------+ 908 | | | 909 | FreeMem | FreeMemSize 910 | | | 911 FreeMemBase --->+---------------------------+<-----------+ 912 | Terminator | 913 +---------------------------+ 914 | BlockDescriptor n | 915 +---------------------------+ 916 | ................. | 917 +---------------------------+ 918 | BlockDescriptor 1 | 919 +---------------------------+ 920 | BlockDescriptor 0 | 921 +---------------------------+ 922 | PrivateDataDesc 0 | 923 MemBase ---->+---------------------------+<----- BlockList 924 925 Caution: This function may receive untrusted input. 926 The capsule data is external input, so this routine will do basic validation before 927 coalesce capsule data into memory. 928 929 @param PeiServices General purpose services available to every PEIM. 930 @param BlockListBuffer Point to the buffer of Capsule Descriptor Variables. 931 @param MemoryBase Pointer to the base of a block of memory that we can walk 932 all over while trying to coalesce our buffers. 933 On output, this variable will hold the base address of 934 a coalesced capsule. 935 @param MemorySize Size of the memory region pointed to by MemoryBase. 936 On output, this variable will contain the size of the 937 coalesced capsule. 938 939 @retval EFI_NOT_FOUND If we could not find the capsule descriptors. 940 941 @retval EFI_BUFFER_TOO_SMALL 942 If we could not coalesce the capsule in the memory 943 region provided to us. 944 945 @retval EFI_SUCCESS Processed the capsule successfully. 946**/ 947EFI_STATUS 948EFIAPI 949CapsuleDataCoalesce ( 950 IN EFI_PEI_SERVICES **PeiServices, 951 IN EFI_PHYSICAL_ADDRESS *BlockListBuffer, 952 IN OUT VOID **MemoryBase, 953 IN OUT UINTN *MemorySize 954 ) 955{ 956 VOID *NewCapsuleBase; 957 VOID *CapsuleImageBase; 958 UINTN CapsuleIndex; 959 UINT8 *FreeMemBase; 960 UINT8 *DestPtr; 961 UINTN DestLength; 962 UINT8 *RelocPtr; 963 UINT64 *AddDataPtr; 964 UINTN CapsuleTimes; 965 UINT64 SizeLeft; 966 UINT64 CapsuleImageSize; 967 UINTN CapsuleSize; 968 UINTN CapsuleNumber; 969 UINTN DescriptorsSize; 970 UINTN FreeMemSize; 971 UINTN NumDescriptors; 972 BOOLEAN CapsuleBeginFlag; 973 EFI_STATUS Status; 974 EFI_CAPSULE_HEADER *CapsuleHeader; 975 EFI_CAPSULE_PEIM_PRIVATE_DATA PrivateData; 976 EFI_CAPSULE_PEIM_PRIVATE_DATA *PrivateDataPtr; 977 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList; 978 EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrentBlockDesc; 979 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockDesc; 980 EFI_CAPSULE_BLOCK_DESCRIPTOR PrivateDataDesc[2]; 981 982 DEBUG ((EFI_D_INFO, "CapsuleDataCoalesce enter\n")); 983 984 CapsuleIndex = 0; 985 SizeLeft = 0; 986 CapsuleTimes = 0; 987 CapsuleImageSize = 0; 988 PrivateDataPtr = NULL; 989 AddDataPtr = NULL; 990 CapsuleHeader = NULL; 991 CapsuleBeginFlag = TRUE; 992 CapsuleSize = 0; 993 NumDescriptors = 0; 994 995 // 996 // Build capsule descriptors list 997 // 998 Status = BuildCapsuleDescriptors (BlockListBuffer, &BlockList); 999 if (EFI_ERROR (Status)) { 1000 return Status; 1001 } 1002 1003 DEBUG_CODE ( 1004 CapsuleTestPatternPreCoalesce (PeiServices, BlockList); 1005 ); 1006 1007 // 1008 // Get the size of our descriptors and the capsule size. GetCapsuleInfo() 1009 // returns the number of descriptors that actually point to data, so add 1010 // one for a terminator. Do that below. 1011 // 1012 Status = GetCapsuleInfo (BlockList, &NumDescriptors, &CapsuleSize, &CapsuleNumber); 1013 if (EFI_ERROR (Status)) { 1014 return Status; 1015 } 1016 DEBUG ((EFI_D_INFO, "CapsuleSize - 0x%x\n", CapsuleSize)); 1017 DEBUG ((EFI_D_INFO, "CapsuleNumber - 0x%x\n", CapsuleNumber)); 1018 DEBUG ((EFI_D_INFO, "NumDescriptors - 0x%x\n", NumDescriptors)); 1019 if ((CapsuleSize == 0) || (NumDescriptors == 0) || (CapsuleNumber == 0)) { 1020 return EFI_NOT_FOUND; 1021 } 1022 1023 if (CapsuleNumber - 1 >= (MAX_ADDRESS - (sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + sizeof(UINT64))) / sizeof(UINT64)) { 1024 DEBUG ((EFI_D_ERROR, "ERROR: CapsuleNumber - 0x%x\n", CapsuleNumber)); 1025 return EFI_BUFFER_TOO_SMALL; 1026 } 1027 1028 // 1029 // Initialize our local copy of private data. When we're done, we'll create a 1030 // descriptor for it as well so that it can be put into free memory without 1031 // trashing anything. 1032 // 1033 PrivateData.Signature = EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE; 1034 PrivateData.CapsuleAllImageSize = (UINT64) CapsuleSize; 1035 PrivateData.CapsuleNumber = (UINT64) CapsuleNumber; 1036 PrivateData.CapsuleOffset[0] = 0; 1037 // 1038 // NOTE: Only data in sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) is valid, CapsuleOffset field is unitialized at this moment. 1039 // The code sets partial length here for Descriptor.Length check, but later it will use full length to reserve those PrivateData region. 1040 // 1041 PrivateDataDesc[0].Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) &PrivateData; 1042 PrivateDataDesc[0].Length = sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA); 1043 PrivateDataDesc[1].Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) BlockList; 1044 PrivateDataDesc[1].Length = 0; 1045 // 1046 // Add PrivateDataDesc[0] in beginning beginning, as it is new descriptor. PrivateDataDesc[1] is NOT needed. 1047 // In addition, one NULL terminator is added in the end. See RelocateBlockDescriptors(). 1048 // 1049 NumDescriptors += 2; 1050 // 1051 // Sandity check 1052 // 1053 if (CapsuleSize >= (MAX_ADDRESS - (sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64) + sizeof(UINT64)))) { 1054 DEBUG ((EFI_D_ERROR, "ERROR: CapsuleSize - 0x%x\n", CapsuleSize)); 1055 return EFI_BUFFER_TOO_SMALL; 1056 } 1057 // 1058 // Need add sizeof(UINT64) for PrivateData alignment 1059 // 1060 CapsuleSize += sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64) + sizeof(UINT64); 1061 BlockList = PrivateDataDesc; 1062 // 1063 // Sandity check 1064 // 1065 if (NumDescriptors >= (MAX_ADDRESS / sizeof(EFI_CAPSULE_BLOCK_DESCRIPTOR))) { 1066 DEBUG ((EFI_D_ERROR, "ERROR: NumDescriptors - 0x%x\n", NumDescriptors)); 1067 return EFI_BUFFER_TOO_SMALL; 1068 } 1069 DescriptorsSize = NumDescriptors * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR); 1070 // 1071 // Sandity check 1072 // 1073 if (DescriptorsSize >= (MAX_ADDRESS - CapsuleSize)) { 1074 DEBUG ((EFI_D_ERROR, "ERROR: DescriptorsSize - 0x%lx, CapsuleSize - 0x%lx\n", (UINT64)DescriptorsSize, (UINT64)CapsuleSize)); 1075 return EFI_BUFFER_TOO_SMALL; 1076 } 1077 1078 // 1079 // Don't go below some min address. If the base is below it, 1080 // then move it up and adjust the size accordingly. 1081 // 1082 DEBUG ((EFI_D_INFO, "Capsule Memory range from 0x%8X to 0x%8X\n", (UINTN) *MemoryBase, (UINTN)*MemoryBase + *MemorySize)); 1083 if ((UINTN)*MemoryBase < (UINTN) MIN_COALESCE_ADDR) { 1084 if (((UINTN)*MemoryBase + *MemorySize) < (UINTN) MIN_COALESCE_ADDR) { 1085 DEBUG ((EFI_D_ERROR, "ERROR: *MemoryBase + *MemorySize - 0x%x\n", (UINTN)*MemoryBase + *MemorySize)); 1086 return EFI_BUFFER_TOO_SMALL; 1087 } else { 1088 *MemorySize = *MemorySize - ((UINTN) MIN_COALESCE_ADDR - (UINTN) *MemoryBase); 1089 *MemoryBase = (VOID *) (UINTN) MIN_COALESCE_ADDR; 1090 } 1091 } 1092 1093 if (*MemorySize <= (CapsuleSize + DescriptorsSize)) { 1094 DEBUG ((EFI_D_ERROR, "ERROR: CapsuleSize + DescriptorsSize - 0x%x\n", CapsuleSize + DescriptorsSize)); 1095 return EFI_BUFFER_TOO_SMALL; 1096 } 1097 1098 FreeMemBase = *MemoryBase; 1099 FreeMemSize = *MemorySize; 1100 DEBUG ((EFI_D_INFO, "Capsule Free Memory from 0x%8X to 0x%8X\n", (UINTN) FreeMemBase, (UINTN) FreeMemBase + FreeMemSize)); 1101 1102 // 1103 // Relocate all the block descriptors to low memory to make further 1104 // processing easier. 1105 // 1106 BlockList = RelocateBlockDescriptors (PeiServices, BlockList, NumDescriptors, FreeMemBase, FreeMemSize); 1107 if (BlockList == NULL) { 1108 // 1109 // Not enough room to relocate the descriptors 1110 // 1111 return EFI_BUFFER_TOO_SMALL; 1112 } 1113 1114 // 1115 // Take the top of memory for the capsule. UINT64 align up. 1116 // 1117 DestPtr = FreeMemBase + FreeMemSize - CapsuleSize; 1118 DestPtr = (UINT8 *) (((UINTN)DestPtr + sizeof (UINT64) - 1) & ~(sizeof (UINT64) - 1)); 1119 FreeMemBase = (UINT8 *) BlockList + DescriptorsSize; 1120 FreeMemSize = (UINTN) DestPtr - (UINTN) FreeMemBase; 1121 NewCapsuleBase = (VOID *) DestPtr; 1122 CapsuleImageBase = (UINT8 *)NewCapsuleBase + sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64); 1123 1124 PrivateDataPtr = (EFI_CAPSULE_PEIM_PRIVATE_DATA *) NewCapsuleBase; 1125 1126 // 1127 // Move all the blocks to the top (high) of memory. 1128 // Relocate all the obstructing blocks. Note that the block descriptors 1129 // were coalesced when they were relocated, so we can just ++ the pointer. 1130 // 1131 CurrentBlockDesc = BlockList; 1132 while ((CurrentBlockDesc->Length != 0) || (CurrentBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) { 1133 if (CapsuleTimes == 0) { 1134 // 1135 // The first entry is the block descriptor for EFI_CAPSULE_PEIM_PRIVATE_DATA. 1136 // CapsuleOffset field is uninitialized at this time. No need copy it, but need to reserve for future use. 1137 // 1138 ASSERT (CurrentBlockDesc->Union.DataBlock == (UINT64)(UINTN)&PrivateData); 1139 DestLength = sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64); 1140 } else { 1141 DestLength = (UINTN)CurrentBlockDesc->Length; 1142 } 1143 // 1144 // See if any of the remaining capsule blocks are in the way 1145 // 1146 TempBlockDesc = CurrentBlockDesc; 1147 while (TempBlockDesc->Length != 0) { 1148 // 1149 // Is this block in the way of where we want to copy the current descriptor to? 1150 // 1151 if (IsOverlapped ( 1152 (UINT8 *) DestPtr, 1153 (UINTN) DestLength, 1154 (UINT8 *) (UINTN) TempBlockDesc->Union.DataBlock, 1155 (UINTN) TempBlockDesc->Length 1156 )) { 1157 // 1158 // Relocate the block 1159 // 1160 RelocPtr = FindFreeMem (BlockList, FreeMemBase, FreeMemSize, (UINTN) TempBlockDesc->Length); 1161 if (RelocPtr == NULL) { 1162 return EFI_BUFFER_TOO_SMALL; 1163 } 1164 1165 CopyMem ((VOID *) RelocPtr, (VOID *) (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) TempBlockDesc->Length); 1166 DEBUG ((EFI_D_INFO, "Capsule reloc data block from 0x%8X to 0x%8X with size 0x%8X\n", 1167 (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) RelocPtr, (UINTN) TempBlockDesc->Length)); 1168 1169 TempBlockDesc->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocPtr; 1170 } 1171 // 1172 // Next descriptor 1173 // 1174 TempBlockDesc++; 1175 } 1176 // 1177 // Ok, we made it through. Copy the block. 1178 // we just support greping one capsule from the lists of block descs list. 1179 // 1180 CapsuleTimes ++; 1181 // 1182 //Skip the first block descriptor that filled with EFI_CAPSULE_PEIM_PRIVATE_DATA 1183 // 1184 if (CapsuleTimes > 1) { 1185 // 1186 //For every capsule entry point, check its header to determine whether to relocate it. 1187 //If it is invalid, skip it and move on to the next capsule. If it is valid, relocate it. 1188 // 1189 if (CapsuleBeginFlag) { 1190 CapsuleBeginFlag = FALSE; 1191 CapsuleHeader = (EFI_CAPSULE_HEADER*)(UINTN)CurrentBlockDesc->Union.DataBlock; 1192 SizeLeft = CapsuleHeader->CapsuleImageSize; 1193 1194 // 1195 // No more check here is needed, because IsCapsuleCorrupted() already in ValidateCapsuleIntegrity() 1196 // 1197 ASSERT (CapsuleIndex < CapsuleNumber); 1198 1199 // 1200 // Relocate this capsule 1201 // 1202 CapsuleImageSize += SizeLeft; 1203 // 1204 // Cache the begin offset of this capsule 1205 // 1206 ASSERT (PrivateDataPtr->Signature == EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE); 1207 ASSERT ((UINTN)DestPtr >= (UINTN)CapsuleImageBase); 1208 PrivateDataPtr->CapsuleOffset[CapsuleIndex++] = (UINT64)((UINTN)DestPtr - (UINTN)CapsuleImageBase); 1209 } 1210 1211 // 1212 // Below ASSERT is checked in ValidateCapsuleIntegrity() 1213 // 1214 ASSERT (CurrentBlockDesc->Length <= SizeLeft); 1215 1216 CopyMem ((VOID *) DestPtr, (VOID *) (UINTN) (CurrentBlockDesc->Union.DataBlock), (UINTN)CurrentBlockDesc->Length); 1217 DEBUG ((EFI_D_INFO, "Capsule coalesce block no.0x%lX from 0x%lX to 0x%lX with size 0x%lX\n",(UINT64)CapsuleTimes, 1218 CurrentBlockDesc->Union.DataBlock, (UINT64)(UINTN)DestPtr, CurrentBlockDesc->Length)); 1219 DestPtr += CurrentBlockDesc->Length; 1220 SizeLeft -= CurrentBlockDesc->Length; 1221 1222 if (SizeLeft == 0) { 1223 // 1224 //Here is the end of the current capsule image. 1225 // 1226 CapsuleBeginFlag = TRUE; 1227 } 1228 } else { 1229 // 1230 // The first entry is the block descriptor for EFI_CAPSULE_PEIM_PRIVATE_DATA. 1231 // CapsuleOffset field is uninitialized at this time. No need copy it, but need to reserve for future use. 1232 // 1233 ASSERT (CurrentBlockDesc->Length == sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA)); 1234 ASSERT ((UINTN)DestPtr == (UINTN)NewCapsuleBase); 1235 CopyMem ((VOID *) DestPtr, (VOID *) (UINTN) CurrentBlockDesc->Union.DataBlock, (UINTN) CurrentBlockDesc->Length); 1236 DestPtr += sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64); 1237 } 1238 // 1239 //Walk through the block descriptor list. 1240 // 1241 CurrentBlockDesc++; 1242 } 1243 // 1244 // We return the base of memory we want reserved, and the size. 1245 // The memory peim should handle it appropriately from there. 1246 // 1247 *MemorySize = (UINTN) CapsuleSize; 1248 *MemoryBase = (VOID *) NewCapsuleBase; 1249 1250 ASSERT (PrivateDataPtr->Signature == EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE); 1251 ASSERT (PrivateDataPtr->CapsuleAllImageSize == CapsuleImageSize); 1252 ASSERT (PrivateDataPtr->CapsuleNumber == CapsuleIndex); 1253 1254 return EFI_SUCCESS; 1255} 1256