3 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
4 Portions copyright (c) 2011, Apple Inc. All rights reserved.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Guid/EventGroup.h>
11 #include <Protocol/FirmwareVolumeBlock.h>
12 #include <Protocol/DevicePath.h>
14 #include <Library/UefiLib.h>
15 #include <Library/UefiDriverEntryPoint.h>
16 #include <Library/BaseLib.h>
17 #include <Library/DxeServicesTableLib.h>
18 #include <Library/UefiRuntimeLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/HobLib.h>
21 #include <Library/BaseMemoryLib.h>
22 #include <Library/MemoryAllocationLib.h>
23 #include <Library/UefiBootServicesTableLib.h>
24 #include <Library/DevicePathLib.h>
26 #include "FwBlockService.h"
28 ESAL_FWB_GLOBAL
*mFvbModuleGlobal
;
30 #define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
32 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
40 sizeof (MEMMAP_DEVICE_PATH
),
50 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
52 sizeof (EFI_DEVICE_PATH_PROTOCOL
),
59 FvbProtocolGetAttributes
,
60 FvbProtocolSetAttributes
,
61 FvbProtocolGetPhysicalAddress
,
62 FvbProtocolGetBlockSize
,
65 FvbProtocolEraseBlocks
,
72 FvbVirtualddressChangeEvent (
81 Fixup internal data so that EFI and SAL can be call in virtual mode.
82 Call the passed in Child Notify event and convert the mFvbModuleGlobal
83 date items to there virtual address.
85 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
86 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
91 (Standard EFI notify event - EFI_EVENT_NOTIFY)
99 EFI_FW_VOL_INSTANCE
*FwhInstance
;
102 EfiConvertPointer (0x0, (VOID
**)&mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
105 // Convert the base address of all the instances
108 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
109 while (Index
< mFvbModuleGlobal
->NumFv
) {
110 EfiConvertPointer (0x0, (VOID
**)&FwhInstance
->FvBase
[FVB_VIRTUAL
]);
111 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
113 (UINTN
)((UINT8
*)FwhInstance
) + FwhInstance
->VolumeHeader
.HeaderLength
+
114 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
119 EfiConvertPointer (0x0, (VOID
**)&mFvbModuleGlobal
);
125 IN ESAL_FWB_GLOBAL
*Global
,
126 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
133 Retrieves the physical address of a memory mapped FV
136 Instance - The FV instance whose base address is going to be
138 Global - Pointer to ESAL_FWB_GLOBAL that contains all
140 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
141 Virtual - Whether CPU is in virtual or physical mode
144 EFI_SUCCESS - Successfully returns
145 EFI_INVALID_PARAMETER - Instance not found
149 EFI_FW_VOL_INSTANCE
*FwhRecord
;
151 if (Instance
>= Global
->NumFv
) {
152 return EFI_INVALID_PARAMETER
;
156 // Find the right instance of the FVB private data
158 FwhRecord
= Global
->FvInstance
[Virtual
];
159 while (Instance
> 0) {
160 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
162 (UINTN
)((UINT8
*)FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
163 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
168 *FwhInstance
= FwhRecord
;
174 FvbGetPhysicalAddress (
176 OUT EFI_PHYSICAL_ADDRESS
*Address
,
177 IN ESAL_FWB_GLOBAL
*Global
,
184 Retrieves the physical address of a memory mapped FV
187 Instance - The FV instance whose base address is going to be
189 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
190 that on successful return, contains the base address
191 of the firmware volume.
192 Global - Pointer to ESAL_FWB_GLOBAL that contains all
194 Virtual - Whether CPU is in virtual or physical mode
197 EFI_SUCCESS - Successfully returns
198 EFI_INVALID_PARAMETER - Instance not found
202 EFI_FW_VOL_INSTANCE
*FwhInstance
= NULL
;
206 // Find the right instance of the FVB private data
208 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
209 ASSERT_EFI_ERROR (Status
);
210 *Address
= FwhInstance
->FvBase
[Virtual
];
216 FvbGetVolumeAttributes (
218 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
219 IN ESAL_FWB_GLOBAL
*Global
,
226 Retrieves attributes, insures positive polarity of attribute bits, returns
227 resulting attributes in output parameter
230 Instance - The FV instance whose attributes is going to be
232 Attributes - Output buffer which contains attributes
233 Global - Pointer to ESAL_FWB_GLOBAL that contains all
235 Virtual - Whether CPU is in virtual or physical mode
238 EFI_SUCCESS - Successfully returns
239 EFI_INVALID_PARAMETER - Instance not found
243 EFI_FW_VOL_INSTANCE
*FwhInstance
= NULL
;
247 // Find the right instance of the FVB private data
249 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
250 ASSERT_EFI_ERROR (Status
);
251 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
260 OUT UINTN
*LbaAddress
,
261 OUT UINTN
*LbaLength
,
262 OUT UINTN
*NumOfBlocks
,
263 IN ESAL_FWB_GLOBAL
*Global
,
270 Retrieves the starting address of an LBA in an FV
273 Instance - The FV instance which the Lba belongs to
274 Lba - The logical block address
275 LbaAddress - On output, contains the physical starting address
277 LbaLength - On output, contains the length of the block
278 NumOfBlocks - A pointer to a caller allocated UINTN in which the
279 number of consecutive blocks starting with Lba is
280 returned. All blocks in this range have a size of
282 Global - Pointer to ESAL_FWB_GLOBAL that contains all
284 Virtual - Whether CPU is in virtual or physical mode
287 EFI_SUCCESS - Successfully returns
288 EFI_INVALID_PARAMETER - Instance not found
297 EFI_FW_VOL_INSTANCE
*FwhInstance
= NULL
;
298 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
302 // Find the right instance of the FVB private data
304 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
305 ASSERT_EFI_ERROR (Status
);
309 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
312 // Parse the blockmap of the FV to find which map entry the Lba belongs to
315 NumBlocks
= BlockMap
->NumBlocks
;
316 BlockLength
= BlockMap
->Length
;
318 if ((NumBlocks
== 0) || (BlockLength
== 0)) {
319 return EFI_INVALID_PARAMETER
;
322 NextLba
= StartLba
+ NumBlocks
;
325 // The map entry found
327 if ((Lba
>= StartLba
) && (Lba
< NextLba
)) {
328 Offset
= Offset
+ (UINTN
)MultU64x32 ((Lba
- StartLba
), BlockLength
);
329 if (LbaAddress
!= NULL
) {
330 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
333 if (LbaLength
!= NULL
) {
334 *LbaLength
= BlockLength
;
337 if (NumOfBlocks
!= NULL
) {
338 *NumOfBlocks
= (UINTN
)(NextLba
- Lba
);
345 Offset
= Offset
+ NumBlocks
* BlockLength
;
354 IN UINTN BlockOffset
,
355 IN OUT UINTN
*NumBytes
,
357 IN ESAL_FWB_GLOBAL
*Global
,
364 Reads specified number of bytes into a buffer from the specified block
367 Instance - The FV instance to be read from
368 Lba - The logical block address to be read from
369 BlockOffset - Offset into the block at which to begin reading
370 NumBytes - Pointer that on input contains the total size of
371 the buffer. On output, it contains the total number
373 Buffer - Pointer to a caller allocated buffer that will be
374 used to hold the data read
375 Global - Pointer to ESAL_FWB_GLOBAL that contains all
377 Virtual - Whether CPU is in virtual or physical mode
380 EFI_SUCCESS - The firmware volume was read successfully and
381 contents are in Buffer
382 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
383 NumBytes contains the total number of bytes returned
385 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
386 EFI_DEVICE_ERROR - The block device is not functioning correctly and
388 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
392 EFI_FVB_ATTRIBUTES_2 Attributes
;
398 // Check for invalid conditions
400 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
401 return EFI_INVALID_PARAMETER
;
404 if (*NumBytes
== 0) {
405 return EFI_INVALID_PARAMETER
;
408 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
409 if (EFI_ERROR (Status
)) {
414 // Check if the FV is read enabled
416 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
418 if ((Attributes
& EFI_FVB2_READ_STATUS
) == 0) {
419 return EFI_ACCESS_DENIED
;
423 // Perform boundary checks and adjust NumBytes
425 if (BlockOffset
> LbaLength
) {
426 return EFI_INVALID_PARAMETER
;
429 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
430 *NumBytes
= (UINT32
)(LbaLength
- BlockOffset
);
431 Status
= EFI_BAD_BUFFER_SIZE
;
434 CopyMem (Buffer
, (UINT8
*)(LbaAddress
+ BlockOffset
), (UINTN
)(*NumBytes
));
443 IN UINTN BlockOffset
,
444 IN OUT UINTN
*NumBytes
,
446 IN ESAL_FWB_GLOBAL
*Global
,
453 Writes specified number of bytes from the input buffer to the block
456 Instance - The FV instance to be written to
457 Lba - The starting logical block index to write to
458 BlockOffset - Offset into the block at which to begin writing
459 NumBytes - Pointer that on input contains the total size of
460 the buffer. On output, it contains the total number
461 of bytes actually written
462 Buffer - Pointer to a caller allocated buffer that contains
463 the source for the write
464 Global - Pointer to ESAL_FWB_GLOBAL that contains all
466 Virtual - Whether CPU is in virtual or physical mode
469 EFI_SUCCESS - The firmware volume was written successfully
470 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
471 NumBytes contains the total number of bytes
473 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
474 EFI_DEVICE_ERROR - The block device is not functioning correctly and
476 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
480 EFI_FVB_ATTRIBUTES_2 Attributes
;
486 // Check for invalid conditions
488 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
489 return EFI_INVALID_PARAMETER
;
492 if (*NumBytes
== 0) {
493 return EFI_INVALID_PARAMETER
;
496 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
497 if (EFI_ERROR (Status
)) {
502 // Check if the FV is write enabled
504 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
506 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
507 return EFI_ACCESS_DENIED
;
511 // Perform boundary checks and adjust NumBytes
513 if (BlockOffset
> LbaLength
) {
514 return EFI_INVALID_PARAMETER
;
517 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
518 *NumBytes
= (UINT32
)(LbaLength
- BlockOffset
);
519 Status
= EFI_BAD_BUFFER_SIZE
;
525 CopyMem ((UINT8
*)(LbaAddress
+ BlockOffset
), Buffer
, (UINTN
)(*NumBytes
));
534 IN ESAL_FWB_GLOBAL
*Global
,
541 Erases and initializes a firmware volume block
544 Instance - The FV instance to be erased
545 Lba - The logical block index to be erased
546 Global - Pointer to ESAL_FWB_GLOBAL that contains all
548 Virtual - Whether CPU is in virtual or physical mode
551 EFI_SUCCESS - The erase request was successfully completed
552 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
553 EFI_DEVICE_ERROR - The block device is not functioning correctly and
554 could not be written. Firmware device may have been
556 EFI_INVALID_PARAMETER - Instance not found
560 EFI_FVB_ATTRIBUTES_2 Attributes
;
567 // Check if the FV is write enabled
569 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
571 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
572 return EFI_ACCESS_DENIED
;
576 // Get the starting address of the block for erase.
578 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
580 if (EFI_ERROR (Status
)) {
584 if ((Attributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
590 SetMem ((UINT8
*)LbaAddress
, LbaLength
, Data
);
596 FvbSetVolumeAttributes (
598 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
599 IN ESAL_FWB_GLOBAL
*Global
,
606 Modifies the current settings of the firmware volume according to the
607 input parameter, and returns the new setting of the volume
610 Instance - The FV instance whose attributes is going to be
612 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
613 containing the desired firmware volume settings.
614 On successful return, it contains the new settings
615 of the firmware volume
616 Global - Pointer to ESAL_FWB_GLOBAL that contains all
618 Virtual - Whether CPU is in virtual or physical mode
621 EFI_SUCCESS - Successfully returns
622 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
623 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
624 in conflict with the capabilities as declared in the
625 firmware volume header
629 EFI_FW_VOL_INSTANCE
*FwhInstance
= NULL
;
630 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
631 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
636 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes
;
639 // Find the right instance of the FVB private data
641 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
642 ASSERT_EFI_ERROR (Status
);
644 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*)&(FwhInstance
->VolumeHeader
.Attributes
);
645 OldAttributes
= *AttribPtr
;
646 Capabilities
= OldAttributes
& (EFI_FVB2_READ_DISABLED_CAP
| \
647 EFI_FVB2_READ_ENABLED_CAP
| \
648 EFI_FVB2_WRITE_DISABLED_CAP
| \
649 EFI_FVB2_WRITE_ENABLED_CAP
| \
653 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
654 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
655 UnchangedAttributes
= EFI_FVB2_READ_DISABLED_CAP
| \
656 EFI_FVB2_READ_ENABLED_CAP
| \
657 EFI_FVB2_WRITE_DISABLED_CAP
| \
658 EFI_FVB2_WRITE_ENABLED_CAP
| \
659 EFI_FVB2_LOCK_CAP
| \
660 EFI_FVB2_STICKY_WRITE
| \
661 EFI_FVB2_MEMORY_MAPPED
| \
662 EFI_FVB2_ERASE_POLARITY
| \
663 EFI_FVB2_READ_LOCK_CAP
| \
664 EFI_FVB2_WRITE_LOCK_CAP
| \
668 // Some attributes of FV is read only can *not* be set
670 if ((OldAttributes
& UnchangedAttributes
) ^ (*Attributes
& UnchangedAttributes
)) {
671 return EFI_INVALID_PARAMETER
;
675 // If firmware volume is locked, no status bit can be updated
677 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
678 if (OldStatus
^ NewStatus
) {
679 return EFI_ACCESS_DENIED
;
686 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
687 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
688 return EFI_INVALID_PARAMETER
;
695 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
696 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
697 return EFI_INVALID_PARAMETER
;
702 // Test write disable
704 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
705 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
706 return EFI_INVALID_PARAMETER
;
713 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
714 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
715 return EFI_INVALID_PARAMETER
;
722 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
723 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
724 return EFI_INVALID_PARAMETER
;
728 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
729 *AttribPtr
= (*AttribPtr
) | NewStatus
;
730 *Attributes
= *AttribPtr
;
740 FvbProtocolGetPhysicalAddress (
741 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
742 OUT EFI_PHYSICAL_ADDRESS
*Address
749 Retrieves the physical address of the device.
753 This - Calling context
754 Address - Output buffer containing the address.
759 EFI_SUCCESS - Successfully returns
763 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
765 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
767 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
772 FvbProtocolGetBlockSize (
773 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
775 OUT UINTN
*BlockSize
,
776 OUT UINTN
*NumOfBlocks
782 Retrieve the size of a logical block
785 This - Calling context
786 Lba - Indicates which block to return the size for.
787 BlockSize - A pointer to a caller allocated UINTN in which
788 the size of the block is returned
789 NumOfBlocks - a pointer to a caller allocated UINTN in which the
790 number of consecutive blocks starting with Lba is
791 returned. All blocks in this range have a size of
795 EFI_SUCCESS - The firmware volume was read successfully and
796 contents are in Buffer
800 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
802 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
804 return FvbGetLbaAddress (
817 FvbProtocolGetAttributes (
818 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
819 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
825 Retrieves Volume attributes. No polarity translations are done.
828 This - Calling context
829 Attributes - output buffer which contains attributes
832 EFI_SUCCESS - Successfully returns
836 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
838 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
840 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
845 FvbProtocolSetAttributes (
846 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
847 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
853 Sets Volume attributes. No polarity translations are done.
856 This - Calling context
857 Attributes - output buffer which contains attributes
860 EFI_SUCCESS - Successfully returns
864 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
866 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
868 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
873 FvbProtocolEraseBlocks (
874 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
882 The EraseBlock() function erases one or more blocks as denoted by the
883 variable argument list. The entire parameter list of blocks must be verified
884 prior to erasing any blocks. If a block is requested that does not exist
885 within the associated firmware volume (it has a larger index than the last
886 block of the firmware volume), the EraseBlock() function must return
887 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
890 This - Calling context
891 ... - Starting LBA followed by Number of Lba to erase.
892 a -1 to terminate the list.
895 EFI_SUCCESS - The erase request was successfully completed
896 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
897 EFI_DEVICE_ERROR - The block device is not functioning correctly and
898 could not be written. Firmware device may have been
903 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
904 EFI_FW_VOL_INSTANCE
*FwhInstance
= NULL
;
911 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
913 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
914 ASSERT_EFI_ERROR (Status
);
916 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
918 VA_START (args
, This
);
921 StartingLba
= VA_ARG (args
, EFI_LBA
);
922 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
926 NumOfLba
= VA_ARG (args
, UINTN
);
929 // Check input parameters
931 if ((NumOfLba
== 0) || ((StartingLba
+ NumOfLba
) > NumOfBlocks
)) {
933 return EFI_INVALID_PARAMETER
;
939 VA_START (args
, This
);
941 StartingLba
= VA_ARG (args
, EFI_LBA
);
942 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
946 NumOfLba
= VA_ARG (args
, UINTN
);
948 while (NumOfLba
> 0) {
949 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
950 if (EFI_ERROR (Status
)) {
968 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
971 IN OUT UINTN
*NumBytes
,
979 Writes data beginning at Lba:Offset from FV. The write terminates either
980 when *NumBytes of data have been written, or when a block boundary is
981 reached. *NumBytes is updated to reflect the actual number of bytes
982 written. The write opertion does not include erase. This routine will
983 attempt to write only the specified bytes. If the writes do not stick,
984 it will return an error.
987 This - Calling context
988 Lba - Block in which to begin write
989 Offset - Offset in the block at which to begin write
990 NumBytes - On input, indicates the requested write size. On
991 output, indicates the actual number of bytes written
992 Buffer - Buffer containing source data for the write.
995 EFI_SUCCESS - The firmware volume was written successfully
996 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
997 NumBytes contains the total number of bytes
999 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1000 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1001 could not be written
1002 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1006 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1008 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1010 return FvbWriteBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1016 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1019 IN OUT UINTN
*NumBytes
,
1025 Routine Description:
1027 Reads data beginning at Lba:Offset from FV. The Read terminates either
1028 when *NumBytes of data have been read, or when a block boundary is
1029 reached. *NumBytes is updated to reflect the actual number of bytes
1030 written. The write opertion does not include erase. This routine will
1031 attempt to write only the specified bytes. If the writes do not stick,
1032 it will return an error.
1035 This - Calling context
1036 Lba - Block in which to begin Read
1037 Offset - Offset in the block at which to begin Read
1038 NumBytes - On input, indicates the requested write size. On
1039 output, indicates the actual number of bytes Read
1040 Buffer - Buffer containing source data for the Read.
1043 EFI_SUCCESS - The firmware volume was read successfully and
1044 contents are in Buffer
1045 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1046 NumBytes contains the total number of bytes returned
1048 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1049 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1051 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1055 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1057 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1059 return FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1064 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1069 Routine Description:
1070 Check the integrity of firmware volume header
1073 FwVolHeader - A pointer to a firmware volume header
1076 EFI_SUCCESS - The firmware volume is consistent
1077 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1082 UINT16 HeaderLength
;
1086 // Verify the header revision, header signature, length
1087 // Length of FvBlock cannot be 2**64-1
1088 // HeaderLength cannot be an odd number
1090 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1091 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1092 (FwVolHeader
->FvLength
== ((UINTN
)-1)) ||
1093 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1096 return EFI_NOT_FOUND
;
1100 // Verify the header checksum
1102 HeaderLength
= (UINT16
)(FwVolHeader
->HeaderLength
/ 2);
1103 Ptr
= (UINT16
*)FwVolHeader
;
1105 while (HeaderLength
> 0) {
1106 Checksum
= Checksum
+ (*Ptr
);
1111 if (Checksum
!= 0) {
1112 return EFI_NOT_FOUND
;
1121 IN EFI_HANDLE ImageHandle
,
1122 IN EFI_SYSTEM_TABLE
*SystemTable
1127 Routine Description:
1128 This function does common initialization for FVB services
1137 EFI_FW_VOL_INSTANCE
*FwhInstance
= NULL
;
1138 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1139 EFI_DXE_SERVICES
*DxeServices
;
1140 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
1142 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1143 EFI_HANDLE FwbHandle
;
1144 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1145 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1146 EFI_DEVICE_PATH_PROTOCOL
*TempFwbDevicePath
;
1147 FV_DEVICE_PATH TempFvbDevicePathData
;
1149 EFI_PHYSICAL_ADDRESS BaseAddress
;
1152 EFI_PEI_HOB_POINTERS FvHob
;
1155 // Get the DXE services table
1160 // Allocate runtime services data for global variable, which contains
1161 // the private data of all firmware volume block instances
1163 Status
= gBS
->AllocatePool (
1164 EfiRuntimeServicesData
,
1165 sizeof (ESAL_FWB_GLOBAL
),
1166 (VOID
**)&mFvbModuleGlobal
1168 ASSERT_EFI_ERROR (Status
);
1171 // Calculate the total size for all firmware volume block instances
1175 FvHob
.Raw
= GetHobList ();
1176 while ((FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
)) != NULL
) {
1177 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1178 Length
= FvHob
.FirmwareVolume
->Length
;
1180 // Check if it is a "real" flash
1182 Status
= DxeServices
->GetMemorySpaceDescriptor (
1186 if (EFI_ERROR (Status
)) {
1190 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1191 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1195 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)BaseAddress
;
1196 Status
= ValidateFvHeader (FwVolHeader
);
1197 if (EFI_ERROR (Status
)) {
1201 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1202 if (EFI_ERROR (Status
)) {
1203 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1208 BufferSize
+= (sizeof (EFI_FW_VOL_INSTANCE
) + FwVolHeader
->HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1209 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1213 // Only need to allocate once. There is only one copy of physical memory for
1214 // the private data of each FV instance. But in virtual mode or in physical
1215 // mode, the address of the the physical memory may be different.
1217 Status
= gBS
->AllocatePool (
1218 EfiRuntimeServicesData
,
1220 (VOID
**)&mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
]
1222 ASSERT_EFI_ERROR (Status
);
1225 // Make a virtual copy of the FvInstance pointer.
1227 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1228 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1230 mFvbModuleGlobal
->NumFv
= 0;
1233 FvHob
.Raw
= GetHobList ();
1234 while (NULL
!= (FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
))) {
1235 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1236 Length
= FvHob
.FirmwareVolume
->Length
;
1238 // Check if it is a "real" flash
1240 Status
= DxeServices
->GetMemorySpaceDescriptor (
1244 if (EFI_ERROR (Status
)) {
1248 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1249 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1253 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)BaseAddress
;
1254 Status
= ValidateFvHeader (FwVolHeader
);
1255 if (EFI_ERROR (Status
)) {
1257 // Get FvbInfo to provide in FwhInstance.
1259 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1260 if (EFI_ERROR (Status
)) {
1261 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1266 // Write healthy FV header back.
1269 (VOID
*)(UINTN
)BaseAddress
,
1270 (VOID
*)FwVolHeader
,
1271 FwVolHeader
->HeaderLength
1275 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
)BaseAddress
;
1276 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
)BaseAddress
;
1278 CopyMem ((UINTN
*)&(FwhInstance
->VolumeHeader
), (UINTN
*)FwVolHeader
, FwVolHeader
->HeaderLength
);
1279 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1280 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1284 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1286 // Get the maximum size of a block. The size will be used to allocate
1287 // buffer for Scratch space, the intermediate buffer for FVB extension
1290 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
1291 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1294 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1298 // The total number of blocks in the FV.
1300 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1303 // Add a FVB Protocol Instance
1305 Status
= gBS
->AllocatePool (
1306 EfiRuntimeServicesData
,
1307 sizeof (EFI_FW_VOL_BLOCK_DEVICE
),
1310 ASSERT_EFI_ERROR (Status
);
1312 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1314 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1315 mFvbModuleGlobal
->NumFv
++;
1318 // Set up the devicepath
1320 FvbDevice
->DevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
1321 FvbDevice
->DevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ (FwVolHeader
->FvLength
- 1);
1324 // Find a handle with a matching device path that has supports FW Block protocol
1326 TempFwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)&TempFvbDevicePathData
;
1327 CopyMem (TempFwbDevicePath
, &FvbDevice
->DevicePath
, sizeof (FV_DEVICE_PATH
));
1328 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &TempFwbDevicePath
, &FwbHandle
);
1329 if (EFI_ERROR (Status
)) {
1331 // LocateDevicePath fails so install a new interface and device path
1334 Status
= gBS
->InstallMultipleProtocolInterfaces (
1336 &gEfiFirmwareVolumeBlockProtocolGuid
,
1337 &FvbDevice
->FwVolBlockInstance
,
1338 &gEfiDevicePathProtocolGuid
,
1339 &FvbDevice
->DevicePath
,
1342 ASSERT_EFI_ERROR (Status
);
1343 } else if (IsDevicePathEnd (TempFwbDevicePath
)) {
1345 // Device allready exists, so reinstall the FVB protocol
1347 Status
= gBS
->HandleProtocol (
1349 &gEfiFirmwareVolumeBlockProtocolGuid
,
1350 (VOID
**)&OldFwbInterface
1352 ASSERT_EFI_ERROR (Status
);
1354 Status
= gBS
->ReinstallProtocolInterface (
1356 &gEfiFirmwareVolumeBlockProtocolGuid
,
1358 &FvbDevice
->FwVolBlockInstance
1360 ASSERT_EFI_ERROR (Status
);
1363 // There was a FVB protocol on an End Device Path node
1368 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1370 (UINTN
)((UINT8
*)FwhInstance
) + FwVolHeader
->HeaderLength
+
1371 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1374 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);