3 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
4 SPDX-License-Identifier: BSD-2-Clause-Patent
17 // The package level header files this module uses
22 // The protocols, PPI and GUID defintions for this module
24 #include <Guid/EventGroup.h>
25 #include <Protocol/FirmwareVolumeBlock.h>
26 #include <Protocol/DevicePath.h>
28 // The Library classes this module consumes
30 #include <Library/UefiLib.h>
31 #include <Library/UefiDriverEntryPoint.h>
32 #include <Library/BaseLib.h>
33 #include <Library/DxeServicesTableLib.h>
34 #include <Library/UefiRuntimeLib.h>
35 #include <Library/DebugLib.h>
36 #include <Library/HobLib.h>
37 #include <Library/BaseMemoryLib.h>
38 #include <Library/MemoryAllocationLib.h>
39 #include <Library/UefiBootServicesTableLib.h>
40 #include <Library/DevicePathLib.h>
42 #include "FWBlockService.h"
44 #define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
46 ESAL_FWB_GLOBAL
*mFvbModuleGlobal
;
48 FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate
= {
54 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
)),
55 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
) >> 8)
59 (EFI_PHYSICAL_ADDRESS
) 0,
60 (EFI_PHYSICAL_ADDRESS
) 0,
64 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
66 END_DEVICE_PATH_LENGTH
,
72 FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate
= {
78 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
)),
79 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
) >> 8)
86 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
88 END_DEVICE_PATH_LENGTH
,
94 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
99 FvbProtocolGetAttributes
,
100 FvbProtocolSetAttributes
,
101 FvbProtocolGetPhysicalAddress
,
102 FvbProtocolGetBlockSize
,
105 FvbProtocolEraseBlocks
,
114 FvbVirtualddressChangeEvent (
122 Fixup internal data so that EFI and SAL can be call in virtual mode.
123 Call the passed in Child Notify event and convert the mFvbModuleGlobal
124 date items to there virtual address.
126 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
127 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
132 (Standard EFI notify event - EFI_EVENT_NOTIFY)
140 EFI_FW_VOL_INSTANCE
*FwhInstance
;
143 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
146 // Convert the base address of all the instances
149 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
150 while (Index
< mFvbModuleGlobal
->NumFv
) {
151 EfiConvertPointer (0x0, (VOID
**) &FwhInstance
->FvBase
[FVB_VIRTUAL
]);
152 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
154 (UINTN
) ((UINT8
*) FwhInstance
) + FwhInstance
->VolumeHeader
.HeaderLength
+
155 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
160 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
]);
161 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
);
167 IN ESAL_FWB_GLOBAL
*Global
,
168 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
174 Retrieves the physical address of a memory mapped FV
177 Instance - The FV instance whose base address is going to be
179 Global - Pointer to ESAL_FWB_GLOBAL that contains all
181 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
182 Virtual - Whether CPU is in virtual or physical mode
185 EFI_SUCCESS - Successfully returns
186 EFI_INVALID_PARAMETER - Instance not found
190 EFI_FW_VOL_INSTANCE
*FwhRecord
;
192 if (Instance
>= Global
->NumFv
) {
193 return EFI_INVALID_PARAMETER
;
196 // Find the right instance of the FVB private data
198 FwhRecord
= Global
->FvInstance
[Virtual
];
199 while (Instance
> 0) {
200 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
202 (UINTN
) ((UINT8
*) FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
203 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
208 *FwhInstance
= FwhRecord
;
214 FvbGetPhysicalAddress (
216 OUT EFI_PHYSICAL_ADDRESS
*Address
,
217 IN ESAL_FWB_GLOBAL
*Global
,
223 Retrieves the physical address of a memory mapped FV
226 Instance - The FV instance whose base address is going to be
228 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
229 that on successful return, contains the base address
230 of the firmware volume.
231 Global - Pointer to ESAL_FWB_GLOBAL that contains all
233 Virtual - Whether CPU is in virtual or physical mode
236 EFI_SUCCESS - Successfully returns
237 EFI_INVALID_PARAMETER - Instance not found
241 EFI_FW_VOL_INSTANCE
*FwhInstance
;
245 // Find the right instance of the FVB private data
247 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
248 ASSERT_EFI_ERROR (Status
);
249 *Address
= FwhInstance
->FvBase
[Virtual
];
255 FvbGetVolumeAttributes (
257 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
258 IN ESAL_FWB_GLOBAL
*Global
,
264 Retrieves attributes, insures positive polarity of attribute bits, returns
265 resulting attributes in output parameter
268 Instance - The FV instance whose attributes is going to be
270 Attributes - Output buffer which contains attributes
271 Global - Pointer to ESAL_FWB_GLOBAL that contains all
273 Virtual - Whether CPU is in virtual or physical mode
276 EFI_SUCCESS - Successfully returns
277 EFI_INVALID_PARAMETER - Instance not found
281 EFI_FW_VOL_INSTANCE
*FwhInstance
;
285 // Find the right instance of the FVB private data
287 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
288 ASSERT_EFI_ERROR (Status
);
289 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
298 OUT UINTN
*LbaAddress
,
299 OUT UINTN
*LbaLength
,
300 OUT UINTN
*NumOfBlocks
,
301 IN ESAL_FWB_GLOBAL
*Global
,
307 Retrieves the starting address of an LBA in an FV
310 Instance - The FV instance which the Lba belongs to
311 Lba - The logical block address
312 LbaAddress - On output, contains the physical starting address
314 LbaLength - On output, contains the length of the block
315 NumOfBlocks - A pointer to a caller allocated UINTN in which the
316 number of consecutive blocks starting with Lba is
317 returned. All blocks in this range have a size of
319 Global - Pointer to ESAL_FWB_GLOBAL that contains all
321 Virtual - Whether CPU is in virtual or physical mode
324 EFI_SUCCESS - Successfully returns
325 EFI_INVALID_PARAMETER - Instance not found
334 EFI_FW_VOL_INSTANCE
*FwhInstance
;
335 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
339 // Find the right instance of the FVB private data
341 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
342 ASSERT_EFI_ERROR (Status
);
346 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
349 // Parse the blockmap of the FV to find which map entry the Lba belongs to
352 NumBlocks
= BlockMap
->NumBlocks
;
353 BlockLength
= BlockMap
->Length
;
355 if (NumBlocks
== 0 || BlockLength
== 0) {
356 return EFI_INVALID_PARAMETER
;
359 NextLba
= StartLba
+ NumBlocks
;
362 // The map entry found
364 if (Lba
>= StartLba
&& Lba
< NextLba
) {
365 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
366 if (LbaAddress
!= NULL
) {
367 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
370 if (LbaLength
!= NULL
) {
371 *LbaLength
= BlockLength
;
374 if (NumOfBlocks
!= NULL
) {
375 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
382 Offset
= Offset
+ NumBlocks
* BlockLength
;
391 IN UINTN BlockOffset
,
392 IN OUT UINTN
*NumBytes
,
394 IN ESAL_FWB_GLOBAL
*Global
,
400 Reads specified number of bytes into a buffer from the specified block
403 Instance - The FV instance to be read from
404 Lba - The logical block address to be read from
405 BlockOffset - Offset into the block at which to begin reading
406 NumBytes - Pointer that on input contains the total size of
407 the buffer. On output, it contains the total number
409 Buffer - Pointer to a caller allocated buffer that will be
410 used to hold the data read
411 Global - Pointer to ESAL_FWB_GLOBAL that contains all
413 Virtual - Whether CPU is in virtual or physical mode
416 EFI_SUCCESS - The firmware volume was read successfully and
417 contents are in Buffer
418 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
419 NumBytes contains the total number of bytes returned
421 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
422 EFI_DEVICE_ERROR - The block device is not functioning correctly and
424 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
428 EFI_FVB_ATTRIBUTES_2 Attributes
;
434 // Check for invalid conditions
436 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
437 return EFI_INVALID_PARAMETER
;
440 if (*NumBytes
== 0) {
441 return EFI_INVALID_PARAMETER
;
444 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
445 if (EFI_ERROR (Status
)) {
449 // Check if the FV is read enabled
451 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
453 if ((Attributes
& EFI_FVB2_READ_STATUS
) == 0) {
454 return EFI_ACCESS_DENIED
;
457 // Perform boundary checks and adjust NumBytes
459 if (BlockOffset
> LbaLength
) {
460 return EFI_INVALID_PARAMETER
;
463 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
464 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
465 Status
= EFI_BAD_BUFFER_SIZE
;
468 CopyMem (Buffer
, (UINT8
*) (LbaAddress
+ BlockOffset
), (UINTN
) (*NumBytes
));
477 IN UINTN BlockOffset
,
478 IN OUT UINTN
*NumBytes
,
480 IN ESAL_FWB_GLOBAL
*Global
,
486 Writes specified number of bytes from the input buffer to the block
489 Instance - The FV instance to be written to
490 Lba - The starting logical block index to write to
491 BlockOffset - Offset into the block at which to begin writing
492 NumBytes - Pointer that on input contains the total size of
493 the buffer. On output, it contains the total number
494 of bytes actually written
495 Buffer - Pointer to a caller allocated buffer that contains
496 the source for the write
497 Global - Pointer to ESAL_FWB_GLOBAL that contains all
499 Virtual - Whether CPU is in virtual or physical mode
502 EFI_SUCCESS - The firmware volume was written successfully
503 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
504 NumBytes contains the total number of bytes
506 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
507 EFI_DEVICE_ERROR - The block device is not functioning correctly and
509 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
513 EFI_FVB_ATTRIBUTES_2 Attributes
;
519 // Check for invalid conditions
521 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
522 return EFI_INVALID_PARAMETER
;
525 if (*NumBytes
== 0) {
526 return EFI_INVALID_PARAMETER
;
529 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
530 if (EFI_ERROR (Status
)) {
534 // Check if the FV is write enabled
536 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
538 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
539 return EFI_ACCESS_DENIED
;
542 // Perform boundary checks and adjust NumBytes
544 if (BlockOffset
> LbaLength
) {
545 return EFI_INVALID_PARAMETER
;
548 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
549 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
550 Status
= EFI_BAD_BUFFER_SIZE
;
555 CopyMem ((UINT8
*) (LbaAddress
+ BlockOffset
), Buffer
, (UINTN
) (*NumBytes
));
564 IN ESAL_FWB_GLOBAL
*Global
,
570 Erases and initializes a firmware volume block
573 Instance - The FV instance to be erased
574 Lba - The logical block index to be erased
575 Global - Pointer to ESAL_FWB_GLOBAL that contains all
577 Virtual - Whether CPU is in virtual or physical mode
580 EFI_SUCCESS - The erase request was successfully completed
581 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
582 EFI_DEVICE_ERROR - The block device is not functioning correctly and
583 could not be written. Firmware device may have been
585 EFI_INVALID_PARAMETER - Instance not found
590 EFI_FVB_ATTRIBUTES_2 Attributes
;
597 // Check if the FV is write enabled
599 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
601 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
602 return EFI_ACCESS_DENIED
;
605 // Get the starting address of the block for erase.
607 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
609 if (EFI_ERROR (Status
)) {
613 if ((Attributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
619 SetMem ((UINT8
*) LbaAddress
, LbaLength
, Data
);
625 FvbSetVolumeAttributes (
627 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
628 IN ESAL_FWB_GLOBAL
*Global
,
634 Modifies the current settings of the firmware volume according to the
635 input parameter, and returns the new setting of the volume
638 Instance - The FV instance whose attributes is going to be
640 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
641 containing the desired firmware volume settings.
642 On successful return, it contains the new settings
643 of the firmware volume
644 Global - Pointer to ESAL_FWB_GLOBAL that contains all
646 Virtual - Whether CPU is in virtual or physical mode
649 EFI_SUCCESS - Successfully returns
650 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
651 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
652 in conflict with the capabilities as declared in the
653 firmware volume header
657 EFI_FW_VOL_INSTANCE
*FwhInstance
;
658 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
659 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
664 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes
;
667 // Find the right instance of the FVB private data
669 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
670 ASSERT_EFI_ERROR (Status
);
672 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
673 OldAttributes
= *AttribPtr
;
674 Capabilities
= OldAttributes
& (EFI_FVB2_READ_DISABLED_CAP
| \
675 EFI_FVB2_READ_ENABLED_CAP
| \
676 EFI_FVB2_WRITE_DISABLED_CAP
| \
677 EFI_FVB2_WRITE_ENABLED_CAP
| \
680 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
681 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
683 UnchangedAttributes
= EFI_FVB2_READ_DISABLED_CAP
| \
684 EFI_FVB2_READ_ENABLED_CAP
| \
685 EFI_FVB2_WRITE_DISABLED_CAP
| \
686 EFI_FVB2_WRITE_ENABLED_CAP
| \
687 EFI_FVB2_LOCK_CAP
| \
688 EFI_FVB2_STICKY_WRITE
| \
689 EFI_FVB2_MEMORY_MAPPED
| \
690 EFI_FVB2_ERASE_POLARITY
| \
691 EFI_FVB2_READ_LOCK_CAP
| \
692 EFI_FVB2_WRITE_LOCK_CAP
| \
696 // Some attributes of FV is read only can *not* be set
698 if ((OldAttributes
& UnchangedAttributes
) ^ (*Attributes
& UnchangedAttributes
)) {
699 return EFI_INVALID_PARAMETER
;
702 // If firmware volume is locked, no status bit can be updated
704 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
705 if (OldStatus
^ NewStatus
) {
706 return EFI_ACCESS_DENIED
;
712 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
713 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
714 return EFI_INVALID_PARAMETER
;
720 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
721 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
722 return EFI_INVALID_PARAMETER
;
726 // Test write disable
728 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
729 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
730 return EFI_INVALID_PARAMETER
;
736 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
737 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
738 return EFI_INVALID_PARAMETER
;
744 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
745 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
746 return EFI_INVALID_PARAMETER
;
750 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
751 *AttribPtr
= (*AttribPtr
) | NewStatus
;
752 *Attributes
= *AttribPtr
;
761 FvbProtocolGetPhysicalAddress (
762 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
763 OUT EFI_PHYSICAL_ADDRESS
*Address
769 Retrieves the physical address of the device.
773 This - Calling context
774 Address - Output buffer containing the address.
779 EFI_SUCCESS - Successfully returns
783 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
785 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
787 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
792 FvbProtocolGetBlockSize (
793 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
794 IN CONST EFI_LBA Lba
,
795 OUT UINTN
*BlockSize
,
796 OUT UINTN
*NumOfBlocks
801 Retrieve the size of a logical block
804 This - Calling context
805 Lba - Indicates which block to return the size for.
806 BlockSize - A pointer to a caller allocated UINTN in which
807 the size of the block is returned
808 NumOfBlocks - a pointer to a caller allocated UINTN in which the
809 number of consecutive blocks starting with Lba is
810 returned. All blocks in this range have a size of
814 EFI_SUCCESS - The firmware volume was read successfully and
815 contents are in Buffer
819 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
821 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
823 return FvbGetLbaAddress (
836 FvbProtocolGetAttributes (
837 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
838 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
843 Retrieves Volume attributes. No polarity translations are done.
846 This - Calling context
847 Attributes - output buffer which contains attributes
850 EFI_SUCCESS - Successfully returns
854 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
856 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
858 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
863 FvbProtocolSetAttributes (
864 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
865 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
870 Sets Volume attributes. No polarity translations are done.
873 This - Calling context
874 Attributes - output buffer which contains attributes
877 EFI_SUCCESS - Successfully returns
881 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
883 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
885 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
890 FvbProtocolEraseBlocks (
891 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
898 The EraseBlock() function erases one or more blocks as denoted by the
899 variable argument list. The entire parameter list of blocks must be verified
900 prior to erasing any blocks. If a block is requested that does not exist
901 within the associated firmware volume (it has a larger index than the last
902 block of the firmware volume), the EraseBlock() function must return
903 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
906 This - Calling context
907 ... - Starting LBA followed by Number of Lba to erase.
908 a -1 to terminate the list.
911 EFI_SUCCESS - The erase request was successfully completed
912 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
913 EFI_DEVICE_ERROR - The block device is not functioning correctly and
914 could not be written. Firmware device may have been
919 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
920 EFI_FW_VOL_INSTANCE
*FwhInstance
;
927 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
929 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
930 ASSERT_EFI_ERROR (Status
);
932 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
934 VA_START (args
, This
);
937 StartingLba
= VA_ARG (args
, EFI_LBA
);
938 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
942 NumOfLba
= VA_ARG (args
, UINTN
);
945 // Check input parameters
947 if ((NumOfLba
== 0) || ((StartingLba
+ NumOfLba
) > NumOfBlocks
)) {
949 return EFI_INVALID_PARAMETER
;
955 VA_START (args
, This
);
957 StartingLba
= VA_ARG (args
, EFI_LBA
);
958 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
962 NumOfLba
= VA_ARG (args
, UINTN
);
964 while (NumOfLba
> 0) {
965 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
966 if (EFI_ERROR (Status
)) {
985 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
988 IN OUT UINTN
*NumBytes
,
995 Writes data beginning at Lba:Offset from FV. The write terminates either
996 when *NumBytes of data have been written, or when a block boundary is
997 reached. *NumBytes is updated to reflect the actual number of bytes
998 written. The write opertion does not include erase. This routine will
999 attempt to write only the specified bytes. If the writes do not stick,
1000 it will return an error.
1003 This - Calling context
1004 Lba - Block in which to begin write
1005 Offset - Offset in the block at which to begin write
1006 NumBytes - On input, indicates the requested write size. On
1007 output, indicates the actual number of bytes written
1008 Buffer - Buffer containing source data for the write.
1011 EFI_SUCCESS - The firmware volume was written successfully
1012 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
1013 NumBytes contains the total number of bytes
1015 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1016 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1017 could not be written
1018 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1023 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1025 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1027 return FvbWriteBlock (FvbDevice
->Instance
, (EFI_LBA
)Lba
, (UINTN
)Offset
, NumBytes
, (UINT8
*)Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1033 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1034 IN CONST EFI_LBA Lba
,
1035 IN CONST UINTN Offset
,
1036 IN OUT UINTN
*NumBytes
,
1041 Routine Description:
1043 Reads data beginning at Lba:Offset from FV. The Read terminates either
1044 when *NumBytes of data have been read, or when a block boundary is
1045 reached. *NumBytes is updated to reflect the actual number of bytes
1046 written. The write opertion does not include erase. This routine will
1047 attempt to write only the specified bytes. If the writes do not stick,
1048 it will return an error.
1051 This - Calling context
1052 Lba - Block in which to begin Read
1053 Offset - Offset in the block at which to begin Read
1054 NumBytes - On input, indicates the requested write size. On
1055 output, indicates the actual number of bytes Read
1056 Buffer - Buffer containing source data for the Read.
1059 EFI_SUCCESS - The firmware volume was read successfully and
1060 contents are in Buffer
1061 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1062 NumBytes contains the total number of bytes returned
1064 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1065 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1067 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1072 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1074 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1076 return FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1081 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1085 Routine Description:
1086 Check the integrity of firmware volume header
1089 FwVolHeader - A pointer to a firmware volume header
1092 EFI_SUCCESS - The firmware volume is consistent
1093 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1098 // Verify the header revision, header signature, length
1099 // Length of FvBlock cannot be 2**64-1
1100 // HeaderLength cannot be an odd number
1102 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1103 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1104 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
1105 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1107 return EFI_NOT_FOUND
;
1111 // Verify the header checksum
1113 if (CalculateCheckSum16 ((UINT16
*) FwVolHeader
, FwVolHeader
->HeaderLength
) != 0) {
1114 return EFI_NOT_FOUND
;
1123 IN EFI_HANDLE ImageHandle
,
1124 IN EFI_SYSTEM_TABLE
*SystemTable
1128 Routine Description:
1129 This function does common initialization for FVB services
1138 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1139 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1140 EFI_DXE_SERVICES
*DxeServices
;
1141 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
1143 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1144 EFI_HANDLE FwbHandle
;
1145 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1146 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1148 EFI_PHYSICAL_ADDRESS BaseAddress
;
1151 EFI_PEI_HOB_POINTERS FvHob
;
1154 // Get the DXE services table
1159 // Allocate runtime services data for global variable, which contains
1160 // the private data of all firmware volume block instances
1162 mFvbModuleGlobal
= AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL
));
1163 ASSERT (mFvbModuleGlobal
!= NULL
);
1166 // Calculate the total size for all firmware volume block instances
1170 FvHob
.Raw
= GetHobList ();
1171 while ((FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
)) != NULL
) {
1172 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1173 Length
= FvHob
.FirmwareVolume
->Length
;
1175 // Check if it is a "real" flash
1177 Status
= DxeServices
->GetMemorySpaceDescriptor (
1181 if (EFI_ERROR (Status
)) {
1185 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1186 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1190 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1191 Status
= ValidateFvHeader (FwVolHeader
);
1192 if (EFI_ERROR (Status
)) {
1196 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1197 if (EFI_ERROR (Status
)) {
1198 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1203 BufferSize
+= (sizeof (EFI_FW_VOL_INSTANCE
) + FwVolHeader
->HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1204 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1208 // Only need to allocate once. There is only one copy of physical memory for
1209 // the private data of each FV instance. But in virtual mode or in physical
1210 // mode, the address of the the physical memory may be different.
1212 mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] = AllocateRuntimePool (BufferSize
);
1213 ASSERT (mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] != NULL
);
1216 // Make a virtual copy of the FvInstance pointer.
1218 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1219 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1221 mFvbModuleGlobal
->NumFv
= 0;
1224 FvHob
.Raw
= GetHobList ();
1225 while (NULL
!= (FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
))) {
1226 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1227 Length
= FvHob
.FirmwareVolume
->Length
;
1229 // Check if it is a "real" flash
1231 Status
= DxeServices
->GetMemorySpaceDescriptor (
1235 if (EFI_ERROR (Status
)) {
1239 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1240 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1244 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1245 Status
= ValidateFvHeader (FwVolHeader
);
1246 if (EFI_ERROR (Status
)) {
1248 // Get FvbInfo to provide in FwhInstance.
1250 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1251 if (EFI_ERROR (Status
)) {
1252 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1256 // Write healthy FV header back.
1259 (VOID
*) (UINTN
) BaseAddress
,
1260 (VOID
*) FwVolHeader
,
1261 FwVolHeader
->HeaderLength
1265 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1266 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1268 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1269 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1270 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1274 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1276 // Get the maximum size of a block.
1278 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
1279 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1282 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1285 // The total number of blocks in the FV.
1287 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1290 // Add a FVB Protocol Instance
1292 FvbDevice
= AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1293 ASSERT (FvbDevice
!= NULL
);
1295 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1297 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1298 mFvbModuleGlobal
->NumFv
++;
1302 // Set up the devicepath
1304 if (FwVolHeader
->ExtHeaderOffset
== 0) {
1306 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
1308 FvbDevice
->DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH
), &mFvMemmapDevicePathTemplate
);
1309 ((FV_MEMMAP_DEVICE_PATH
*) FvbDevice
->DevicePath
)->MemMapDevPath
.StartingAddress
= BaseAddress
;
1310 ((FV_MEMMAP_DEVICE_PATH
*) FvbDevice
->DevicePath
)->MemMapDevPath
.EndingAddress
= BaseAddress
+ FwVolHeader
->FvLength
- 1;
1312 FvbDevice
->DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH
), &mFvPIWGDevicePathTemplate
);
1314 &((FV_PIWG_DEVICE_PATH
*)FvbDevice
->DevicePath
)->FvDevPath
.FvName
,
1315 (GUID
*)(UINTN
)(BaseAddress
+ FwVolHeader
->ExtHeaderOffset
)
1319 // Find a handle with a matching device path that has supports FW Block protocol
1321 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &FvbDevice
->DevicePath
, &FwbHandle
);
1322 if (EFI_ERROR (Status
)) {
1324 // LocateDevicePath fails so install a new interface and device path
1327 Status
= gBS
->InstallMultipleProtocolInterfaces (
1329 &gEfiFirmwareVolumeBlockProtocolGuid
,
1330 &FvbDevice
->FwVolBlockInstance
,
1331 &gEfiDevicePathProtocolGuid
,
1332 FvbDevice
->DevicePath
,
1335 ASSERT_EFI_ERROR (Status
);
1336 } else if (IsDevicePathEnd (FvbDevice
->DevicePath
)) {
1338 // Device allready exists, so reinstall the FVB protocol
1340 Status
= gBS
->HandleProtocol (
1342 &gEfiFirmwareVolumeBlockProtocolGuid
,
1343 (VOID
**)&OldFwbInterface
1345 ASSERT_EFI_ERROR (Status
);
1347 Status
= gBS
->ReinstallProtocolInterface (
1349 &gEfiFirmwareVolumeBlockProtocolGuid
,
1351 &FvbDevice
->FwVolBlockInstance
1353 ASSERT_EFI_ERROR (Status
);
1357 // There was a FVB protocol on an End Device Path node
1362 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1364 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1365 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1368 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);