1 /** @file 2 Implements functions to pad firmware file. 3 4 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> 5 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions 8 of the BSD License which accompanies this distribution. The 9 full text of the license may be found at 10 http://opensource.org/licenses/bsd-license.php 11 12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 15 **/ 16 17 #include "FwVolDriver.h" 18 19 /** 20 Calculate the checksum for a PAD file. 21 22 @param PadFileHeader The Pad File to be caculeted the checksum. 23 24 **/ 25 VOID 26 SetPadFileChecksum ( 27 IN EFI_FFS_FILE_HEADER *PadFileHeader 28 ) 29 { 30 if ((PadFileHeader->Attributes & FFS_ATTRIB_CHECKSUM) != 0) { 31 32 if (IS_FFS_FILE2 (PadFileHeader)) { 33 // 34 // Calculate checksum of Pad File Data 35 // 36 PadFileHeader->IntegrityCheck.Checksum.File = 37 CalculateCheckSum8 ((UINT8 *) PadFileHeader + sizeof (EFI_FFS_FILE_HEADER2), FFS_FILE2_SIZE (PadFileHeader) - sizeof (EFI_FFS_FILE_HEADER2)); 38 39 } else { 40 // 41 // Calculate checksum of Pad File Data 42 // 43 PadFileHeader->IntegrityCheck.Checksum.File = 44 CalculateCheckSum8 ((UINT8 *) PadFileHeader + sizeof (EFI_FFS_FILE_HEADER), FFS_FILE_SIZE (PadFileHeader) - sizeof (EFI_FFS_FILE_HEADER)); 45 } 46 47 } else { 48 49 PadFileHeader->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; 50 51 } 52 53 return ; 54 } 55 56 /** 57 Create a PAD File in the Free Space. 58 59 @param FvDevice Firmware Volume Device. 60 @param FreeSpaceEntry Indicating in which Free Space(Cache) the Pad file will be inserted. 61 @param Size Pad file Size, not include the header. 62 @param PadFileEntry The Ffs File Entry that points to this Pad File. 63 64 @retval EFI_SUCCESS Successfully create a PAD file. 65 @retval EFI_OUT_OF_RESOURCES No enough free space to create a PAD file. 66 @retval EFI_INVALID_PARAMETER Size is not 8 byte alignment. 67 @retval EFI_DEVICE_ERROR Free space is not erased. 68 **/ 69 EFI_STATUS 70 FvCreatePadFileInFreeSpace ( 71 IN FV_DEVICE *FvDevice, 72 IN FREE_SPACE_ENTRY *FreeSpaceEntry, 73 IN UINTN Size, 74 OUT FFS_FILE_LIST_ENTRY **PadFileEntry 75 ) 76 { 77 EFI_STATUS Status; 78 EFI_FFS_FILE_HEADER *PadFileHeader; 79 UINTN Offset; 80 UINTN NumBytesWritten; 81 UINTN StateOffset; 82 UINT8 *StartPos; 83 FFS_FILE_LIST_ENTRY *FfsFileEntry; 84 UINTN HeaderSize; 85 UINTN FileSize; 86 87 HeaderSize = sizeof (EFI_FFS_FILE_HEADER); 88 FileSize = Size + HeaderSize; 89 if (FileSize > 0x00FFFFFF) { 90 HeaderSize = sizeof (EFI_FFS_FILE_HEADER2); 91 FileSize = Size + HeaderSize; 92 } 93 94 if (FreeSpaceEntry->Length < FileSize) { 95 return EFI_OUT_OF_RESOURCES; 96 } 97 98 if ((Size & 0x07) != 0) { 99 return EFI_INVALID_PARAMETER; 100 } 101 102 StartPos = FreeSpaceEntry->StartingAddress; 103 104 // 105 // First double check the space 106 // 107 if (!IsBufferErased ( 108 FvDevice->ErasePolarity, 109 StartPos, 110 FileSize 111 )) { 112 return EFI_DEVICE_ERROR; 113 } 114 115 PadFileHeader = (EFI_FFS_FILE_HEADER *) StartPos; 116 117 // 118 // Create File Step 1 119 // 120 SetFileState (EFI_FILE_HEADER_CONSTRUCTION, PadFileHeader); 121 122 Offset = (UINTN) (StartPos - FvDevice->CachedFv); 123 StateOffset = Offset + (UINT8 *) &PadFileHeader->State - (UINT8 *) PadFileHeader; 124 125 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE); 126 Status = FvcWrite ( 127 FvDevice, 128 StateOffset, 129 &NumBytesWritten, 130 &PadFileHeader->State 131 ); 132 if (EFI_ERROR (Status)) { 133 SetFileState (EFI_FILE_HEADER_CONSTRUCTION, PadFileHeader); 134 return Status; 135 } 136 // 137 // Update Free Space Entry, since header is allocated 138 // 139 FreeSpaceEntry->Length -= HeaderSize; 140 FreeSpaceEntry->StartingAddress += HeaderSize; 141 142 // 143 // Fill File Name Guid, here we assign a NULL-GUID to Pad files 144 // 145 ZeroMem (&PadFileHeader->Name, sizeof (EFI_GUID)); 146 147 // 148 // Fill File Type, checksum(0), Attributes(0), Size 149 // 150 PadFileHeader->Type = EFI_FV_FILETYPE_FFS_PAD; 151 PadFileHeader->Attributes = 0; 152 if ((FileSize) > 0x00FFFFFF) { 153 ((EFI_FFS_FILE_HEADER2 *) PadFileHeader)->ExtendedSize = (UINT32) FileSize; 154 *(UINT32 *) PadFileHeader->Size &= 0xFF000000; 155 PadFileHeader->Attributes |= FFS_ATTRIB_LARGE_FILE; 156 } else { 157 *(UINT32 *) PadFileHeader->Size &= 0xFF000000; 158 *(UINT32 *) PadFileHeader->Size |= FileSize; 159 } 160 161 SetHeaderChecksum (PadFileHeader); 162 SetPadFileChecksum (PadFileHeader); 163 164 Offset = (UINTN) (StartPos - FvDevice->CachedFv); 165 166 NumBytesWritten = HeaderSize; 167 Status = FvcWrite ( 168 FvDevice, 169 Offset, 170 &NumBytesWritten, 171 (UINT8 *) PadFileHeader 172 ); 173 if (EFI_ERROR (Status)) { 174 return Status; 175 } 176 177 // 178 // Step 2, then Mark header valid, since no data write, 179 // mark the data valid at the same time. 180 // 181 SetFileState (EFI_FILE_HEADER_VALID, PadFileHeader); 182 SetFileState (EFI_FILE_DATA_VALID, PadFileHeader); 183 184 Offset = (UINTN) (StartPos - FvDevice->CachedFv); 185 StateOffset = Offset + (UINT8 *) &PadFileHeader->State - (UINT8 *) PadFileHeader; 186 187 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE); 188 Status = FvcWrite ( 189 FvDevice, 190 StateOffset, 191 &NumBytesWritten, 192 &PadFileHeader->State 193 ); 194 if (EFI_ERROR (Status)) { 195 SetFileState (EFI_FILE_HEADER_VALID, PadFileHeader); 196 SetFileState (EFI_FILE_DATA_VALID, PadFileHeader); 197 return Status; 198 } 199 // 200 // Update Free Space Entry, since header is allocated 201 // 202 FreeSpaceEntry->Length -= Size; 203 FreeSpaceEntry->StartingAddress += Size; 204 205 // 206 // If successfully, insert an FfsFileEntry at the end of ffs file list 207 // 208 FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY)); 209 ASSERT (FfsFileEntry != NULL); 210 211 FfsFileEntry->FfsHeader = (UINT8 *) (UINTN) StartPos; 212 InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link); 213 214 *PadFileEntry = FfsFileEntry; 215 FvDevice->CurrentFfsFile = FfsFileEntry; 216 217 return EFI_SUCCESS; 218 } 219 220 /** 221 Fill pad file header within firmware cache. 222 223 @param PadFileHeader The start of the Pad File Buffer. 224 @param PadFileLength The length of the pad file including the header. 225 226 **/ 227 VOID 228 FvFillPadFile ( 229 IN EFI_FFS_FILE_HEADER *PadFileHeader, 230 IN UINTN PadFileLength 231 ) 232 { 233 // 234 // Fill File Name Guid, here we assign a NULL-GUID to Pad files 235 // 236 ZeroMem (&PadFileHeader->Name, sizeof (EFI_GUID)); 237 238 // 239 // Fill File Type, checksum(0), Attributes(0), Size 240 // 241 PadFileHeader->Type = EFI_FV_FILETYPE_FFS_PAD; 242 PadFileHeader->Attributes = 0; 243 if (PadFileLength > 0x00FFFFFF) { 244 ((EFI_FFS_FILE_HEADER2 *) PadFileHeader)->ExtendedSize = (UINT32) PadFileLength; 245 *(UINT32 *) PadFileHeader->Size &= 0xFF000000; 246 PadFileHeader->Attributes |= FFS_ATTRIB_LARGE_FILE; 247 } else { 248 *(UINT32 *) PadFileHeader->Size &= 0xFF000000; 249 *(UINT32 *) PadFileHeader->Size |= PadFileLength; 250 } 251 252 SetHeaderChecksum (PadFileHeader); 253 SetPadFileChecksum (PadFileHeader); 254 255 // 256 // Set File State to 0x00000111 257 // 258 SetFileState (EFI_FILE_HEADER_CONSTRUCTION, PadFileHeader); 259 SetFileState (EFI_FILE_HEADER_VALID, PadFileHeader); 260 SetFileState (EFI_FILE_DATA_VALID, PadFileHeader); 261 262 return ; 263 } 264 265 /** 266 Create entire FFS file. 267 268 @param FileHeader Starting Address of a Buffer that hold the FFS File image. 269 @param FfsFileBuffer The source buffer that contains the File Data. 270 @param BufferSize The length of FfsFileBuffer. 271 @param ActualFileSize Size of FFS file. 272 @param FileName The Guid of Ffs File. 273 @param FileType The type of the written Ffs File. 274 @param FileAttributes The attributes of the written Ffs File. 275 276 @retval EFI_INVALID_PARAMETER File type is not valid. 277 @retval EFI_SUCCESS FFS file is successfully created. 278 279 **/ 280 EFI_STATUS 281 FvFillFfsFile ( 282 OUT EFI_FFS_FILE_HEADER *FileHeader, 283 IN UINT8 *FfsFileBuffer, 284 IN UINTN BufferSize, 285 IN UINTN ActualFileSize, 286 IN EFI_GUID *FileName, 287 IN EFI_FV_FILETYPE FileType, 288 IN EFI_FV_FILE_ATTRIBUTES FileAttributes 289 ) 290 { 291 EFI_FFS_FILE_ATTRIBUTES TmpFileAttribute; 292 EFI_FFS_FILE_HEADER *TmpFileHeader; 293 294 // 295 // File Type value 0x0E~0xE0 are reserved 296 // 297 if ((FileType > EFI_FV_FILETYPE_SMM_CORE) && (FileType < 0xE0)) { 298 return EFI_INVALID_PARAMETER; 299 } 300 301 TmpFileHeader = (EFI_FFS_FILE_HEADER *) FfsFileBuffer; 302 // 303 // First fill all fields ready in FfsFileBuffer 304 // 305 CopyGuid (&TmpFileHeader->Name, FileName); 306 TmpFileHeader->Type = FileType; 307 308 // 309 // Convert the FileAttributes to FFSFileAttributes 310 // 311 FvFileAttrib2FfsFileAttrib (FileAttributes, &TmpFileAttribute); 312 313 TmpFileHeader->Attributes = TmpFileAttribute; 314 315 if (ActualFileSize > 0x00FFFFFF) { 316 ((EFI_FFS_FILE_HEADER2 *) FileHeader)->ExtendedSize = (UINT32) ActualFileSize; 317 *(UINT32 *) FileHeader->Size &= 0xFF000000; 318 FileHeader->Attributes |= FFS_ATTRIB_LARGE_FILE; 319 } else { 320 *(UINT32 *) FileHeader->Size &= 0xFF000000; 321 *(UINT32 *) FileHeader->Size |= ActualFileSize; 322 } 323 324 SetHeaderChecksum (TmpFileHeader); 325 SetFileChecksum (TmpFileHeader, ActualFileSize); 326 327 SetFileState (EFI_FILE_HEADER_CONSTRUCTION, TmpFileHeader); 328 SetFileState (EFI_FILE_HEADER_VALID, TmpFileHeader); 329 SetFileState (EFI_FILE_DATA_VALID, TmpFileHeader); 330 331 // 332 // Copy data from FfsFileBuffer to FileHeader(cache) 333 // 334 CopyMem (FileHeader, FfsFileBuffer, BufferSize); 335 336 return EFI_SUCCESS; 337 } 338 339 /** 340 Fill some other extra space using 0xFF(Erase Value). 341 342 @param ErasePolarity Fv erase value. 343 @param FileHeader Point to the start of FFS File. 344 @param ExtraLength The pading length. 345 346 **/ 347 VOID 348 FvAdjustFfsFile ( 349 IN UINT8 ErasePolarity, 350 IN EFI_FFS_FILE_HEADER *FileHeader, 351 IN UINTN ExtraLength 352 ) 353 { 354 UINT8 *Ptr; 355 UINT8 PadingByte; 356 357 if (IS_FFS_FILE2 (FileHeader)) { 358 Ptr = (UINT8 *) FileHeader + FFS_FILE2_SIZE (FileHeader); 359 } else { 360 Ptr = (UINT8 *) FileHeader + FFS_FILE_SIZE (FileHeader); 361 } 362 363 if (ErasePolarity == 0) { 364 PadingByte = 0; 365 } else { 366 PadingByte = 0xFF; 367 } 368 // 369 // Fill the non-used space with Padding Byte 370 // 371 SetMem (Ptr, ExtraLength, PadingByte); 372 373 return ; 374 } 375 376 /** 377 Free File List entry pointed by FileListHead. 378 379 @param FileListHeader FileListEntry Header. 380 381 **/ 382 VOID 383 FreeFileList ( 384 IN LIST_ENTRY *FileListHead 385 ) 386 { 387 FFS_FILE_LIST_ENTRY *FfsFileEntry; 388 LIST_ENTRY *NextEntry; 389 390 FfsFileEntry = (FFS_FILE_LIST_ENTRY *) (FileListHead->ForwardLink); 391 392 // 393 // Loop the whole list entry to free resources 394 // 395 while (&FfsFileEntry->Link != FileListHead) { 396 NextEntry = (&FfsFileEntry->Link)->ForwardLink; 397 FreePool (FfsFileEntry); 398 FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry; 399 } 400 401 return ; 402 } 403 404 /** 405 Create a new file within a PAD file area. 406 407 @param FvDevice Firmware Volume Device. 408 @param FfsFileBuffer A buffer that holds an FFS file,(it contains a File Header which is in init state). 409 @param BufferSize The size of FfsFileBuffer. 410 @param ActualFileSize The actual file length, it may not be multiples of 8. 411 @param FileName The FFS File Name. 412 @param FileType The FFS File Type. 413 @param FileAttributes The Attributes of the FFS File to be created. 414 415 @retval EFI_SUCCESS Successfully create a new file within the found PAD file area. 416 @retval EFI_OUT_OF_RESOURCES No suitable PAD file is found. 417 @retval other errors New file is created failed. 418 419 **/ 420 EFI_STATUS 421 FvCreateNewFileInsidePadFile ( 422 IN FV_DEVICE *FvDevice, 423 IN UINT8 *FfsFileBuffer, 424 IN UINTN BufferSize, 425 IN UINTN ActualFileSize, 426 IN EFI_GUID *FileName, 427 IN EFI_FV_FILETYPE FileType, 428 IN EFI_FV_FILE_ATTRIBUTES FileAttributes 429 ) 430 { 431 UINTN RequiredAlignment; 432 FFS_FILE_LIST_ENTRY *PadFileEntry; 433 EFI_STATUS Status; 434 UINTN PadAreaLength; 435 UINTN PadSize; 436 EFI_FFS_FILE_HEADER *FileHeader; 437 EFI_FFS_FILE_HEADER *OldPadFileHeader; 438 EFI_FFS_FILE_HEADER *PadFileHeader; 439 EFI_FFS_FILE_HEADER *TailPadFileHeader; 440 UINTN StateOffset; 441 UINTN Offset; 442 UINTN NumBytesWritten; 443 UINT8 *StartPos; 444 LIST_ENTRY NewFileList; 445 FFS_FILE_LIST_ENTRY *NewFileListEntry; 446 FFS_FILE_LIST_ENTRY *FfsEntry; 447 FFS_FILE_LIST_ENTRY *NextFfsEntry; 448 449 // 450 // First get the required alignment from the File Attributes 451 // 452 RequiredAlignment = GetRequiredAlignment (FileAttributes); 453 454 // 455 // Find a suitable PAD File 456 // 457 Status = FvLocatePadFile ( 458 FvDevice, 459 BufferSize, 460 RequiredAlignment, 461 &PadSize, 462 &PadFileEntry 463 ); 464 465 if (EFI_ERROR (Status)) { 466 return EFI_OUT_OF_RESOURCES; 467 } 468 469 OldPadFileHeader = (EFI_FFS_FILE_HEADER *) PadFileEntry->FfsHeader; 470 471 // 472 // Step 1: Update Pad File Header 473 // 474 SetFileState (EFI_FILE_MARKED_FOR_UPDATE, OldPadFileHeader); 475 476 StartPos = PadFileEntry->FfsHeader; 477 478 Offset = (UINTN) (StartPos - FvDevice->CachedFv); 479 StateOffset = Offset + (UINT8 *) &OldPadFileHeader->State - (UINT8 *) OldPadFileHeader; 480 481 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE); 482 Status = FvcWrite ( 483 FvDevice, 484 StateOffset, 485 &NumBytesWritten, 486 &OldPadFileHeader->State 487 ); 488 if (EFI_ERROR (Status)) { 489 SetFileState (EFI_FILE_HEADER_CONSTRUCTION, OldPadFileHeader); 490 return Status; 491 } 492 493 // 494 // Step 2: Update Pad area 495 // 496 InitializeListHead (&NewFileList); 497 498 if (IS_FFS_FILE2 (OldPadFileHeader)) { 499 PadAreaLength = FFS_FILE2_SIZE (OldPadFileHeader) - sizeof (EFI_FFS_FILE_HEADER); 500 PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER2)); 501 } else { 502 PadAreaLength = FFS_FILE_SIZE (OldPadFileHeader) - sizeof (EFI_FFS_FILE_HEADER); 503 PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER)); 504 } 505 506 if (PadSize != 0) { 507 // 508 // Insert a PAD file before to achieve required alignment 509 // 510 FvFillPadFile (PadFileHeader, PadSize); 511 NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY)); 512 ASSERT (NewFileListEntry != NULL); 513 NewFileListEntry->FfsHeader = (UINT8 *) PadFileHeader; 514 InsertTailList (&NewFileList, &NewFileListEntry->Link); 515 } 516 517 FileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) PadFileHeader + PadSize); 518 519 Status = FvFillFfsFile ( 520 FileHeader, 521 FfsFileBuffer, 522 BufferSize, 523 ActualFileSize, 524 FileName, 525 FileType, 526 FileAttributes 527 ); 528 if (EFI_ERROR (Status)) { 529 FreeFileList (&NewFileList); 530 return Status; 531 } 532 533 NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY)); 534 ASSERT (NewFileListEntry != NULL); 535 536 NewFileListEntry->FfsHeader = (UINT8 *) FileHeader; 537 InsertTailList (&NewFileList, &NewFileListEntry->Link); 538 539 FvDevice->CurrentFfsFile = NewFileListEntry; 540 541 if (PadAreaLength > (BufferSize + PadSize)) { 542 if ((PadAreaLength - BufferSize - PadSize) >= sizeof (EFI_FFS_FILE_HEADER)) { 543 // 544 // we can insert another PAD file 545 // 546 TailPadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FileHeader + BufferSize); 547 FvFillPadFile (TailPadFileHeader, PadAreaLength - BufferSize - PadSize); 548 549 NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY)); 550 ASSERT (NewFileListEntry != NULL); 551 552 NewFileListEntry->FfsHeader = (UINT8 *) TailPadFileHeader; 553 InsertTailList (&NewFileList, &NewFileListEntry->Link); 554 } else { 555 // 556 // because left size cannot hold another PAD file header, 557 // adjust the writing file size (just in cache) 558 // 559 FvAdjustFfsFile ( 560 FvDevice->ErasePolarity, 561 FileHeader, 562 PadAreaLength - BufferSize - PadSize 563 ); 564 } 565 } 566 // 567 // Start writing to FV 568 // 569 if (IS_FFS_FILE2 (OldPadFileHeader)) { 570 StartPos = (UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER2); 571 } else { 572 StartPos = (UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER); 573 } 574 575 Offset = (UINTN) (StartPos - FvDevice->CachedFv); 576 577 NumBytesWritten = PadAreaLength; 578 Status = FvcWrite ( 579 FvDevice, 580 Offset, 581 &NumBytesWritten, 582 StartPos 583 ); 584 if (EFI_ERROR (Status)) { 585 FreeFileList (&NewFileList); 586 FvDevice->CurrentFfsFile = NULL; 587 return Status; 588 } 589 590 // 591 // Step 3: Mark Pad file header as EFI_FILE_HEADER_INVALID 592 // 593 SetFileState (EFI_FILE_HEADER_INVALID, OldPadFileHeader); 594 595 StartPos = PadFileEntry->FfsHeader; 596 597 Offset = (UINTN) (StartPos - FvDevice->CachedFv); 598 StateOffset = Offset + (UINT8 *) &OldPadFileHeader->State - (UINT8 *) OldPadFileHeader; 599 600 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE); 601 Status = FvcWrite ( 602 FvDevice, 603 StateOffset, 604 &NumBytesWritten, 605 &OldPadFileHeader->State 606 ); 607 if (EFI_ERROR (Status)) { 608 SetFileState (EFI_FILE_HEADER_INVALID, OldPadFileHeader); 609 FreeFileList (&NewFileList); 610 FvDevice->CurrentFfsFile = NULL; 611 return Status; 612 } 613 614 // 615 // If all successfully, update FFS_FILE_LIST 616 // 617 618 // 619 // Delete old pad file entry 620 // 621 FfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.BackLink; 622 NextFfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.ForwardLink; 623 624 FreePool (PadFileEntry); 625 626 FfsEntry->Link.ForwardLink = NewFileList.ForwardLink; 627 (NewFileList.ForwardLink)->BackLink = &FfsEntry->Link; 628 NextFfsEntry->Link.BackLink = NewFileList.BackLink; 629 (NewFileList.BackLink)->ForwardLink = &NextFfsEntry->Link; 630 631 return EFI_SUCCESS; 632 } 633 634 /** 635 Free all FfsBuffer. 636 637 @param NumOfFiles Number of FfsBuffer. 638 @param FfsBuffer An array of pointer to an FFS File Buffer 639 640 **/ 641 VOID 642 FreeFfsBuffer ( 643 IN UINTN NumOfFiles, 644 IN UINT8 **FfsBuffer 645 ) 646 { 647 UINTN Index; 648 for (Index = 0; Index < NumOfFiles; Index++) { 649 if (FfsBuffer[Index] != NULL) { 650 FreePool (FfsBuffer[Index]); 651 } 652 } 653 } 654 655 /** 656 Create multiple files within a PAD File area. 657 658 @param FvDevice Firmware Volume Device. 659 @param PadFileEntry The pad file entry to be written in. 660 @param NumOfFiles Total File number to be written. 661 @param BufferSize The array of buffer size of each FfsBuffer. 662 @param ActualFileSize The array of actual file size. 663 @param PadSize The array of leading pad file size for each FFS File 664 @param FfsBuffer The array of Ffs Buffer pointer. 665 @param FileData The array of EFI_FV_WRITE_FILE_DATA structure, 666 used to get name, attributes, type, etc. 667 668 @retval EFI_SUCCESS Add the input multiple files into PAD file area. 669 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. 670 @retval other error Files can't be added into PAD file area. 671 672 **/ 673 EFI_STATUS 674 FvCreateMultipleFilesInsidePadFile ( 675 IN FV_DEVICE *FvDevice, 676 IN FFS_FILE_LIST_ENTRY *PadFileEntry, 677 IN UINTN NumOfFiles, 678 IN UINTN *BufferSize, 679 IN UINTN *ActualFileSize, 680 IN UINTN *PadSize, 681 IN UINT8 **FfsBuffer, 682 IN EFI_FV_WRITE_FILE_DATA *FileData 683 ) 684 { 685 EFI_STATUS Status; 686 EFI_FFS_FILE_HEADER *OldPadFileHeader; 687 UINTN Index; 688 EFI_FFS_FILE_HEADER *PadFileHeader; 689 EFI_FFS_FILE_HEADER *FileHeader; 690 EFI_FFS_FILE_HEADER *TailPadFileHeader; 691 UINTN TotalSize; 692 UINTN PadAreaLength; 693 LIST_ENTRY NewFileList; 694 FFS_FILE_LIST_ENTRY *NewFileListEntry; 695 UINTN Offset; 696 UINTN NumBytesWritten; 697 UINT8 *StartPos; 698 FFS_FILE_LIST_ENTRY *FfsEntry; 699 FFS_FILE_LIST_ENTRY *NextFfsEntry; 700 701 InitializeListHead (&NewFileList); 702 703 NewFileListEntry = NULL; 704 705 OldPadFileHeader = (EFI_FFS_FILE_HEADER *) PadFileEntry->FfsHeader; 706 if (IS_FFS_FILE2 (OldPadFileHeader)) { 707 PadAreaLength = FFS_FILE2_SIZE (OldPadFileHeader) - sizeof (EFI_FFS_FILE_HEADER2); 708 } else { 709 PadAreaLength = FFS_FILE_SIZE (OldPadFileHeader) - sizeof (EFI_FFS_FILE_HEADER); 710 } 711 712 Status = UpdateHeaderBit ( 713 FvDevice, 714 OldPadFileHeader, 715 EFI_FILE_MARKED_FOR_UPDATE 716 ); 717 if (EFI_ERROR (Status)) { 718 return Status; 719 } 720 // 721 // Update PAD area 722 // 723 TotalSize = 0; 724 if (IS_FFS_FILE2 (OldPadFileHeader)) { 725 PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER2)); 726 } else { 727 PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER)); 728 } 729 FileHeader = PadFileHeader; 730 731 for (Index = 0; Index < NumOfFiles; Index++) { 732 if (PadSize[Index] != 0) { 733 FvFillPadFile (PadFileHeader, PadSize[Index]); 734 NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY)); 735 if (NewFileListEntry == NULL) { 736 FreeFileList (&NewFileList); 737 return EFI_OUT_OF_RESOURCES; 738 } 739 740 NewFileListEntry->FfsHeader = (UINT8 *) PadFileHeader; 741 InsertTailList (&NewFileList, &NewFileListEntry->Link); 742 } 743 744 FileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) PadFileHeader + PadSize[Index]); 745 Status = FvFillFfsFile ( 746 FileHeader, 747 FfsBuffer[Index], 748 BufferSize[Index], 749 ActualFileSize[Index], 750 FileData[Index].NameGuid, 751 FileData[Index].Type, 752 FileData[Index].FileAttributes 753 ); 754 if (EFI_ERROR (Status)) { 755 FreeFileList (&NewFileList); 756 return Status; 757 } 758 759 NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY)); 760 if (NewFileListEntry == NULL) { 761 FreeFileList (&NewFileList); 762 return EFI_OUT_OF_RESOURCES; 763 } 764 765 NewFileListEntry->FfsHeader = (UINT8 *) FileHeader; 766 InsertTailList (&NewFileList, &NewFileListEntry->Link); 767 768 PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FileHeader + BufferSize[Index]); 769 TotalSize += PadSize[Index]; 770 TotalSize += BufferSize[Index]; 771 } 772 773 FvDevice->CurrentFfsFile = NewFileListEntry; 774 // 775 // Maybe we need a tail pad file 776 // 777 if (PadAreaLength > TotalSize) { 778 if ((PadAreaLength - TotalSize) >= sizeof (EFI_FFS_FILE_HEADER)) { 779 // 780 // we can insert another PAD file 781 // 782 TailPadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FileHeader + BufferSize[NumOfFiles - 1]); 783 FvFillPadFile (TailPadFileHeader, PadAreaLength - TotalSize); 784 785 NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY)); 786 if (NewFileListEntry == NULL) { 787 FreeFileList (&NewFileList); 788 FvDevice->CurrentFfsFile = NULL; 789 return EFI_OUT_OF_RESOURCES; 790 } 791 792 NewFileListEntry->FfsHeader = (UINT8 *) TailPadFileHeader; 793 InsertTailList (&NewFileList, &NewFileListEntry->Link); 794 } else { 795 // 796 // because left size cannot hold another PAD file header, 797 // adjust the writing file size (just in cache) 798 // 799 FvAdjustFfsFile ( 800 FvDevice->ErasePolarity, 801 FileHeader, 802 PadAreaLength - TotalSize 803 ); 804 } 805 } 806 // 807 // Start writing to FV 808 // 809 if (IS_FFS_FILE2 (OldPadFileHeader)) { 810 StartPos = (UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER2); 811 } else { 812 StartPos = (UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER); 813 } 814 815 Offset = (UINTN) (StartPos - FvDevice->CachedFv); 816 817 NumBytesWritten = PadAreaLength; 818 Status = FvcWrite ( 819 FvDevice, 820 Offset, 821 &NumBytesWritten, 822 StartPos 823 ); 824 if (EFI_ERROR (Status)) { 825 FreeFileList (&NewFileList); 826 FvDevice->CurrentFfsFile = NULL; 827 return Status; 828 } 829 830 Status = UpdateHeaderBit ( 831 FvDevice, 832 OldPadFileHeader, 833 EFI_FILE_HEADER_INVALID 834 ); 835 if (EFI_ERROR (Status)) { 836 FreeFileList (&NewFileList); 837 FvDevice->CurrentFfsFile = NULL; 838 return Status; 839 } 840 841 // 842 // Update File List Link 843 // 844 845 // 846 // First delete old pad file entry 847 // 848 FfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.BackLink; 849 NextFfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.ForwardLink; 850 851 FreePool (PadFileEntry); 852 853 FfsEntry->Link.ForwardLink = NewFileList.ForwardLink; 854 (NewFileList.ForwardLink)->BackLink = &FfsEntry->Link; 855 NextFfsEntry->Link.BackLink = NewFileList.BackLink; 856 (NewFileList.BackLink)->ForwardLink = &NextFfsEntry->Link; 857 858 return EFI_SUCCESS; 859 } 860 861 /** 862 Create multiple files within the Free Space. 863 864 @param FvDevice Firmware Volume Device. 865 @param FreeSpaceEntry Indicating in which Free Space(Cache) the multiple files will be inserted. 866 @param NumOfFiles Total File number to be written. 867 @param BufferSize The array of buffer size of each FfsBuffer. 868 @param ActualFileSize The array of actual file size. 869 @param PadSize The array of leading pad file size for each FFS File 870 @param FfsBuffer The array of Ffs Buffer pointer. 871 @param FileData The array of EFI_FV_WRITE_FILE_DATA structure, 872 used to get name, attributes, type, etc. 873 874 @retval EFI_SUCCESS Add the input multiple files into PAD file area. 875 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. 876 @retval other error Files can't be added into PAD file area. 877 878 **/ 879 EFI_STATUS 880 FvCreateMultipleFilesInsideFreeSpace ( 881 IN FV_DEVICE *FvDevice, 882 IN FREE_SPACE_ENTRY *FreeSpaceEntry, 883 IN UINTN NumOfFiles, 884 IN UINTN *BufferSize, 885 IN UINTN *ActualFileSize, 886 IN UINTN *PadSize, 887 IN UINT8 **FfsBuffer, 888 IN EFI_FV_WRITE_FILE_DATA *FileData 889 ) 890 { 891 EFI_STATUS Status; 892 UINTN Index; 893 EFI_FFS_FILE_HEADER *PadFileHeader; 894 EFI_FFS_FILE_HEADER *FileHeader; 895 UINTN TotalSize; 896 LIST_ENTRY NewFileList; 897 FFS_FILE_LIST_ENTRY *NewFileListEntry; 898 UINTN Offset; 899 UINTN NumBytesWritten; 900 UINT8 *StartPos; 901 902 InitializeListHead (&NewFileList); 903 904 NewFileListEntry = NULL; 905 906 TotalSize = 0; 907 StartPos = FreeSpaceEntry->StartingAddress; 908 PadFileHeader = (EFI_FFS_FILE_HEADER *) StartPos; 909 FileHeader = PadFileHeader; 910 911 for (Index = 0; Index < NumOfFiles; Index++) { 912 if (PadSize[Index] != 0) { 913 FvFillPadFile (PadFileHeader, PadSize[Index]); 914 NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY)); 915 if (NewFileListEntry == NULL) { 916 FreeFileList (&NewFileList); 917 return EFI_OUT_OF_RESOURCES; 918 } 919 920 NewFileListEntry->FfsHeader = (UINT8 *) PadFileHeader; 921 InsertTailList (&NewFileList, &NewFileListEntry->Link); 922 } 923 924 FileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) PadFileHeader + PadSize[Index]); 925 Status = FvFillFfsFile ( 926 FileHeader, 927 FfsBuffer[Index], 928 BufferSize[Index], 929 ActualFileSize[Index], 930 FileData[Index].NameGuid, 931 FileData[Index].Type, 932 FileData[Index].FileAttributes 933 ); 934 if (EFI_ERROR (Status)) { 935 FreeFileList (&NewFileList); 936 return Status; 937 } 938 939 NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY)); 940 if (NewFileListEntry == NULL) { 941 FreeFileList (&NewFileList); 942 return EFI_OUT_OF_RESOURCES; 943 } 944 945 NewFileListEntry->FfsHeader = (UINT8 *) FileHeader; 946 InsertTailList (&NewFileList, &NewFileListEntry->Link); 947 948 PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FileHeader + BufferSize[Index]); 949 TotalSize += PadSize[Index]; 950 TotalSize += BufferSize[Index]; 951 } 952 953 if (FreeSpaceEntry->Length < TotalSize) { 954 FreeFileList (&NewFileList); 955 return EFI_OUT_OF_RESOURCES; 956 } 957 958 FvDevice->CurrentFfsFile = NewFileListEntry; 959 960 // 961 // Start writing to FV 962 // 963 Offset = (UINTN) (StartPos - FvDevice->CachedFv); 964 965 NumBytesWritten = TotalSize; 966 Status = FvcWrite ( 967 FvDevice, 968 Offset, 969 &NumBytesWritten, 970 StartPos 971 ); 972 if (EFI_ERROR (Status)) { 973 FreeFileList (&NewFileList); 974 FvDevice->CurrentFfsFile = NULL; 975 return Status; 976 } 977 978 FreeSpaceEntry->Length -= TotalSize; 979 FreeSpaceEntry->StartingAddress += TotalSize; 980 981 NewFileListEntry = (FFS_FILE_LIST_ENTRY *) (NewFileList.ForwardLink); 982 983 while (NewFileListEntry != (FFS_FILE_LIST_ENTRY *) &NewFileList) { 984 InsertTailList (&FvDevice->FfsFileListHeader, &NewFileListEntry->Link); 985 NewFileListEntry = (FFS_FILE_LIST_ENTRY *) (NewFileListEntry->Link.ForwardLink); 986 } 987 988 return EFI_SUCCESS; 989 } 990 991 /** 992 Write multiple files into FV in reliable method. 993 994 @param FvDevice Firmware Volume Device. 995 @param NumOfFiles Total File number to be written. 996 @param FileData The array of EFI_FV_WRITE_FILE_DATA structure, 997 used to get name, attributes, type, etc 998 @param FileOperation The array of operation for each file. 999 1000 @retval EFI_SUCCESS Files are added into FV. 1001 @retval EFI_OUT_OF_RESOURCES No enough free PAD files to add the input files. 1002 @retval EFI_INVALID_PARAMETER File number is less than or equal to 1. 1003 @retval EFI_UNSUPPORTED File number exceeds the supported max numbers of files. 1004 1005 **/ 1006 EFI_STATUS 1007 FvCreateMultipleFiles ( 1008 IN FV_DEVICE *FvDevice, 1009 IN UINTN NumOfFiles, 1010 IN EFI_FV_WRITE_FILE_DATA *FileData, 1011 IN BOOLEAN *FileOperation 1012 ) 1013 { 1014 EFI_STATUS Status; 1015 UINT8 *FfsBuffer[MAX_FILES]; 1016 UINTN Index1; 1017 UINTN Index2; 1018 UINTN BufferSize[MAX_FILES]; 1019 UINTN ActualFileSize[MAX_FILES]; 1020 UINTN RequiredAlignment[MAX_FILES]; 1021 UINTN PadSize[MAX_FILES]; 1022 FFS_FILE_LIST_ENTRY *PadFileEntry; 1023 UINTN TotalSizeNeeded; 1024 FREE_SPACE_ENTRY *FreeSpaceEntry; 1025 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; 1026 UINTN Key; 1027 EFI_GUID FileNameGuid; 1028 EFI_FV_FILETYPE OldFileType; 1029 EFI_FV_FILE_ATTRIBUTES OldFileAttributes; 1030 UINTN OldFileSize; 1031 FFS_FILE_LIST_ENTRY *OldFfsFileEntry[MAX_FILES]; 1032 EFI_FFS_FILE_HEADER *OldFileHeader[MAX_FILES]; 1033 BOOLEAN IsCreateFile; 1034 UINTN HeaderSize; 1035 1036 // 1037 // To use this function, we must ensure that the NumOfFiles is great 1038 // than 1 1039 // 1040 if (NumOfFiles <= 1) { 1041 return EFI_INVALID_PARAMETER; 1042 } 1043 1044 if (NumOfFiles > MAX_FILES) { 1045 return EFI_UNSUPPORTED; 1046 } 1047 1048 Fv = &FvDevice->Fv; 1049 1050 SetMem (FfsBuffer, NumOfFiles, 0); 1051 SetMem (RequiredAlignment, NumOfFiles, 8); 1052 SetMem (PadSize, NumOfFiles, 0); 1053 ZeroMem (OldFfsFileEntry, sizeof (OldFfsFileEntry)); 1054 ZeroMem (OldFileHeader, sizeof (OldFileHeader)); 1055 1056 // 1057 // Adjust file size 1058 // 1059 for (Index1 = 0; Index1 < NumOfFiles; Index1++) { 1060 HeaderSize = sizeof (EFI_FFS_FILE_HEADER); 1061 ActualFileSize[Index1] = FileData[Index1].BufferSize + HeaderSize; 1062 if (ActualFileSize[Index1] > 0x00FFFFFF) { 1063 HeaderSize = sizeof (EFI_FFS_FILE_HEADER2); 1064 ActualFileSize[Index1] = FileData[Index1].BufferSize + HeaderSize; 1065 } 1066 BufferSize[Index1] = ActualFileSize[Index1]; 1067 1068 if (BufferSize[Index1] == HeaderSize) { 1069 // 1070 // clear file attributes, zero-length file does not have any attributes 1071 // 1072 FileData[Index1].FileAttributes = 0; 1073 } 1074 1075 while ((BufferSize[Index1] & 0x07) != 0) { 1076 BufferSize[Index1]++; 1077 } 1078 1079 FfsBuffer[Index1] = AllocateZeroPool (BufferSize[Index1]); 1080 1081 // 1082 // Copy File Data into FileBuffer 1083 // 1084 CopyMem ( 1085 FfsBuffer[Index1] + HeaderSize, 1086 FileData[Index1].Buffer, 1087 FileData[Index1].BufferSize 1088 ); 1089 1090 if (FvDevice->ErasePolarity == 1) { 1091 for (Index2 = 0; Index2 < HeaderSize; Index2++) { 1092 FfsBuffer[Index1][Index2] = (UINT8)~FfsBuffer[Index1][Index2]; 1093 } 1094 } 1095 1096 if ((FileData[Index1].FileAttributes & EFI_FV_FILE_ATTRIB_ALIGNMENT) != 0) { 1097 RequiredAlignment[Index1] = GetRequiredAlignment (FileData[Index1].FileAttributes); 1098 } 1099 // 1100 // If update file, mark the original file header to 1101 // EFI_FILE_MARKED_FOR_UPDATE 1102 // 1103 IsCreateFile = FileOperation[Index1]; 1104 if (!IsCreateFile) { 1105 1106 Key = 0; 1107 do { 1108 OldFileType = 0; 1109 Status = Fv->GetNextFile ( 1110 Fv, 1111 &Key, 1112 &OldFileType, 1113 &FileNameGuid, 1114 &OldFileAttributes, 1115 &OldFileSize 1116 ); 1117 if (EFI_ERROR (Status)) { 1118 FreeFfsBuffer (NumOfFiles, FfsBuffer); 1119 return Status; 1120 } 1121 } while (!CompareGuid (&FileNameGuid, FileData[Index1].NameGuid)); 1122 1123 // 1124 // Get FfsFileEntry from the search key 1125 // 1126 OldFfsFileEntry[Index1] = (FFS_FILE_LIST_ENTRY *) Key; 1127 OldFileHeader[Index1] = (EFI_FFS_FILE_HEADER *) OldFfsFileEntry[Index1]->FfsHeader; 1128 Status = UpdateHeaderBit ( 1129 FvDevice, 1130 OldFileHeader[Index1], 1131 EFI_FILE_MARKED_FOR_UPDATE 1132 ); 1133 if (EFI_ERROR (Status)) { 1134 FreeFfsBuffer (NumOfFiles, FfsBuffer); 1135 return Status; 1136 } 1137 } 1138 } 1139 // 1140 // First to search a suitable pad file that can hold so 1141 // many files 1142 // 1143 Status = FvSearchSuitablePadFile ( 1144 FvDevice, 1145 NumOfFiles, 1146 BufferSize, 1147 RequiredAlignment, 1148 PadSize, 1149 &TotalSizeNeeded, 1150 &PadFileEntry 1151 ); 1152 1153 if (Status == EFI_NOT_FOUND) { 1154 // 1155 // Try to find a free space that can hold these files 1156 // 1157 Status = FvSearchSuitableFreeSpace ( 1158 FvDevice, 1159 NumOfFiles, 1160 BufferSize, 1161 RequiredAlignment, 1162 PadSize, 1163 &TotalSizeNeeded, 1164 &FreeSpaceEntry 1165 ); 1166 if (EFI_ERROR (Status)) { 1167 FreeFfsBuffer (NumOfFiles, FfsBuffer); 1168 return EFI_OUT_OF_RESOURCES; 1169 } 1170 Status = FvCreateMultipleFilesInsideFreeSpace ( 1171 FvDevice, 1172 FreeSpaceEntry, 1173 NumOfFiles, 1174 BufferSize, 1175 ActualFileSize, 1176 PadSize, 1177 FfsBuffer, 1178 FileData 1179 ); 1180 1181 } else { 1182 // 1183 // Create multiple files inside such a pad file 1184 // to achieve lock-step update 1185 // 1186 Status = FvCreateMultipleFilesInsidePadFile ( 1187 FvDevice, 1188 PadFileEntry, 1189 NumOfFiles, 1190 BufferSize, 1191 ActualFileSize, 1192 PadSize, 1193 FfsBuffer, 1194 FileData 1195 ); 1196 } 1197 1198 FreeFfsBuffer (NumOfFiles, FfsBuffer); 1199 1200 if (EFI_ERROR (Status)) { 1201 return Status; 1202 } 1203 // 1204 // Delete those updated files 1205 // 1206 for (Index1 = 0; Index1 < NumOfFiles; Index1++) { 1207 IsCreateFile = FileOperation[Index1]; 1208 if (!IsCreateFile && OldFfsFileEntry[Index1] != NULL) { 1209 (OldFfsFileEntry[Index1]->Link.BackLink)->ForwardLink = OldFfsFileEntry[Index1]->Link.ForwardLink; 1210 (OldFfsFileEntry[Index1]->Link.ForwardLink)->BackLink = OldFfsFileEntry[Index1]->Link.BackLink; 1211 FreePool (OldFfsFileEntry[Index1]); 1212 } 1213 } 1214 // 1215 // Set those files' state to EFI_FILE_DELETED 1216 // 1217 for (Index1 = 0; Index1 < NumOfFiles; Index1++) { 1218 IsCreateFile = FileOperation[Index1]; 1219 if (!IsCreateFile && OldFileHeader[Index1] != NULL) { 1220 Status = UpdateHeaderBit (FvDevice, OldFileHeader[Index1], EFI_FILE_DELETED); 1221 if (EFI_ERROR (Status)) { 1222 return Status; 1223 } 1224 } 1225 } 1226 1227 return EFI_SUCCESS; 1228 } 1229