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
,
64 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
69 FvbProtocolGetAttributes
,
70 FvbProtocolSetAttributes
,
71 FvbProtocolGetPhysicalAddress
,
72 FvbProtocolGetBlockSize
,
75 FvbProtocolEraseBlocks
,
77 } // FwVolBlockInstance
82 Get the pointer to EFI_FW_VOL_INSTANCE from the buffer pointed
83 by mFvbModuleGlobal.FvInstance based on a index.
84 Each EFI_FW_VOL_INSTANCE is with variable length as
85 we have a block map at the end of the EFI_FIRMWARE_VOLUME_HEADER.
87 @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.
89 @return A pointer to EFI_FW_VOL_INSTANCE.
97 EFI_FW_VOL_INSTANCE
*FwhRecord
;
99 if ( Instance
>= mFvbModuleGlobal
.NumFv
) {
100 ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER
);
105 // Find the right instance of the FVB private data
107 FwhRecord
= mFvbModuleGlobal
.FvInstance
;
108 while ( Instance
> 0 ) {
109 FwhRecord
= (EFI_FW_VOL_INSTANCE
*) ((UINTN
)((UINT8
*)FwhRecord
) +
110 FwhRecord
->VolumeHeader
.HeaderLength
+
111 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
)));
121 Get the EFI_FVB_ATTRIBUTES_2 of a FV.
123 @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.
125 @retval EFI_FVB_ATTRIBUTES_2 of the FV identified by Instance.
130 FvbGetVolumeAttributes (
134 EFI_FW_VOL_INSTANCE
* FwInstance
;
135 FwInstance
= GetFvbInstance(Instance
);
136 ASSERT (FwInstance
!= NULL
);
138 if (FwInstance
== NULL
) {
142 return FwInstance
->VolumeHeader
.Attributes
;
148 Retrieves the starting address of an LBA in an FV. It also
149 return a few other attribut of the FV.
151 @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.
152 @param[in] Lba The logical block address
153 @param[out] LbaAddress On output, contains the physical starting address
155 @param[out] LbaLength On output, contains the length of the block
156 @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which the
157 number of consecutive blocks starting with Lba is
158 returned. All blocks in this range have a size of
161 @retval EFI_SUCCESS Successfully returns
162 @retval EFI_INVALID_PARAMETER Instance not found
170 OUT UINTN
*LbaAddress
,
171 OUT UINTN
*LbaLength
,
172 OUT UINTN
*NumOfBlocks
180 EFI_FW_VOL_INSTANCE
*FwhInstance
;
181 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
184 // Find the right instance of the FVB private data
186 FwhInstance
= GetFvbInstance (Instance
);
187 if (FwhInstance
== NULL
) {
188 return EFI_INVALID_PARAMETER
;
193 BlockMap
= &FwhInstance
->VolumeHeader
.BlockMap
[0];
194 ASSERT (BlockMap
!= NULL
);
197 // Parse the blockmap of the FV to find which map entry the Lba belongs to
200 if ( BlockMap
!= NULL
) {
201 NumBlocks
= BlockMap
->NumBlocks
;
202 BlockLength
= BlockMap
->Length
;
205 if ( NumBlocks
== 0 || BlockLength
== 0) {
206 return EFI_INVALID_PARAMETER
;
209 NextLba
= StartLba
+ NumBlocks
;
212 // The map entry found
214 if (Lba
>= StartLba
&& Lba
< NextLba
) {
215 Offset
= Offset
+ (UINTN
)MultU64x32((Lba
- StartLba
), BlockLength
);
216 if (LbaAddress
!= NULL
) {
217 *LbaAddress
= FwhInstance
->FvBase
+ Offset
;
220 if (LbaLength
!= NULL
) {
221 *LbaLength
= BlockLength
;
224 if (NumOfBlocks
!= NULL
) {
225 *NumOfBlocks
= (UINTN
)(NextLba
- Lba
);
231 Offset
= Offset
+ NumBlocks
* BlockLength
;
238 Reads specified number of bytes into a buffer from the specified block
240 @param[in] Instance The FV instance to be read from
241 @param[in] Lba The logical block address to be read from
242 @param[in] BlockOffset Offset into the block at which to begin reading
243 @param[in, out] NumBytes Pointer that on input contains the total size of
244 the buffer. On output, it contains the total number
246 @param[in] Buffer Pointer to a caller allocated buffer that will be
247 used to hold the data read
250 @retval EFI_SUCCESS The firmware volume was read successfully and
251 contents are in Buffer
252 @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On output,
253 NumBytes contains the total number of bytes returned
255 @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state
256 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
258 @retval EFI_INVALID_PARAMETER Instance not found, or NumBytes, Buffer are NULL
266 IN UINTN BlockOffset
,
267 IN OUT UINTN
*NumBytes
,
271 EFI_FVB_ATTRIBUTES_2 Attributes
;
275 EFI_STATUS ReadStatus
;
277 if ( (NumBytes
== NULL
) || (Buffer
== NULL
)) {
278 return (EFI_INVALID_PARAMETER
);
280 if (*NumBytes
== 0) {
281 return (EFI_INVALID_PARAMETER
);
284 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
);
285 if (EFI_ERROR(Status
)) {
289 Attributes
= FvbGetVolumeAttributes (Instance
);
291 if ( (Attributes
& EFI_FVB2_READ_STATUS
) == 0) {
292 return (EFI_ACCESS_DENIED
);
295 if (BlockOffset
> LbaLength
) {
296 return (EFI_INVALID_PARAMETER
);
299 if (LbaLength
< ( *NumBytes
+ BlockOffset
) ) {
300 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
301 Status
= EFI_BAD_BUFFER_SIZE
;
304 ReadStatus
= LibFvbFlashDeviceRead (LbaAddress
+ BlockOffset
, NumBytes
, Buffer
);
305 if (EFI_ERROR(ReadStatus
)) {
314 Writes specified number of bytes from the input buffer to the block
316 @param[in] Instance The FV instance to be written to
317 @param[in] Lba The starting logical block index to write to
318 @param[in] BlockOffset Offset into the block at which to begin writing
319 @param[in, out] NumBytes Pointer that on input contains the total size of
320 the buffer. On output, it contains the total number
321 of bytes actually written
322 @param[in] Buffer Pointer to a caller allocated buffer that contains
323 the source for the write
324 @retval EFI_SUCCESS The firmware volume was written successfully
325 @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On output,
326 NumBytes contains the total number of bytes
328 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state
329 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
331 @retval EFI_INVALID_PARAMETER Instance not found, or NumBytes, Buffer are NULL
338 IN UINTN BlockOffset
,
339 IN OUT UINTN
*NumBytes
,
343 EFI_FVB_ATTRIBUTES_2 Attributes
;
348 if ( (NumBytes
== NULL
) || (Buffer
== NULL
)) {
349 return (EFI_INVALID_PARAMETER
);
351 if (*NumBytes
== 0) {
352 return (EFI_INVALID_PARAMETER
);
355 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
);
356 if (EFI_ERROR(Status
)) {
361 // Check if the FV is write enabled
363 Attributes
= FvbGetVolumeAttributes (Instance
);
364 if ( (Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
365 return EFI_ACCESS_DENIED
;
369 // Perform boundary checks and adjust NumBytes
371 if (BlockOffset
> LbaLength
) {
372 return EFI_INVALID_PARAMETER
;
375 if ( LbaLength
< ( *NumBytes
+ BlockOffset
) ) {
377 "FvWriteBlock: Reducing Numbytes from 0x%x to 0x%x\n",
378 *NumBytes
, (UINT32
)(LbaLength
- BlockOffset
)));
379 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
380 return EFI_BAD_BUFFER_SIZE
;
383 LibFvbFlashDeviceBlockLock (LbaAddress
, LbaLength
, FALSE
);
384 Status
= LibFvbFlashDeviceWrite (LbaAddress
+ BlockOffset
, NumBytes
, Buffer
);
386 LibFvbFlashDeviceBlockLock (LbaAddress
, LbaLength
, TRUE
);
387 WriteBackInvalidateDataCacheRange ((VOID
*) (LbaAddress
+ BlockOffset
), *NumBytes
);
393 Erases and initializes a firmware volume block
395 @param[in] Instance The FV instance to be erased
396 @param[in] Lba The logical block index to be erased
398 @retval EFI_SUCCESS The erase request was successfully completed
399 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state
400 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
401 could not be written. Firmware device may have been
403 @retval EFI_INVALID_PARAMETER Instance not found
413 EFI_FVB_ATTRIBUTES_2 Attributes
;
419 // Check if the FV is write enabled
421 Attributes
= FvbGetVolumeAttributes (Instance
);
423 if( (Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
424 return (EFI_ACCESS_DENIED
);
428 // Get the starting address of the block for erase.
430 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
);
431 if (EFI_ERROR(Status
)) {
435 LibFvbFlashDeviceBlockLock (LbaAddress
, LbaLength
, FALSE
);
437 Status
= LibFvbFlashDeviceBlockErase (LbaAddress
, LbaLength
);
439 LibFvbFlashDeviceBlockLock (LbaAddress
, LbaLength
, TRUE
);
441 WriteBackInvalidateDataCacheRange ((VOID
*) LbaAddress
, LbaLength
);
447 Modifies the current settings of the firmware volume according to the
448 input parameter, and returns the new setting of the volume
450 @param[in] Instance The FV instance whose attributes is going to be
452 @param[in, out] Attributes On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
453 containing the desired firmware volume settings.
454 On successful return, it contains the new settings
455 of the firmware volume
457 @retval EFI_SUCCESS Successfully returns
458 @retval EFI_ACCESS_DENIED The volume setting is locked and cannot be modified
459 @retval EFI_INVALID_PARAMETER Instance not found, or The attributes requested are
460 in conflict with the capabilities as declared in the
461 firmware volume header
466 FvbSetVolumeAttributes (
468 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
471 EFI_FW_VOL_INSTANCE
*FwhInstance
;
472 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
473 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
474 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes
;
480 // Find the right instance of the FVB private data
482 FwhInstance
= GetFvbInstance (Instance
);
483 if (FwhInstance
== NULL
) {
484 return EFI_INVALID_PARAMETER
;
487 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
488 ASSERT (AttribPtr
!= NULL
);
489 if ( AttribPtr
== NULL
) {
490 return EFI_INVALID_PARAMETER
;
493 OldAttributes
= *AttribPtr
;
494 Capabilities
= OldAttributes
& EFI_FVB2_CAPABILITIES
;
495 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
496 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
498 UnchangedAttributes
= EFI_FVB2_READ_DISABLED_CAP
| \
499 EFI_FVB2_READ_ENABLED_CAP
| \
500 EFI_FVB2_WRITE_DISABLED_CAP
| \
501 EFI_FVB2_WRITE_ENABLED_CAP
| \
502 EFI_FVB2_LOCK_CAP
| \
503 EFI_FVB2_STICKY_WRITE
| \
504 EFI_FVB2_MEMORY_MAPPED
| \
505 EFI_FVB2_ERASE_POLARITY
| \
506 EFI_FVB2_READ_LOCK_CAP
| \
507 EFI_FVB2_WRITE_LOCK_CAP
| \
511 // Some attributes of FV is read only can *not* be set
513 if ((OldAttributes
& UnchangedAttributes
) ^ (*Attributes
& UnchangedAttributes
)) {
514 return EFI_INVALID_PARAMETER
;
518 // If firmware volume is locked, no status bit can be updated
520 if ((OldAttributes
& EFI_FVB2_LOCK_STATUS
) != 0) {
521 if ((OldStatus
^ NewStatus
) != 0) {
522 return EFI_ACCESS_DENIED
;
529 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
530 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
531 return EFI_INVALID_PARAMETER
;
538 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
539 if ((NewStatus
& EFI_FVB2_READ_STATUS
) != 0) {
540 return EFI_INVALID_PARAMETER
;
545 // Test write disable
547 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
548 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
549 return EFI_INVALID_PARAMETER
;
556 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
557 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) != 0) {
558 return EFI_INVALID_PARAMETER
;
565 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
566 if ((NewStatus
& EFI_FVB2_LOCK_STATUS
) != 0) {
567 return EFI_INVALID_PARAMETER
;
571 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
572 *AttribPtr
= (*AttribPtr
) | NewStatus
;
573 *Attributes
= *AttribPtr
;
580 Retrieves the physical address of the device.
582 @param[in] This A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL.
583 @param[out] Address Output buffer containing the address.
585 @retval EFI_SUCCESS The function always return successfully.
586 @retval EFI_INVALID_PARAMETER Instance not found.
591 FvbProtocolGetPhysicalAddress (
592 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
593 OUT EFI_PHYSICAL_ADDRESS
*Address
596 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
597 EFI_FW_VOL_INSTANCE
*FwhInstance
;
599 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
600 FwhInstance
= GetFvbInstance(FvbDevice
->Instance
);
601 if (FwhInstance
== NULL
) {
602 return EFI_INVALID_PARAMETER
;
605 *Address
= FwhInstance
->FvBase
;
612 Retrieve the size of a logical block
614 @param[in] This Calling context
615 @param[in] Lba Indicates which block to return the size for.
616 @param[out] BlockSize A pointer to a caller allocated UINTN in which
617 the size of the block is returned
618 @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which the
619 number of consecutive blocks starting with Lba is
620 returned. All blocks in this range have a size of
623 @retval EFI_SUCCESS The function always return successfully.
628 FvbProtocolGetBlockSize (
629 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
631 OUT UINTN
*BlockSize
,
632 OUT UINTN
*NumOfBlocks
635 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
637 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
638 return FvbGetLbaAddress (FvbDevice
->Instance
, Lba
, NULL
, BlockSize
, NumOfBlocks
);
643 Retrieves Volume attributes. No polarity translations are done.
645 @param[in] This Calling context
646 @param[out] Attributes Output buffer which contains attributes
648 @retval EFI_SUCCESS The function always return successfully.
653 FvbProtocolGetAttributes (
654 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
655 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
658 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
660 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
661 *Attributes
= FvbGetVolumeAttributes (FvbDevice
->Instance
);
668 Sets Volume attributes. No polarity translations are done.
670 @param[in] This Calling context
671 @param[in, out] Attributes Output buffer which contains attributes
673 @retval EFI_SUCCESS The function always return successfully.
678 FvbProtocolSetAttributes (
679 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
680 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
684 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
686 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
687 Status
= FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
);
694 This function erases one or more blocks as denoted by the
695 variable argument list. The entire parameter list of blocks must be verified
696 prior to erasing any blocks. If a block is requested that does not exist
697 within the associated firmware volume (it has a larger index than the last
698 block of the firmware volume), the EraseBlock() function must return
699 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
701 @param[in] This Calling context
702 @param[in] ... Starting LBA followed by Number of Lba to erase.
703 a -1 to terminate the list.
705 @retval EFI_SUCCESS The erase request was successfully completed
706 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state
707 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
708 could not be written. Firmware device may have been
714 FvbProtocolEraseBlocks (
715 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
719 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
720 EFI_FW_VOL_INSTANCE
*FwhInstance
;
727 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
728 FwhInstance
= GetFvbInstance (FvbDevice
->Instance
);
729 if (FwhInstance
== NULL
) {
730 return EFI_OUT_OF_RESOURCES
;
733 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
734 VA_START (args
, This
);
737 StartingLba
= VA_ARG (args
, EFI_LBA
);
738 if ( StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
742 NumOfLba
= VA_ARG (args
, UINT32
);
745 // Check input parameters
749 return EFI_INVALID_PARAMETER
;
752 if ( ( StartingLba
+ NumOfLba
) > NumOfBlocks
) {
753 return EFI_INVALID_PARAMETER
;
759 VA_START (args
, This
);
761 StartingLba
= VA_ARG (args
, EFI_LBA
);
762 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
766 NumOfLba
= VA_ARG (args
, UINT32
);
768 while ( NumOfLba
> 0 ) {
769 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
);
770 if ( EFI_ERROR(Status
)) {
787 Writes data beginning at Lba:Offset from FV. The write terminates either
788 when *NumBytes of data have been written, or when a block boundary is
789 reached. *NumBytes is updated to reflect the actual number of bytes
790 written. The write opertion does not include erase. This routine will
791 attempt to write only the specified bytes. If the writes do not stick,
792 it will return an error.
794 @param[in] This Calling context
795 @param[in] Lba Block in which to begin write
796 @param[in] Offset Offset in the block at which to begin write
797 @param[in,out] NumBytes On input, indicates the requested write size. On
798 output, indicates the actual number of bytes written
799 @param[in] Buffer Buffer containing source data for the write.
801 @retval EFI_SUCCESS The firmware volume was written successfully
802 @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On output,
803 NumBytes contains the total number of bytes
805 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state
806 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
808 @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL
814 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
817 IN OUT UINTN
*NumBytes
,
821 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
824 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
825 Status
= FvbWriteBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
);
826 DEBUG((DEBUG_VERBOSE
,
827 "FvbWrite: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x Status:%r\n",
828 Lba
, Offset
, *NumBytes
, Buffer
, Status
));
835 Reads data beginning at Lba:Offset from FV. The Read terminates either
836 when *NumBytes of data have been read, or when a block boundary is
837 reached. *NumBytes is updated to reflect the actual number of bytes
838 written. The write opertion does not include erase. This routine will
839 attempt to write only the specified bytes. If the writes do not stick,
840 it will return an error.
842 @param[in] This Calling context
843 @param[in] Lba Block in which to begin write
844 @param[in] Offset Offset in the block at which to begin write
845 @param[in,out] NumBytes On input, indicates the requested write size. On
846 output, indicates the actual number of bytes written
847 @param[out] Buffer Buffer containing source data for the write.
851 @retval EFI_SUCCESS The firmware volume was read successfully and
852 contents are in Buffer
853 @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On output,
854 NumBytes contains the total number of bytes returned
856 @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state
857 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
859 @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL
865 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
868 IN OUT UINTN
*NumBytes
,
873 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
876 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
877 Status
= FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
);
878 DEBUG((DEBUG_VERBOSE
,
879 "FvbRead: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x, Status:%r\n",
880 Lba
, Offset
, *NumBytes
, Buffer
, Status
));
886 Check the integrity of firmware volume header in FvBase
888 @param[in] FvBase A pointer to firmware volume base address.
890 @retval TRUE The firmware volume is consistent
891 @retval FALSE The firmware volume has corrupted.
896 IN EFI_PHYSICAL_ADDRESS FvBase
900 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
902 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) FvBase
;
903 if (FvBase
== PcdGet32(PcdFlashNvStorageVariableBase
)) {
904 if (CompareMem (&FwVolHeader
->FileSystemGuid
, &gEfiSystemNvDataFvGuid
, sizeof(EFI_GUID
)) != 0 ) {
905 DEBUG((DEBUG_INFO
, " --FileSystemGuid not match: %g\n", &FwVolHeader
->FileSystemGuid
));
909 if (CompareMem (&FwVolHeader
->FileSystemGuid
, &gEfiFirmwareFileSystem2Guid
, sizeof(EFI_GUID
)) != 0 ) {
910 DEBUG((DEBUG_INFO
, " --not expected guid.\n"));
915 if ( (FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
916 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
917 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
918 ((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
));
935 Get intial variable data.
937 @param[out] VarData Valid variable data.
938 @param[out] VarSize Valid variable size.
940 @retval RETURN_SUCCESS Successfully found initial variable data.
941 @retval RETURN_NOT_FOUND Failed to find the variable data file from FV.
942 @retval EFI_INVALID_PARAMETER VarData or VarSize is null.
946 GetInitialVariableData (
954 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
955 VARIABLE_STORE_HEADER
*VariableStore
;
956 AUTHENTICATED_VARIABLE_HEADER
*Variable
;
960 if ((VarData
== NULL
) || (VarSize
== NULL
)) {
961 return EFI_INVALID_PARAMETER
;
964 Status
= GetSectionFromAnyFv (PcdGetPtr(PcdNvsDataFile
), EFI_SECTION_RAW
, 0, &ImageData
, &ImageSize
);
965 if (EFI_ERROR (Status
)) {
969 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ImageData
;
970 VariableStore
= (VARIABLE_STORE_HEADER
*) ((UINT8
*)ImageData
+ FvHeader
->HeaderLength
);
971 VarEndAddr
= (UINTN
)VariableStore
+ VariableStore
->Size
;
972 Variable
= (AUTHENTICATED_VARIABLE_HEADER
*) HEADER_ALIGN (VariableStore
+ 1);
973 *VarData
= (VOID
*)Variable
;
974 while (((UINTN
)Variable
< VarEndAddr
)) {
975 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
;
1068 FwVolInstance
->FvBase
= (UINTN
)BaseAddress
;
1069 CopyMem (&FwVolInstance
->VolumeHeader
, FvHeader
, FvHeader
->HeaderLength
);
1072 // Process the block map for each FV. Assume it has same block size.
1074 FwVolInstance
->NumOfBlocks
= 0;
1075 FvHeader
= &FwVolInstance
->VolumeHeader
;
1076 for (BlockMap
= FvHeader
->BlockMap
; BlockMap
->NumBlocks
!= 0; BlockMap
++) {
1077 FwVolInstance
->NumOfBlocks
+= BlockMap
->NumBlocks
;
1081 // Add a FVB Protocol Instance
1083 Status
= InstallFvbProtocol (FwVolInstance
, mFvbModuleGlobal
.NumFv
);
1084 mFvbModuleGlobal
.NumFv
++;
1085 mFvbModuleGlobal
.FvInstance
= FwVolInstance
;