1 /**@file 2 Copyright (c) 2007 - 2009, Intel Corporation. All rights reserved.<BR> 3 This program and the accompanying materials 4 are licensed and made available under the terms and conditions of the BSD License 5 which accompanies this distribution. The full text of the license may be found at 6 http://opensource.org/licenses/bsd-license.php 7 8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 10 11 Module Name: 12 13 FWBlockService.c 14 15 Abstract: 16 17 Revision History 18 19 **/ 20 #include "FWBlockService.h" 21 #include "EfiFlashMap.h" 22 #include "FileIo.h" 23 #include "FlashLayout.h" 24 25 ESAL_FWB_GLOBAL *mFvbModuleGlobal; 26 VOID *mSFSRegistration; 27 #define TRY_ASSIGN(var, value) if(var != NULL) {*var = value;} 28 29 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = { 30 FVB_DEVICE_SIGNATURE, 31 { 32 { 33 { 34 HARDWARE_DEVICE_PATH, 35 HW_MEMMAP_DP, 36 { 37 sizeof (MEMMAP_DEVICE_PATH), 38 0 39 } 40 }, 41 EfiMemoryMappedIO, 42 0, 43 0, 44 }, 45 { 46 END_DEVICE_PATH_TYPE, 47 END_ENTIRE_DEVICE_PATH_SUBTYPE, 48 { 49 sizeof (EFI_DEVICE_PATH_PROTOCOL), 50 0 51 } 52 } 53 }, 54 0, 55 { 56 FvbProtocolGetAttributes, 57 FvbProtocolSetAttributes, 58 FvbProtocolGetPhysicalAddress, 59 FvbProtocolGetBlockSize, 60 FvbProtocolRead, 61 FvbProtocolWrite, 62 FvbProtocolEraseBlocks, 63 NULL 64 } 65 }; 66 67 68 EFI_STATUS 69 FlashFdWrite ( 70 IN UINTN Address, 71 IN EFI_FW_VOL_INSTANCE *FwhInstance, 72 IN OUT UINTN *NumBytes, 73 IN UINT8 *Buffer 74 ) 75 /*++ 76 77 Routine Description: 78 Writes specified number of bytes from the input buffer to the address 79 80 Arguments: 81 82 Returns: 83 84 --*/ 85 { 86 EFI_STATUS Status; 87 EFI_FILE_PROTOCOL *File; 88 UINTN FileOffset; 89 UINTN BufferForFile; 90 UINTN Length; 91 92 Status = EFI_SUCCESS; 93 CopyMem ((VOID *) Address, Buffer, *NumBytes); 94 95 if (!EfiAtRuntime () && (FwhInstance->Device != NULL)) { 96 Status = FileOpen (FwhInstance->Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE); 97 ASSERT_EFI_ERROR (Status); 98 if (!EFI_ERROR (Status)) { 99 if (Address - FwhInstance->FvBase[FVB_PHYSICAL] < FwhInstance->Offset) { 100 FileOffset = 0; 101 BufferForFile = FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset; 102 Length = *NumBytes - (FwhInstance->Offset - (Address - FwhInstance->FvBase[FVB_PHYSICAL])); 103 } else { 104 FileOffset = Address - FwhInstance->FvBase[FVB_PHYSICAL] - FwhInstance->Offset; 105 BufferForFile = Address; 106 Length = *NumBytes; 107 } 108 109 Status = FileWrite (File, FileOffset, BufferForFile, Length); 110 ASSERT_EFI_ERROR (Status); 111 FileClose (File); 112 } 113 } 114 return Status; 115 } 116 117 EFI_STATUS 118 FlashFdErase ( 119 IN UINTN Address, 120 IN EFI_FW_VOL_INSTANCE *FwhInstance, 121 IN UINTN LbaLength 122 ) 123 /*++ 124 125 Routine Description: 126 Erase a certain block from address LbaWriteAddress 127 128 Arguments: 129 130 Returns: 131 132 --*/ 133 { 134 EFI_STATUS Status; 135 EFI_FILE_PROTOCOL *File; 136 UINTN FileOffset; 137 UINTN BufferForFile; 138 UINTN Length; 139 140 Status = EFI_SUCCESS; 141 142 SetMem ((VOID *)Address, LbaLength, 0xff); 143 144 if (!EfiAtRuntime () && (FwhInstance->Device != NULL)) { 145 Status = FileOpen (FwhInstance->Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE); 146 ASSERT_EFI_ERROR (Status); 147 if (!EFI_ERROR (Status)) { 148 if (Address - FwhInstance->FvBase[FVB_PHYSICAL] < FwhInstance->Offset) { 149 FileOffset = 0; 150 BufferForFile = FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset; 151 Length = LbaLength - (FwhInstance->Offset - (Address - FwhInstance->FvBase[FVB_PHYSICAL])); 152 } else { 153 FileOffset = Address - FwhInstance->FvBase[FVB_PHYSICAL] - FwhInstance->Offset; 154 BufferForFile = Address; 155 Length = LbaLength; 156 } 157 158 Status = FileWrite (File, FileOffset, BufferForFile, Length); 159 ASSERT_EFI_ERROR (Status); 160 FileClose (File); 161 } 162 } 163 return Status; 164 } 165 166 VOID 167 EFIAPI 168 FvbVirtualddressChangeEvent ( 169 IN EFI_EVENT Event, 170 IN VOID *Context 171 ) 172 /*++ 173 174 Routine Description: 175 176 Fixup internal data so that EFI and SAL can be call in virtual mode. 177 Call the passed in Child Notify event and convert the mFvbModuleGlobal 178 date items to there virtual address. 179 180 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data 181 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common 182 instance data. 183 184 Arguments: 185 186 (Standard EFI notify event - EFI_EVENT_NOTIFY) 187 188 Returns: 189 190 None 191 192 --*/ 193 { 194 EFI_FW_VOL_INSTANCE *FwhInstance; 195 UINTN Index; 196 197 EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]); 198 199 // 200 // Convert the base address of all the instances 201 // 202 Index = 0; 203 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]; 204 while (Index < mFvbModuleGlobal->NumFv) { 205 EfiConvertPointer (0, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]); 206 FwhInstance = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhInstance) + FwhInstance->VolumeHeader.HeaderLength 207 + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))); 208 Index++; 209 } 210 211 EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL]); 212 EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal); 213 } 214 215 EFI_STATUS 216 GetFvbInstance ( 217 IN UINTN Instance, 218 IN ESAL_FWB_GLOBAL *Global, 219 OUT EFI_FW_VOL_INSTANCE **FwhInstance, 220 IN BOOLEAN Virtual 221 ) 222 /*++ 223 224 Routine Description: 225 Retrieves the physical address of a memory mapped FV 226 227 Arguments: 228 Instance - The FV instance whose base address is going to be 229 returned 230 Global - Pointer to ESAL_FWB_GLOBAL that contains all 231 instance data 232 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure 233 Virtual - Whether CPU is in virtual or physical mode 234 235 Returns: 236 EFI_SUCCESS - Successfully returns 237 EFI_INVALID_PARAMETER - Instance not found 238 239 --*/ 240 { 241 EFI_FW_VOL_INSTANCE *FwhRecord; 242 243 if (Instance >= Global->NumFv) { 244 return EFI_INVALID_PARAMETER; 245 } 246 // 247 // Find the right instance of the FVB private data 248 // 249 FwhRecord = Global->FvInstance[Virtual]; 250 while (Instance > 0) { 251 FwhRecord = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhRecord) + FwhRecord->VolumeHeader.HeaderLength 252 + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))); 253 Instance--; 254 } 255 256 *FwhInstance = FwhRecord; 257 258 return EFI_SUCCESS; 259 } 260 261 EFI_STATUS 262 FvbGetPhysicalAddress ( 263 IN UINTN Instance, 264 OUT EFI_PHYSICAL_ADDRESS *Address, 265 IN ESAL_FWB_GLOBAL *Global, 266 IN BOOLEAN Virtual 267 ) 268 /*++ 269 270 Routine Description: 271 Retrieves the physical address of a memory mapped FV 272 273 Arguments: 274 Instance - The FV instance whose base address is going to be 275 returned 276 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS 277 that on successful return, contains the base address 278 of the firmware volume. 279 Global - Pointer to ESAL_FWB_GLOBAL that contains all 280 instance data 281 Virtual - Whether CPU is in virtual or physical mode 282 283 Returns: 284 EFI_SUCCESS - Successfully returns 285 EFI_INVALID_PARAMETER - Instance not found 286 287 --*/ 288 { 289 EFI_FW_VOL_INSTANCE *FwhInstance; 290 EFI_STATUS Status; 291 292 // 293 // Find the right instance of the FVB private data 294 // 295 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); 296 ASSERT_EFI_ERROR (Status); 297 *Address = FwhInstance->FvBase[Virtual]; 298 299 return EFI_SUCCESS; 300 } 301 302 EFI_STATUS 303 FvbGetVolumeAttributes ( 304 IN UINTN Instance, 305 OUT EFI_FVB_ATTRIBUTES_2 *Attributes, 306 IN ESAL_FWB_GLOBAL *Global, 307 IN BOOLEAN Virtual 308 ) 309 /*++ 310 311 Routine Description: 312 Retrieves attributes, insures positive polarity of attribute bits, returns 313 resulting attributes in output parameter 314 315 Arguments: 316 Instance - The FV instance whose attributes is going to be 317 returned 318 Attributes - Output buffer which contains attributes 319 Global - Pointer to ESAL_FWB_GLOBAL that contains all 320 instance data 321 Virtual - Whether CPU is in virtual or physical mode 322 323 Returns: 324 EFI_SUCCESS - Successfully returns 325 EFI_INVALID_PARAMETER - Instance not found 326 327 --*/ 328 { 329 EFI_FW_VOL_INSTANCE *FwhInstance; 330 EFI_STATUS Status; 331 332 // 333 // Find the right instance of the FVB private data 334 // 335 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); 336 ASSERT_EFI_ERROR (Status); 337 *Attributes = FwhInstance->VolumeHeader.Attributes; 338 339 return EFI_SUCCESS; 340 } 341 342 EFI_STATUS 343 FvbGetLbaAddress ( 344 IN UINTN Instance, 345 IN EFI_LBA Lba, 346 OUT UINTN *LbaAddress OPTIONAL, 347 OUT UINTN *LbaLength OPTIONAL, 348 OUT UINTN *NumOfBlocks OPTIONAL, 349 IN ESAL_FWB_GLOBAL *Global, 350 IN BOOLEAN Virtual 351 ) 352 /*++ 353 354 Routine Description: 355 Retrieves the starting address of an LBA in an FV 356 357 Arguments: 358 Instance - The FV instance which the Lba belongs to 359 Lba - The logical block address 360 LbaAddress - On output, contains the physical starting address 361 of the Lba for writing 362 LbaLength - On output, contains the length of the block 363 NumOfBlocks - A pointer to a caller allocated UINTN in which the 364 number of consecutive blocks starting with Lba is 365 returned. All blocks in this range have a size of 366 BlockSize 367 Global - Pointer to ESAL_FWB_GLOBAL that contains all 368 instance data 369 Virtual - Whether CPU is in virtual or physical mode 370 371 Returns: 372 EFI_SUCCESS - Successfully returns 373 EFI_INVALID_PARAMETER - Instance not found 374 375 --*/ 376 { 377 UINT32 NumBlocks; 378 UINT32 BlockLength; 379 UINTN Offset; 380 EFI_LBA StartLba; 381 EFI_LBA NextLba; 382 EFI_FW_VOL_INSTANCE *FwhInstance; 383 EFI_FV_BLOCK_MAP_ENTRY *BlockMap; 384 EFI_STATUS Status; 385 386 // 387 // Find the right instance of the FVB private data 388 // 389 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); 390 ASSERT_EFI_ERROR (Status); 391 392 StartLba = 0; 393 Offset = 0; 394 BlockMap = &(FwhInstance->VolumeHeader.BlockMap[0]); 395 396 // 397 // Parse the blockmap of the FV to find which map entry the Lba belongs to 398 // 399 while (TRUE) { 400 NumBlocks = BlockMap->NumBlocks; 401 BlockLength = BlockMap->Length; 402 403 if (NumBlocks == 0 || BlockLength == 0) { 404 return EFI_INVALID_PARAMETER; 405 } 406 407 NextLba = StartLba + NumBlocks; 408 409 // 410 // The map entry found 411 // 412 if (Lba >= StartLba && Lba < NextLba) { 413 Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength); 414 415 if (LbaAddress) { 416 *LbaAddress = FwhInstance->FvBase[Virtual] + Offset; 417 } 418 419 if (LbaLength) { 420 *LbaLength = BlockLength; 421 } 422 423 if (NumOfBlocks) { 424 *NumOfBlocks = (UINTN) (NextLba - Lba); 425 } 426 427 return EFI_SUCCESS; 428 } 429 430 StartLba = NextLba; 431 Offset = Offset + NumBlocks * BlockLength; 432 BlockMap++; 433 } 434 } 435 436 EFI_STATUS 437 FvbReadBlock ( 438 IN UINTN Instance, 439 IN EFI_LBA Lba, 440 IN UINTN BlockOffset, 441 IN OUT UINTN *NumBytes, 442 IN UINT8 *Buffer, 443 IN ESAL_FWB_GLOBAL *Global, 444 IN BOOLEAN Virtual 445 ) 446 /*++ 447 448 Routine Description: 449 Reads specified number of bytes into a buffer from the specified block 450 451 Arguments: 452 Instance - The FV instance to be read from 453 Lba - The logical block address to be read from 454 BlockOffset - Offset into the block at which to begin reading 455 NumBytes - Pointer that on input contains the total size of 456 the buffer. On output, it contains the total number 457 of bytes read 458 Buffer - Pointer to a caller allocated buffer that will be 459 used to hold the data read 460 Global - Pointer to ESAL_FWB_GLOBAL that contains all 461 instance data 462 Virtual - Whether CPU is in virtual or physical mode 463 464 Returns: 465 EFI_SUCCESS - The firmware volume was read successfully and 466 contents are in Buffer 467 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output, 468 NumBytes contains the total number of bytes returned 469 in Buffer 470 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state 471 EFI_DEVICE_ERROR - The block device is not functioning correctly and 472 could not be read 473 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL 474 475 --*/ 476 { 477 EFI_FVB_ATTRIBUTES_2 Attributes; 478 UINTN LbaAddress; 479 UINTN LbaLength; 480 EFI_STATUS Status; 481 482 // 483 // Check for invalid conditions 484 // 485 if ((NumBytes == NULL) || (Buffer == NULL)) { 486 return EFI_INVALID_PARAMETER; 487 } 488 489 if (*NumBytes == 0) { 490 return EFI_INVALID_PARAMETER; 491 } 492 493 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual); 494 if (EFI_ERROR (Status)) { 495 return Status; 496 } 497 // 498 // Check if the FV is read enabled 499 // 500 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual); 501 502 if ((Attributes & EFI_FVB2_READ_STATUS) == 0) { 503 return EFI_ACCESS_DENIED; 504 } 505 // 506 // Perform boundary checks and adjust NumBytes 507 // 508 if (BlockOffset > LbaLength) { 509 return EFI_INVALID_PARAMETER; 510 } 511 512 if (LbaLength < (*NumBytes + BlockOffset)) { 513 *NumBytes = (UINT32) (LbaLength - BlockOffset); 514 Status = EFI_BAD_BUFFER_SIZE; 515 } 516 517 CopyMem (Buffer, (VOID *) (LbaAddress + BlockOffset), (UINTN) *NumBytes); 518 519 return Status; 520 } 521 EFI_STATUS 522 FvbWriteBlock ( 523 IN UINTN Instance, 524 IN EFI_LBA Lba, 525 IN UINTN BlockOffset, 526 IN OUT UINTN *NumBytes, 527 IN UINT8 *Buffer, 528 IN ESAL_FWB_GLOBAL *Global, 529 IN BOOLEAN Virtual 530 ) 531 /*++ 532 533 Routine Description: 534 Writes specified number of bytes from the input buffer to the block 535 536 Arguments: 537 Instance - The FV instance to be written to 538 Lba - The starting logical block index to write to 539 BlockOffset - Offset into the block at which to begin writing 540 NumBytes - Pointer that on input contains the total size of 541 the buffer. On output, it contains the total number 542 of bytes actually written 543 Buffer - Pointer to a caller allocated buffer that contains 544 the source for the write 545 Global - Pointer to ESAL_FWB_GLOBAL that contains all 546 instance data 547 Virtual - Whether CPU is in virtual or physical mode 548 549 Returns: 550 EFI_SUCCESS - The firmware volume was written successfully 551 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output, 552 NumBytes contains the total number of bytes 553 actually written 554 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state 555 EFI_DEVICE_ERROR - The block device is not functioning correctly and 556 could not be written 557 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL 558 559 --*/ 560 { 561 EFI_FVB_ATTRIBUTES_2 Attributes; 562 UINTN LbaAddress; 563 UINTN LbaLength; 564 EFI_FW_VOL_INSTANCE *FwhInstance; 565 EFI_STATUS Status; 566 EFI_STATUS ReturnStatus; 567 568 // 569 // Find the right instance of the FVB private data 570 // 571 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); 572 ASSERT_EFI_ERROR (Status); 573 574 // 575 // Writes are enabled in the init routine itself 576 // 577 if (!FwhInstance->WriteEnabled) { 578 return EFI_ACCESS_DENIED; 579 } 580 // 581 // Check for invalid conditions 582 // 583 if ((NumBytes == NULL) || (Buffer == NULL)) { 584 return EFI_INVALID_PARAMETER; 585 } 586 587 if (*NumBytes == 0) { 588 return EFI_INVALID_PARAMETER; 589 } 590 591 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual); 592 if (EFI_ERROR (Status)) { 593 return Status; 594 } 595 // 596 // Check if the FV is write enabled 597 // 598 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual); 599 600 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) { 601 return EFI_ACCESS_DENIED; 602 } 603 // 604 // Perform boundary checks and adjust NumBytes 605 // 606 if (BlockOffset > LbaLength) { 607 return EFI_INVALID_PARAMETER; 608 } 609 610 if (LbaLength < (*NumBytes + BlockOffset)) { 611 *NumBytes = (UINT32) (LbaLength - BlockOffset); 612 Status = EFI_BAD_BUFFER_SIZE; 613 } 614 615 ReturnStatus = FlashFdWrite ( 616 LbaAddress + BlockOffset, 617 FwhInstance, 618 NumBytes, 619 Buffer 620 ); 621 if (EFI_ERROR (ReturnStatus)) { 622 return ReturnStatus; 623 } 624 625 return Status; 626 } 627 628 EFI_STATUS 629 FvbEraseBlock ( 630 IN UINTN Instance, 631 IN EFI_LBA Lba, 632 IN ESAL_FWB_GLOBAL *Global, 633 IN BOOLEAN Virtual 634 ) 635 /*++ 636 637 Routine Description: 638 Erases and initializes a firmware volume block 639 640 Arguments: 641 Instance - The FV instance to be erased 642 Lba - The logical block index to be erased 643 Global - Pointer to ESAL_FWB_GLOBAL that contains all 644 instance data 645 Virtual - Whether CPU is in virtual or physical mode 646 647 Returns: 648 EFI_SUCCESS - The erase request was successfully completed 649 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state 650 EFI_DEVICE_ERROR - The block device is not functioning correctly and 651 could not be written. Firmware device may have been 652 partially erased 653 EFI_INVALID_PARAMETER - Instance not found 654 655 --*/ 656 { 657 658 EFI_FVB_ATTRIBUTES_2 Attributes; 659 UINTN LbaAddress; 660 EFI_FW_VOL_INSTANCE *FwhInstance; 661 UINTN LbaLength; 662 EFI_STATUS Status; 663 664 // 665 // Find the right instance of the FVB private data 666 // 667 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); 668 ASSERT_EFI_ERROR (Status); 669 670 // 671 // Writes are enabled in the init routine itself 672 // 673 if (!FwhInstance->WriteEnabled) { 674 return EFI_ACCESS_DENIED; 675 } 676 // 677 // Check if the FV is write enabled 678 // 679 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual); 680 681 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) { 682 return EFI_ACCESS_DENIED; 683 } 684 // 685 // Get the starting address of the block for erase. For debug reasons, 686 // LbaWriteAddress may not be the same as LbaAddress. 687 // 688 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual); 689 if (EFI_ERROR (Status)) { 690 return Status; 691 } 692 693 return FlashFdErase ( 694 LbaAddress, 695 FwhInstance, 696 LbaLength 697 ); 698 } 699 700 EFI_STATUS 701 FvbSetVolumeAttributes ( 702 IN UINTN Instance, 703 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes, 704 IN ESAL_FWB_GLOBAL *Global, 705 IN BOOLEAN Virtual 706 ) 707 /*++ 708 709 Routine Description: 710 Modifies the current settings of the firmware volume according to the 711 input parameter, and returns the new setting of the volume 712 713 Arguments: 714 Instance - The FV instance whose attributes is going to be 715 modified 716 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2 717 containing the desired firmware volume settings. 718 On successful return, it contains the new settings 719 of the firmware volume 720 Global - Pointer to ESAL_FWB_GLOBAL that contains all 721 instance data 722 Virtual - Whether CPU is in virtual or physical mode 723 724 Returns: 725 EFI_SUCCESS - Successfully returns 726 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified 727 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are 728 in conflict with the capabilities as declared in the 729 firmware volume header 730 731 --*/ 732 { 733 EFI_FW_VOL_INSTANCE *FwhInstance; 734 EFI_FVB_ATTRIBUTES_2 OldAttributes; 735 EFI_FVB_ATTRIBUTES_2 *AttribPtr; 736 UINT32 Capabilities; 737 UINT32 OldStatus; 738 UINT32 NewStatus; 739 EFI_STATUS Status; 740 741 // 742 // Find the right instance of the FVB private data 743 // 744 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); 745 ASSERT_EFI_ERROR (Status); 746 747 AttribPtr = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes); 748 OldAttributes = *AttribPtr; 749 Capabilities = OldAttributes & EFI_FVB2_CAPABILITIES; 750 OldStatus = OldAttributes & EFI_FVB2_STATUS; 751 NewStatus = *Attributes & EFI_FVB2_STATUS; 752 753 // 754 // If firmware volume is locked, no status bit can be updated 755 // 756 if (OldAttributes & EFI_FVB2_LOCK_STATUS) { 757 if (OldStatus ^ NewStatus) { 758 return EFI_ACCESS_DENIED; 759 } 760 } 761 // 762 // Test read disable 763 // 764 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) { 765 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) { 766 return EFI_INVALID_PARAMETER; 767 } 768 } 769 // 770 // Test read enable 771 // 772 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) { 773 if (NewStatus & EFI_FVB2_READ_STATUS) { 774 return EFI_INVALID_PARAMETER; 775 } 776 } 777 // 778 // Test write disable 779 // 780 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) { 781 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) { 782 return EFI_INVALID_PARAMETER; 783 } 784 } 785 // 786 // Test write enable 787 // 788 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) { 789 if (NewStatus & EFI_FVB2_WRITE_STATUS) { 790 return EFI_INVALID_PARAMETER; 791 } 792 } 793 // 794 // Test lock 795 // 796 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) { 797 if (NewStatus & EFI_FVB2_LOCK_STATUS) { 798 return EFI_INVALID_PARAMETER; 799 } 800 } 801 802 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS)); 803 *AttribPtr = (*AttribPtr) | NewStatus; 804 *Attributes = *AttribPtr; 805 806 return EFI_SUCCESS; 807 } 808 // 809 // FVB protocol APIs 810 // 811 EFI_STATUS 812 EFIAPI 813 FvbProtocolGetPhysicalAddress ( 814 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 815 OUT EFI_PHYSICAL_ADDRESS *Address 816 ) 817 /*++ 818 819 Routine Description: 820 821 Retrieves the physical address of the device. 822 823 Arguments: 824 825 This - Calling context 826 Address - Output buffer containing the address. 827 828 Returns: 829 830 Returns: 831 EFI_SUCCESS - Successfully returns 832 833 --*/ 834 { 835 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 836 837 FvbDevice = FVB_DEVICE_FROM_THIS (This); 838 839 return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ()); 840 } 841 842 EFI_STATUS 843 EFIAPI 844 FvbProtocolGetBlockSize ( 845 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 846 IN EFI_LBA Lba, 847 OUT UINTN *BlockSize, 848 OUT UINTN *NumOfBlocks 849 ) 850 /*++ 851 852 Routine Description: 853 Retrieve the size of a logical block 854 855 Arguments: 856 This - Calling context 857 Lba - Indicates which block to return the size for. 858 BlockSize - A pointer to a caller allocated UINTN in which 859 the size of the block is returned 860 NumOfBlocks - a pointer to a caller allocated UINTN in which the 861 number of consecutive blocks starting with Lba is 862 returned. All blocks in this range have a size of 863 BlockSize 864 865 Returns: 866 EFI_SUCCESS - The firmware volume was read successfully and 867 contents are in Buffer 868 869 --*/ 870 { 871 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 872 873 FvbDevice = FVB_DEVICE_FROM_THIS (This); 874 875 return FvbGetLbaAddress ( 876 FvbDevice->Instance, 877 Lba, 878 NULL, 879 BlockSize, 880 NumOfBlocks, 881 mFvbModuleGlobal, 882 EfiGoneVirtual () 883 ); 884 } 885 886 EFI_STATUS 887 EFIAPI 888 FvbProtocolGetAttributes ( 889 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 890 OUT EFI_FVB_ATTRIBUTES_2 *Attributes 891 ) 892 /*++ 893 894 Routine Description: 895 Retrieves Volume attributes. No polarity translations are done. 896 897 Arguments: 898 This - Calling context 899 Attributes - output buffer which contains attributes 900 901 Returns: 902 EFI_SUCCESS - Successfully returns 903 904 --*/ 905 { 906 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 907 908 FvbDevice = FVB_DEVICE_FROM_THIS (This); 909 910 return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ()); 911 } 912 913 EFI_STATUS 914 EFIAPI 915 FvbProtocolSetAttributes ( 916 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 917 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes 918 ) 919 /*++ 920 921 Routine Description: 922 Sets Volume attributes. No polarity translations are done. 923 924 Arguments: 925 This - Calling context 926 Attributes - output buffer which contains attributes 927 928 Returns: 929 EFI_SUCCESS - Successfully returns 930 931 --*/ 932 { 933 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 934 935 FvbDevice = FVB_DEVICE_FROM_THIS (This); 936 937 return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ()); 938 } 939 940 EFI_STATUS 941 EFIAPI 942 FvbProtocolEraseBlocks ( 943 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 944 ... 945 ) 946 /*++ 947 948 Routine Description: 949 950 The EraseBlock() function erases one or more blocks as denoted by the 951 variable argument list. The entire parameter list of blocks must be verified 952 prior to erasing any blocks. If a block is requested that does not exist 953 within the associated firmware volume (it has a larger index than the last 954 block of the firmware volume), the EraseBlock() function must return 955 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume. 956 957 Arguments: 958 This - Calling context 959 ... - Starting LBA followed by Number of Lba to erase. 960 a -1 to terminate the list. 961 962 Returns: 963 EFI_SUCCESS - The erase request was successfully completed 964 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state 965 EFI_DEVICE_ERROR - The block device is not functioning correctly and 966 could not be written. Firmware device may have been 967 partially erased 968 969 --*/ 970 { 971 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 972 EFI_FW_VOL_INSTANCE *FwhInstance; 973 UINTN NumOfBlocks; 974 VA_LIST args; 975 EFI_LBA StartingLba; 976 UINTN NumOfLba; 977 EFI_STATUS Status; 978 979 FvbDevice = FVB_DEVICE_FROM_THIS (This); 980 981 Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ()); 982 ASSERT_EFI_ERROR (Status); 983 984 NumOfBlocks = FwhInstance->NumOfBlocks; 985 986 VA_START (args, This); 987 988 do { 989 StartingLba = VA_ARG (args, EFI_LBA); 990 if (StartingLba == EFI_LBA_LIST_TERMINATOR) { 991 break; 992 } 993 994 NumOfLba = VA_ARG (args, UINT32); 995 996 // 997 // Check input parameters 998 // 999 if ((NumOfLba == 0) || ((StartingLba + NumOfLba) > NumOfBlocks)) { 1000 VA_END (args); 1001 return EFI_INVALID_PARAMETER; 1002 } 1003 } while (1); 1004 1005 VA_END (args); 1006 1007 VA_START (args, This); 1008 do { 1009 StartingLba = VA_ARG (args, EFI_LBA); 1010 if (StartingLba == EFI_LBA_LIST_TERMINATOR) { 1011 break; 1012 } 1013 1014 NumOfLba = VA_ARG (args, UINT32); 1015 1016 while (NumOfLba > 0) { 1017 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ()); 1018 if (EFI_ERROR (Status)) { 1019 VA_END (args); 1020 return Status; 1021 } 1022 1023 StartingLba++; 1024 NumOfLba--; 1025 } 1026 1027 } while (1); 1028 1029 VA_END (args); 1030 1031 return EFI_SUCCESS; 1032 } 1033 1034 EFI_STATUS 1035 EFIAPI 1036 FvbProtocolWrite ( 1037 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 1038 IN EFI_LBA Lba, 1039 IN UINTN Offset, 1040 IN OUT UINTN *NumBytes, 1041 IN UINT8 *Buffer 1042 ) 1043 /*++ 1044 1045 Routine Description: 1046 1047 Writes data beginning at Lba:Offset from FV. The write terminates either 1048 when *NumBytes of data have been written, or when a block boundary is 1049 reached. *NumBytes is updated to reflect the actual number of bytes 1050 written. The write opertion does not include erase. This routine will 1051 attempt to write only the specified bytes. If the writes do not stick, 1052 it will return an error. 1053 1054 Arguments: 1055 This - Calling context 1056 Lba - Block in which to begin write 1057 Offset - Offset in the block at which to begin write 1058 NumBytes - On input, indicates the requested write size. On 1059 output, indicates the actual number of bytes written 1060 Buffer - Buffer containing source data for the write. 1061 1062 Returns: 1063 EFI_SUCCESS - The firmware volume was written successfully 1064 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output, 1065 NumBytes contains the total number of bytes 1066 actually written 1067 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state 1068 EFI_DEVICE_ERROR - The block device is not functioning correctly and 1069 could not be written 1070 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL 1071 1072 --*/ 1073 { 1074 1075 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 1076 1077 FvbDevice = FVB_DEVICE_FROM_THIS (This); 1078 1079 return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ()); 1080 } 1081 1082 EFI_STATUS 1083 EFIAPI 1084 FvbProtocolRead ( 1085 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 1086 IN EFI_LBA Lba, 1087 IN UINTN Offset, 1088 IN OUT UINTN *NumBytes, 1089 IN UINT8 *Buffer 1090 ) 1091 /*++ 1092 1093 Routine Description: 1094 1095 Reads data beginning at Lba:Offset from FV. The Read terminates either 1096 when *NumBytes of data have been read, or when a block boundary is 1097 reached. *NumBytes is updated to reflect the actual number of bytes 1098 written. The write opertion does not include erase. This routine will 1099 attempt to write only the specified bytes. If the writes do not stick, 1100 it will return an error. 1101 1102 Arguments: 1103 This - Calling context 1104 Lba - Block in which to begin Read 1105 Offset - Offset in the block at which to begin Read 1106 NumBytes - On input, indicates the requested write size. On 1107 output, indicates the actual number of bytes Read 1108 Buffer - Buffer containing source data for the Read. 1109 1110 Returns: 1111 EFI_SUCCESS - The firmware volume was read successfully and 1112 contents are in Buffer 1113 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output, 1114 NumBytes contains the total number of bytes returned 1115 in Buffer 1116 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state 1117 EFI_DEVICE_ERROR - The block device is not functioning correctly and 1118 could not be read 1119 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL 1120 1121 --*/ 1122 { 1123 1124 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 1125 1126 FvbDevice = FVB_DEVICE_FROM_THIS (This); 1127 1128 return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ()); 1129 } 1130 1131 EFI_STATUS 1132 ValidateFvHeader ( 1133 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader 1134 ) 1135 /*++ 1136 1137 Routine Description: 1138 Check the integrity of firmware volume header 1139 1140 Arguments: 1141 FwVolHeader - A pointer to a firmware volume header 1142 1143 Returns: 1144 EFI_SUCCESS - The firmware volume is consistent 1145 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV 1146 1147 --*/ 1148 { 1149 UINT16 *Ptr; 1150 UINT16 HeaderLength; 1151 UINT16 Checksum; 1152 1153 // 1154 // Verify the header revision, header signature, length 1155 // Length of FvBlock cannot be 2**64-1 1156 // HeaderLength cannot be an odd number 1157 // 1158 if ((FwVolHeader->Revision != EFI_FVH_REVISION) || 1159 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) || 1160 (FwVolHeader->FvLength == ((UINTN) -1)) || 1161 ((FwVolHeader->HeaderLength & 0x01) != 0) 1162 ) { 1163 return EFI_NOT_FOUND; 1164 } 1165 // 1166 // Verify the header checksum 1167 // 1168 HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2); 1169 Ptr = (UINT16 *) FwVolHeader; 1170 Checksum = 0; 1171 while (HeaderLength > 0) { 1172 Checksum = Checksum + (*Ptr); 1173 HeaderLength--; 1174 Ptr++; 1175 } 1176 1177 if (Checksum != 0) { 1178 return EFI_NOT_FOUND; 1179 } 1180 1181 return EFI_SUCCESS; 1182 } 1183 1184 1185 EFI_STATUS 1186 GetFvbHeader ( 1187 IN OUT EFI_PEI_HOB_POINTERS *HobList, 1188 OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader, 1189 OUT EFI_PHYSICAL_ADDRESS *BaseAddress OPTIONAL, 1190 OUT UINT32 *VolumeId OPTIONAL, 1191 OUT CHAR16 **MappedFile OPTIONAL, 1192 OUT UINT32 *ActuralSize OPTIONAL, 1193 OUT UINT32 *Offset OPTIONAL, 1194 OUT BOOLEAN *WriteBack OPTIONAL 1195 ) 1196 { 1197 EFI_STATUS Status; 1198 EFI_FLASH_MAP_FS_ENTRY_DATA *FlashMapEntry; 1199 EFI_FLASH_SUBAREA_ENTRY *FlashMapSubEntry; 1200 1201 Status = EFI_SUCCESS; 1202 *FwVolHeader = NULL; 1203 TRY_ASSIGN (WriteBack, FALSE); 1204 1205 DEBUG ((EFI_D_INFO, "Hob start is 0x%x\n", (UINTN)(*HobList).Raw)); 1206 (*HobList).Raw = GetNextGuidHob (&gEfiFlashMapHobGuid, (*HobList).Raw); 1207 if ((*HobList).Raw == NULL) { 1208 return EFI_NOT_FOUND; 1209 } 1210 1211 FlashMapEntry = (EFI_FLASH_MAP_FS_ENTRY_DATA *) GET_GUID_HOB_DATA ((*HobList).Guid); 1212 FlashMapSubEntry = &FlashMapEntry->Entries[0]; 1213 1214 // 1215 // Check if it is a "FVB" area 1216 // 1217 if (!CompareGuid (&FlashMapSubEntry->FileSystem, &gEfiFirmwareVolumeBlockProtocolGuid)) { 1218 return Status; 1219 } 1220 // 1221 // Check if it is a "real" flash 1222 // 1223 if (FlashMapSubEntry->Attributes != (EFI_FLASH_AREA_FV | EFI_FLASH_AREA_MEMMAPPED_FV)) { 1224 return Status; 1225 } 1226 1227 TRY_ASSIGN (BaseAddress, FlashMapSubEntry->Base); 1228 1229 // 1230 // Cast buffer to FLASH_AREA_INFO to get extra information related to the special FVB driver 1231 // 1232 TRY_ASSIGN (VolumeId, FlashMapEntry->VolumeId); 1233 TRY_ASSIGN (ActuralSize, FlashMapEntry->ActuralSize); 1234 TRY_ASSIGN (MappedFile, ((CHAR16 *) FlashMapEntry->FilePath)); 1235 TRY_ASSIGN (Offset, FlashMapEntry->Offset); 1236 1237 DEBUG (( 1238 EFI_D_INFO, 1239 "FlashMap HOB: BaseAddress = 0x%x, Length = 0x%x, ActuralLength = 0x%x, Offset = 0x%x\n", 1240 (UINTN) FlashMapSubEntry->Base, (UINTN) FlashMapSubEntry->Length, 1241 (UINTN) FlashMapEntry->ActuralSize, (UINTN) FlashMapEntry->Offset 1242 )); 1243 DEBUG (( 1244 EFI_D_INFO, 1245 "FlashMap HOB: VolumeId = 0x%lx, MappedFile = %s\n", 1246 (UINTN) FlashMapEntry->VolumeId, (UINTN) FlashMapEntry->FilePath 1247 )); 1248 *FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (FlashMapSubEntry->Base); 1249 Status = ValidateFvHeader (*FwVolHeader); 1250 if (EFI_ERROR (Status)) { 1251 // 1252 // Get FvbInfo 1253 // 1254 TRY_ASSIGN (WriteBack, TRUE); 1255 Status = GetFvbInfo (FlashMapSubEntry->Length, FwVolHeader); 1256 DEBUG ((EFI_D_ERROR, "Fvb: FV header invalid, GetFvbInfo - %r\n", Status)); 1257 ASSERT_EFI_ERROR (Status); 1258 } 1259 1260 return EFI_SUCCESS; 1261 } 1262 1263 VOID 1264 EFIAPI 1265 OnSimpleFileSystemInstall ( 1266 IN EFI_EVENT Event, 1267 IN VOID *Context 1268 ) 1269 { 1270 EFI_STATUS Status; 1271 UINTN HandleSize; 1272 EFI_HANDLE Handle; 1273 UINTN Instance; 1274 EFI_DEVICE_PATH_PROTOCOL *Device; 1275 EFI_FILE_PROTOCOL *File; 1276 EFI_FW_VOL_INSTANCE *FwhInstance; 1277 while (TRUE) { 1278 HandleSize = sizeof (EFI_HANDLE); 1279 Status = gBS->LocateHandle ( 1280 ByRegisterNotify, 1281 NULL, 1282 mSFSRegistration, 1283 &HandleSize, 1284 &Handle 1285 ); 1286 if (Status == EFI_NOT_FOUND) { 1287 break; 1288 } 1289 DEBUG ((EFI_D_ERROR, "Fwh: New FileSystem Installed!\n")); 1290 ASSERT_EFI_ERROR (Status); 1291 // 1292 // Check if this is the storage we care about, and store it in FwhInstance 1293 // 1294 for (Instance = 0; Instance < mFvbModuleGlobal->NumFv; ++Instance) { 1295 Status = GetFvbInstance (Instance, mFvbModuleGlobal, &FwhInstance, FALSE); 1296 ASSERT_EFI_ERROR (Status); 1297 1298 if (FwhInstance->MappedFile[0] == L'\0') { 1299 // 1300 // The instance of FVB isn't mapped to file. 1301 // 1302 continue; 1303 } 1304 1305 if ((FwhInstance->Device != NULL) && 1306 !EFI_ERROR (CheckStoreExists (FwhInstance->Device)) 1307 ) { 1308 // 1309 // The instance of FVB has already associated to a device 1310 // and the device is not removed from system. 1311 // 1312 DEBUG (( 1313 EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Already mapped, Skip!\n", 1314 (UINTN) FwhInstance->FvBase[FVB_PHYSICAL], 1315 (UINTN) FwhInstance->Offset 1316 )); 1317 continue; 1318 } 1319 1320 Status = CheckStore (Handle, FwhInstance->VolumeId, &Device); 1321 if (!EFI_ERROR (Status)) { 1322 // 1323 // Write back memory content to file 1324 // 1325 Status = FileOpen (Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ | EFI_FILE_MODE_CREATE); 1326 ASSERT_EFI_ERROR (Status); 1327 if (!EFI_ERROR (Status)) { 1328 DEBUG (( 1329 EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Write back to mapped file!\n", 1330 (UINTN) FwhInstance->FvBase[FVB_PHYSICAL], 1331 (UINTN) FwhInstance->Offset 1332 )); 1333 Status = FileWrite ( 1334 File, 1335 0, 1336 FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset, 1337 FwhInstance->ActuralSize - FwhInstance->Offset 1338 ); 1339 ASSERT_EFI_ERROR (Status); 1340 if (!EFI_ERROR (Status)) { 1341 if (FwhInstance->Device != NULL) { 1342 gBS->FreePool (FwhInstance->Device); 1343 } 1344 FwhInstance->Device = Device; 1345 DEBUG (( 1346 EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Mapped!\n", 1347 (UINTN) FwhInstance->FvBase[FVB_PHYSICAL], 1348 (UINTN) FwhInstance->Offset 1349 )); 1350 } 1351 FileClose (File); 1352 } 1353 } 1354 } 1355 } 1356 } 1357 1358 VOID 1359 FvbInstallSfsNotify ( 1360 VOID 1361 ) 1362 { 1363 EFI_STATUS Status; 1364 EFI_EVENT Event; 1365 1366 Status = gBS->CreateEvent ( 1367 EVT_NOTIFY_SIGNAL, 1368 TPL_CALLBACK, 1369 OnSimpleFileSystemInstall, 1370 NULL, 1371 &Event 1372 ); 1373 ASSERT_EFI_ERROR (Status); 1374 1375 Status = gBS->RegisterProtocolNotify ( 1376 &gEfiSimpleFileSystemProtocolGuid, 1377 Event, 1378 &mSFSRegistration 1379 ); 1380 ASSERT_EFI_ERROR (Status); 1381 } 1382 1383 1384 EFI_STATUS 1385 EFIAPI 1386 FvbInitialize ( 1387 IN EFI_HANDLE ImageHandle, 1388 IN EFI_SYSTEM_TABLE *SystemTable 1389 ) 1390 /*++ 1391 1392 Routine Description: 1393 This function does common initialization for FVB services 1394 1395 Arguments: 1396 1397 Returns: 1398 1399 --*/ 1400 { 1401 EFI_STATUS Status; 1402 EFI_FW_VOL_INSTANCE *FwhInstance; 1403 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; 1404 EFI_PEI_HOB_POINTERS FirmwareVolumeHobList; 1405 UINT32 BufferSize; 1406 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; 1407 UINTN LbaAddress; 1408 EFI_HANDLE FwbHandle; 1409 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; 1410 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface; 1411 EFI_DEVICE_PATH_PROTOCOL *TempFwbDevicePath; 1412 FV_DEVICE_PATH TempFvbDevicePathData; 1413 UINT32 MaxLbaSize; 1414 EFI_PHYSICAL_ADDRESS BaseAddress; 1415 UINT32 VolumeId; 1416 CHAR16 *MappedFile; 1417 UINT32 ActuralSize; 1418 UINT32 Offset; 1419 BOOLEAN WriteBack; 1420 UINTN NumOfBlocks; 1421 UINTN HeaderLength; 1422 BOOLEAN InstallSfsNotify; 1423 1424 HeaderLength = 0; 1425 InstallSfsNotify = FALSE; 1426 1427 // 1428 // Allocate runtime services data for global variable, which contains 1429 // the private data of all firmware volume block instances 1430 // 1431 Status = gBS->AllocatePool ( 1432 EfiRuntimeServicesData, 1433 sizeof (ESAL_FWB_GLOBAL), 1434 &mFvbModuleGlobal 1435 ); 1436 ASSERT_EFI_ERROR (Status); 1437 // 1438 // Calculate the total size for all firmware volume block instances 1439 // 1440 BufferSize = 0; 1441 FirmwareVolumeHobList.Raw = GetHobList(); 1442 do { 1443 Status = GetFvbHeader (&FirmwareVolumeHobList, &FwVolHeader, NULL, NULL, NULL, NULL, NULL, NULL); 1444 if (EFI_ERROR (Status)) { 1445 break; 1446 } 1447 FirmwareVolumeHobList.Raw = GET_NEXT_HOB (FirmwareVolumeHobList); 1448 1449 if (FwVolHeader) { 1450 BufferSize += (FwVolHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)); 1451 } 1452 } while (TRUE); 1453 1454 // 1455 // Only need to allocate once. There is only one copy of physical memory for 1456 // the private data of each FV instance. But in virtual mode or in physical 1457 // mode, the address of the the physical memory may be different. 1458 // 1459 Status = gBS->AllocatePool ( 1460 EfiRuntimeServicesData, 1461 BufferSize, 1462 &mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] 1463 ); 1464 ASSERT_EFI_ERROR (Status); 1465 1466 // 1467 // Make a virtual copy of the FvInstance pointer. 1468 // 1469 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]; 1470 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance; 1471 1472 mFvbModuleGlobal->NumFv = 0; 1473 FirmwareVolumeHobList.Raw = GetHobList(); 1474 MaxLbaSize = 0; 1475 1476 // 1477 // Fill in the private data of each firmware volume block instance 1478 // 1479 do { 1480 Status = GetFvbHeader ( 1481 &FirmwareVolumeHobList, &FwVolHeader, 1482 &BaseAddress, &VolumeId, &MappedFile, &ActuralSize, &Offset, 1483 &WriteBack 1484 ); 1485 if (EFI_ERROR (Status)) { 1486 break; 1487 } 1488 FirmwareVolumeHobList.Raw = GET_NEXT_HOB (FirmwareVolumeHobList); 1489 1490 if (!FwVolHeader) { 1491 continue; 1492 } 1493 1494 CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength); 1495 FwVolHeader = &(FwhInstance->VolumeHeader); 1496 1497 FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress; 1498 FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress; 1499 FwhInstance->Device = NULL; 1500 FwhInstance->Offset = Offset; 1501 1502 if (*MappedFile != '\0') { 1503 FwhInstance->VolumeId = VolumeId; 1504 FwhInstance->ActuralSize = ActuralSize; 1505 StrCpy (FwhInstance->MappedFile, MappedFile); 1506 1507 InstallSfsNotify = TRUE; 1508 } else { 1509 FwhInstance->VolumeId = (UINT32) -1; 1510 FwhInstance->ActuralSize = (UINT32) -1; 1511 FwhInstance->MappedFile[0] = L'\0'; 1512 } 1513 1514 DEBUG ((EFI_D_INFO, "FirmVolume Found! BaseAddress=0x%lx, VolumeId=0x%x, MappedFile=%s, Size=0x%x\n", 1515 (UINTN) BaseAddress, VolumeId, MappedFile, ActuralSize)); 1516 // 1517 // We may expose readonly FVB in future. 1518 // 1519 FwhInstance->WriteEnabled = TRUE; // Ken: Why enable write? 1520 EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL); 1521 1522 LbaAddress = (UINTN) FwhInstance->FvBase[0]; 1523 NumOfBlocks = 0; 1524 1525 if (FwhInstance->WriteEnabled) { 1526 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) { 1527 1528 LbaAddress += PtrBlockMapEntry->NumBlocks * PtrBlockMapEntry->Length; 1529 // 1530 // Get the maximum size of a block. The size will be used to allocate 1531 // buffer for Scratch space, the intermediate buffer for FVB extension 1532 // protocol 1533 // 1534 if (MaxLbaSize < PtrBlockMapEntry->Length) { 1535 MaxLbaSize = PtrBlockMapEntry->Length; 1536 } 1537 1538 NumOfBlocks += PtrBlockMapEntry->NumBlocks; 1539 } 1540 // 1541 // Write back a healthy FV header 1542 // 1543 if (WriteBack) { 1544 Status = FlashFdErase ( 1545 (UINTN) FwhInstance->FvBase[0], 1546 FwhInstance, 1547 FwVolHeader->BlockMap->Length 1548 ); 1549 1550 HeaderLength = (UINTN) FwVolHeader->HeaderLength; 1551 1552 Status = FlashFdWrite ( 1553 (UINTN) FwhInstance->FvBase[0], 1554 FwhInstance, 1555 (UINTN *) &HeaderLength, 1556 (UINT8 *) FwVolHeader 1557 ); 1558 1559 FwVolHeader->HeaderLength = (UINT16) HeaderLength; 1560 1561 DEBUG ((EFI_D_ERROR, "Fvb (0x%x): FV header invalid, write back - %r\n", (UINTN) FwhInstance->FvBase[0], Status)); 1562 } 1563 } 1564 // 1565 // The total number of blocks in the FV. 1566 // 1567 FwhInstance->NumOfBlocks = NumOfBlocks; 1568 1569 // 1570 // Add a FVB Protocol Instance 1571 // 1572 Status = gBS->AllocatePool ( 1573 EfiRuntimeServicesData, 1574 sizeof (EFI_FW_VOL_BLOCK_DEVICE), 1575 &FvbDevice 1576 ); 1577 ASSERT_EFI_ERROR (Status); 1578 1579 CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE)); 1580 1581 FvbDevice->Instance = mFvbModuleGlobal->NumFv; 1582 mFvbModuleGlobal->NumFv++; 1583 1584 // 1585 // Set up the devicepath 1586 // 1587 FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress; 1588 FvbDevice->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1); 1589 1590 // 1591 // Find a handle with a matching device path that has supports FW Block protocol 1592 // 1593 TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData; 1594 CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH)); 1595 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle); 1596 if (EFI_ERROR (Status)) { 1597 // 1598 // LocateDevicePath fails so install a new interface and device path 1599 // 1600 FwbHandle = NULL; 1601 Status = gBS->InstallMultipleProtocolInterfaces ( 1602 &FwbHandle, 1603 &gEfiFirmwareVolumeBlockProtocolGuid, 1604 &FvbDevice->FwVolBlockInstance, 1605 &gEfiDevicePathProtocolGuid, 1606 &FvbDevice->DevicePath, 1607 NULL 1608 ); 1609 ASSERT_EFI_ERROR (Status); 1610 } else if (IsDevicePathEnd (TempFwbDevicePath)) { 1611 // 1612 // Device allready exists, so reinstall the FVB protocol 1613 // 1614 Status = gBS->HandleProtocol ( 1615 FwbHandle, 1616 &gEfiFirmwareVolumeBlockProtocolGuid, 1617 &OldFwbInterface 1618 ); 1619 ASSERT_EFI_ERROR (Status); 1620 1621 Status = gBS->ReinstallProtocolInterface ( 1622 FwbHandle, 1623 &gEfiFirmwareVolumeBlockProtocolGuid, 1624 OldFwbInterface, 1625 &FvbDevice->FwVolBlockInstance 1626 ); 1627 ASSERT_EFI_ERROR (Status); 1628 1629 } else { 1630 // 1631 // There was a FVB protocol on an End Device Path node 1632 // 1633 ASSERT (FALSE); 1634 } 1635 1636 FwhInstance = (EFI_FW_VOL_INSTANCE *) 1637 ( 1638 (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength + 1639 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)) 1640 ); 1641 } while (TRUE); 1642 1643 // 1644 // Allocate for scratch space, an intermediate buffer for FVB extention 1645 // 1646 Status = gBS->AllocatePool ( 1647 EfiRuntimeServicesData, 1648 MaxLbaSize, 1649 &mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL] 1650 ); 1651 ASSERT_EFI_ERROR (Status); 1652 1653 mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL] = mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL]; 1654 1655 if (InstallSfsNotify) { 1656 FvbInstallSfsNotify (); 1657 } 1658 return EFI_SUCCESS; 1659 } 1660