1 /*++ @file 2 3 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> 4 Portions copyright (c) 2011, Apple Inc. All rights reserved. 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 **/ 14 15 #include "PiDxe.h" 16 #include <Guid/EventGroup.h> 17 #include <Protocol/FirmwareVolumeBlock.h> 18 #include <Protocol/DevicePath.h> 19 20 #include <Library/UefiLib.h> 21 #include <Library/UefiDriverEntryPoint.h> 22 #include <Library/BaseLib.h> 23 #include <Library/DxeServicesTableLib.h> 24 #include <Library/UefiRuntimeLib.h> 25 #include <Library/DebugLib.h> 26 #include <Library/HobLib.h> 27 #include <Library/BaseMemoryLib.h> 28 #include <Library/MemoryAllocationLib.h> 29 #include <Library/UefiBootServicesTableLib.h> 30 #include <Library/DevicePathLib.h> 31 32 #include "FwBlockService.h" 33 34 ESAL_FWB_GLOBAL *mFvbModuleGlobal; 35 36 #define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS) 37 38 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = { 39 FVB_DEVICE_SIGNATURE, 40 { 41 { 42 { 43 HARDWARE_DEVICE_PATH, 44 HW_MEMMAP_DP, 45 { 46 sizeof (MEMMAP_DEVICE_PATH), 47 0 48 } 49 }, 50 EfiMemoryMappedIO, 51 0, 52 0, 53 }, 54 { 55 END_DEVICE_PATH_TYPE, 56 END_ENTIRE_DEVICE_PATH_SUBTYPE, 57 { 58 sizeof (EFI_DEVICE_PATH_PROTOCOL), 59 0 60 } 61 } 62 }, 63 0, 64 { 65 FvbProtocolGetAttributes, 66 FvbProtocolSetAttributes, 67 FvbProtocolGetPhysicalAddress, 68 FvbProtocolGetBlockSize, 69 FvbProtocolRead, 70 FvbProtocolWrite, 71 FvbProtocolEraseBlocks, 72 NULL 73 } 74 }; 75 76 77 78 VOID 79 EFIAPI 80 FvbVirtualddressChangeEvent ( 81 IN EFI_EVENT Event, 82 IN VOID *Context 83 ) 84 /*++ 85 86 Routine Description: 87 88 Fixup internal data so that EFI and SAL can be call in virtual mode. 89 Call the passed in Child Notify event and convert the mFvbModuleGlobal 90 date items to there virtual address. 91 92 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data 93 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common 94 instance data. 95 96 Arguments: 97 98 (Standard EFI notify event - EFI_EVENT_NOTIFY) 99 100 Returns: 101 102 None 103 104 **/ 105 { 106 EFI_FW_VOL_INSTANCE *FwhInstance; 107 UINTN Index; 108 109 EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]); 110 111 // 112 // Convert the base address of all the instances 113 // 114 Index = 0; 115 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]; 116 while (Index < mFvbModuleGlobal->NumFv) { 117 EfiConvertPointer (0x0, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]); 118 FwhInstance = (EFI_FW_VOL_INSTANCE *) 119 ( 120 (UINTN) ((UINT8 *) FwhInstance) + FwhInstance->VolumeHeader.HeaderLength + 121 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)) 122 ); 123 Index++; 124 } 125 126 EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal); 127 } 128 129 EFI_STATUS 130 GetFvbInstance ( 131 IN UINTN Instance, 132 IN ESAL_FWB_GLOBAL *Global, 133 OUT EFI_FW_VOL_INSTANCE **FwhInstance, 134 IN BOOLEAN Virtual 135 ) 136 /*++ 137 138 Routine Description: 139 Retrieves the physical address of a memory mapped FV 140 141 Arguments: 142 Instance - The FV instance whose base address is going to be 143 returned 144 Global - Pointer to ESAL_FWB_GLOBAL that contains all 145 instance data 146 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure 147 Virtual - Whether CPU is in virtual or physical mode 148 149 Returns: 150 EFI_SUCCESS - Successfully returns 151 EFI_INVALID_PARAMETER - Instance not found 152 153 **/ 154 { 155 EFI_FW_VOL_INSTANCE *FwhRecord; 156 157 if (Instance >= Global->NumFv) { 158 return EFI_INVALID_PARAMETER; 159 } 160 // 161 // Find the right instance of the FVB private data 162 // 163 FwhRecord = Global->FvInstance[Virtual]; 164 while (Instance > 0) { 165 FwhRecord = (EFI_FW_VOL_INSTANCE *) 166 ( 167 (UINTN) ((UINT8 *) FwhRecord) + FwhRecord->VolumeHeader.HeaderLength + 168 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)) 169 ); 170 Instance--; 171 } 172 173 *FwhInstance = FwhRecord; 174 175 return EFI_SUCCESS; 176 } 177 178 EFI_STATUS 179 FvbGetPhysicalAddress ( 180 IN UINTN Instance, 181 OUT EFI_PHYSICAL_ADDRESS *Address, 182 IN ESAL_FWB_GLOBAL *Global, 183 IN BOOLEAN Virtual 184 ) 185 /*++ 186 187 Routine Description: 188 Retrieves the physical address of a memory mapped FV 189 190 Arguments: 191 Instance - The FV instance whose base address is going to be 192 returned 193 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS 194 that on successful return, contains the base address 195 of the firmware volume. 196 Global - Pointer to ESAL_FWB_GLOBAL that contains all 197 instance data 198 Virtual - Whether CPU is in virtual or physical mode 199 200 Returns: 201 EFI_SUCCESS - Successfully returns 202 EFI_INVALID_PARAMETER - Instance not found 203 204 **/ 205 { 206 EFI_FW_VOL_INSTANCE *FwhInstance = NULL; 207 EFI_STATUS Status; 208 209 // 210 // Find the right instance of the FVB private data 211 // 212 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); 213 ASSERT_EFI_ERROR (Status); 214 *Address = FwhInstance->FvBase[Virtual]; 215 216 return EFI_SUCCESS; 217 } 218 219 EFI_STATUS 220 FvbGetVolumeAttributes ( 221 IN UINTN Instance, 222 OUT EFI_FVB_ATTRIBUTES_2 *Attributes, 223 IN ESAL_FWB_GLOBAL *Global, 224 IN BOOLEAN Virtual 225 ) 226 /*++ 227 228 Routine Description: 229 Retrieves attributes, insures positive polarity of attribute bits, returns 230 resulting attributes in output parameter 231 232 Arguments: 233 Instance - The FV instance whose attributes is going to be 234 returned 235 Attributes - Output buffer which contains attributes 236 Global - Pointer to ESAL_FWB_GLOBAL that contains all 237 instance data 238 Virtual - Whether CPU is in virtual or physical mode 239 240 Returns: 241 EFI_SUCCESS - Successfully returns 242 EFI_INVALID_PARAMETER - Instance not found 243 244 **/ 245 { 246 EFI_FW_VOL_INSTANCE *FwhInstance = NULL; 247 EFI_STATUS Status; 248 249 // 250 // Find the right instance of the FVB private data 251 // 252 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); 253 ASSERT_EFI_ERROR (Status); 254 *Attributes = FwhInstance->VolumeHeader.Attributes; 255 256 return EFI_SUCCESS; 257 } 258 259 EFI_STATUS 260 FvbGetLbaAddress ( 261 IN UINTN Instance, 262 IN EFI_LBA Lba, 263 OUT UINTN *LbaAddress, 264 OUT UINTN *LbaLength, 265 OUT UINTN *NumOfBlocks, 266 IN ESAL_FWB_GLOBAL *Global, 267 IN BOOLEAN Virtual 268 ) 269 /*++ 270 271 Routine Description: 272 Retrieves the starting address of an LBA in an FV 273 274 Arguments: 275 Instance - The FV instance which the Lba belongs to 276 Lba - The logical block address 277 LbaAddress - On output, contains the physical starting address 278 of the Lba 279 LbaLength - On output, contains the length of the block 280 NumOfBlocks - A pointer to a caller allocated UINTN in which the 281 number of consecutive blocks starting with Lba is 282 returned. All blocks in this range have a size of 283 BlockSize 284 Global - Pointer to ESAL_FWB_GLOBAL that contains all 285 instance data 286 Virtual - Whether CPU is in virtual or physical mode 287 288 Returns: 289 EFI_SUCCESS - Successfully returns 290 EFI_INVALID_PARAMETER - Instance not found 291 292 **/ 293 { 294 UINT32 NumBlocks; 295 UINT32 BlockLength; 296 UINTN Offset; 297 EFI_LBA StartLba; 298 EFI_LBA NextLba; 299 EFI_FW_VOL_INSTANCE *FwhInstance = NULL; 300 EFI_FV_BLOCK_MAP_ENTRY *BlockMap; 301 EFI_STATUS Status; 302 303 // 304 // Find the right instance of the FVB private data 305 // 306 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); 307 ASSERT_EFI_ERROR (Status); 308 309 StartLba = 0; 310 Offset = 0; 311 BlockMap = &(FwhInstance->VolumeHeader.BlockMap[0]); 312 313 // 314 // Parse the blockmap of the FV to find which map entry the Lba belongs to 315 // 316 while (TRUE) { 317 NumBlocks = BlockMap->NumBlocks; 318 BlockLength = BlockMap->Length; 319 320 if (NumBlocks == 0 || BlockLength == 0) { 321 return EFI_INVALID_PARAMETER; 322 } 323 324 NextLba = StartLba + NumBlocks; 325 326 // 327 // The map entry found 328 // 329 if (Lba >= StartLba && Lba < NextLba) { 330 Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength); 331 if (LbaAddress != NULL) { 332 *LbaAddress = FwhInstance->FvBase[Virtual] + Offset; 333 } 334 335 if (LbaLength != NULL) { 336 *LbaLength = BlockLength; 337 } 338 339 if (NumOfBlocks != NULL) { 340 *NumOfBlocks = (UINTN) (NextLba - Lba); 341 } 342 343 return EFI_SUCCESS; 344 } 345 346 StartLba = NextLba; 347 Offset = Offset + NumBlocks * BlockLength; 348 BlockMap++; 349 } 350 } 351 352 EFI_STATUS 353 FvbReadBlock ( 354 IN UINTN Instance, 355 IN EFI_LBA Lba, 356 IN UINTN BlockOffset, 357 IN OUT UINTN *NumBytes, 358 IN UINT8 *Buffer, 359 IN ESAL_FWB_GLOBAL *Global, 360 IN BOOLEAN Virtual 361 ) 362 /*++ 363 364 Routine Description: 365 Reads specified number of bytes into a buffer from the specified block 366 367 Arguments: 368 Instance - The FV instance to be read from 369 Lba - The logical block address to be read from 370 BlockOffset - Offset into the block at which to begin reading 371 NumBytes - Pointer that on input contains the total size of 372 the buffer. On output, it contains the total number 373 of bytes read 374 Buffer - Pointer to a caller allocated buffer that will be 375 used to hold the data read 376 Global - Pointer to ESAL_FWB_GLOBAL that contains all 377 instance data 378 Virtual - Whether CPU is in virtual or physical mode 379 380 Returns: 381 EFI_SUCCESS - The firmware volume was read successfully and 382 contents are in Buffer 383 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output, 384 NumBytes contains the total number of bytes returned 385 in Buffer 386 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state 387 EFI_DEVICE_ERROR - The block device is not functioning correctly and 388 could not be read 389 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL 390 391 **/ 392 { 393 EFI_FVB_ATTRIBUTES_2 Attributes; 394 UINTN LbaAddress; 395 UINTN LbaLength; 396 EFI_STATUS Status; 397 398 // 399 // Check for invalid conditions 400 // 401 if ((NumBytes == NULL) || (Buffer == NULL)) { 402 return EFI_INVALID_PARAMETER; 403 } 404 405 if (*NumBytes == 0) { 406 return EFI_INVALID_PARAMETER; 407 } 408 409 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual); 410 if (EFI_ERROR (Status)) { 411 return Status; 412 } 413 // 414 // Check if the FV is read enabled 415 // 416 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual); 417 418 if ((Attributes & EFI_FVB2_READ_STATUS) == 0) { 419 return EFI_ACCESS_DENIED; 420 } 421 // 422 // Perform boundary checks and adjust NumBytes 423 // 424 if (BlockOffset > LbaLength) { 425 return EFI_INVALID_PARAMETER; 426 } 427 428 if (LbaLength < (*NumBytes + BlockOffset)) { 429 *NumBytes = (UINT32) (LbaLength - BlockOffset); 430 Status = EFI_BAD_BUFFER_SIZE; 431 } 432 433 CopyMem (Buffer, (UINT8 *) (LbaAddress + BlockOffset), (UINTN) (*NumBytes)); 434 435 return Status; 436 } 437 438 EFI_STATUS 439 FvbWriteBlock ( 440 IN UINTN Instance, 441 IN EFI_LBA Lba, 442 IN UINTN BlockOffset, 443 IN OUT UINTN *NumBytes, 444 IN UINT8 *Buffer, 445 IN ESAL_FWB_GLOBAL *Global, 446 IN BOOLEAN Virtual 447 ) 448 /*++ 449 450 Routine Description: 451 Writes specified number of bytes from the input buffer to the block 452 453 Arguments: 454 Instance - The FV instance to be written to 455 Lba - The starting logical block index to write to 456 BlockOffset - Offset into the block at which to begin writing 457 NumBytes - Pointer that on input contains the total size of 458 the buffer. On output, it contains the total number 459 of bytes actually written 460 Buffer - Pointer to a caller allocated buffer that contains 461 the source for the write 462 Global - Pointer to ESAL_FWB_GLOBAL that contains all 463 instance data 464 Virtual - Whether CPU is in virtual or physical mode 465 466 Returns: 467 EFI_SUCCESS - The firmware volume was written successfully 468 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output, 469 NumBytes contains the total number of bytes 470 actually written 471 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state 472 EFI_DEVICE_ERROR - The block device is not functioning correctly and 473 could not be written 474 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL 475 476 **/ 477 { 478 EFI_FVB_ATTRIBUTES_2 Attributes; 479 UINTN LbaAddress; 480 UINTN LbaLength; 481 EFI_STATUS Status; 482 483 // 484 // Check for invalid conditions 485 // 486 if ((NumBytes == NULL) || (Buffer == NULL)) { 487 return EFI_INVALID_PARAMETER; 488 } 489 490 if (*NumBytes == 0) { 491 return EFI_INVALID_PARAMETER; 492 } 493 494 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual); 495 if (EFI_ERROR (Status)) { 496 return Status; 497 } 498 // 499 // Check if the FV is write enabled 500 // 501 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual); 502 503 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) { 504 return EFI_ACCESS_DENIED; 505 } 506 // 507 // Perform boundary checks and adjust NumBytes 508 // 509 if (BlockOffset > LbaLength) { 510 return EFI_INVALID_PARAMETER; 511 } 512 513 if (LbaLength < (*NumBytes + BlockOffset)) { 514 *NumBytes = (UINT32) (LbaLength - BlockOffset); 515 Status = EFI_BAD_BUFFER_SIZE; 516 } 517 // 518 // Write data 519 // 520 CopyMem ((UINT8 *) (LbaAddress + BlockOffset), Buffer, (UINTN) (*NumBytes)); 521 522 return Status; 523 } 524 525 EFI_STATUS 526 FvbEraseBlock ( 527 IN UINTN Instance, 528 IN EFI_LBA Lba, 529 IN ESAL_FWB_GLOBAL *Global, 530 IN BOOLEAN Virtual 531 ) 532 /*++ 533 534 Routine Description: 535 Erases and initializes a firmware volume block 536 537 Arguments: 538 Instance - The FV instance to be erased 539 Lba - The logical block index to be erased 540 Global - Pointer to ESAL_FWB_GLOBAL that contains all 541 instance data 542 Virtual - Whether CPU is in virtual or physical mode 543 544 Returns: 545 EFI_SUCCESS - The erase request was successfully completed 546 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state 547 EFI_DEVICE_ERROR - The block device is not functioning correctly and 548 could not be written. Firmware device may have been 549 partially erased 550 EFI_INVALID_PARAMETER - Instance not found 551 552 **/ 553 { 554 555 EFI_FVB_ATTRIBUTES_2 Attributes; 556 UINTN LbaAddress; 557 UINTN LbaLength; 558 EFI_STATUS Status; 559 UINT8 Data; 560 561 // 562 // Check if the FV is write enabled 563 // 564 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual); 565 566 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) { 567 return EFI_ACCESS_DENIED; 568 } 569 // 570 // Get the starting address of the block for erase. 571 // 572 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual); 573 574 if (EFI_ERROR (Status)) { 575 return Status; 576 } 577 578 if ((Attributes & EFI_FVB2_ERASE_POLARITY) != 0) { 579 Data = 0xFF; 580 } else { 581 Data = 0x0; 582 } 583 584 SetMem ((UINT8 *) LbaAddress, LbaLength, Data); 585 586 return EFI_SUCCESS; 587 } 588 589 EFI_STATUS 590 FvbSetVolumeAttributes ( 591 IN UINTN Instance, 592 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes, 593 IN ESAL_FWB_GLOBAL *Global, 594 IN BOOLEAN Virtual 595 ) 596 /*++ 597 598 Routine Description: 599 Modifies the current settings of the firmware volume according to the 600 input parameter, and returns the new setting of the volume 601 602 Arguments: 603 Instance - The FV instance whose attributes is going to be 604 modified 605 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2 606 containing the desired firmware volume settings. 607 On successful return, it contains the new settings 608 of the firmware volume 609 Global - Pointer to ESAL_FWB_GLOBAL that contains all 610 instance data 611 Virtual - Whether CPU is in virtual or physical mode 612 613 Returns: 614 EFI_SUCCESS - Successfully returns 615 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified 616 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are 617 in conflict with the capabilities as declared in the 618 firmware volume header 619 620 **/ 621 { 622 EFI_FW_VOL_INSTANCE *FwhInstance = NULL; 623 EFI_FVB_ATTRIBUTES_2 OldAttributes; 624 EFI_FVB_ATTRIBUTES_2 *AttribPtr; 625 UINT32 Capabilities; 626 UINT32 OldStatus; 627 UINT32 NewStatus; 628 EFI_STATUS Status; 629 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes; 630 631 632 // 633 // Find the right instance of the FVB private data 634 // 635 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); 636 ASSERT_EFI_ERROR (Status); 637 638 AttribPtr = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes); 639 OldAttributes = *AttribPtr; 640 Capabilities = OldAttributes & (EFI_FVB2_READ_DISABLED_CAP | \ 641 EFI_FVB2_READ_ENABLED_CAP | \ 642 EFI_FVB2_WRITE_DISABLED_CAP | \ 643 EFI_FVB2_WRITE_ENABLED_CAP | \ 644 EFI_FVB2_LOCK_CAP \ 645 ); 646 647 OldStatus = OldAttributes & EFI_FVB2_STATUS; 648 NewStatus = *Attributes & EFI_FVB2_STATUS; 649 UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \ 650 EFI_FVB2_READ_ENABLED_CAP | \ 651 EFI_FVB2_WRITE_DISABLED_CAP | \ 652 EFI_FVB2_WRITE_ENABLED_CAP | \ 653 EFI_FVB2_LOCK_CAP | \ 654 EFI_FVB2_STICKY_WRITE | \ 655 EFI_FVB2_MEMORY_MAPPED | \ 656 EFI_FVB2_ERASE_POLARITY | \ 657 EFI_FVB2_READ_LOCK_CAP | \ 658 EFI_FVB2_WRITE_LOCK_CAP | \ 659 EFI_FVB2_ALIGNMENT; 660 661 // 662 // Some attributes of FV is read only can *not* be set 663 // 664 if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) { 665 return EFI_INVALID_PARAMETER; 666 } 667 668 // 669 // If firmware volume is locked, no status bit can be updated 670 // 671 if (OldAttributes & EFI_FVB2_LOCK_STATUS) { 672 if (OldStatus ^ NewStatus) { 673 return EFI_ACCESS_DENIED; 674 } 675 } 676 // 677 // Test read disable 678 // 679 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) { 680 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) { 681 return EFI_INVALID_PARAMETER; 682 } 683 } 684 // 685 // Test read enable 686 // 687 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) { 688 if (NewStatus & EFI_FVB2_READ_STATUS) { 689 return EFI_INVALID_PARAMETER; 690 } 691 } 692 // 693 // Test write disable 694 // 695 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) { 696 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) { 697 return EFI_INVALID_PARAMETER; 698 } 699 } 700 // 701 // Test write enable 702 // 703 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) { 704 if (NewStatus & EFI_FVB2_WRITE_STATUS) { 705 return EFI_INVALID_PARAMETER; 706 } 707 } 708 // 709 // Test lock 710 // 711 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) { 712 if (NewStatus & EFI_FVB2_LOCK_STATUS) { 713 return EFI_INVALID_PARAMETER; 714 } 715 } 716 717 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS)); 718 *AttribPtr = (*AttribPtr) | NewStatus; 719 *Attributes = *AttribPtr; 720 721 return EFI_SUCCESS; 722 } 723 // 724 // FVB protocol APIs 725 // 726 EFI_STATUS 727 EFIAPI 728 FvbProtocolGetPhysicalAddress ( 729 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 730 OUT EFI_PHYSICAL_ADDRESS *Address 731 ) 732 /*++ 733 734 Routine Description: 735 736 Retrieves the physical address of the device. 737 738 Arguments: 739 740 This - Calling context 741 Address - Output buffer containing the address. 742 743 Returns: 744 745 Returns: 746 EFI_SUCCESS - Successfully returns 747 748 **/ 749 { 750 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 751 752 FvbDevice = FVB_DEVICE_FROM_THIS (This); 753 754 return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ()); 755 } 756 757 EFI_STATUS 758 EFIAPI 759 FvbProtocolGetBlockSize ( 760 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 761 IN EFI_LBA Lba, 762 OUT UINTN *BlockSize, 763 OUT UINTN *NumOfBlocks 764 ) 765 /*++ 766 767 Routine Description: 768 Retrieve the size of a logical block 769 770 Arguments: 771 This - Calling context 772 Lba - Indicates which block to return the size for. 773 BlockSize - A pointer to a caller allocated UINTN in which 774 the size of the block is returned 775 NumOfBlocks - a pointer to a caller allocated UINTN in which the 776 number of consecutive blocks starting with Lba is 777 returned. All blocks in this range have a size of 778 BlockSize 779 780 Returns: 781 EFI_SUCCESS - The firmware volume was read successfully and 782 contents are in Buffer 783 784 **/ 785 { 786 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 787 788 FvbDevice = FVB_DEVICE_FROM_THIS (This); 789 790 return FvbGetLbaAddress ( 791 FvbDevice->Instance, 792 Lba, 793 NULL, 794 BlockSize, 795 NumOfBlocks, 796 mFvbModuleGlobal, 797 EfiGoneVirtual () 798 ); 799 } 800 801 EFI_STATUS 802 EFIAPI 803 FvbProtocolGetAttributes ( 804 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 805 OUT EFI_FVB_ATTRIBUTES_2 *Attributes 806 ) 807 /*++ 808 809 Routine Description: 810 Retrieves Volume attributes. No polarity translations are done. 811 812 Arguments: 813 This - Calling context 814 Attributes - output buffer which contains attributes 815 816 Returns: 817 EFI_SUCCESS - Successfully returns 818 819 **/ 820 { 821 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 822 823 FvbDevice = FVB_DEVICE_FROM_THIS (This); 824 825 return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ()); 826 } 827 828 EFI_STATUS 829 EFIAPI 830 FvbProtocolSetAttributes ( 831 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 832 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes 833 ) 834 /*++ 835 836 Routine Description: 837 Sets Volume attributes. No polarity translations are done. 838 839 Arguments: 840 This - Calling context 841 Attributes - output buffer which contains attributes 842 843 Returns: 844 EFI_SUCCESS - Successfully returns 845 846 **/ 847 { 848 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 849 850 FvbDevice = FVB_DEVICE_FROM_THIS (This); 851 852 return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ()); 853 } 854 855 EFI_STATUS 856 EFIAPI 857 FvbProtocolEraseBlocks ( 858 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 859 ... 860 ) 861 /*++ 862 863 Routine Description: 864 865 The EraseBlock() function erases one or more blocks as denoted by the 866 variable argument list. The entire parameter list of blocks must be verified 867 prior to erasing any blocks. If a block is requested that does not exist 868 within the associated firmware volume (it has a larger index than the last 869 block of the firmware volume), the EraseBlock() function must return 870 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume. 871 872 Arguments: 873 This - Calling context 874 ... - Starting LBA followed by Number of Lba to erase. 875 a -1 to terminate the list. 876 877 Returns: 878 EFI_SUCCESS - The erase request was successfully completed 879 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state 880 EFI_DEVICE_ERROR - The block device is not functioning correctly and 881 could not be written. Firmware device may have been 882 partially erased 883 884 **/ 885 { 886 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 887 EFI_FW_VOL_INSTANCE *FwhInstance = NULL; 888 UINTN NumOfBlocks; 889 VA_LIST args; 890 EFI_LBA StartingLba; 891 UINTN NumOfLba; 892 EFI_STATUS Status; 893 894 FvbDevice = FVB_DEVICE_FROM_THIS (This); 895 896 Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ()); 897 ASSERT_EFI_ERROR (Status); 898 899 NumOfBlocks = FwhInstance->NumOfBlocks; 900 901 VA_START (args, This); 902 903 do { 904 StartingLba = VA_ARG (args, EFI_LBA); 905 if (StartingLba == EFI_LBA_LIST_TERMINATOR) { 906 break; 907 } 908 909 NumOfLba = VA_ARG (args, UINT32); 910 911 // 912 // Check input parameters 913 // 914 if (NumOfLba == 0 || (StartingLba + NumOfLba) > NumOfBlocks) { 915 VA_END (args); 916 return EFI_INVALID_PARAMETER; 917 } 918 } while (1); 919 920 VA_END (args); 921 922 VA_START (args, This); 923 do { 924 StartingLba = VA_ARG (args, EFI_LBA); 925 if (StartingLba == EFI_LBA_LIST_TERMINATOR) { 926 break; 927 } 928 929 NumOfLba = VA_ARG (args, UINT32); 930 931 while (NumOfLba > 0) { 932 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ()); 933 if (EFI_ERROR (Status)) { 934 VA_END (args); 935 return Status; 936 } 937 938 StartingLba++; 939 NumOfLba--; 940 } 941 942 } while (1); 943 944 VA_END (args); 945 946 return EFI_SUCCESS; 947 } 948 949 EFI_STATUS 950 EFIAPI 951 FvbProtocolWrite ( 952 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 953 IN EFI_LBA Lba, 954 IN UINTN Offset, 955 IN OUT UINTN *NumBytes, 956 IN UINT8 *Buffer 957 ) 958 /*++ 959 960 Routine Description: 961 962 Writes data beginning at Lba:Offset from FV. The write terminates either 963 when *NumBytes of data have been written, or when a block boundary is 964 reached. *NumBytes is updated to reflect the actual number of bytes 965 written. The write opertion does not include erase. This routine will 966 attempt to write only the specified bytes. If the writes do not stick, 967 it will return an error. 968 969 Arguments: 970 This - Calling context 971 Lba - Block in which to begin write 972 Offset - Offset in the block at which to begin write 973 NumBytes - On input, indicates the requested write size. On 974 output, indicates the actual number of bytes written 975 Buffer - Buffer containing source data for the write. 976 977 Returns: 978 EFI_SUCCESS - The firmware volume was written successfully 979 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output, 980 NumBytes contains the total number of bytes 981 actually written 982 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state 983 EFI_DEVICE_ERROR - The block device is not functioning correctly and 984 could not be written 985 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL 986 987 **/ 988 { 989 990 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 991 992 FvbDevice = FVB_DEVICE_FROM_THIS (This); 993 994 return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ()); 995 } 996 997 EFI_STATUS 998 EFIAPI 999 FvbProtocolRead ( 1000 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 1001 IN EFI_LBA Lba, 1002 IN UINTN Offset, 1003 IN OUT UINTN *NumBytes, 1004 IN UINT8 *Buffer 1005 ) 1006 /*++ 1007 1008 Routine Description: 1009 1010 Reads data beginning at Lba:Offset from FV. The Read terminates either 1011 when *NumBytes of data have been read, or when a block boundary is 1012 reached. *NumBytes is updated to reflect the actual number of bytes 1013 written. The write opertion does not include erase. This routine will 1014 attempt to write only the specified bytes. If the writes do not stick, 1015 it will return an error. 1016 1017 Arguments: 1018 This - Calling context 1019 Lba - Block in which to begin Read 1020 Offset - Offset in the block at which to begin Read 1021 NumBytes - On input, indicates the requested write size. On 1022 output, indicates the actual number of bytes Read 1023 Buffer - Buffer containing source data for the Read. 1024 1025 Returns: 1026 EFI_SUCCESS - The firmware volume was read successfully and 1027 contents are in Buffer 1028 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output, 1029 NumBytes contains the total number of bytes returned 1030 in Buffer 1031 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state 1032 EFI_DEVICE_ERROR - The block device is not functioning correctly and 1033 could not be read 1034 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL 1035 1036 **/ 1037 { 1038 1039 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 1040 1041 FvbDevice = FVB_DEVICE_FROM_THIS (This); 1042 1043 return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ()); 1044 } 1045 EFI_STATUS 1046 ValidateFvHeader ( 1047 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader 1048 ) 1049 /*++ 1050 1051 Routine Description: 1052 Check the integrity of firmware volume header 1053 1054 Arguments: 1055 FwVolHeader - A pointer to a firmware volume header 1056 1057 Returns: 1058 EFI_SUCCESS - The firmware volume is consistent 1059 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV 1060 1061 **/ 1062 { 1063 UINT16 *Ptr; 1064 UINT16 HeaderLength; 1065 UINT16 Checksum; 1066 1067 // 1068 // Verify the header revision, header signature, length 1069 // Length of FvBlock cannot be 2**64-1 1070 // HeaderLength cannot be an odd number 1071 // 1072 if ((FwVolHeader->Revision != EFI_FVH_REVISION) || 1073 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) || 1074 (FwVolHeader->FvLength == ((UINTN) -1)) || 1075 ((FwVolHeader->HeaderLength & 0x01) != 0) 1076 ) { 1077 return EFI_NOT_FOUND; 1078 } 1079 // 1080 // Verify the header checksum 1081 // 1082 HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2); 1083 Ptr = (UINT16 *) FwVolHeader; 1084 Checksum = 0; 1085 while (HeaderLength > 0) { 1086 Checksum = Checksum + (*Ptr); 1087 HeaderLength--; 1088 Ptr++; 1089 } 1090 1091 if (Checksum != 0) { 1092 return EFI_NOT_FOUND; 1093 } 1094 1095 return EFI_SUCCESS; 1096 } 1097 1098 EFI_STATUS 1099 EFIAPI 1100 FvbInitialize ( 1101 IN EFI_HANDLE ImageHandle, 1102 IN EFI_SYSTEM_TABLE *SystemTable 1103 ) 1104 /*++ 1105 1106 Routine Description: 1107 This function does common initialization for FVB services 1108 1109 Arguments: 1110 1111 Returns: 1112 1113 **/ 1114 { 1115 EFI_STATUS Status; 1116 EFI_FW_VOL_INSTANCE *FwhInstance = NULL; 1117 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; 1118 EFI_DXE_SERVICES *DxeServices; 1119 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; 1120 UINT32 BufferSize; 1121 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; 1122 EFI_HANDLE FwbHandle; 1123 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 1124 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface; 1125 EFI_DEVICE_PATH_PROTOCOL *TempFwbDevicePath; 1126 FV_DEVICE_PATH TempFvbDevicePathData; 1127 UINT32 MaxLbaSize; 1128 EFI_PHYSICAL_ADDRESS BaseAddress; 1129 UINT64 Length; 1130 UINTN NumOfBlocks; 1131 EFI_PEI_HOB_POINTERS FvHob; 1132 1133 // 1134 // Get the DXE services table 1135 // 1136 DxeServices = gDS; 1137 1138 // 1139 // Allocate runtime services data for global variable, which contains 1140 // the private data of all firmware volume block instances 1141 // 1142 Status = gBS->AllocatePool ( 1143 EfiRuntimeServicesData, 1144 sizeof (ESAL_FWB_GLOBAL), 1145 (VOID**) &mFvbModuleGlobal 1146 ); 1147 ASSERT_EFI_ERROR (Status); 1148 1149 // 1150 // Calculate the total size for all firmware volume block instances 1151 // 1152 BufferSize = 0; 1153 1154 FvHob.Raw = GetHobList (); 1155 while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) { 1156 BaseAddress = FvHob.FirmwareVolume->BaseAddress; 1157 Length = FvHob.FirmwareVolume->Length; 1158 // 1159 // Check if it is a "real" flash 1160 // 1161 Status = DxeServices->GetMemorySpaceDescriptor ( 1162 BaseAddress, 1163 &Descriptor 1164 ); 1165 if (EFI_ERROR (Status)) { 1166 break; 1167 } 1168 1169 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) { 1170 FvHob.Raw = GET_NEXT_HOB (FvHob); 1171 continue; 1172 } 1173 1174 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress; 1175 Status = ValidateFvHeader (FwVolHeader); 1176 if (EFI_ERROR (Status)) { 1177 // 1178 // Get FvbInfo 1179 // 1180 Status = GetFvbInfo (Length, &FwVolHeader); 1181 if (EFI_ERROR (Status)) { 1182 FvHob.Raw = GET_NEXT_HOB (FvHob); 1183 continue; 1184 } 1185 } 1186 1187 BufferSize += (sizeof (EFI_FW_VOL_INSTANCE) + FwVolHeader->HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER)); 1188 FvHob.Raw = GET_NEXT_HOB (FvHob); 1189 } 1190 1191 // 1192 // Only need to allocate once. There is only one copy of physical memory for 1193 // the private data of each FV instance. But in virtual mode or in physical 1194 // mode, the address of the the physical memory may be different. 1195 // 1196 Status = gBS->AllocatePool ( 1197 EfiRuntimeServicesData, 1198 BufferSize, 1199 (VOID**) &mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] 1200 ); 1201 ASSERT_EFI_ERROR (Status); 1202 1203 // 1204 // Make a virtual copy of the FvInstance pointer. 1205 // 1206 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]; 1207 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance; 1208 1209 mFvbModuleGlobal->NumFv = 0; 1210 MaxLbaSize = 0; 1211 1212 FvHob.Raw = GetHobList (); 1213 while (NULL != (FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw))) { 1214 BaseAddress = FvHob.FirmwareVolume->BaseAddress; 1215 Length = FvHob.FirmwareVolume->Length; 1216 // 1217 // Check if it is a "real" flash 1218 // 1219 Status = DxeServices->GetMemorySpaceDescriptor ( 1220 BaseAddress, 1221 &Descriptor 1222 ); 1223 if (EFI_ERROR (Status)) { 1224 break; 1225 } 1226 1227 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) { 1228 FvHob.Raw = GET_NEXT_HOB (FvHob); 1229 continue; 1230 } 1231 1232 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress; 1233 Status = ValidateFvHeader (FwVolHeader); 1234 if (EFI_ERROR (Status)) { 1235 // 1236 // Get FvbInfo to provide in FwhInstance. 1237 // 1238 Status = GetFvbInfo (Length, &FwVolHeader); 1239 if (EFI_ERROR (Status)) { 1240 FvHob.Raw = GET_NEXT_HOB (FvHob); 1241 continue; 1242 } 1243 // 1244 // Write healthy FV header back. 1245 // 1246 CopyMem ( 1247 (VOID *) (UINTN) BaseAddress, 1248 (VOID *) FwVolHeader, 1249 FwVolHeader->HeaderLength 1250 ); 1251 } 1252 1253 FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress; 1254 FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress; 1255 1256 CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength); 1257 FwVolHeader = &(FwhInstance->VolumeHeader); 1258 EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL); 1259 1260 NumOfBlocks = 0; 1261 1262 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) { 1263 // 1264 // Get the maximum size of a block. The size will be used to allocate 1265 // buffer for Scratch space, the intermediate buffer for FVB extension 1266 // protocol 1267 // 1268 if (MaxLbaSize < PtrBlockMapEntry->Length) { 1269 MaxLbaSize = PtrBlockMapEntry->Length; 1270 } 1271 1272 NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks; 1273 } 1274 // 1275 // The total number of blocks in the FV. 1276 // 1277 FwhInstance->NumOfBlocks = NumOfBlocks; 1278 1279 // 1280 // Add a FVB Protocol Instance 1281 // 1282 Status = gBS->AllocatePool ( 1283 EfiRuntimeServicesData, 1284 sizeof (EFI_FW_VOL_BLOCK_DEVICE), 1285 (VOID**) &FvbDevice 1286 ); 1287 ASSERT_EFI_ERROR (Status); 1288 1289 CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE)); 1290 1291 FvbDevice->Instance = mFvbModuleGlobal->NumFv; 1292 mFvbModuleGlobal->NumFv++; 1293 1294 // 1295 // Set up the devicepath 1296 // 1297 FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress; 1298 FvbDevice->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1); 1299 1300 // 1301 // Find a handle with a matching device path that has supports FW Block protocol 1302 // 1303 TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData; 1304 CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH)); 1305 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle); 1306 if (EFI_ERROR (Status)) { 1307 // 1308 // LocateDevicePath fails so install a new interface and device path 1309 // 1310 FwbHandle = NULL; 1311 Status = gBS->InstallMultipleProtocolInterfaces ( 1312 &FwbHandle, 1313 &gEfiFirmwareVolumeBlockProtocolGuid, 1314 &FvbDevice->FwVolBlockInstance, 1315 &gEfiDevicePathProtocolGuid, 1316 &FvbDevice->DevicePath, 1317 NULL 1318 ); 1319 ASSERT_EFI_ERROR (Status); 1320 } else if (IsDevicePathEnd (TempFwbDevicePath)) { 1321 // 1322 // Device allready exists, so reinstall the FVB protocol 1323 // 1324 Status = gBS->HandleProtocol ( 1325 FwbHandle, 1326 &gEfiFirmwareVolumeBlockProtocolGuid, 1327 (VOID**)&OldFwbInterface 1328 ); 1329 ASSERT_EFI_ERROR (Status); 1330 1331 Status = gBS->ReinstallProtocolInterface ( 1332 FwbHandle, 1333 &gEfiFirmwareVolumeBlockProtocolGuid, 1334 OldFwbInterface, 1335 &FvbDevice->FwVolBlockInstance 1336 ); 1337 ASSERT_EFI_ERROR (Status); 1338 1339 } else { 1340 // 1341 // There was a FVB protocol on an End Device Path node 1342 // 1343 ASSERT (FALSE); 1344 } 1345 1346 FwhInstance = (EFI_FW_VOL_INSTANCE *) 1347 ( 1348 (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength + 1349 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)) 1350 ); 1351 1352 FvHob.Raw = GET_NEXT_HOB (FvHob); 1353 } 1354 1355 return EFI_SUCCESS; 1356 } 1357