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 7Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> 8 9 10 This program and the accompanying materials are licensed and made available under 11 12 the terms and conditions of the BSD License that accompanies this distribution. 13 14 The full text of the license may be found at 15 16 http://opensource.org/licenses/bsd-license.php. 17 18 19 20 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 21 22 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 23 24 25 26 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// 35FWB_GLOBAL mFvbModuleGlobal; 36 37// 38// This platform driver knows there are 3 FVs on 39// FD, which are FvRecovery, FvMain and FvNvStorage. 40// 41UINT32 mPlatformFvBaseAddress[] = { 42 FixedPcdGet32(PcdFlashNvStorageVariableBase), 43}; 44 45FV_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 69FV_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// 94EFI_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**/ 122EFI_FW_VOL_INSTANCE * 123GetFvbInstance ( 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**/ 158STATIC 159EFI_FVB_ATTRIBUTES_2 160FvbGetVolumeAttributes ( 161 IN UINTN Instance 162 ) 163{ 164 EFI_FW_VOL_INSTANCE * FwInstance = NULL; 165 FwInstance = GetFvbInstance(Instance); 166 ASSERT_EFI_ERROR (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**/ 194STATIC 195EFI_STATUS 196FvbGetLbaAddress ( 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_EFI_ERROR (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**/ 287STATIC 288EFI_STATUS 289FvbReadBlock ( 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**/ 356EFI_STATUS 357FvbWriteBlock ( 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_FW_VOL_INSTANCE *FwhInstance; 369 EFI_STATUS Status; 370 EFI_STATUS Status1; 371 372 FwhInstance = GetFvbInstance (Instance); 373 374 if ( (NumBytes == NULL) || (Buffer == NULL)) { 375 return (EFI_INVALID_PARAMETER); 376 } 377 if (*NumBytes == 0) { 378 return (EFI_INVALID_PARAMETER); 379 } 380 381 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL); 382 if (EFI_ERROR(Status)) { 383 return Status; 384 } 385 386 // 387 // Check if the FV is write enabled. 388 // 389 Attributes = FvbGetVolumeAttributes (Instance); 390 if ( (Attributes & EFI_FVB2_WRITE_STATUS) == 0) { 391 return (EFI_ACCESS_DENIED); 392 } 393 394 // 395 // Perform boundary checks and adjust NumBytes. 396 // 397 if (BlockOffset > LbaLength) { 398 return (EFI_INVALID_PARAMETER); 399 } 400 401 if ( LbaLength < ( *NumBytes + BlockOffset ) ) { 402 DEBUG ((EFI_D_ERROR, 403 "FvWriteBlock: Reducing Numbytes from 0x%x to 0x%x\n", 404 *NumBytes, 405 (UINT32)(LbaLength-BlockOffset)) 406 ); 407 *NumBytes = (UINT32) (LbaLength - BlockOffset); 408 Status = EFI_BAD_BUFFER_SIZE; 409 } 410 411 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE); 412 413 Status1 = LibFvbFlashDeviceWrite (LbaAddress + BlockOffset, NumBytes, Buffer); 414 415 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE); 416 WriteBackInvalidateDataCacheRange ((VOID *) (LbaAddress + BlockOffset), *NumBytes); 417 418 if ( EFI_ERROR (Status1) ) { 419 return Status1; 420 } 421 422 return Status; 423} 424 425 426/** 427 Erases and initializes a firmware volume block. 428 429 @param[in] Instance The FV instance to be erased. 430 @param[in] Lba The logical block index to be erased. 431 432 @retval EFI_SUCCESS The erase request was successfully completed. 433 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state. 434 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and 435 could not be written. Firmware device may have been 436 partially erased. 437 @retval EFI_INVALID_PARAMETER Instance not found. 438 439**/ 440EFI_STATUS 441FvbEraseBlock ( 442 IN UINTN Instance, 443 IN EFI_LBA Lba 444 ) 445{ 446 EFI_FVB_ATTRIBUTES_2 Attributes; 447 UINTN LbaAddress; 448 EFI_FW_VOL_INSTANCE *FwhInstance; 449 UINTN LbaLength; 450 EFI_STATUS Status; 451 452 // 453 // Find the right instance of the FVB private data. 454 // 455 FwhInstance = GetFvbInstance (Instance); 456 457 // 458 // Check if the FV is write enabled. 459 // 460 Attributes = FvbGetVolumeAttributes (Instance); 461 462 if( (Attributes & EFI_FVB2_WRITE_STATUS) == 0) { 463 return (EFI_ACCESS_DENIED); 464 } 465 466 // 467 // Get the starting address of the block for erase. 468 // 469 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL); 470 if (EFI_ERROR(Status)) { 471 return Status; 472 } 473 474 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE); 475 476 Status = LibFvbFlashDeviceBlockErase (LbaAddress, LbaLength); 477 478 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE); 479 480 WriteBackInvalidateDataCacheRange ((VOID *) LbaAddress, LbaLength); 481 482 return Status; 483} 484 485 486/** 487 Modifies the current settings of the firmware volume according to the 488 input parameter, and returns the new setting of the volume. 489 490 @param[in] Instance The FV instance whose attributes is going to be 491 modified. 492 @param[in] Attributes On input, it is a pointer to EFI_FVB_ATTRIBUTES_2 493 containing the desired firmware volume settings. 494 On successful return, it contains the new settings 495 of the firmware volume. 496 497 @retval EFI_SUCCESS Successfully returns. 498 @retval EFI_ACCESS_DENIED The volume setting is locked and cannot be modified. 499 @retval EFI_INVALID_PARAMETER Instance not found, or The attributes requested are 500 in conflict with the capabilities as declared in the 501 firmware volume header. 502 503**/ 504STATIC 505EFI_STATUS 506FvbSetVolumeAttributes ( 507 IN UINTN Instance, 508 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes 509 ) 510{ 511 EFI_FW_VOL_INSTANCE *FwhInstance = NULL; 512 EFI_FVB_ATTRIBUTES_2 OldAttributes = 0; 513 EFI_FVB_ATTRIBUTES_2 *AttribPtr = NULL; 514 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes; 515 UINT32 Capabilities; 516 UINT32 OldStatus, NewStatus; 517 518 // 519 // Find the right instance of the FVB private data. 520 // 521 FwhInstance = GetFvbInstance (Instance); 522 523 AttribPtr = (EFI_FVB_ATTRIBUTES_2 *) & (FwhInstance->VolumeHeader.Attributes); 524 ASSERT_EFI_ERROR (AttribPtr != NULL); 525 526 if ( AttribPtr != NULL) { 527 OldAttributes = *AttribPtr; 528 } 529 530 Capabilities = OldAttributes & EFI_FVB2_CAPABILITIES; 531 OldStatus = OldAttributes & EFI_FVB2_STATUS; 532 NewStatus = *Attributes & EFI_FVB2_STATUS; 533 534 UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \ 535 EFI_FVB2_READ_ENABLED_CAP | \ 536 EFI_FVB2_WRITE_DISABLED_CAP | \ 537 EFI_FVB2_WRITE_ENABLED_CAP | \ 538 EFI_FVB2_LOCK_CAP | \ 539 EFI_FVB2_STICKY_WRITE | \ 540 EFI_FVB2_MEMORY_MAPPED | \ 541 EFI_FVB2_ERASE_POLARITY | \ 542 EFI_FVB2_READ_LOCK_CAP | \ 543 EFI_FVB2_WRITE_LOCK_CAP | \ 544 EFI_FVB2_ALIGNMENT; 545 546 // 547 // Some attributes of FV is read only can *not* be set. 548 // 549 if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) { 550 return EFI_INVALID_PARAMETER; 551 } 552 553 // 554 // If firmware volume is locked, no status bit can be updated. 555 // 556 if ( OldAttributes & EFI_FVB2_LOCK_STATUS ) { 557 if ( OldStatus ^ NewStatus ) { 558 return EFI_ACCESS_DENIED; 559 } 560 } 561 562 // 563 // Test read disable. 564 // 565 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) { 566 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) { 567 return EFI_INVALID_PARAMETER; 568 } 569 } 570 571 // 572 // Test read enable. 573 // 574 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) { 575 if (NewStatus & EFI_FVB2_READ_STATUS) { 576 return EFI_INVALID_PARAMETER; 577 } 578 } 579 580 // 581 // Test write disable. 582 // 583 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) { 584 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) { 585 return EFI_INVALID_PARAMETER; 586 } 587 } 588 589 // 590 // Test write enable. 591 // 592 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) { 593 if (NewStatus & EFI_FVB2_WRITE_STATUS) { 594 return EFI_INVALID_PARAMETER; 595 } 596 } 597 598 // 599 // Test lock. 600 // 601 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) { 602 if (NewStatus & EFI_FVB2_LOCK_STATUS) { 603 return EFI_INVALID_PARAMETER; 604 } 605 } 606 607 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS)); 608 *AttribPtr = (*AttribPtr) | NewStatus; 609 *Attributes = *AttribPtr; 610 611 return EFI_SUCCESS; 612} 613 614// 615// FVB protocol APIs. 616// 617/** 618 Retrieves the physical address of the device. 619 620 @param[in] This A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL. 621 @param[out] Address Output buffer containing the address. 622 623 retval EFI_SUCCESS The function always return successfully. 624 625**/ 626EFI_STATUS 627EFIAPI 628FvbProtocolGetPhysicalAddress ( 629 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 630 OUT EFI_PHYSICAL_ADDRESS *Address 631 ) 632{ 633 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 634 EFI_FW_VOL_INSTANCE *FvInstance; 635 636 FvbDevice = FVB_DEVICE_FROM_THIS (This); 637 FvInstance = GetFvbInstance(FvbDevice->Instance); 638 639 if (FvInstance != NULL) { 640 *Address = FvInstance->FvBase; 641 } 642 643 return EFI_SUCCESS; 644} 645 646 647/** 648 Retrieve the size of a logical block. 649 650 @param[in] This Calling context. 651 @param[in] Lba Indicates which block to return the size for. 652 @param[out] BlockSize A pointer to a caller allocated UINTN in which 653 the size of the block is returned. 654 @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which the 655 number of consecutive blocks starting with Lba is 656 returned. All blocks in this range have a size of 657 BlockSize. 658 659 @retval EFI_SUCCESS The function always return successfully. 660 661**/ 662EFI_STATUS 663EFIAPI 664FvbProtocolGetBlockSize ( 665 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 666 IN EFI_LBA Lba, 667 OUT UINTN *BlockSize, 668 OUT UINTN *NumOfBlocks 669 ) 670{ 671 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 672 673 DEBUG((EFI_D_INFO, 674 "FvbProtocolGetBlockSize: Lba: 0x%lx BlockSize: 0x%x NumOfBlocks: 0x%x\n", 675 Lba, 676 BlockSize, 677 NumOfBlocks) 678 ); 679 680 FvbDevice = FVB_DEVICE_FROM_THIS (This); 681 682 return FvbGetLbaAddress ( 683 FvbDevice->Instance, 684 Lba, 685 NULL, 686 BlockSize, 687 NumOfBlocks 688 ); 689} 690 691 692/** 693 Retrieves Volume attributes. No polarity translations are done. 694 695 @param[in] This Calling context. 696 @param[out] Attributes Output buffer which contains attributes. 697 698 @retval EFI_SUCCESS The function always return successfully. 699 700**/ 701EFI_STATUS 702EFIAPI 703FvbProtocolGetAttributes ( 704 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 705 OUT EFI_FVB_ATTRIBUTES_2 *Attributes 706 ) 707{ 708 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 709 710 FvbDevice = FVB_DEVICE_FROM_THIS (This); 711 712 *Attributes = FvbGetVolumeAttributes (FvbDevice->Instance); 713 714 DEBUG ((EFI_D_INFO, 715 "FvbProtocolGetAttributes: This: 0x%x Attributes: 0x%x\n", 716 This, 717 *Attributes) 718 ); 719 720 return EFI_SUCCESS; 721} 722 723 724/** 725 Sets Volume attributes. No polarity translations are done. 726 727 @param[in] This Calling context. 728 @param[out] Attributes Output buffer which contains attributes. 729 730 @retval EFI_SUCCESS The function always return successfully. 731 732**/ 733EFI_STATUS 734EFIAPI 735FvbProtocolSetAttributes ( 736 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 737 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes 738 ) 739{ 740 EFI_STATUS Status; 741 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 742 743 DEBUG((EFI_D_INFO, 744 "FvbProtocolSetAttributes: Before SET - This: 0x%x Attributes: 0x%x\n", 745 This, 746 *Attributes) 747 ); 748 749 FvbDevice = FVB_DEVICE_FROM_THIS (This); 750 751 Status = FvbSetVolumeAttributes (FvbDevice->Instance, Attributes); 752 753 DEBUG((EFI_D_INFO, 754 "FvbProtocolSetAttributes: After SET - This: 0x%x Attributes: 0x%x\n", 755 This, 756 *Attributes) 757 ); 758 759 return Status; 760} 761 762 763/** 764 The EraseBlock() function erases one or more blocks as denoted by the 765 variable argument list. The entire parameter list of blocks must be verified 766 prior to erasing any blocks. If a block is requested that does not exist 767 within the associated firmware volume (it has a larger index than the last 768 block of the firmware volume), the EraseBlock() function must return 769 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume. 770 771 @param[in] This Calling context. 772 @param[in] ... Starting LBA followed by Number of Lba to erase. 773 a -1 to terminate the list. 774 775 @retval EFI_SUCCESS The erase request was successfully completed. 776 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state. 777 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and 778 could not be written. Firmware device may have been 779 partially erased. 780 781**/ 782EFI_STATUS 783EFIAPI 784FvbProtocolEraseBlocks ( 785 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 786 ... 787 ) 788{ 789 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 790 EFI_FW_VOL_INSTANCE *FwhInstance; 791 UINTN NumOfBlocks = 0; 792 VA_LIST args; 793 EFI_LBA StartingLba; 794 UINTN NumOfLba; 795 EFI_STATUS Status; 796 797 DEBUG((EFI_D_INFO, "FvbProtocolEraseBlocks: \n")); 798 FvbDevice = FVB_DEVICE_FROM_THIS (This); 799 800 FwhInstance = GetFvbInstance (FvbDevice->Instance); 801 802 if (FwhInstance != NULL) { 803 NumOfBlocks = FwhInstance->NumOfBlocks; 804 } 805 806 VA_START (args, This); 807 808 do { 809 StartingLba = VA_ARG (args, EFI_LBA); 810 if ( StartingLba == EFI_LBA_LIST_TERMINATOR ) { 811 break; 812 } 813 814 NumOfLba = VA_ARG (args, UINT32); 815 816 // 817 // Check input parameters. 818 // 819 if (NumOfLba == 0) { 820 VA_END (args); 821 return EFI_INVALID_PARAMETER; 822 } 823 824 if ( ( StartingLba + NumOfLba ) > NumOfBlocks ) { 825 return EFI_INVALID_PARAMETER; 826 } 827 } while ( 1 ); 828 829 VA_END (args); 830 831 VA_START (args, This); 832 do { 833 StartingLba = VA_ARG (args, EFI_LBA); 834 if (StartingLba == EFI_LBA_LIST_TERMINATOR) { 835 break; 836 } 837 838 NumOfLba = VA_ARG (args, UINT32); 839 840 while ( NumOfLba > 0 ) { 841 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba); 842 if ( EFI_ERROR(Status)) { 843 VA_END (args); 844 return Status; 845 } 846 StartingLba ++; 847 NumOfLba --; 848 } 849 850 } while ( 1 ); 851 852 VA_END (args); 853 854 return EFI_SUCCESS; 855} 856 857 858/** 859 Writes data beginning at Lba:Offset from FV. The write terminates either 860 when *NumBytes of data have been written, or when a block boundary is 861 reached. *NumBytes is updated to reflect the actual number of bytes 862 written. The write opertion does not include erase. This routine will 863 attempt to write only the specified bytes. If the writes do not stick, 864 it will return an error. 865 866 @param[in] This Calling context. 867 @param[in] Lba Block in which to begin write. 868 @param[in] Offset Offset in the block at which to begin write. 869 @param[in,out] NumBytes On input, indicates the requested write size. On 870 output, indicates the actual number of bytes written 871 @param[in] Buffer Buffer containing source data for the write. 872 873 @retval EFI_SUCCESS The firmware volume was written successfully. 874 @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On output, 875 NumBytes contains the total number of bytes 876 actually written. 877 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state. 878 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and 879 could not be written. 880 @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL. 881 882**/ 883EFI_STATUS 884EFIAPI 885FvbProtocolWrite ( 886 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 887 IN EFI_LBA Lba, 888 IN UINTN Offset, 889 IN OUT UINTN *NumBytes, 890 IN UINT8 *Buffer 891 ) 892{ 893 894 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 895 896 FvbDevice = FVB_DEVICE_FROM_THIS (This); 897 898 DEBUG((EFI_D_INFO, 899 "FvbProtocolWrite: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x\n", 900 Lba, 901 Offset, 902 *NumBytes, 903 Buffer) 904 ); 905 906 return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer); 907} 908 909 910/** 911 Reads data beginning at Lba:Offset from FV. The Read terminates either 912 when *NumBytes of data have been read, or when a block boundary is 913 reached. *NumBytes is updated to reflect the actual number of bytes 914 written. The write opertion does not include erase. This routine will 915 attempt to write only the specified bytes. If the writes do not stick, 916 it will return an error. 917 918 @param[in] This Calling context. 919 @param[in] Lba Block in which to begin write. 920 @param[in] Offset Offset in the block at which to begin write 921 @param[in,out] NumBytes On input, indicates the requested write size. On 922 output, indicates the actual number of bytes written. 923 @param[in] Buffer Buffer containing source data for the write. 924 925 926Returns: 927 @retval EFI_SUCCESS The firmware volume was read successfully and 928 contents are in Buffer. 929 @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On output, 930 NumBytes contains the total number of bytes returned 931 in Buffer. 932 @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state 933 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and 934 could not be read. 935 @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL. 936 937**/ 938EFI_STATUS 939EFIAPI 940FvbProtocolRead ( 941 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 942 IN EFI_LBA Lba, 943 IN UINTN Offset, 944 IN OUT UINTN *NumBytes, 945 OUT UINT8 *Buffer 946 ) 947{ 948 949 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 950 EFI_STATUS Status; 951 952 FvbDevice = FVB_DEVICE_FROM_THIS (This); 953 Status = FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer); 954 DEBUG((EFI_D_INFO, 955 "FvbProtocolRead: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x\n", 956 Lba, 957 Offset, 958 *NumBytes, 959 Buffer) 960 ); 961 962 return Status; 963} 964 965 966/** 967 Check the integrity of firmware volume header. 968 969 @param[in] FwVolHeader A pointer to a firmware volume header. 970 971 @retval TRUE The firmware volume is consistent. 972 @retval FALSE The firmware volume has corrupted. 973 974**/ 975BOOLEAN 976IsFvHeaderValid ( 977 IN EFI_PHYSICAL_ADDRESS FvBase, 978 IN CONST EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader 979 ) 980{ 981 if (FvBase == PcdGet32(PcdFlashNvStorageVariableBase)) { 982 if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid, sizeof(EFI_GUID)) != 0 ) { 983 return FALSE; 984 } 985 } else { 986 if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid, sizeof(EFI_GUID)) != 0 ) { 987 return FALSE; 988 } 989 } 990 if ( (FwVolHeader->Revision != EFI_FVH_REVISION) || 991 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) || 992 (FwVolHeader->FvLength == ((UINTN) -1)) || 993 ((FwVolHeader->HeaderLength & 0x01 ) !=0) ) { 994 return FALSE; 995 } 996 997 if (CalculateCheckSum16 ((UINT16 *) FwVolHeader, FwVolHeader->HeaderLength) != 0) { 998 return FALSE; 999 } 1000 1001 return TRUE; 1002} 1003 1004 1005/** 1006 The function does the necessary initialization work for 1007 Firmware Volume Block Driver. 1008 1009 @retval EFI_SUCCESS This funtion always return EFI_SUCCESS. 1010 It will ASSERT on errors. 1011 1012**/ 1013EFI_STATUS 1014FvbInitialize ( 1015 VOID 1016 ) 1017{ 1018 EFI_FW_VOL_INSTANCE *FwhInstance; 1019 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; 1020 EFI_FIRMWARE_VOLUME_HEADER *FvHeader; 1021 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; 1022 EFI_PHYSICAL_ADDRESS BaseAddress; 1023 EFI_STATUS Status; 1024 UINTN BufferSize; 1025 UINTN TmpHeaderLength; 1026 UINTN Idx; 1027 UINT32 MaxLbaSize; 1028 BOOLEAN FvHeaderValid; 1029 1030 // 1031 // Calculate the total size for all firmware volume block instances. 1032 // 1033 BufferSize = 0; 1034 for (Idx = 0; Idx < 1; Idx++) { 1035 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) mPlatformFvBaseAddress[Idx]; 1036 BufferSize += (FvHeader->HeaderLength + 1037 sizeof (EFI_FW_VOL_INSTANCE) - 1038 sizeof (EFI_FIRMWARE_VOLUME_HEADER) 1039 ); 1040 } 1041 1042 mFvbModuleGlobal.FvInstance = (EFI_FW_VOL_INSTANCE *) AllocateRuntimeZeroPool (BufferSize); 1043 ASSERT (NULL != mFvbModuleGlobal.FvInstance); 1044 1045 1046 MaxLbaSize = 0; 1047 FwhInstance = mFvbModuleGlobal.FvInstance; 1048 mFvbModuleGlobal.NumFv = 0; 1049 1050 for (Idx = 0; Idx < 1; Idx++) { 1051 BaseAddress = mPlatformFvBaseAddress[Idx]; 1052 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress; 1053 1054 if (!IsFvHeaderValid (BaseAddress, FwVolHeader)) { 1055 FvHeaderValid = FALSE; 1056 // 1057 // If not valid, get FvbInfo from the information carried in 1058 // FVB driver. 1059 // 1060 DEBUG ((EFI_D_ERROR, "Fvb: FV header @ 0x%lx invalid\n", BaseAddress)); 1061 Status = GetFvbInfo (BaseAddress, &FwVolHeader); 1062 ASSERT_EFI_ERROR(Status); 1063 // 1064 // Write back a healthy FV header. 1065 // 1066 DEBUG ((EFI_D_ERROR, "FwBlockService.c: Writing back healthy FV header\n")); 1067 LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length, FALSE); 1068 1069 Status = LibFvbFlashDeviceBlockErase ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length); 1070 1071 TmpHeaderLength = (UINTN) FwVolHeader->HeaderLength; 1072 Status = LibFvbFlashDeviceWrite ( 1073 (UINTN)BaseAddress, 1074 &TmpHeaderLength, 1075 (UINT8 *) FwVolHeader 1076 ); 1077 1078 LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length, TRUE); 1079 1080 WriteBackInvalidateDataCacheRange ( 1081 (VOID *) (UINTN) BaseAddress, 1082 FwVolHeader->BlockMap->Length 1083 ); 1084 1085 } 1086 1087 CopyMem (&(FwhInstance->VolumeHeader), FwVolHeader, FwVolHeader->HeaderLength); 1088 1089 FwVolHeader = &(FwhInstance->VolumeHeader); 1090 FwhInstance->FvBase = (UINTN)BaseAddress; 1091 1092 // 1093 // Process the block map for each FV. 1094 // 1095 FwhInstance->NumOfBlocks = 0; 1096 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) { 1097 // 1098 // Get the maximum size of a block. 1099 // 1100 if (MaxLbaSize < PtrBlockMapEntry->Length) { 1101 MaxLbaSize = PtrBlockMapEntry->Length; 1102 } 1103 FwhInstance->NumOfBlocks += PtrBlockMapEntry->NumBlocks; 1104 } 1105 1106 // 1107 // Add a FVB Protocol Instance. 1108 // 1109 mFvbModuleGlobal.NumFv++; 1110 InstallFvbProtocol (FwhInstance, mFvbModuleGlobal.NumFv - 1); 1111 1112 // 1113 // Move on to the next FwhInstance. 1114 // 1115 FwhInstance = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhInstance) + 1116 FwVolHeader->HeaderLength + 1117 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))); 1118 1119 } 1120 1121 return EFI_SUCCESS; 1122} 1123 1124