2 Firmware Volume Block Driver to provide FVB service.
4 Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "FvbService.h"
12 // Global variable for this FVB driver which contains
13 // the private data of all firmware volume block instances
15 FWB_GLOBAL mFvbModuleGlobal
;
17 FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate
= {
23 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
)),
24 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
) >> 8)
28 (EFI_PHYSICAL_ADDRESS
)0,
29 (EFI_PHYSICAL_ADDRESS
)0,
33 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
35 END_DEVICE_PATH_LENGTH
,
41 FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate
= {
47 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
)),
48 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
) >> 8)
55 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
57 END_DEVICE_PATH_LENGTH
,
63 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
68 FvbProtocolGetAttributes
,
69 FvbProtocolSetAttributes
,
70 FvbProtocolGetPhysicalAddress
,
71 FvbProtocolGetBlockSize
,
74 FvbProtocolEraseBlocks
,
76 } // FwVolBlockInstance
80 Get the pointer to EFI_FW_VOL_INSTANCE from the buffer pointed
81 by mFvbModuleGlobal.FvInstance based on a index.
82 Each EFI_FW_VOL_INSTANCE is with variable length as
83 we have a block map at the end of the EFI_FIRMWARE_VOLUME_HEADER.
85 @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.
87 @return A pointer to EFI_FW_VOL_INSTANCE.
95 EFI_FW_VOL_INSTANCE
*FwhRecord
;
97 if ( Instance
>= mFvbModuleGlobal
.NumFv
) {
98 ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER
);
103 // Find the right instance of the FVB private data
105 FwhRecord
= mFvbModuleGlobal
.FvInstance
;
106 while ( Instance
> 0 ) {
107 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)((UINTN
)((UINT8
*)FwhRecord
) +
108 FwhRecord
->VolumeHeader
.HeaderLength
+
109 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
)));
117 Get the EFI_FVB_ATTRIBUTES_2 of a FV.
119 @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.
121 @retval EFI_FVB_ATTRIBUTES_2 of the FV identified by Instance.
126 FvbGetVolumeAttributes (
130 EFI_FW_VOL_INSTANCE
*FwInstance
;
132 FwInstance
= GetFvbInstance (Instance
);
133 ASSERT (FwInstance
!= NULL
);
135 if (FwInstance
== NULL
) {
139 return FwInstance
->VolumeHeader
.Attributes
;
143 Retrieves the starting address of an LBA in an FV. It also
144 return a few other attribut of the FV.
146 @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.
147 @param[in] Lba The logical block address
148 @param[out] LbaAddress On output, contains the physical starting address
150 @param[out] LbaLength On output, contains the length of the block
151 @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which the
152 number of consecutive blocks starting with Lba is
153 returned. All blocks in this range have a size of
156 @retval EFI_SUCCESS Successfully returns
157 @retval EFI_INVALID_PARAMETER Instance not found
165 OUT UINTN
*LbaAddress
,
166 OUT UINTN
*LbaLength
,
167 OUT UINTN
*NumOfBlocks
175 EFI_FW_VOL_INSTANCE
*FwhInstance
;
176 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
179 // Find the right instance of the FVB private data
181 FwhInstance
= GetFvbInstance (Instance
);
182 if (FwhInstance
== NULL
) {
183 return EFI_INVALID_PARAMETER
;
188 BlockMap
= &FwhInstance
->VolumeHeader
.BlockMap
[0];
189 ASSERT (BlockMap
!= NULL
);
192 // Parse the blockmap of the FV to find which map entry the Lba belongs to
195 if ( BlockMap
!= NULL
) {
196 NumBlocks
= BlockMap
->NumBlocks
;
197 BlockLength
= BlockMap
->Length
;
200 if ((NumBlocks
== 0) || (BlockLength
== 0)) {
201 return EFI_INVALID_PARAMETER
;
204 NextLba
= StartLba
+ NumBlocks
;
207 // The map entry found
209 if ((Lba
>= StartLba
) && (Lba
< NextLba
)) {
210 Offset
= Offset
+ (UINTN
)MultU64x32 ((Lba
- StartLba
), BlockLength
);
211 if (LbaAddress
!= NULL
) {
212 *LbaAddress
= FwhInstance
->FvBase
+ Offset
;
215 if (LbaLength
!= NULL
) {
216 *LbaLength
= BlockLength
;
219 if (NumOfBlocks
!= NULL
) {
220 *NumOfBlocks
= (UINTN
)(NextLba
- Lba
);
227 Offset
= Offset
+ NumBlocks
* BlockLength
;
233 Reads specified number of bytes into a buffer from the specified block
235 @param[in] Instance The FV instance to be read from
236 @param[in] Lba The logical block address to be read from
237 @param[in] BlockOffset Offset into the block at which to begin reading
238 @param[in, out] NumBytes Pointer that on input contains the total size of
239 the buffer. On output, it contains the total number
241 @param[in] Buffer Pointer to a caller allocated buffer that will be
242 used to hold the data read
245 @retval EFI_SUCCESS The firmware volume was read successfully and
246 contents are in Buffer
247 @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On output,
248 NumBytes contains the total number of bytes returned
250 @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state
251 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
253 @retval EFI_INVALID_PARAMETER Instance not found, or NumBytes, Buffer are NULL
261 IN UINTN BlockOffset
,
262 IN OUT UINTN
*NumBytes
,
266 EFI_FVB_ATTRIBUTES_2 Attributes
;
270 EFI_STATUS ReadStatus
;
272 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
273 return (EFI_INVALID_PARAMETER
);
276 if (*NumBytes
== 0) {
277 return (EFI_INVALID_PARAMETER
);
280 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
);
281 if (EFI_ERROR (Status
)) {
285 Attributes
= FvbGetVolumeAttributes (Instance
);
287 if ((Attributes
& EFI_FVB2_READ_STATUS
) == 0) {
288 return (EFI_ACCESS_DENIED
);
291 if (BlockOffset
> LbaLength
) {
292 return (EFI_INVALID_PARAMETER
);
295 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
296 *NumBytes
= (UINT32
)(LbaLength
- BlockOffset
);
297 Status
= EFI_BAD_BUFFER_SIZE
;
300 ReadStatus
= LibFvbFlashDeviceRead (LbaAddress
+ BlockOffset
, NumBytes
, Buffer
);
301 if (EFI_ERROR (ReadStatus
)) {
309 Writes specified number of bytes from the input buffer to the block
311 @param[in] Instance The FV instance to be written to
312 @param[in] Lba The starting logical block index to write to
313 @param[in] BlockOffset Offset into the block at which to begin writing
314 @param[in, out] NumBytes Pointer that on input contains the total size of
315 the buffer. On output, it contains the total number
316 of bytes actually written
317 @param[in] Buffer Pointer to a caller allocated buffer that contains
318 the source for the write
319 @retval EFI_SUCCESS The firmware volume was written successfully
320 @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On output,
321 NumBytes contains the total number of bytes
323 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state
324 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
326 @retval EFI_INVALID_PARAMETER Instance not found, or NumBytes, Buffer are NULL
333 IN UINTN BlockOffset
,
334 IN OUT UINTN
*NumBytes
,
338 EFI_FVB_ATTRIBUTES_2 Attributes
;
343 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
344 return (EFI_INVALID_PARAMETER
);
347 if (*NumBytes
== 0) {
348 return (EFI_INVALID_PARAMETER
);
351 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
);
352 if (EFI_ERROR (Status
)) {
357 // Check if the FV is write enabled
359 Attributes
= FvbGetVolumeAttributes (Instance
);
360 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
361 return EFI_ACCESS_DENIED
;
365 // Perform boundary checks and adjust NumBytes
367 if (BlockOffset
> LbaLength
) {
368 return EFI_INVALID_PARAMETER
;
371 if ( LbaLength
< (*NumBytes
+ BlockOffset
)) {
374 "FvWriteBlock: Reducing Numbytes from 0x%x to 0x%x\n",
376 (UINT32
)(LbaLength
- BlockOffset
)
378 *NumBytes
= (UINT32
)(LbaLength
- BlockOffset
);
379 return EFI_BAD_BUFFER_SIZE
;
382 LibFvbFlashDeviceBlockLock (LbaAddress
, LbaLength
, FALSE
);
383 Status
= LibFvbFlashDeviceWrite (LbaAddress
+ BlockOffset
, NumBytes
, Buffer
);
385 LibFvbFlashDeviceBlockLock (LbaAddress
, LbaLength
, TRUE
);
386 WriteBackInvalidateDataCacheRange ((VOID
*)(LbaAddress
+ BlockOffset
), *NumBytes
);
391 Erases and initializes a firmware volume block
393 @param[in] Instance The FV instance to be erased
394 @param[in] Lba The logical block index to be erased
396 @retval EFI_SUCCESS The erase request was successfully completed
397 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state
398 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
399 could not be written. Firmware device may have been
401 @retval EFI_INVALID_PARAMETER Instance not found
410 EFI_FVB_ATTRIBUTES_2 Attributes
;
416 // Check if the FV is write enabled
418 Attributes
= FvbGetVolumeAttributes (Instance
);
420 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
421 return (EFI_ACCESS_DENIED
);
425 // Get the starting address of the block for erase.
427 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
);
428 if (EFI_ERROR (Status
)) {
432 LibFvbFlashDeviceBlockLock (LbaAddress
, LbaLength
, FALSE
);
434 Status
= LibFvbFlashDeviceBlockErase (LbaAddress
, LbaLength
);
436 LibFvbFlashDeviceBlockLock (LbaAddress
, LbaLength
, TRUE
);
438 WriteBackInvalidateDataCacheRange ((VOID
*)LbaAddress
, LbaLength
);
444 Modifies the current settings of the firmware volume according to the
445 input parameter, and returns the new setting of the volume
447 @param[in] Instance The FV instance whose attributes is going to be
449 @param[in, out] Attributes On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
450 containing the desired firmware volume settings.
451 On successful return, it contains the new settings
452 of the firmware volume
454 @retval EFI_SUCCESS Successfully returns
455 @retval EFI_ACCESS_DENIED The volume setting is locked and cannot be modified
456 @retval EFI_INVALID_PARAMETER Instance not found, or The attributes requested are
457 in conflict with the capabilities as declared in the
458 firmware volume header
463 FvbSetVolumeAttributes (
465 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
468 EFI_FW_VOL_INSTANCE
*FwhInstance
;
469 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
470 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
471 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes
;
477 // Find the right instance of the FVB private data
479 FwhInstance
= GetFvbInstance (Instance
);
480 if (FwhInstance
== NULL
) {
481 return EFI_INVALID_PARAMETER
;
484 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*)&(FwhInstance
->VolumeHeader
.Attributes
);
485 ASSERT (AttribPtr
!= NULL
);
486 if ( AttribPtr
== NULL
) {
487 return EFI_INVALID_PARAMETER
;
490 OldAttributes
= *AttribPtr
;
491 Capabilities
= OldAttributes
& EFI_FVB2_CAPABILITIES
;
492 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
493 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
495 UnchangedAttributes
= EFI_FVB2_READ_DISABLED_CAP
| \
496 EFI_FVB2_READ_ENABLED_CAP
| \
497 EFI_FVB2_WRITE_DISABLED_CAP
| \
498 EFI_FVB2_WRITE_ENABLED_CAP
| \
499 EFI_FVB2_LOCK_CAP
| \
500 EFI_FVB2_STICKY_WRITE
| \
501 EFI_FVB2_MEMORY_MAPPED
| \
502 EFI_FVB2_ERASE_POLARITY
| \
503 EFI_FVB2_READ_LOCK_CAP
| \
504 EFI_FVB2_WRITE_LOCK_CAP
| \
508 // Some attributes of FV is read only can *not* be set
510 if ((OldAttributes
& UnchangedAttributes
) ^ (*Attributes
& UnchangedAttributes
)) {
511 return EFI_INVALID_PARAMETER
;
515 // If firmware volume is locked, no status bit can be updated
517 if ((OldAttributes
& EFI_FVB2_LOCK_STATUS
) != 0) {
518 if ((OldStatus
^ NewStatus
) != 0) {
519 return EFI_ACCESS_DENIED
;
526 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
527 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
528 return EFI_INVALID_PARAMETER
;
535 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
536 if ((NewStatus
& EFI_FVB2_READ_STATUS
) != 0) {
537 return EFI_INVALID_PARAMETER
;
542 // Test write disable
544 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
545 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
546 return EFI_INVALID_PARAMETER
;
553 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
554 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) != 0) {
555 return EFI_INVALID_PARAMETER
;
562 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
563 if ((NewStatus
& EFI_FVB2_LOCK_STATUS
) != 0) {
564 return EFI_INVALID_PARAMETER
;
568 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
569 *AttribPtr
= (*AttribPtr
) | NewStatus
;
570 *Attributes
= *AttribPtr
;
576 Retrieves the physical address of the device.
578 @param[in] This A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL.
579 @param[out] Address Output buffer containing the address.
581 @retval EFI_SUCCESS The function always return successfully.
582 @retval EFI_INVALID_PARAMETER Instance not found.
587 FvbProtocolGetPhysicalAddress (
588 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
589 OUT EFI_PHYSICAL_ADDRESS
*Address
592 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
593 EFI_FW_VOL_INSTANCE
*FwhInstance
;
595 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
596 FwhInstance
= GetFvbInstance (FvbDevice
->Instance
);
597 if (FwhInstance
== NULL
) {
598 return EFI_INVALID_PARAMETER
;
601 *Address
= FwhInstance
->FvBase
;
606 Retrieve the size of a logical block
608 @param[in] This Calling context
609 @param[in] Lba Indicates which block to return the size for.
610 @param[out] BlockSize A pointer to a caller allocated UINTN in which
611 the size of the block is returned
612 @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which the
613 number of consecutive blocks starting with Lba is
614 returned. All blocks in this range have a size of
617 @retval EFI_SUCCESS The function always return successfully.
622 FvbProtocolGetBlockSize (
623 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
625 OUT UINTN
*BlockSize
,
626 OUT UINTN
*NumOfBlocks
629 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
631 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
632 return FvbGetLbaAddress (FvbDevice
->Instance
, Lba
, NULL
, BlockSize
, NumOfBlocks
);
636 Retrieves Volume attributes. No polarity translations are done.
638 @param[in] This Calling context
639 @param[out] Attributes Output buffer which contains attributes
641 @retval EFI_SUCCESS The function always return successfully.
646 FvbProtocolGetAttributes (
647 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
648 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
651 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
653 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
654 *Attributes
= FvbGetVolumeAttributes (FvbDevice
->Instance
);
660 Sets Volume attributes. No polarity translations are done.
662 @param[in] This Calling context
663 @param[in, out] Attributes Output buffer which contains attributes
665 @retval EFI_SUCCESS The function always return successfully.
670 FvbProtocolSetAttributes (
671 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
672 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
676 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
678 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
679 Status
= FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
);
684 This function erases one or more blocks as denoted by the
685 variable argument list. The entire parameter list of blocks must be verified
686 prior to erasing any blocks. If a block is requested that does not exist
687 within the associated firmware volume (it has a larger index than the last
688 block of the firmware volume), the EraseBlock() function must return
689 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
691 @param[in] This Calling context
692 @param[in] ... Starting LBA followed by Number of Lba to erase.
693 a -1 to terminate the list.
695 @retval EFI_SUCCESS The erase request was successfully completed
696 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state
697 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
698 could not be written. Firmware device may have been
704 FvbProtocolEraseBlocks (
705 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
709 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
710 EFI_FW_VOL_INSTANCE
*FwhInstance
;
717 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
718 FwhInstance
= GetFvbInstance (FvbDevice
->Instance
);
719 if (FwhInstance
== NULL
) {
720 return EFI_OUT_OF_RESOURCES
;
723 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
724 VA_START (args
, This
);
727 StartingLba
= VA_ARG (args
, EFI_LBA
);
728 if ( StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
732 NumOfLba
= VA_ARG (args
, UINT32
);
735 // Check input parameters
739 return EFI_INVALID_PARAMETER
;
742 if ((StartingLba
+ NumOfLba
) > NumOfBlocks
) {
743 return EFI_INVALID_PARAMETER
;
749 VA_START (args
, This
);
751 StartingLba
= VA_ARG (args
, EFI_LBA
);
752 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
756 NumOfLba
= VA_ARG (args
, UINT32
);
758 while ( NumOfLba
> 0 ) {
759 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
);
760 if ( EFI_ERROR (Status
)) {
776 Writes data beginning at Lba:Offset from FV. The write terminates either
777 when *NumBytes of data have been written, or when a block boundary is
778 reached. *NumBytes is updated to reflect the actual number of bytes
779 written. The write opertion does not include erase. This routine will
780 attempt to write only the specified bytes. If the writes do not stick,
781 it will return an error.
783 @param[in] This Calling context
784 @param[in] Lba Block in which to begin write
785 @param[in] Offset Offset in the block at which to begin write
786 @param[in,out] NumBytes On input, indicates the requested write size. On
787 output, indicates the actual number of bytes written
788 @param[in] Buffer Buffer containing source data for the write.
790 @retval EFI_SUCCESS The firmware volume was written successfully
791 @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On output,
792 NumBytes contains the total number of bytes
794 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state
795 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
797 @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL
803 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
806 IN OUT UINTN
*NumBytes
,
810 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
813 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
814 Status
= FvbWriteBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
);
817 "FvbWrite: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x Status:%r\n",
829 Reads data beginning at Lba:Offset from FV. The Read terminates either
830 when *NumBytes of data have been read, or when a block boundary is
831 reached. *NumBytes is updated to reflect the actual number of bytes
832 written. The write opertion does not include erase. This routine will
833 attempt to write only the specified bytes. If the writes do not stick,
834 it will return an error.
836 @param[in] This Calling context
837 @param[in] Lba Block in which to begin write
838 @param[in] Offset Offset in the block at which to begin write
839 @param[in,out] NumBytes On input, indicates the requested write size. On
840 output, indicates the actual number of bytes written
841 @param[out] Buffer Buffer containing source data for the write.
845 @retval EFI_SUCCESS The firmware volume was read successfully and
846 contents are in Buffer
847 @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On output,
848 NumBytes contains the total number of bytes returned
850 @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state
851 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
853 @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL
859 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
862 IN OUT UINTN
*NumBytes
,
866 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
869 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
870 Status
= FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
);
873 "FvbRead: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x, Status:%r\n",
885 Check the integrity of firmware volume header in FvBase
887 @param[in] FvBase A pointer to firmware volume base address.
889 @retval TRUE The firmware volume is consistent
890 @retval FALSE The firmware volume has corrupted.
895 IN EFI_PHYSICAL_ADDRESS FvBase
899 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
901 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)FvBase
;
902 if (FvBase
== PcdGet32 (PcdFlashNvStorageVariableBase
)) {
903 if (CompareMem (&FwVolHeader
->FileSystemGuid
, &gEfiSystemNvDataFvGuid
, sizeof (EFI_GUID
)) != 0 ) {
904 DEBUG ((DEBUG_INFO
, " --FileSystemGuid not match: %g\n", &FwVolHeader
->FileSystemGuid
));
908 if (CompareMem (&FwVolHeader
->FileSystemGuid
, &gEfiFirmwareFileSystem2Guid
, sizeof (EFI_GUID
)) != 0 ) {
909 DEBUG ((DEBUG_INFO
, " --not expected guid.\n"));
914 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
915 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
916 (FwVolHeader
->FvLength
== ((UINTN
)-1)) ||
917 ((FwVolHeader
->HeaderLength
& 0x01) != 0))
919 DEBUG ((DEBUG_INFO
, " -- >Revision = 0x%x, Signature = 0x%x\n", FwVolHeader
->Revision
, FwVolHeader
->Signature
));
920 DEBUG ((DEBUG_INFO
, " -- >FvLength = 0x%lx, HeaderLength = 0x%x\n", FwVolHeader
->FvLength
, FwVolHeader
->HeaderLength
));
924 Sum
= CalculateSum16 ((UINT16
*)FwVolHeader
, FwVolHeader
->HeaderLength
);
926 DEBUG ((DEBUG_INFO
, "error: checksum: 0x%04X (expect 0x0)\n", Sum
));
934 Get intial variable data.
936 @param[out] VarData Valid variable data.
937 @param[out] VarSize Valid variable size.
939 @retval RETURN_SUCCESS Successfully found initial variable data.
940 @retval RETURN_NOT_FOUND Failed to find the variable data file from FV.
941 @retval EFI_INVALID_PARAMETER VarData or VarSize is null.
945 GetInitialVariableData (
953 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
954 VARIABLE_STORE_HEADER
*VariableStore
;
955 AUTHENTICATED_VARIABLE_HEADER
*Variable
;
959 if ((VarData
== NULL
) || (VarSize
== NULL
)) {
960 return EFI_INVALID_PARAMETER
;
963 Status
= GetSectionFromAnyFv (PcdGetPtr (PcdNvsDataFile
), EFI_SECTION_RAW
, 0, &ImageData
, &ImageSize
);
964 if (EFI_ERROR (Status
)) {
968 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)ImageData
;
969 VariableStore
= (VARIABLE_STORE_HEADER
*)((UINT8
*)ImageData
+ FvHeader
->HeaderLength
);
970 VarEndAddr
= (UINTN
)VariableStore
+ VariableStore
->Size
;
971 Variable
= (AUTHENTICATED_VARIABLE_HEADER
*)HEADER_ALIGN (VariableStore
+ 1);
972 *VarData
= (VOID
*)Variable
;
973 while (((UINTN
)Variable
< VarEndAddr
)) {
974 if (Variable
->StartId
!= VARIABLE_DATA
) {
978 VariableSize
= sizeof (AUTHENTICATED_VARIABLE_HEADER
) + Variable
->DataSize
+ Variable
->NameSize
;
979 Variable
= (AUTHENTICATED_VARIABLE_HEADER
*)HEADER_ALIGN ((UINTN
)Variable
+ VariableSize
);
982 *VarSize
= (UINTN
)Variable
- HEADER_ALIGN (VariableStore
+ 1);
988 The function does the necessary initialization work for
989 Firmware Volume Block Driver.
991 @retval EFI_SUCCESS This funtion always return EFI_SUCCESS.
992 It will ASSERT on errors.
1000 EFI_FW_VOL_INSTANCE
*FwVolInstance
;
1001 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
1002 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
1003 EFI_PHYSICAL_ADDRESS BaseAddress
;
1008 VARIABLE_STORE_HEADER VariableStore
;
1011 InitVariableStore ();
1012 BaseAddress
= PcdGet32 (PcdFlashNvStorageVariableBase
);
1013 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)BaseAddress
;
1016 // Check FV header and variable store header
1018 if (!IsFvHeaderValid (BaseAddress
)) {
1020 // Write back a healthy FV header
1022 DEBUG ((DEBUG_ERROR
, "Fvb: Writing back a healthy FV header: 0x%lx\n", BaseAddress
));
1023 FvHeader
= GetFvHeaderTemplate ();
1024 LibFvbFlashDeviceBlockLock ((UINTN
)BaseAddress
, FvHeader
->BlockMap
->Length
, FALSE
);
1026 Status
= LibFvbFlashDeviceBlockErase ((UINTN
)BaseAddress
, FvHeader
->BlockMap
->Length
);
1027 ASSERT_EFI_ERROR (Status
);
1029 Length
= FvHeader
->HeaderLength
;
1030 WriteAddr
= (UINTN
)BaseAddress
;
1031 Status
= LibFvbFlashDeviceWrite (WriteAddr
, &Length
, (UINT8
*)FvHeader
);
1032 WriteAddr
+= Length
;
1033 ASSERT_EFI_ERROR (Status
);
1036 // Write back variable store header
1038 VariableStore
.Size
= PcdGet32 (PcdFlashNvStorageVariableSize
) - FvHeader
->HeaderLength
;
1039 VariableStore
.Format
= VARIABLE_STORE_FORMATTED
;
1040 VariableStore
.State
= VARIABLE_STORE_HEALTHY
;
1041 CopyGuid (&VariableStore
.Signature
, &gEfiAuthenticatedVariableGuid
);
1042 BufferSize
= sizeof (VARIABLE_STORE_HEADER
);
1043 Status
= LibFvbFlashDeviceWrite (WriteAddr
, &BufferSize
, (UINT8
*)&VariableStore
);
1044 WriteAddr
+= BufferSize
;
1045 ASSERT_EFI_ERROR (Status
);
1048 // Write initial variable data if found
1050 Status
= GetInitialVariableData (&VarData
, &Length
);
1051 if (!EFI_ERROR (Status
)) {
1052 Status
= LibFvbFlashDeviceWrite (WriteAddr
, &Length
, (UINT8
*)VarData
);
1053 ASSERT_EFI_ERROR (Status
);
1056 LibFvbFlashDeviceBlockLock ((UINTN
)BaseAddress
, FvHeader
->BlockMap
->Length
, TRUE
);
1057 WriteBackInvalidateDataCacheRange ((VOID
*)(UINTN
)BaseAddress
, FvHeader
->BlockMap
->Length
);
1061 // Create a new FW volume instance for NVS variable
1063 BufferSize
= FvHeader
->HeaderLength
+ sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
1064 FwVolInstance
= (EFI_FW_VOL_INSTANCE
*)AllocateRuntimeZeroPool (BufferSize
);
1065 if (FwVolInstance
== NULL
) {
1066 return EFI_OUT_OF_RESOURCES
;
1069 FwVolInstance
->FvBase
= (UINTN
)BaseAddress
;
1070 CopyMem (&FwVolInstance
->VolumeHeader
, FvHeader
, FvHeader
->HeaderLength
);
1073 // Process the block map for each FV. Assume it has same block size.
1075 FwVolInstance
->NumOfBlocks
= 0;
1076 FvHeader
= &FwVolInstance
->VolumeHeader
;
1077 for (BlockMap
= FvHeader
->BlockMap
; BlockMap
->NumBlocks
!= 0; BlockMap
++) {
1078 FwVolInstance
->NumOfBlocks
+= BlockMap
->NumBlocks
;
1082 // Add a FVB Protocol Instance
1084 Status
= InstallFvbProtocol (FwVolInstance
, mFvbModuleGlobal
.NumFv
);
1085 mFvbModuleGlobal
.NumFv
++;
1086 mFvbModuleGlobal
.FvInstance
= FwVolInstance
;