1 /** @file 2 FFS file access utilities. 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 #define PHYSICAL_ADDRESS_TO_POINTER(Address) ((VOID *) ((UINTN) Address)) 20 21 /** 22 Set File State in the FfsHeader. 23 24 @param State File state to be set into FFS header. 25 @param FfsHeader Points to the FFS file header 26 27 **/ 28 VOID 29 SetFileState ( 30 IN UINT8 State, 31 IN EFI_FFS_FILE_HEADER *FfsHeader 32 ) 33 { 34 // 35 // Set File State in the FfsHeader 36 // 37 FfsHeader->State = (EFI_FFS_FILE_STATE) (FfsHeader->State ^ State); 38 return ; 39 } 40 41 /** 42 Get the FFS file state by checking the highest bit set in the header's state field. 43 44 @param ErasePolarity Erase polarity attribute of the firmware volume 45 @param FfsHeader Points to the FFS file header 46 47 @return FFS File state 48 49 **/ 50 EFI_FFS_FILE_STATE 51 GetFileState ( 52 IN UINT8 ErasePolarity, 53 IN EFI_FFS_FILE_HEADER *FfsHeader 54 ) 55 { 56 EFI_FFS_FILE_STATE FileState; 57 UINT8 HighestBit; 58 59 FileState = FfsHeader->State; 60 61 if (ErasePolarity != 0) { 62 FileState = (EFI_FFS_FILE_STATE)~FileState; 63 } 64 65 HighestBit = 0x80; 66 while (HighestBit != 0 && ((HighestBit & FileState) == 0)) { 67 HighestBit >>= 1; 68 } 69 70 return (EFI_FFS_FILE_STATE) HighestBit; 71 } 72 73 /** 74 Convert the Buffer Address to LBA Entry Address. 75 76 @param FvDevice Cached FvDevice 77 @param BufferAddress Address of Buffer 78 @param LbaListEntry Pointer to the got LBA entry that contains the address. 79 80 @retval EFI_NOT_FOUND Buffer address is out of FvDevice. 81 @retval EFI_SUCCESS LBA entry is found for Buffer address. 82 83 **/ 84 EFI_STATUS 85 Buffer2LbaEntry ( 86 IN FV_DEVICE *FvDevice, 87 IN EFI_PHYSICAL_ADDRESS BufferAddress, 88 OUT LBA_ENTRY **LbaListEntry 89 ) 90 { 91 LBA_ENTRY *LbaEntry; 92 LIST_ENTRY *Link; 93 94 Link = FvDevice->LbaHeader.ForwardLink; 95 LbaEntry = (LBA_ENTRY *) Link; 96 97 // 98 // Locate LBA which contains the address 99 // 100 while (&LbaEntry->Link != &FvDevice->LbaHeader) { 101 if ((EFI_PHYSICAL_ADDRESS) (UINTN) (LbaEntry->StartingAddress) > BufferAddress) { 102 break; 103 } 104 105 Link = LbaEntry->Link.ForwardLink; 106 LbaEntry = (LBA_ENTRY *) Link; 107 } 108 109 if (&LbaEntry->Link == &FvDevice->LbaHeader) { 110 return EFI_NOT_FOUND; 111 } 112 113 Link = LbaEntry->Link.BackLink; 114 LbaEntry = (LBA_ENTRY *) Link; 115 116 if (&LbaEntry->Link == &FvDevice->LbaHeader) { 117 return EFI_NOT_FOUND; 118 } 119 120 *LbaListEntry = LbaEntry; 121 122 return EFI_SUCCESS; 123 } 124 125 /** 126 Convert the Buffer Address to LBA Address & Offset. 127 128 @param FvDevice Cached FvDevice 129 @param BufferAddress Address of Buffer 130 @param Lba Pointer to the gob Lba value 131 @param Offset Pointer to the got Offset 132 133 @retval EFI_NOT_FOUND Buffer address is out of FvDevice. 134 @retval EFI_SUCCESS LBA and Offset is found for Buffer address. 135 136 **/ 137 EFI_STATUS 138 Buffer2Lba ( 139 IN FV_DEVICE *FvDevice, 140 IN EFI_PHYSICAL_ADDRESS BufferAddress, 141 OUT EFI_LBA *Lba, 142 OUT UINTN *Offset 143 ) 144 { 145 LBA_ENTRY *LbaEntry; 146 EFI_STATUS Status; 147 148 LbaEntry = NULL; 149 150 Status = Buffer2LbaEntry ( 151 FvDevice, 152 BufferAddress, 153 &LbaEntry 154 ); 155 if (EFI_ERROR (Status)) { 156 return Status; 157 } 158 159 *Lba = LbaEntry->LbaIndex; 160 *Offset = (UINTN) BufferAddress - (UINTN) LbaEntry->StartingAddress; 161 162 return EFI_SUCCESS; 163 } 164 165 /** 166 Check if a block of buffer is erased. 167 168 @param ErasePolarity Erase polarity attribute of the firmware volume 169 @param Buffer The buffer to be checked 170 @param BufferSize Size of the buffer in bytes 171 172 @retval TRUE The block of buffer is erased 173 @retval FALSE The block of buffer is not erased 174 175 **/ 176 BOOLEAN 177 IsBufferErased ( 178 IN UINT8 ErasePolarity, 179 IN UINT8 *Buffer, 180 IN UINTN BufferSize 181 ) 182 { 183 UINTN Count; 184 UINT8 EraseByte; 185 186 if (ErasePolarity == 1) { 187 EraseByte = 0xFF; 188 } else { 189 EraseByte = 0; 190 } 191 192 for (Count = 0; Count < BufferSize; Count++) { 193 if (Buffer[Count] != EraseByte) { 194 return FALSE; 195 } 196 } 197 198 return TRUE; 199 } 200 201 /** 202 Verify checksum of the firmware volume header. 203 204 @param FvHeader Points to the firmware volume header to be checked 205 206 @retval TRUE Checksum verification passed 207 @retval FALSE Checksum verification failed 208 209 **/ 210 BOOLEAN 211 VerifyFvHeaderChecksum ( 212 IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader 213 ) 214 { 215 UINT16 Checksum; 216 217 Checksum = CalculateSum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength); 218 219 if (Checksum == 0) { 220 return TRUE; 221 } else { 222 return FALSE; 223 } 224 } 225 226 /** 227 Verify checksum of the FFS file header. 228 229 @param FfsHeader Points to the FFS file header to be checked 230 231 @retval TRUE Checksum verification passed 232 @retval FALSE Checksum verification failed 233 234 **/ 235 BOOLEAN 236 VerifyHeaderChecksum ( 237 IN EFI_FFS_FILE_HEADER *FfsHeader 238 ) 239 { 240 UINT8 HeaderChecksum; 241 242 if (IS_FFS_FILE2 (FfsHeader)) { 243 HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER2)); 244 } else { 245 HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER)); 246 } 247 HeaderChecksum = (UINT8) (HeaderChecksum - FfsHeader->State - FfsHeader->IntegrityCheck.Checksum.File); 248 249 if (HeaderChecksum == 0) { 250 return TRUE; 251 } else { 252 return FALSE; 253 } 254 } 255 256 /** 257 Verify checksum of the FFS file data. 258 259 @param FfsHeader Points to the FFS file header to be checked 260 261 @retval TRUE Checksum verification passed 262 @retval FALSE Checksum verification failed 263 264 **/ 265 BOOLEAN 266 VerifyFileChecksum ( 267 IN EFI_FFS_FILE_HEADER *FfsHeader 268 ) 269 { 270 UINT8 FileChecksum; 271 EFI_FV_FILE_ATTRIBUTES Attributes; 272 273 Attributes = FfsHeader->Attributes; 274 275 if ((Attributes & FFS_ATTRIB_CHECKSUM) != 0) { 276 277 // 278 // Check checksum of FFS data 279 // 280 if (IS_FFS_FILE2 (FfsHeader)) { 281 FileChecksum = CalculateSum8 ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2), FFS_FILE2_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER2)); 282 } else { 283 FileChecksum = CalculateSum8 ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER), FFS_FILE_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER)); 284 } 285 FileChecksum = (UINT8) (FileChecksum + FfsHeader->IntegrityCheck.Checksum.File); 286 287 if (FileChecksum == 0) { 288 return TRUE; 289 } else { 290 return FALSE; 291 } 292 293 } else { 294 295 if (FfsHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) { 296 return FALSE; 297 } else { 298 return TRUE; 299 } 300 } 301 302 } 303 304 /** 305 Check if it's a valid FFS file header. 306 307 @param ErasePolarity Erase polarity attribute of the firmware volume 308 @param FfsHeader Points to the FFS file header to be checked 309 310 @retval TRUE Valid FFS file header 311 @retval FALSE Invalid FFS file header 312 313 **/ 314 BOOLEAN 315 IsValidFFSHeader ( 316 IN UINT8 ErasePolarity, 317 IN EFI_FFS_FILE_HEADER *FfsHeader 318 ) 319 { 320 EFI_FFS_FILE_STATE FileState; 321 322 // 323 // Check if it is a free space 324 // 325 if (IsBufferErased ( 326 ErasePolarity, 327 (UINT8 *) FfsHeader, 328 sizeof (EFI_FFS_FILE_HEADER) 329 )) { 330 return FALSE; 331 } 332 333 FileState = GetFileState (ErasePolarity, FfsHeader); 334 335 switch (FileState) { 336 case EFI_FILE_HEADER_CONSTRUCTION: 337 // 338 // fall through 339 // 340 case EFI_FILE_HEADER_INVALID: 341 return FALSE; 342 343 case EFI_FILE_HEADER_VALID: 344 // 345 // fall through 346 // 347 case EFI_FILE_DATA_VALID: 348 // 349 // fall through 350 // 351 case EFI_FILE_MARKED_FOR_UPDATE: 352 // 353 // fall through 354 // 355 case EFI_FILE_DELETED: 356 // 357 // Here we need to verify header checksum 358 // 359 if (!VerifyHeaderChecksum (FfsHeader)) { 360 return FALSE; 361 } 362 break; 363 364 default: 365 // 366 // return 367 // 368 return FALSE; 369 } 370 371 return TRUE; 372 } 373 374 /** 375 Get next possible of Firmware File System Header. 376 377 @param ErasePolarity Erase polarity attribute of the firmware volume 378 @param FfsHeader Points to the FFS file header to be skipped. 379 380 @return Pointer to next FFS header. 381 382 **/ 383 EFI_PHYSICAL_ADDRESS 384 GetNextPossibleFileHeader ( 385 IN UINT8 ErasePolarity, 386 IN EFI_FFS_FILE_HEADER *FfsHeader 387 ) 388 { 389 UINT32 FileLength; 390 UINT32 SkipLength; 391 392 if (!IsValidFFSHeader (ErasePolarity, FfsHeader)) { 393 // 394 // Skip this header 395 // 396 if (IS_FFS_FILE2 (FfsHeader)) { 397 return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2); 398 } else { 399 return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + sizeof (EFI_FFS_FILE_HEADER); 400 } 401 } 402 403 if (IS_FFS_FILE2 (FfsHeader)) { 404 FileLength = FFS_FILE2_SIZE (FfsHeader); 405 } else { 406 FileLength = FFS_FILE_SIZE (FfsHeader); 407 } 408 409 // 410 // Since FileLength is not multiple of 8, we need skip some bytes 411 // to get next possible header 412 // 413 SkipLength = FileLength; 414 while ((SkipLength & 0x07) != 0) { 415 SkipLength++; 416 } 417 418 return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + SkipLength; 419 } 420 421 /** 422 Search FFS file with the same FFS name in FV Cache. 423 424 @param FvDevice Cached FV image. 425 @param FfsHeader Points to the FFS file header to be skipped. 426 @param StateBit FFS file state bit to be checked. 427 428 @return Pointer to next found FFS header. NULL will return if no found. 429 430 **/ 431 EFI_FFS_FILE_HEADER * 432 DuplicateFileExist ( 433 IN FV_DEVICE *FvDevice, 434 IN EFI_FFS_FILE_HEADER *FfsHeader, 435 IN EFI_FFS_FILE_STATE StateBit 436 ) 437 { 438 UINT8 *Ptr; 439 EFI_FFS_FILE_HEADER *NextFfsFile; 440 441 // 442 // Search duplicate file, not from the beginning of FV, 443 // just search the next ocurrence of this file 444 // 445 NextFfsFile = FfsHeader; 446 447 do { 448 Ptr = (UINT8 *) PHYSICAL_ADDRESS_TO_POINTER ( 449 GetNextPossibleFileHeader (FvDevice->ErasePolarity, 450 NextFfsFile) 451 ); 452 NextFfsFile = (EFI_FFS_FILE_HEADER *) Ptr; 453 454 if ((UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (FvDevice->CachedFv) + FvDevice->FwVolHeader->FvLength - Ptr < 455 sizeof (EFI_FFS_FILE_HEADER) 456 ) { 457 break; 458 } 459 460 if (!IsValidFFSHeader (FvDevice->ErasePolarity, NextFfsFile)) { 461 continue; 462 } 463 464 if (!VerifyFileChecksum (NextFfsFile)) { 465 continue; 466 } 467 468 if (CompareGuid (&NextFfsFile->Name, &FfsHeader->Name)) { 469 if (GetFileState (FvDevice->ErasePolarity, NextFfsFile) == StateBit) { 470 return NextFfsFile; 471 } 472 } 473 } while (Ptr < (UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (FvDevice->CachedFv) + FvDevice->FwVolHeader->FvLength); 474 475 return NULL; 476 } 477 478 /** 479 Change FFS file header state and write to FV. 480 481 @param FvDevice Cached FV image. 482 @param FfsHeader Points to the FFS file header to be updated. 483 @param State FFS file state to be set. 484 485 @retval EFI_SUCCESS File state is writen into FV. 486 @retval others File state can't be writen into FV. 487 488 **/ 489 EFI_STATUS 490 UpdateHeaderBit ( 491 IN FV_DEVICE *FvDevice, 492 IN EFI_FFS_FILE_HEADER *FfsHeader, 493 IN EFI_FFS_FILE_STATE State 494 ) 495 { 496 EFI_STATUS Status; 497 EFI_LBA Lba; 498 UINTN Offset; 499 UINTN NumBytesWritten; 500 501 Lba = 0; 502 Offset = 0; 503 504 SetFileState (State, FfsHeader); 505 506 Buffer2Lba ( 507 FvDevice, 508 (EFI_PHYSICAL_ADDRESS) (UINTN) (&FfsHeader->State), 509 &Lba, 510 &Offset 511 ); 512 // 513 // Write the state byte into FV 514 // 515 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE); 516 Status = FvDevice->Fvb->Write ( 517 FvDevice->Fvb, 518 Lba, 519 Offset, 520 &NumBytesWritten, 521 &FfsHeader->State 522 ); 523 return Status; 524 } 525 526 /** 527 Check if it's a valid FFS file. 528 Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first. 529 530 @param FvDevice Cached FV image. 531 @param FfsHeader Points to the FFS file to be checked 532 533 @retval TRUE Valid FFS file 534 @retval FALSE Invalid FFS file 535 536 **/ 537 BOOLEAN 538 IsValidFFSFile ( 539 IN FV_DEVICE *FvDevice, 540 IN EFI_FFS_FILE_HEADER *FfsHeader 541 ) 542 { 543 EFI_FFS_FILE_STATE FileState; 544 UINT8 ErasePolarity; 545 546 ErasePolarity = FvDevice->ErasePolarity; 547 548 FileState = GetFileState (ErasePolarity, FfsHeader); 549 550 switch (FileState) { 551 case EFI_FILE_DATA_VALID: 552 if (!VerifyFileChecksum (FfsHeader)) { 553 return FALSE; 554 } 555 556 if (FfsHeader->Type == EFI_FV_FILETYPE_FFS_PAD) { 557 break; 558 } 559 // 560 // Check if there is another duplicated file with the EFI_FILE_DATA_VALID 561 // 562 if (DuplicateFileExist (FvDevice, FfsHeader, EFI_FILE_DATA_VALID) != NULL) { 563 return FALSE; 564 } 565 566 break; 567 568 case EFI_FILE_MARKED_FOR_UPDATE: 569 if (!VerifyFileChecksum (FfsHeader)) { 570 return FALSE; 571 } 572 573 if (FfsHeader->Type == EFI_FV_FILETYPE_FFS_PAD) { 574 // 575 // since its data area is not unperturbed, it cannot be reclaimed, 576 // marked it as deleted 577 // 578 UpdateHeaderBit (FvDevice, FfsHeader, EFI_FILE_DELETED); 579 return TRUE; 580 581 } else if (DuplicateFileExist (FvDevice, FfsHeader, EFI_FILE_DATA_VALID) != NULL) { 582 // 583 // Here the found file is more recent than this file, 584 // mark it as deleted 585 // 586 UpdateHeaderBit (FvDevice, FfsHeader, EFI_FILE_DELETED); 587 return TRUE; 588 589 } else { 590 return TRUE; 591 } 592 593 break; 594 595 case EFI_FILE_DELETED: 596 if (!VerifyFileChecksum (FfsHeader)) { 597 return FALSE; 598 } 599 600 break; 601 602 default: 603 return FALSE; 604 } 605 606 return TRUE; 607 } 608 609