1 /** @file 2 Firmware Volume Block Driver for Lakeport Platform. 3 4 Firmware volume block driver for FWH or SPI device. 5 It depends on which Flash Device Library to be linked with this driver. 6 7 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> 8 9 This program and the accompanying materials are licensed and made available under 11 the terms and conditions of the BSD License that accompanies this distribution. 13 The full text of the license may be found at 15 http://opensource.org/licenses/bsd-license.php. 17 19 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 21 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 23 25 27 **/ 28 29 #include "FvbService.h" 30 31 // 32 // Global variable for this FVB driver which contains 33 // the private data of all firmware volume block instances. 34 // 35 FWB_GLOBAL mFvbModuleGlobal; 36 37 // 38 // This platform driver knows there are 3 FVs on 39 // FD, which are FvRecovery, FvMain and FvNvStorage. 40 // 41 UINT32 mPlatformFvBaseAddress[] = { 42 FixedPcdGet32(PcdFlashNvStorageVariableBase), 43 }; 44 45 FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = { 46 { 47 { 48 HARDWARE_DEVICE_PATH, 49 HW_MEMMAP_DP, 50 { 51 (UINT8)(sizeof (MEMMAP_DEVICE_PATH)), 52 (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8) 53 } 54 }, 55 EfiMemoryMappedIO, 56 (EFI_PHYSICAL_ADDRESS) 0, 57 (EFI_PHYSICAL_ADDRESS) 0, 58 }, 59 { 60 END_DEVICE_PATH_TYPE, 61 END_ENTIRE_DEVICE_PATH_SUBTYPE, 62 { 63 END_DEVICE_PATH_LENGTH, 64 0 65 } 66 } 67 }; 68 69 FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = { 70 { 71 { 72 MEDIA_DEVICE_PATH, 73 MEDIA_PIWG_FW_VOL_DP, 74 { 75 (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)), 76 (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8) 77 } 78 }, 79 { 0 } 80 }, 81 { 82 END_DEVICE_PATH_TYPE, 83 END_ENTIRE_DEVICE_PATH_SUBTYPE, 84 { 85 END_DEVICE_PATH_LENGTH, 86 0 87 } 88 } 89 }; 90 91 // 92 // Template structure used when installing FVB protocol. 93 // 94 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = { 95 FVB_DEVICE_SIGNATURE, 96 NULL, 97 0, // Instance 98 { 99 FvbProtocolGetAttributes, 100 FvbProtocolSetAttributes, 101 FvbProtocolGetPhysicalAddress, 102 FvbProtocolGetBlockSize, 103 FvbProtocolRead, 104 FvbProtocolWrite, 105 FvbProtocolEraseBlocks, 106 NULL 107 } // FwVolBlockInstance 108 }; 109 110 111 /** 112 Get the pointer to EFI_FW_VOL_INSTANCE from the buffer pointed 113 by mFvbModuleGlobal.FvInstance based on a index. 114 Each EFI_FW_VOL_INSTANCE is with variable length as 115 we have a block map at the end of the EFI_FIRMWARE_VOLUME_HEADER. 116 117 @param[in] Instance The index of the EFI_FW_VOL_INSTANCE. 118 119 @return A pointer to EFI_FW_VOL_INSTANCE. 120 121 **/ 122 EFI_FW_VOL_INSTANCE * 123 GetFvbInstance ( 124 IN UINTN Instance 125 ) 126 { 127 EFI_FW_VOL_INSTANCE *FwhRecord; 128 129 if ( Instance >= mFvbModuleGlobal.NumFv ) { 130 ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); 131 return NULL; 132 } 133 134 // 135 // Find the right instance of the FVB private data. 136 // 137 FwhRecord = mFvbModuleGlobal.FvInstance; 138 while ( Instance > 0 ) { 139 FwhRecord = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhRecord) + 140 FwhRecord->VolumeHeader.HeaderLength + 141 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))); 142 Instance --; 143 } 144 145 return FwhRecord; 146 147 } 148 149 150 /** 151 Get the EFI_FVB_ATTRIBUTES_2 of a FV. 152 153 @param[in] The index of the EFI_FW_VOL_INSTANCE. 154 155 @return EFI_FVB_ATTRIBUTES_2 of the FV identified by Instance. 156 157 **/ 158 STATIC 159 EFI_FVB_ATTRIBUTES_2 160 FvbGetVolumeAttributes ( 161 IN UINTN Instance 162 ) 163 { 164 EFI_FW_VOL_INSTANCE * FwInstance = NULL; 165 FwInstance = GetFvbInstance(Instance); 166 ASSERT (FwInstance != NULL); 167 168 if ( FwInstance != NULL ) { 169 return FwInstance->VolumeHeader.Attributes; 170 } else { 171 return 0; 172 } 173 } 174 175 176 /** 177 Retrieves the starting address of an LBA in an FV. It also 178 return a few other attribut of the FV. 179 180 @param[in] Instance The index of the EFI_FW_VOL_INSTANCE. 181 @param[in] Lba The logical block address. 182 @param[out] LbaAddress On output, contains the physical starting address 183 of the Lba. 184 @param[out] LbaLength On output, contains the length of the block. 185 @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which the 186 number of consecutive blocks starting with Lba is 187 returned. All blocks in this range have a size of 188 BlockSize. 189 190 @retval EFI_SUCCESS Successfully returns. 191 @retval EFI_INVALID_PARAMETER Instance not found. 192 193 **/ 194 STATIC 195 EFI_STATUS 196 FvbGetLbaAddress ( 197 IN UINTN Instance, 198 IN EFI_LBA Lba, 199 OUT UINTN *LbaAddress, 200 OUT UINTN *LbaLength, 201 OUT UINTN *NumOfBlocks 202 ) 203 { 204 UINT32 NumBlocks = 0; 205 UINT32 BlockLength = 0; 206 UINTN Offset; 207 EFI_LBA StartLba; 208 EFI_LBA NextLba; 209 EFI_FW_VOL_INSTANCE *FwhInstance; 210 EFI_FV_BLOCK_MAP_ENTRY *BlockMap = NULL; 211 212 // 213 // Find the right instance of the FVB private data. 214 // 215 FwhInstance = GetFvbInstance (Instance); 216 217 StartLba = 0; 218 Offset = 0; 219 BlockMap = &(FwhInstance->VolumeHeader.BlockMap[0]); 220 ASSERT (BlockMap != NULL); 221 222 // 223 // Parse the blockmap of the FV to find which map entry the Lba belongs to. 224 // 225 while (TRUE) { 226 if ( BlockMap != NULL) { 227 NumBlocks = BlockMap->NumBlocks; 228 BlockLength = BlockMap->Length; 229 } 230 231 if ( NumBlocks == 0 || BlockLength == 0) { 232 return EFI_INVALID_PARAMETER; 233 } 234 235 NextLba = StartLba + NumBlocks; 236 237 // 238 // The map entry found. 239 // 240 if (Lba >= StartLba && Lba < NextLba) { 241 Offset = Offset + (UINTN)MultU64x32((Lba - StartLba), BlockLength); 242 if ( LbaAddress && FwhInstance ) { 243 *LbaAddress = FwhInstance->FvBase + Offset; 244 } 245 246 if (LbaLength ) { 247 *LbaLength = BlockLength; 248 } 249 250 if (NumOfBlocks ) { 251 *NumOfBlocks = (UINTN)(NextLba - Lba); 252 } 253 return EFI_SUCCESS; 254 } 255 256 StartLba = NextLba; 257 Offset = Offset + NumBlocks * BlockLength; 258 BlockMap++; 259 } 260 } 261 262 263 /** 264 Reads specified number of bytes into a buffer from the specified block. 265 266 @param[in] Instance The FV instance to be read from. 267 @param[in] Lba The logical block address to be read from. 268 @param[in] BlockOffset Offset into the block at which to begin reading. 269 @param[in] NumBytes Pointer that on input contains the total size of 270 the buffer. On output, it contains the total number 271 of bytes read. 272 @param[in] Buffer Pointer to a caller allocated buffer that will be 273 used to hold the data read. 274 275 276 @retval EFI_SUCCESS The firmware volume was read successfully and 277 contents are in Buffer. 278 @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On output, 279 NumBytes contains the total number of bytes returned 280 in Buffer. 281 @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state. 282 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and 283 could not be read. 284 @retval EFI_INVALID_PARAMETER Instance not found, or NumBytes, Buffer are NULL. 285 286 **/ 287 STATIC 288 EFI_STATUS 289 FvbReadBlock ( 290 IN UINTN Instance, 291 IN EFI_LBA Lba, 292 IN UINTN BlockOffset, 293 IN OUT UINTN *NumBytes, 294 IN UINT8 *Buffer 295 ) 296 { 297 EFI_FVB_ATTRIBUTES_2 Attributes; 298 UINTN LbaAddress; 299 UINTN LbaLength; 300 EFI_STATUS Status; 301 302 if ( (NumBytes == NULL) || (Buffer == NULL)) { 303 return (EFI_INVALID_PARAMETER); 304 } 305 if (*NumBytes == 0) { 306 return (EFI_INVALID_PARAMETER); 307 } 308 309 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL); 310 if (EFI_ERROR(Status)) { 311 return Status; 312 } 313 314 Attributes = FvbGetVolumeAttributes (Instance); 315 316 if ( (Attributes & EFI_FVB2_READ_STATUS) == 0) { 317 return (EFI_ACCESS_DENIED); 318 } 319 320 if (BlockOffset > LbaLength) { 321 return (EFI_INVALID_PARAMETER); 322 } 323 324 if (LbaLength < ( *NumBytes + BlockOffset ) ) { 325 *NumBytes = (UINT32) (LbaLength - BlockOffset); 326 Status = EFI_BAD_BUFFER_SIZE; 327 } 328 329 LibFvbFlashDeviceRead (LbaAddress + BlockOffset, NumBytes, Buffer); 330 331 return Status; 332 } 333 334 335 /** 336 Writes specified number of bytes from the input buffer to the block. 337 338 @param[in] Instance The FV instance to be written to. 339 @param[in] Lba The starting logical block index to write to. 340 @param[in] BlockOffset Offset into the block at which to begin writing. 341 @param[in] NumBytes Pointer that on input contains the total size of 342 the buffer. On output, it contains the total number 343 of bytes actually written. 344 @param[in] Buffer Pointer to a caller allocated buffer that contains 345 the source for the write. 346 @retval EFI_SUCCESS The firmware volume was written successfully. 347 @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On output, 348 NumBytes contains the total number of bytes 349 actually writte. 350 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state. 351 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and 352 could not be written. 353 @retval EFI_INVALID_PARAMETER Instance not found, or NumBytes, Buffer are NULL. 354 355 **/ 356 EFI_STATUS 357 FvbWriteBlock ( 358 IN UINTN Instance, 359 IN EFI_LBA Lba, 360 IN UINTN BlockOffset, 361 IN OUT UINTN *NumBytes, 362 IN UINT8 *Buffer 363 ) 364 { 365 EFI_FVB_ATTRIBUTES_2 Attributes; 366 UINTN LbaAddress; 367 UINTN LbaLength; 368 EFI_STATUS Status; 369 EFI_STATUS Status1; 370 371 if ( (NumBytes == NULL) || (Buffer == NULL)) { 372 return (EFI_INVALID_PARAMETER); 373 } 374 if (*NumBytes == 0) { 375 return (EFI_INVALID_PARAMETER); 376 } 377 378 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL); 379 if (EFI_ERROR(Status)) { 380 return Status; 381 } 382 383 // 384 // Check if the FV is write enabled. 385 // 386 Attributes = FvbGetVolumeAttributes (Instance); 387 if ( (Attributes & EFI_FVB2_WRITE_STATUS) == 0) { 388 return (EFI_ACCESS_DENIED); 389 } 390 391 // 392 // Perform boundary checks and adjust NumBytes. 393 // 394 if (BlockOffset > LbaLength) { 395 return (EFI_INVALID_PARAMETER); 396 } 397 398 if ( LbaLength < ( *NumBytes + BlockOffset ) ) { 399 DEBUG ((EFI_D_ERROR, 400 "FvWriteBlock: Reducing Numbytes from 0x%x to 0x%x\n", 401 *NumBytes, 402 (UINT32)(LbaLength-BlockOffset)) 403 ); 404 *NumBytes = (UINT32) (LbaLength - BlockOffset); 405 Status = EFI_BAD_BUFFER_SIZE; 406 } 407 408 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE); 409 410 Status1 = LibFvbFlashDeviceWrite (LbaAddress + BlockOffset, NumBytes, Buffer); 411 412 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE); 413 WriteBackInvalidateDataCacheRange ((VOID *) (LbaAddress + BlockOffset), *NumBytes); 414 415 if ( EFI_ERROR (Status1) ) { 416 return Status1; 417 } 418 419 return Status; 420 } 421 422 423 /** 424 Erases and initializes a firmware volume block. 425 426 @param[in] Instance The FV instance to be erased. 427 @param[in] Lba The logical block index to be erased. 428 429 @retval EFI_SUCCESS The erase request was successfully completed. 430 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state. 431 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and 432 could not be written. Firmware device may have been 433 partially erased. 434 @retval EFI_INVALID_PARAMETER Instance not found. 435 436 **/ 437 EFI_STATUS 438 FvbEraseBlock ( 439 IN UINTN Instance, 440 IN EFI_LBA Lba 441 ) 442 { 443 EFI_FVB_ATTRIBUTES_2 Attributes; 444 UINTN LbaAddress; 445 UINTN LbaLength; 446 EFI_STATUS Status; 447 448 // 449 // Check if the FV is write enabled. 450 // 451 Attributes = FvbGetVolumeAttributes (Instance); 452 453 if( (Attributes & EFI_FVB2_WRITE_STATUS) == 0) { 454 return (EFI_ACCESS_DENIED); 455 } 456 457 // 458 // Get the starting address of the block for erase. 459 // 460 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL); 461 if (EFI_ERROR(Status)) { 462 return Status; 463 } 464 465 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE); 466 467 Status = LibFvbFlashDeviceBlockErase (LbaAddress, LbaLength); 468 469 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE); 470 471 WriteBackInvalidateDataCacheRange ((VOID *) LbaAddress, LbaLength); 472 473 return Status; 474 } 475 476 477 /** 478 Modifies the current settings of the firmware volume according to the 479 input parameter, and returns the new setting of the volume. 480 481 @param[in] Instance The FV instance whose attributes is going to be 482 modified. 483 @param[in] Attributes On input, it is a pointer to EFI_FVB_ATTRIBUTES_2 484 containing the desired firmware volume settings. 485 On successful return, it contains the new settings 486 of the firmware volume. 487 488 @retval EFI_SUCCESS Successfully returns. 489 @retval EFI_ACCESS_DENIED The volume setting is locked and cannot be modified. 490 @retval EFI_INVALID_PARAMETER Instance not found, or The attributes requested are 491 in conflict with the capabilities as declared in the 492 firmware volume header. 493 494 **/ 495 STATIC 496 EFI_STATUS 497 FvbSetVolumeAttributes ( 498 IN UINTN Instance, 499 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes 500 ) 501 { 502 EFI_FW_VOL_INSTANCE *FwhInstance = NULL; 503 EFI_FVB_ATTRIBUTES_2 OldAttributes = 0; 504 EFI_FVB_ATTRIBUTES_2 *AttribPtr = NULL; 505 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes; 506 UINT32 Capabilities; 507 UINT32 OldStatus, NewStatus; 508 509 // 510 // Find the right instance of the FVB private data. 511 // 512 FwhInstance = GetFvbInstance (Instance); 513 514 AttribPtr = (EFI_FVB_ATTRIBUTES_2 *) & (FwhInstance->VolumeHeader.Attributes); 515 ASSERT (AttribPtr != NULL); 516 517 if ( AttribPtr != NULL) { 518 OldAttributes = *AttribPtr; 519 } 520 521 Capabilities = OldAttributes & EFI_FVB2_CAPABILITIES; 522 OldStatus = OldAttributes & EFI_FVB2_STATUS; 523 NewStatus = *Attributes & EFI_FVB2_STATUS; 524 525 UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \ 526 EFI_FVB2_READ_ENABLED_CAP | \ 527 EFI_FVB2_WRITE_DISABLED_CAP | \ 528 EFI_FVB2_WRITE_ENABLED_CAP | \ 529 EFI_FVB2_LOCK_CAP | \ 530 EFI_FVB2_STICKY_WRITE | \ 531 EFI_FVB2_MEMORY_MAPPED | \ 532 EFI_FVB2_ERASE_POLARITY | \ 533 EFI_FVB2_READ_LOCK_CAP | \ 534 EFI_FVB2_WRITE_LOCK_CAP | \ 535 EFI_FVB2_ALIGNMENT; 536 537 // 538 // Some attributes of FV is read only can *not* be set. 539 // 540 if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) { 541 return EFI_INVALID_PARAMETER; 542 } 543 544 // 545 // If firmware volume is locked, no status bit can be updated. 546 // 547 if ( OldAttributes & EFI_FVB2_LOCK_STATUS ) { 548 if ( OldStatus ^ NewStatus ) { 549 return EFI_ACCESS_DENIED; 550 } 551 } 552 553 // 554 // Test read disable. 555 // 556 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) { 557 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) { 558 return EFI_INVALID_PARAMETER; 559 } 560 } 561 562 // 563 // Test read enable. 564 // 565 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) { 566 if (NewStatus & EFI_FVB2_READ_STATUS) { 567 return EFI_INVALID_PARAMETER; 568 } 569 } 570 571 // 572 // Test write disable. 573 // 574 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) { 575 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) { 576 return EFI_INVALID_PARAMETER; 577 } 578 } 579 580 // 581 // Test write enable. 582 // 583 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) { 584 if (NewStatus & EFI_FVB2_WRITE_STATUS) { 585 return EFI_INVALID_PARAMETER; 586 } 587 } 588 589 // 590 // Test lock. 591 // 592 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) { 593 if (NewStatus & EFI_FVB2_LOCK_STATUS) { 594 return EFI_INVALID_PARAMETER; 595 } 596 } 597 598 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS)); 599 *AttribPtr = (*AttribPtr) | NewStatus; 600 *Attributes = *AttribPtr; 601 602 return EFI_SUCCESS; 603 } 604 605 // 606 // FVB protocol APIs. 607 // 608 /** 609 Retrieves the physical address of the device. 610 611 @param[in] This A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL. 612 @param[out] Address Output buffer containing the address. 613 614 retval EFI_SUCCESS The function always return successfully. 615 616 **/ 617 EFI_STATUS 618 EFIAPI 619 FvbProtocolGetPhysicalAddress ( 620 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 621 OUT EFI_PHYSICAL_ADDRESS *Address 622 ) 623 { 624 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 625 EFI_FW_VOL_INSTANCE *FvInstance; 626 627 FvbDevice = FVB_DEVICE_FROM_THIS (This); 628 FvInstance = GetFvbInstance(FvbDevice->Instance); 629 630 if (FvInstance != NULL) { 631 *Address = FvInstance->FvBase; 632 } 633 634 return EFI_SUCCESS; 635 } 636 637 638 /** 639 Retrieve the size of a logical block. 640 641 @param[in] This Calling context. 642 @param[in] Lba Indicates which block to return the size for. 643 @param[out] BlockSize A pointer to a caller allocated UINTN in which 644 the size of the block is returned. 645 @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which the 646 number of consecutive blocks starting with Lba is 647 returned. All blocks in this range have a size of 648 BlockSize. 649 650 @retval EFI_SUCCESS The function always return successfully. 651 652 **/ 653 EFI_STATUS 654 EFIAPI 655 FvbProtocolGetBlockSize ( 656 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 657 IN EFI_LBA Lba, 658 OUT UINTN *BlockSize, 659 OUT UINTN *NumOfBlocks 660 ) 661 { 662 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 663 664 DEBUG((EFI_D_INFO, 665 "FvbProtocolGetBlockSize: Lba: 0x%lx BlockSize: 0x%x NumOfBlocks: 0x%x\n", 666 Lba, 667 BlockSize, 668 NumOfBlocks) 669 ); 670 671 FvbDevice = FVB_DEVICE_FROM_THIS (This); 672 673 return FvbGetLbaAddress ( 674 FvbDevice->Instance, 675 Lba, 676 NULL, 677 BlockSize, 678 NumOfBlocks 679 ); 680 } 681 682 683 /** 684 Retrieves Volume attributes. No polarity translations are done. 685 686 @param[in] This Calling context. 687 @param[out] Attributes Output buffer which contains attributes. 688 689 @retval EFI_SUCCESS The function always return successfully. 690 691 **/ 692 EFI_STATUS 693 EFIAPI 694 FvbProtocolGetAttributes ( 695 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 696 OUT EFI_FVB_ATTRIBUTES_2 *Attributes 697 ) 698 { 699 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 700 701 FvbDevice = FVB_DEVICE_FROM_THIS (This); 702 703 *Attributes = FvbGetVolumeAttributes (FvbDevice->Instance); 704 705 DEBUG ((EFI_D_INFO, 706 "FvbProtocolGetAttributes: This: 0x%x Attributes: 0x%x\n", 707 This, 708 *Attributes) 709 ); 710 711 return EFI_SUCCESS; 712 } 713 714 715 /** 716 Sets Volume attributes. No polarity translations are done. 717 718 @param[in] This Calling context. 719 @param[out] Attributes Output buffer which contains attributes. 720 721 @retval EFI_SUCCESS The function always return successfully. 722 723 **/ 724 EFI_STATUS 725 EFIAPI 726 FvbProtocolSetAttributes ( 727 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 728 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes 729 ) 730 { 731 EFI_STATUS Status; 732 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 733 734 DEBUG((EFI_D_INFO, 735 "FvbProtocolSetAttributes: Before SET - This: 0x%x Attributes: 0x%x\n", 736 This, 737 *Attributes) 738 ); 739 740 FvbDevice = FVB_DEVICE_FROM_THIS (This); 741 742 Status = FvbSetVolumeAttributes (FvbDevice->Instance, Attributes); 743 744 DEBUG((EFI_D_INFO, 745 "FvbProtocolSetAttributes: After SET - This: 0x%x Attributes: 0x%x\n", 746 This, 747 *Attributes) 748 ); 749 750 return Status; 751 } 752 753 754 /** 755 The EraseBlock() function erases one or more blocks as denoted by the 756 variable argument list. The entire parameter list of blocks must be verified 757 prior to erasing any blocks. If a block is requested that does not exist 758 within the associated firmware volume (it has a larger index than the last 759 block of the firmware volume), the EraseBlock() function must return 760 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume. 761 762 @param[in] This Calling context. 763 @param[in] ... Starting LBA followed by Number of Lba to erase. 764 a -1 to terminate the list. 765 766 @retval EFI_SUCCESS The erase request was successfully completed. 767 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state. 768 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and 769 could not be written. Firmware device may have been 770 partially erased. 771 772 **/ 773 EFI_STATUS 774 EFIAPI 775 FvbProtocolEraseBlocks ( 776 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 777 ... 778 ) 779 { 780 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 781 EFI_FW_VOL_INSTANCE *FwhInstance; 782 UINTN NumOfBlocks = 0; 783 VA_LIST args; 784 EFI_LBA StartingLba; 785 UINTN NumOfLba; 786 EFI_STATUS Status; 787 788 DEBUG((EFI_D_INFO, "FvbProtocolEraseBlocks: \n")); 789 FvbDevice = FVB_DEVICE_FROM_THIS (This); 790 791 FwhInstance = GetFvbInstance (FvbDevice->Instance); 792 793 if (FwhInstance != NULL) { 794 NumOfBlocks = FwhInstance->NumOfBlocks; 795 } 796 797 VA_START (args, This); 798 799 do { 800 StartingLba = VA_ARG (args, EFI_LBA); 801 if ( StartingLba == EFI_LBA_LIST_TERMINATOR ) { 802 break; 803 } 804 805 NumOfLba = VA_ARG (args, UINT32); 806 807 // 808 // Check input parameters. 809 // 810 if (NumOfLba == 0) { 811 VA_END (args); 812 return EFI_INVALID_PARAMETER; 813 } 814 815 if ( ( StartingLba + NumOfLba ) > NumOfBlocks ) { 816 return EFI_INVALID_PARAMETER; 817 } 818 } while ( 1 ); 819 820 VA_END (args); 821 822 VA_START (args, This); 823 do { 824 StartingLba = VA_ARG (args, EFI_LBA); 825 if (StartingLba == EFI_LBA_LIST_TERMINATOR) { 826 break; 827 } 828 829 NumOfLba = VA_ARG (args, UINT32); 830 831 while ( NumOfLba > 0 ) { 832 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba); 833 if ( EFI_ERROR(Status)) { 834 VA_END (args); 835 return Status; 836 } 837 StartingLba ++; 838 NumOfLba --; 839 } 840 841 } while ( 1 ); 842 843 VA_END (args); 844 845 return EFI_SUCCESS; 846 } 847 848 849 /** 850 Writes data beginning at Lba:Offset from FV. The write terminates either 851 when *NumBytes of data have been written, or when a block boundary is 852 reached. *NumBytes is updated to reflect the actual number of bytes 853 written. The write opertion does not include erase. This routine will 854 attempt to write only the specified bytes. If the writes do not stick, 855 it will return an error. 856 857 @param[in] This Calling context. 858 @param[in] Lba Block in which to begin write. 859 @param[in] Offset Offset in the block at which to begin write. 860 @param[in,out] NumBytes On input, indicates the requested write size. On 861 output, indicates the actual number of bytes written 862 @param[in] Buffer Buffer containing source data for the write. 863 864 @retval EFI_SUCCESS The firmware volume was written successfully. 865 @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On output, 866 NumBytes contains the total number of bytes 867 actually written. 868 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state. 869 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and 870 could not be written. 871 @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL. 872 873 **/ 874 EFI_STATUS 875 EFIAPI 876 FvbProtocolWrite ( 877 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 878 IN EFI_LBA Lba, 879 IN UINTN Offset, 880 IN OUT UINTN *NumBytes, 881 IN UINT8 *Buffer 882 ) 883 { 884 885 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 886 887 FvbDevice = FVB_DEVICE_FROM_THIS (This); 888 889 DEBUG((EFI_D_INFO, 890 "FvbProtocolWrite: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x\n", 891 Lba, 892 Offset, 893 *NumBytes, 894 Buffer) 895 ); 896 897 return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer); 898 } 899 900 901 /** 902 Reads data beginning at Lba:Offset from FV. The Read terminates either 903 when *NumBytes of data have been read, or when a block boundary is 904 reached. *NumBytes is updated to reflect the actual number of bytes 905 written. The write opertion does not include erase. This routine will 906 attempt to write only the specified bytes. If the writes do not stick, 907 it will return an error. 908 909 @param[in] This Calling context. 910 @param[in] Lba Block in which to begin write. 911 @param[in] Offset Offset in the block at which to begin write 912 @param[in,out] NumBytes On input, indicates the requested write size. On 913 output, indicates the actual number of bytes written. 914 @param[in] Buffer Buffer containing source data for the write. 915 916 917 Returns: 918 @retval EFI_SUCCESS The firmware volume was read successfully and 919 contents are in Buffer. 920 @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On output, 921 NumBytes contains the total number of bytes returned 922 in Buffer. 923 @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state 924 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and 925 could not be read. 926 @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL. 927 928 **/ 929 EFI_STATUS 930 EFIAPI 931 FvbProtocolRead ( 932 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 933 IN EFI_LBA Lba, 934 IN UINTN Offset, 935 IN OUT UINTN *NumBytes, 936 OUT UINT8 *Buffer 937 ) 938 { 939 940 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 941 EFI_STATUS Status; 942 943 FvbDevice = FVB_DEVICE_FROM_THIS (This); 944 Status = FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer); 945 DEBUG((EFI_D_INFO, 946 "FvbProtocolRead: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x\n", 947 Lba, 948 Offset, 949 *NumBytes, 950 Buffer) 951 ); 952 953 return Status; 954 } 955 956 957 /** 958 Check the integrity of firmware volume header. 959 960 @param[in] FwVolHeader A pointer to a firmware volume header. 961 962 @retval TRUE The firmware volume is consistent. 963 @retval FALSE The firmware volume has corrupted. 964 965 **/ 966 BOOLEAN 967 IsFvHeaderValid ( 968 IN EFI_PHYSICAL_ADDRESS FvBase, 969 IN CONST EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader 970 ) 971 { 972 if (FvBase == PcdGet32(PcdFlashNvStorageVariableBase)) { 973 if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid, sizeof(EFI_GUID)) != 0 ) { 974 return FALSE; 975 } 976 } else { 977 if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid, sizeof(EFI_GUID)) != 0 ) { 978 return FALSE; 979 } 980 } 981 if ( (FwVolHeader->Revision != EFI_FVH_REVISION) || 982 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) || 983 (FwVolHeader->FvLength == ((UINTN) -1)) || 984 ((FwVolHeader->HeaderLength & 0x01 ) !=0) ) { 985 return FALSE; 986 } 987 988 if (CalculateCheckSum16 ((UINT16 *) FwVolHeader, FwVolHeader->HeaderLength) != 0) { 989 return FALSE; 990 } 991 992 return TRUE; 993 } 994 995 996 /** 997 The function does the necessary initialization work for 998 Firmware Volume Block Driver. 999 1000 @retval EFI_SUCCESS This funtion always return EFI_SUCCESS. 1001 It will ASSERT on errors. 1002 1003 **/ 1004 EFI_STATUS 1005 FvbInitialize ( 1006 VOID 1007 ) 1008 { 1009 EFI_FW_VOL_INSTANCE *FwhInstance; 1010 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; 1011 EFI_FIRMWARE_VOLUME_HEADER *FvHeader; 1012 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; 1013 EFI_PHYSICAL_ADDRESS BaseAddress; 1014 EFI_STATUS Status; 1015 UINTN BufferSize; 1016 UINTN TmpHeaderLength; 1017 UINTN Idx; 1018 UINT32 MaxLbaSize; 1019 1020 // 1021 // Calculate the total size for all firmware volume block instances. 1022 // 1023 BufferSize = 0; 1024 for (Idx = 0; Idx < 1; Idx++) { 1025 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) mPlatformFvBaseAddress[Idx]; 1026 BufferSize += (FvHeader->HeaderLength + 1027 sizeof (EFI_FW_VOL_INSTANCE) - 1028 sizeof (EFI_FIRMWARE_VOLUME_HEADER) 1029 ); 1030 } 1031 1032 mFvbModuleGlobal.FvInstance = (EFI_FW_VOL_INSTANCE *) AllocateRuntimeZeroPool (BufferSize); 1033 ASSERT (NULL != mFvbModuleGlobal.FvInstance); 1034 1035 1036 MaxLbaSize = 0; 1037 FwhInstance = mFvbModuleGlobal.FvInstance; 1038 mFvbModuleGlobal.NumFv = 0; 1039 1040 for (Idx = 0; Idx < 1; Idx++) { 1041 BaseAddress = mPlatformFvBaseAddress[Idx]; 1042 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress; 1043 1044 if (!IsFvHeaderValid (BaseAddress, FwVolHeader)) { 1045 // 1046 // If not valid, get FvbInfo from the information carried in 1047 // FVB driver. 1048 // 1049 DEBUG ((EFI_D_ERROR, "Fvb: FV header @ 0x%lx invalid\n", BaseAddress)); 1050 Status = GetFvbInfo (BaseAddress, &FwVolHeader); 1051 ASSERT_EFI_ERROR(Status); 1052 // 1053 // Write back a healthy FV header. 1054 // 1055 DEBUG ((EFI_D_ERROR, "FwBlockService.c: Writing back healthy FV header\n")); 1056 LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length, FALSE); 1057 1058 Status = LibFvbFlashDeviceBlockErase ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length); 1059 1060 TmpHeaderLength = (UINTN) FwVolHeader->HeaderLength; 1061 Status = LibFvbFlashDeviceWrite ( 1062 (UINTN)BaseAddress, 1063 &TmpHeaderLength, 1064 (UINT8 *) FwVolHeader 1065 ); 1066 1067 LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length, TRUE); 1068 1069 WriteBackInvalidateDataCacheRange ( 1070 (VOID *) (UINTN) BaseAddress, 1071 FwVolHeader->BlockMap->Length 1072 ); 1073 1074 } 1075 1076 CopyMem (&(FwhInstance->VolumeHeader), FwVolHeader, FwVolHeader->HeaderLength); 1077 1078 FwVolHeader = &(FwhInstance->VolumeHeader); 1079 FwhInstance->FvBase = (UINTN)BaseAddress; 1080 1081 // 1082 // Process the block map for each FV. 1083 // 1084 FwhInstance->NumOfBlocks = 0; 1085 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) { 1086 // 1087 // Get the maximum size of a block. 1088 // 1089 if (MaxLbaSize < PtrBlockMapEntry->Length) { 1090 MaxLbaSize = PtrBlockMapEntry->Length; 1091 } 1092 FwhInstance->NumOfBlocks += PtrBlockMapEntry->NumBlocks; 1093 } 1094 1095 // 1096 // Add a FVB Protocol Instance. 1097 // 1098 mFvbModuleGlobal.NumFv++; 1099 InstallFvbProtocol (FwhInstance, mFvbModuleGlobal.NumFv - 1); 1100 1101 // 1102 // Move on to the next FwhInstance. 1103 // 1104 FwhInstance = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhInstance) + 1105 FwVolHeader->HeaderLength + 1106 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))); 1107 1108 } 1109 1110 return EFI_SUCCESS; 1111 } 1112 1113