1 /** @file 2 3 Implement the Firmware Volume Block (FVB) services based on SMM FVB 4 module and install FVB protocol. 5 6 Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved. <BR> 7 8 9 This program and the accompanying materials are licensed and made available under 10 11 the terms and conditions of the BSD License that accompanies this distribution. 12 13 The full text of the license may be found at 14 15 http://opensource.org/licenses/bsd-license.php. 16 17 18 19 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 20 21 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 22 23 24 25 26 **/ 27 28 #include "FvbSmmDxe.h" 29 30 EFI_HANDLE mHandle = NULL; 31 EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL; 32 33 // 34 // Template structure used when installing FVB protocol. 35 // 36 EFI_FVB_DEVICE mFvbDeviceTemplate = { 37 FVB_DEVICE_SIGNATURE, 38 NULL, 39 { 40 FvbGetAttributes, 41 FvbSetAttributes, 42 FvbGetPhysicalAddress, 43 FvbGetBlockSize, 44 FvbRead, 45 FvbWrite, 46 FvbEraseBlocks, 47 NULL 48 }, 49 NULL 50 }; 51 52 FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = { 53 { 54 { 55 HARDWARE_DEVICE_PATH, 56 HW_MEMMAP_DP, 57 { 58 (UINT8)(sizeof (MEMMAP_DEVICE_PATH)), 59 (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8) 60 } 61 }, 62 EfiMemoryMappedIO, 63 (EFI_PHYSICAL_ADDRESS) 0, 64 (EFI_PHYSICAL_ADDRESS) 0, 65 }, 66 { 67 END_DEVICE_PATH_TYPE, 68 END_ENTIRE_DEVICE_PATH_SUBTYPE, 69 { 70 END_DEVICE_PATH_LENGTH, 71 0 72 } 73 } 74 }; 75 76 FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = { 77 { 78 { 79 MEDIA_DEVICE_PATH, 80 MEDIA_PIWG_FW_VOL_DP, 81 { 82 (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)), 83 (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8) 84 } 85 }, 86 { 0 } 87 }, 88 { 89 END_DEVICE_PATH_TYPE, 90 END_ENTIRE_DEVICE_PATH_SUBTYPE, 91 { 92 END_DEVICE_PATH_LENGTH, 93 0 94 } 95 } 96 }; 97 98 /** 99 Initialize the communicate buffer using DataSize and Function. 100 101 The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + 102 DataSize. 103 104 @param[out] CommunicateBuffer The communicate buffer. Caller should free it after use. InitCommunicateBuffer(OUT VOID ** CommunicateBuffer,OUT VOID ** DataPtr,IN UINTN DataSize,IN UINTN Function)105 @param[out] DataPtr Points to the data in the communicate buffer. Caller should not free it. 106 @param[in] DataSize The payload size. 107 @param[in] Function The function number used to initialize the communicate header. 108 109 @retval EFI_INVALID_PARAMETER The data size is too big. 110 @retval EFI_SUCCESS Find the specified variable. 111 112 **/ 113 EFI_STATUS 114 InitCommunicateBuffer ( 115 OUT VOID **CommunicateBuffer, 116 OUT VOID **DataPtr, 117 IN UINTN DataSize, 118 IN UINTN Function 119 ) 120 { 121 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; 122 SMM_FVB_COMMUNICATE_FUNCTION_HEADER *SmmFvbFunctionHeader; 123 124 // 125 // The whole buffer size: SMM_COMMUNICATE_HEADER_SIZE + SMM_FVB_COMMUNICATE_HEADER_SIZE + DataSize. 126 // 127 SmmCommunicateHeader = AllocatePool (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_FVB_COMMUNICATE_HEADER_SIZE); 128 ASSERT (SmmCommunicateHeader != NULL); 129 130 // 131 // Prepare data buffer. 132 // 133 CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmFirmwareVolumeBlockProtocolGuid); 134 SmmCommunicateHeader->MessageLength = DataSize + SMM_FVB_COMMUNICATE_HEADER_SIZE; 135 136 SmmFvbFunctionHeader = (SMM_FVB_COMMUNICATE_FUNCTION_HEADER *) SmmCommunicateHeader->Data; 137 SmmFvbFunctionHeader->Function = Function; 138 139 *CommunicateBuffer = SmmCommunicateHeader; 140 *DataPtr = SmmFvbFunctionHeader->Data; 141 142 return EFI_SUCCESS; 143 } 144 SendCommunicateBuffer(IN EFI_SMM_COMMUNICATE_HEADER * SmmCommunicateHeader,IN UINTN DataSize)145 146 /** 147 Send the data in communicate buffer to SMM. 148 149 @param[out] SmmCommunicateHeader The communicate buffer. 150 @param[in] DataSize The payload size. 151 152 **/ 153 EFI_STATUS 154 SendCommunicateBuffer ( 155 IN EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader, 156 IN UINTN DataSize 157 ) 158 { 159 EFI_STATUS Status; 160 UINTN CommSize; 161 SMM_FVB_COMMUNICATE_FUNCTION_HEADER *SmmFvbFunctionHeader; 162 163 CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_FVB_COMMUNICATE_HEADER_SIZE; 164 Status = mSmmCommunication->Communicate ( 165 mSmmCommunication, 166 SmmCommunicateHeader, 167 &CommSize 168 ); 169 ASSERT_EFI_ERROR (Status); 170 171 SmmFvbFunctionHeader = (SMM_FVB_COMMUNICATE_FUNCTION_HEADER *) SmmCommunicateHeader->Data; 172 return SmmFvbFunctionHeader->ReturnStatus; 173 } 174 175 /** 176 This function retrieves the attributes and current settings of the block. 177 178 @param[in] This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. 179 FvbGetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,OUT EFI_FVB_ATTRIBUTES_2 * Attributes)180 @param[out] Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes 181 and current settings are returned. Type EFI_FVB_ATTRIBUTES_2 182 is defined in EFI_FIRMWARE_VOLUME_HEADER. 183 184 @retval EFI_SUCCESS The firmware volume attributes were returned. 185 @retval EFI_INVALID_PARAMETER Attributes is NULL. 186 **/ 187 EFI_STATUS 188 EFIAPI 189 FvbGetAttributes ( 190 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 191 OUT EFI_FVB_ATTRIBUTES_2 *Attributes 192 ) 193 { 194 EFI_STATUS Status; 195 UINTN PayloadSize; 196 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; 197 SMM_FVB_ATTRIBUTES_HEADER *SmmFvbAttributesHeader; 198 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; 199 EFI_FVB_DEVICE *FvbDevice; 200 201 if (Attributes == NULL) { 202 return EFI_INVALID_PARAMETER; 203 } 204 205 FvbDevice = FVB_DEVICE_FROM_THIS (This); 206 SmmFvb = FvbDevice->SmmFvbInstance; 207 208 // 209 // Initialize the communicate buffer. 210 // 211 PayloadSize = sizeof (SMM_FVB_ATTRIBUTES_HEADER); 212 Status = InitCommunicateBuffer ( 213 (VOID **)&SmmCommunicateHeader, 214 (VOID **)&SmmFvbAttributesHeader, 215 PayloadSize, 216 EFI_FUNCTION_GET_ATTRIBUTES 217 ); 218 if (EFI_ERROR (Status)) { 219 return Status; 220 } 221 222 SmmFvbAttributesHeader->SmmFvb = SmmFvb; 223 SmmFvbAttributesHeader->Attributes = 0; 224 225 // 226 // Send data to SMM. 227 // 228 Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize); 229 230 // 231 // Get data from SMM. 232 // 233 *Attributes = SmmFvbAttributesHeader->Attributes; 234 FreePool (SmmCommunicateHeader); 235 236 return Status; 237 } 238 239 240 /** 241 Sets Volume attributes. No polarity translations are done. 242 FvbSetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN OUT EFI_FVB_ATTRIBUTES_2 * Attributes)243 @param[in] This Calling context. 244 @param[out] Attributes Output buffer which contains attributes. 245 246 @retval EFI_SUCCESS Set the Attributes successfully. 247 @retval EFI_INVALID_PARAMETER Attributes is NULL. 248 249 **/ 250 EFI_STATUS 251 EFIAPI 252 FvbSetAttributes ( 253 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 254 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes 255 ) 256 { 257 EFI_STATUS Status; 258 UINTN PayloadSize; 259 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; 260 SMM_FVB_ATTRIBUTES_HEADER *SmmFvbAttributesHeader; 261 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; 262 EFI_FVB_DEVICE *FvbDevice; 263 264 if (Attributes == NULL) { 265 return EFI_INVALID_PARAMETER; 266 } 267 268 FvbDevice = FVB_DEVICE_FROM_THIS (This); 269 SmmFvb = FvbDevice->SmmFvbInstance; 270 271 // 272 // Initialize the communicate buffer. 273 // 274 PayloadSize = sizeof (SMM_FVB_ATTRIBUTES_HEADER); 275 Status = InitCommunicateBuffer ( 276 (VOID **)&SmmCommunicateHeader, 277 (VOID **)&SmmFvbAttributesHeader, 278 PayloadSize, 279 EFI_FUNCTION_SET_ATTRIBUTES 280 ); 281 if (EFI_ERROR (Status)) { 282 return Status; 283 } 284 285 SmmFvbAttributesHeader->SmmFvb = SmmFvb; 286 SmmFvbAttributesHeader->Attributes = *Attributes; 287 288 // 289 // Send data to SMM. 290 // 291 Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize); 292 293 // 294 // Get data from SMM. 295 // 296 *Attributes = SmmFvbAttributesHeader->Attributes; 297 FreePool (SmmCommunicateHeader); 298 299 return Status; 300 } 301 302 303 /** 304 Retrieves the physical address of the FVB instance. GetPhysicalAddress(IN EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL * SmmFvb,OUT EFI_PHYSICAL_ADDRESS * Address)305 306 @param[in] SmmFvb A pointer to EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL. 307 @param[out] Address Output buffer containing the address. 308 309 @retval EFI_SUCCESS Get the address successfully. 310 @retval Others Failed to get address. 311 312 **/ 313 EFI_STATUS 314 GetPhysicalAddress ( 315 IN EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb, 316 OUT EFI_PHYSICAL_ADDRESS *Address 317 ) 318 { 319 EFI_STATUS Status; 320 UINTN PayloadSize; 321 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; 322 SMM_FVB_PHYSICAL_ADDRESS_HEADER *SmmFvbPhysicalAddressHeader; 323 324 // 325 // Initialize the communicate buffer. 326 // 327 PayloadSize = sizeof (SMM_FVB_PHYSICAL_ADDRESS_HEADER); 328 Status = InitCommunicateBuffer ( 329 (VOID **)&SmmCommunicateHeader, 330 (VOID **)&SmmFvbPhysicalAddressHeader, 331 PayloadSize, 332 EFI_FUNCTION_GET_PHYSICAL_ADDRESS 333 ); 334 if (EFI_ERROR (Status)) { 335 return Status; 336 } 337 338 SmmFvbPhysicalAddressHeader->SmmFvb = SmmFvb; 339 SmmFvbPhysicalAddressHeader->Address = 0; 340 341 // 342 // Send data to SMM. 343 // 344 Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize); 345 346 // 347 // Get data from SMM. 348 // 349 *Address = SmmFvbPhysicalAddressHeader->Address; 350 FreePool (SmmCommunicateHeader); 351 352 return Status; 353 } 354 355 356 /** 357 Retrieves the physical address of the FVB instance. 358 FvbGetPhysicalAddress(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,OUT EFI_PHYSICAL_ADDRESS * Address)359 @param[in] This A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL. 360 @param[out] Address Output buffer containing the address. 361 362 @retval EFI_SUCCESS Get the address successfully. 363 @retval Others Failed to get the address. 364 365 **/ 366 EFI_STATUS 367 EFIAPI 368 FvbGetPhysicalAddress ( 369 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 370 OUT EFI_PHYSICAL_ADDRESS *Address 371 ) 372 { 373 EFI_STATUS Status; 374 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; 375 EFI_FVB_DEVICE *FvbDevice; 376 377 if (Address == NULL) { 378 return EFI_INVALID_PARAMETER; 379 } 380 381 FvbDevice = FVB_DEVICE_FROM_THIS (This); 382 SmmFvb = FvbDevice->SmmFvbInstance; 383 384 Status = GetPhysicalAddress (SmmFvb, Address); 385 386 return Status; 387 } 388 389 390 /** 391 Retrieve the size of a logical block. 392 393 @param[in] This Calling context. 394 @param[in] Lba Indicates which block to return the size for. 395 @param[out] BlockSize A pointer to a caller allocated UINTN in which 396 the size of the block is returned. 397 @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which the FvbGetBlockSize(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN EFI_LBA Lba,OUT UINTN * BlockSize,OUT UINTN * NumOfBlocks)398 number of consecutive blocks starting with Lba is 399 returned. All blocks in this range have a size of 400 BlockSize. 401 402 @retval EFI_SUCCESS Get BlockSize and NumOfBlocks successfully. 403 @retval EFI_INVALID_PARAMETER BlockSize or NumOfBlocks are NULL. 404 **/ 405 EFI_STATUS 406 EFIAPI 407 FvbGetBlockSize ( 408 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 409 IN EFI_LBA Lba, 410 OUT UINTN *BlockSize, 411 OUT UINTN *NumOfBlocks 412 ) 413 { 414 EFI_STATUS Status; 415 UINTN PayloadSize; 416 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; 417 SMM_FVB_BLOCK_SIZE_HEADER *SmmFvbBlockSizeHeader; 418 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; 419 EFI_FVB_DEVICE *FvbDevice; 420 421 if ((BlockSize == NULL) || (NumOfBlocks == NULL)) { 422 return EFI_INVALID_PARAMETER; 423 } 424 425 FvbDevice = FVB_DEVICE_FROM_THIS (This); 426 SmmFvb = FvbDevice->SmmFvbInstance; 427 428 // 429 // Initialize the communicate buffer. 430 // 431 PayloadSize = sizeof (SMM_FVB_BLOCK_SIZE_HEADER); 432 Status = InitCommunicateBuffer ( 433 (VOID **)&SmmCommunicateHeader, 434 (VOID **)&SmmFvbBlockSizeHeader, 435 PayloadSize, 436 EFI_FUNCTION_GET_BLOCK_SIZE 437 ); 438 if (EFI_ERROR (Status)) { 439 return Status; 440 } 441 442 SmmFvbBlockSizeHeader->SmmFvb = SmmFvb; 443 SmmFvbBlockSizeHeader->Lba = Lba; 444 445 // 446 // Send data to SMM. 447 // 448 Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize); 449 450 // 451 // Get data from SMM. 452 // 453 *BlockSize = SmmFvbBlockSizeHeader->BlockSize; 454 *NumOfBlocks = SmmFvbBlockSizeHeader->NumOfBlocks; 455 FreePool (SmmCommunicateHeader); 456 457 return Status; 458 } 459 460 461 /** 462 Reads data beginning at Lba:Offset from FV. The Read terminates either 463 when *NumBytes of data have been read, or when a block boundary is 464 reached. *NumBytes is updated to reflect the actual number of bytes 465 written. The write opertion does not include erase. This routine will 466 attempt to write only the specified bytes. If the writes do not stick, 467 it will return an error. 468 469 @param[in] This Calling context 470 @param[in] Lba Block in which to begin write 471 @param[in] Offset Offset in the block at which to begin write 472 @param[in,out] NumBytes On input, indicates the requested write size. On 473 output, indicates the actual number of bytes written 474 @param[in] Buffer Buffer containing source data for the write. 475 476 @retval EFI_SUCCESS The firmware volume was read successfully and 477 contents are in Buffer. 478 @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On output, 479 NumBytes contains the total number of bytes returned FvbRead(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Offset,IN OUT UINTN * NumBytes,OUT UINT8 * Buffer)480 in Buffer. 481 @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state 482 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and 483 could not be read. 484 @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL. 485 486 **/ 487 EFI_STATUS 488 EFIAPI 489 FvbRead ( 490 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 491 IN EFI_LBA Lba, 492 IN UINTN Offset, 493 IN OUT UINTN *NumBytes, 494 OUT UINT8 *Buffer 495 ) 496 { 497 EFI_STATUS Status; 498 UINTN PayloadSize; 499 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; 500 SMM_FVB_READ_WRITE_HEADER *SmmFvbReadWriteHeader; 501 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; 502 EFI_FVB_DEVICE *FvbDevice; 503 504 if ((NumBytes == NULL) || (Buffer == NULL)) { 505 return EFI_INVALID_PARAMETER; 506 } 507 508 FvbDevice = FVB_DEVICE_FROM_THIS (This); 509 SmmFvb = FvbDevice->SmmFvbInstance; 510 511 // 512 // Initialize the communicate buffer. 513 // 514 PayloadSize = sizeof (SMM_FVB_READ_WRITE_HEADER) + *NumBytes; 515 Status = InitCommunicateBuffer ( 516 (VOID **)&SmmCommunicateHeader, 517 (VOID **)&SmmFvbReadWriteHeader, 518 PayloadSize, EFI_FUNCTION_READ 519 ); 520 if (EFI_ERROR (Status)) { 521 return Status; 522 } 523 524 SmmFvbReadWriteHeader->SmmFvb = SmmFvb; 525 SmmFvbReadWriteHeader->Lba = Lba; 526 SmmFvbReadWriteHeader->Offset = Offset; 527 SmmFvbReadWriteHeader->NumBytes = *NumBytes; 528 529 // 530 // Send data to SMM. 531 // 532 Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize); 533 534 // 535 // Get data from SMM. 536 // 537 *NumBytes = SmmFvbReadWriteHeader->NumBytes; 538 if (!EFI_ERROR (Status)) { 539 CopyMem (Buffer, (UINT8 *)(SmmFvbReadWriteHeader + 1), *NumBytes); 540 } 541 FreePool (SmmCommunicateHeader); 542 543 return Status; 544 } 545 546 547 /** 548 Writes data beginning at Lba:Offset from FV. The write terminates either 549 when *NumBytes of data have been written, or when a block boundary is 550 reached. *NumBytes is updated to reflect the actual number of bytes 551 written. The write opertion does not include erase. This routine will 552 attempt to write only the specified bytes. If the writes do not stick, 553 it will return an error. 554 555 @param[in] This Calling context. 556 @param[in] Lba Block in which to begin write. 557 @param[in] Offset Offset in the block at which to begin write. 558 @param[in,out] NumBytes On input, indicates the requested write size. On 559 output, indicates the actual number of bytes written. 560 @param[in] Buffer Buffer containing source data for the write. 561 562 @retval EFI_SUCCESS The firmware volume was written successfully. 563 @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On output, 564 NumBytes contains the total number of bytes FvbWrite(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Offset,IN OUT UINTN * NumBytes,IN UINT8 * Buffer)565 actually written. 566 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state. 567 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and 568 could not be written. 569 @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL. 570 571 **/ 572 EFI_STATUS 573 EFIAPI 574 FvbWrite ( 575 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 576 IN EFI_LBA Lba, 577 IN UINTN Offset, 578 IN OUT UINTN *NumBytes, 579 IN UINT8 *Buffer 580 ) 581 { 582 EFI_STATUS Status; 583 UINTN PayloadSize; 584 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; 585 SMM_FVB_READ_WRITE_HEADER *SmmFvbReadWriteHeader; 586 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; 587 EFI_FVB_DEVICE *FvbDevice; 588 589 if ((NumBytes == NULL) || (Buffer == NULL)) { 590 return EFI_INVALID_PARAMETER; 591 } 592 593 FvbDevice = FVB_DEVICE_FROM_THIS (This); 594 SmmFvb = FvbDevice->SmmFvbInstance; 595 596 // 597 // Initialize the communicate buffer. 598 // 599 PayloadSize = sizeof (SMM_FVB_READ_WRITE_HEADER) + *NumBytes; 600 Status = InitCommunicateBuffer ( 601 (VOID **)&SmmCommunicateHeader, 602 (VOID **)&SmmFvbReadWriteHeader, 603 PayloadSize, 604 EFI_FUNCTION_WRITE 605 ); 606 if (EFI_ERROR (Status)) { 607 return Status; 608 } 609 610 SmmFvbReadWriteHeader->SmmFvb = SmmFvb; 611 SmmFvbReadWriteHeader->Lba = Lba; 612 SmmFvbReadWriteHeader->Offset = Offset; 613 SmmFvbReadWriteHeader->NumBytes = *NumBytes; 614 CopyMem ((UINT8 *)(SmmFvbReadWriteHeader + 1), Buffer, *NumBytes); 615 616 // 617 // Send data to SMM. 618 // 619 Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize); 620 621 // 622 // Get data from SMM. 623 // 624 *NumBytes = SmmFvbReadWriteHeader->NumBytes; 625 FreePool (SmmCommunicateHeader); 626 627 return Status; 628 } 629 630 631 /** 632 The EraseBlock() function erases NumOfLba blocks started from StartingLba. 633 634 @param[in] This Calling context. 635 @param[in] StartingLba Starting LBA followed to erase. 636 @param[in] NumOfLba Number of block to erase. EraseBlock(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN EFI_LBA StartingLba,IN UINTN NumOfLba)637 638 @retval EFI_SUCCESS The erase request was successfully completed. 639 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state. 640 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and 641 could not be written. Firmware device may have been 642 partially erased. 643 644 **/ 645 EFI_STATUS 646 EraseBlock ( 647 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 648 IN EFI_LBA StartingLba, 649 IN UINTN NumOfLba 650 ) 651 { 652 EFI_STATUS Status; 653 UINTN PayloadSize; 654 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; 655 SMM_FVB_BLOCKS_HEADER *SmmFvbBlocksHeader; 656 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; 657 EFI_FVB_DEVICE *FvbDevice; 658 659 FvbDevice = FVB_DEVICE_FROM_THIS (This); 660 SmmFvb = FvbDevice->SmmFvbInstance; 661 662 // 663 // Initialize the communicate buffer. 664 // 665 PayloadSize = sizeof (SMM_FVB_BLOCKS_HEADER); 666 Status = InitCommunicateBuffer ( 667 (VOID **)&SmmCommunicateHeader, 668 (VOID **)&SmmFvbBlocksHeader, 669 PayloadSize, 670 EFI_FUNCTION_ERASE_BLOCKS 671 ); 672 if (EFI_ERROR (Status)) { 673 return Status; 674 } 675 676 SmmFvbBlocksHeader->SmmFvb = SmmFvb; 677 SmmFvbBlocksHeader->StartLba = StartingLba; 678 SmmFvbBlocksHeader->NumOfLba = NumOfLba; 679 680 // 681 // Send data to SMM. 682 // 683 Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize); 684 685 // 686 // Get data from SMM. 687 // 688 FreePool (SmmCommunicateHeader); 689 690 return Status; 691 } 692 693 694 /** 695 The EraseBlocks() function erases one or more blocks as denoted by the 696 variable argument list. The entire parameter list of blocks must be verified 697 prior to erasing any blocks. If a block is requested that does not exist 698 within the associated firmware volume (it has a larger index than the last 699 block of the firmware volume), the EraseBlock() function must return 700 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume. 701 702 @param[in] This Calling context/ 703 @param[in] ... Starting LBA followed by Number of Lba to erase. 704 a -1 to terminate the list. 705 / FvbEraseBlocks(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,...)706 @retval EFI_SUCCESS The erase request was successfully completed 707 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state/ 708 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and 709 could not be written. Firmware device may have been 710 partially erased/ 711 712 **/ 713 EFI_STATUS 714 EFIAPI 715 FvbEraseBlocks ( 716 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, 717 ... 718 ) 719 { 720 EFI_STATUS Status; 721 VA_LIST Marker; 722 EFI_LBA StartingLba; 723 UINTN NumOfLba; 724 725 Status = EFI_SUCCESS; 726 727 // 728 // Check the parameter. 729 // 730 VA_START (Marker, This); 731 do { 732 StartingLba = VA_ARG (Marker, EFI_LBA); 733 if (StartingLba == EFI_LBA_LIST_TERMINATOR ) { 734 break; 735 } 736 737 NumOfLba = VA_ARG (Marker, UINT32); 738 if (NumOfLba == 0) { 739 return EFI_INVALID_PARAMETER; 740 } 741 742 } while ( 1 ); 743 VA_END (Marker); 744 745 // 746 // Erase the blocks. 747 // 748 VA_START (Marker, This); 749 do { 750 StartingLba = VA_ARG (Marker, EFI_LBA); 751 if (StartingLba == EFI_LBA_LIST_TERMINATOR ) { 752 break; 753 } 754 NumOfLba = VA_ARG (Marker, UINT32); 755 Status = EraseBlock (This, StartingLba, NumOfLba); 756 if (EFI_ERROR (Status)) { 757 break; 758 } 759 } while ( 1 ); 760 VA_END (Marker); 761 762 return Status; 763 } InstallFvb(IN EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL * SmmFvb)764 765 766 /** 767 Install the FVB protocol which based on SMM FVB protocol. 768 769 @param[in] SmmFvb The SMM FVB protocol. 770 771 **/ 772 VOID 773 InstallFvb ( 774 IN EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb 775 ) 776 { 777 EFI_STATUS Status; 778 EFI_HANDLE FvbHandle; 779 EFI_FVB_DEVICE *FvbDevice; 780 EFI_FIRMWARE_VOLUME_HEADER *VolumeHeader; 781 EFI_PHYSICAL_ADDRESS Address; 782 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFvbInterface; 783 784 FvbDevice = AllocateRuntimeCopyPool (sizeof (EFI_FVB_DEVICE), &mFvbDeviceTemplate); 785 ASSERT (FvbDevice != NULL); 786 FvbDevice->SmmFvbInstance = SmmFvb; 787 788 Status = gBS->LocateProtocol ( 789 &gEfiSmmCommunicationProtocolGuid, 790 NULL, 791 (VOID **) &mSmmCommunication 792 ); 793 ASSERT_EFI_ERROR (Status); 794 795 Status = GetPhysicalAddress (SmmFvb, &Address); 796 ASSERT_EFI_ERROR (Status); 797 798 VolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN)Address; 799 800 // 801 // Set up the devicepath. 802 // 803 if (VolumeHeader->ExtHeaderOffset == 0) { 804 // 805 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH. 806 // 807 FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate); 808 ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.StartingAddress = (UINTN)Address; 809 ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.EndingAddress = (UINTN)Address + VolumeHeader->FvLength - 1; 810 } else { 811 FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate); 812 CopyGuid ( 813 &((FV_PIWG_DEVICE_PATH *)FvbDevice->DevicePath)->FvDevPath.FvName, 814 (GUID *)(UINTN)((UINTN)Address + VolumeHeader->ExtHeaderOffset) 815 ); 816 } 817 818 // 819 // Find a handle with a matching device path that has supports FW Block protocol. 820 // 821 Status = gBS->LocateDevicePath ( 822 &gEfiFirmwareVolumeBlockProtocolGuid, 823 &FvbDevice->DevicePath, 824 &FvbHandle 825 ); 826 if (EFI_ERROR (Status) ) { 827 // 828 // LocateDevicePath fails so install a new interface and device path. 829 // 830 FvbHandle = NULL; 831 Status = gBS->InstallMultipleProtocolInterfaces ( 832 &FvbHandle, 833 &gEfiFirmwareVolumeBlockProtocolGuid, 834 &FvbDevice->FvbInstance, 835 &gEfiDevicePathProtocolGuid, 836 FvbDevice->DevicePath, 837 NULL 838 ); 839 ASSERT_EFI_ERROR (Status); 840 } else if (IsDevicePathEnd (FvbDevice->DevicePath)) { 841 // 842 // Device allready exists, so reinstall the FVB protocol. 843 // 844 Status = gBS->HandleProtocol ( 845 FvbHandle, 846 &gEfiFirmwareVolumeBlockProtocolGuid, 847 (VOID **) &OldFvbInterface 848 ); 849 ASSERT_EFI_ERROR (Status); 850 851 Status = gBS->ReinstallProtocolInterface ( 852 FvbHandle, 853 &gEfiFirmwareVolumeBlockProtocolGuid, 854 OldFvbInterface, 855 &FvbDevice->FvbInstance 856 ); 857 ASSERT_EFI_ERROR (Status); 858 } else { 859 // 860 // There was a FVB protocol on an End Device Path node. 861 // 862 ASSERT (FALSE); 863 } 864 } 865 866 867 /** SmmFvbReady(IN EFI_EVENT Event,IN VOID * Context)868 SMM Firmware Volume Block Protocol notification event handler. 869 870 Discover NV Variable Store and install Variable Write Arch Protocol. 871 872 @param[in] Event Event whose notification function is being invoked. 873 @param[in] Context Pointer to the notification function's context. 874 **/ 875 VOID 876 EFIAPI 877 SmmFvbReady ( 878 IN EFI_EVENT Event, 879 IN VOID *Context 880 ) 881 { 882 EFI_STATUS Status; 883 EFI_HANDLE *HandleBuffer; 884 UINTN HandleCount; 885 UINTN Index; 886 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; 887 888 // 889 // Locate all handles of Smm Fvb protocol. 890 // 891 Status = gBS->LocateHandleBuffer ( 892 ByProtocol, 893 &gEfiSmmFirmwareVolumeBlockProtocolGuid, 894 NULL, 895 &HandleCount, 896 &HandleBuffer 897 ); 898 if (EFI_ERROR (Status)) { 899 return ; 900 } 901 902 // 903 // Install FVB protocol. 904 // 905 for (Index = 0; Index < HandleCount; Index++) { 906 SmmFvb = NULL; 907 Status = gBS->HandleProtocol ( 908 HandleBuffer[Index], 909 &gEfiSmmFirmwareVolumeBlockProtocolGuid, 910 (VOID **) &SmmFvb 911 ); 912 if (EFI_ERROR (Status)) { 913 break; 914 } 915 916 InstallFvb (SmmFvb); 917 } 918 919 FreePool (HandleBuffer); 920 } 921 922 923 /** 924 The driver entry point for Firmware Volume Block Driver. 925 926 The function does the necessary initialization work 927 Firmware Volume Block Driver. 928 FvbSmmDxeInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)929 @param[in] ImageHandle The firmware allocated handle for the UEFI image. 930 @param[in] SystemTable A pointer to the EFI system table. 931 932 @retval EFI_SUCCESS This funtion always return EFI_SUCCESS. 933 It will ASSERT on errors. 934 935 **/ 936 EFI_STATUS 937 EFIAPI 938 FvbSmmDxeInitialize ( 939 IN EFI_HANDLE ImageHandle, 940 IN EFI_SYSTEM_TABLE *SystemTable 941 ) 942 { 943 VOID *SmmFvbRegistration; 944 945 // 946 // Smm FVB driver is ready. 947 // 948 EfiCreateProtocolNotifyEvent ( 949 &gEfiSmmFirmwareVolumeBlockProtocolGuid, 950 TPL_CALLBACK, 951 SmmFvbReady, 952 NULL, 953 &SmmFvbRegistration 954 ); 955 956 return EFI_SUCCESS; 957 } 958 959