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
,
74 FvbVirtualddressChangeEvent (
82 Fixup internal data so that EFI and SAL can be call in virtual mode.
83 Call the passed in Child Notify event and convert the mFvbModuleGlobal
84 date items to there virtual address.
86 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
87 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
92 (Standard EFI notify event - EFI_EVENT_NOTIFY)
100 EFI_FW_VOL_INSTANCE
*FwhInstance
;
103 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
106 // Convert the base address of all the instances
109 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
110 while (Index
< mFvbModuleGlobal
->NumFv
) {
111 EfiConvertPointer (0x0, (VOID
**) &FwhInstance
->FvBase
[FVB_VIRTUAL
]);
112 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
114 (UINTN
) ((UINT8
*) FwhInstance
) + FwhInstance
->VolumeHeader
.HeaderLength
+
115 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
120 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
);
126 IN ESAL_FWB_GLOBAL
*Global
,
127 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
;
155 // Find the right instance of the FVB private data
157 FwhRecord
= Global
->FvInstance
[Virtual
];
158 while (Instance
> 0) {
159 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
161 (UINTN
) ((UINT8
*) FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
162 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
167 *FwhInstance
= FwhRecord
;
173 FvbGetPhysicalAddress (
175 OUT EFI_PHYSICAL_ADDRESS
*Address
,
176 IN ESAL_FWB_GLOBAL
*Global
,
182 Retrieves the physical address of a memory mapped FV
185 Instance - The FV instance whose base address is going to be
187 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
188 that on successful return, contains the base address
189 of the firmware volume.
190 Global - Pointer to ESAL_FWB_GLOBAL that contains all
192 Virtual - Whether CPU is in virtual or physical mode
195 EFI_SUCCESS - Successfully returns
196 EFI_INVALID_PARAMETER - Instance not found
200 EFI_FW_VOL_INSTANCE
*FwhInstance
= NULL
;
204 // Find the right instance of the FVB private data
206 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
207 ASSERT_EFI_ERROR (Status
);
208 *Address
= FwhInstance
->FvBase
[Virtual
];
214 FvbGetVolumeAttributes (
216 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
217 IN ESAL_FWB_GLOBAL
*Global
,
223 Retrieves attributes, insures positive polarity of attribute bits, returns
224 resulting attributes in output parameter
227 Instance - The FV instance whose attributes is going to be
229 Attributes - Output buffer which contains attributes
230 Global - Pointer to ESAL_FWB_GLOBAL that contains all
232 Virtual - Whether CPU is in virtual or physical mode
235 EFI_SUCCESS - Successfully returns
236 EFI_INVALID_PARAMETER - Instance not found
240 EFI_FW_VOL_INSTANCE
*FwhInstance
= NULL
;
244 // Find the right instance of the FVB private data
246 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
247 ASSERT_EFI_ERROR (Status
);
248 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
257 OUT UINTN
*LbaAddress
,
258 OUT UINTN
*LbaLength
,
259 OUT UINTN
*NumOfBlocks
,
260 IN ESAL_FWB_GLOBAL
*Global
,
266 Retrieves the starting address of an LBA in an FV
269 Instance - The FV instance which the Lba belongs to
270 Lba - The logical block address
271 LbaAddress - On output, contains the physical starting address
273 LbaLength - On output, contains the length of the block
274 NumOfBlocks - A pointer to a caller allocated UINTN in which the
275 number of consecutive blocks starting with Lba is
276 returned. All blocks in this range have a size of
278 Global - Pointer to ESAL_FWB_GLOBAL that contains all
280 Virtual - Whether CPU is in virtual or physical mode
283 EFI_SUCCESS - Successfully returns
284 EFI_INVALID_PARAMETER - Instance not found
293 EFI_FW_VOL_INSTANCE
*FwhInstance
= NULL
;
294 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
298 // Find the right instance of the FVB private data
300 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
301 ASSERT_EFI_ERROR (Status
);
305 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
308 // Parse the blockmap of the FV to find which map entry the Lba belongs to
311 NumBlocks
= BlockMap
->NumBlocks
;
312 BlockLength
= BlockMap
->Length
;
314 if (NumBlocks
== 0 || BlockLength
== 0) {
315 return EFI_INVALID_PARAMETER
;
318 NextLba
= StartLba
+ NumBlocks
;
321 // The map entry found
323 if (Lba
>= StartLba
&& Lba
< NextLba
) {
324 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
325 if (LbaAddress
!= NULL
) {
326 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
329 if (LbaLength
!= NULL
) {
330 *LbaLength
= BlockLength
;
333 if (NumOfBlocks
!= NULL
) {
334 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
341 Offset
= Offset
+ NumBlocks
* BlockLength
;
350 IN UINTN BlockOffset
,
351 IN OUT UINTN
*NumBytes
,
353 IN ESAL_FWB_GLOBAL
*Global
,
359 Reads specified number of bytes into a buffer from the specified block
362 Instance - The FV instance to be read from
363 Lba - The logical block address to be read from
364 BlockOffset - Offset into the block at which to begin reading
365 NumBytes - Pointer that on input contains the total size of
366 the buffer. On output, it contains the total number
368 Buffer - Pointer to a caller allocated buffer that will be
369 used to hold the data read
370 Global - Pointer to ESAL_FWB_GLOBAL that contains all
372 Virtual - Whether CPU is in virtual or physical mode
375 EFI_SUCCESS - The firmware volume was read successfully and
376 contents are in Buffer
377 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
378 NumBytes contains the total number of bytes returned
380 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
381 EFI_DEVICE_ERROR - The block device is not functioning correctly and
383 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
387 EFI_FVB_ATTRIBUTES_2 Attributes
;
393 // Check for invalid conditions
395 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
396 return EFI_INVALID_PARAMETER
;
399 if (*NumBytes
== 0) {
400 return EFI_INVALID_PARAMETER
;
403 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
404 if (EFI_ERROR (Status
)) {
408 // Check if the FV is read enabled
410 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
412 if ((Attributes
& EFI_FVB2_READ_STATUS
) == 0) {
413 return EFI_ACCESS_DENIED
;
416 // Perform boundary checks and adjust NumBytes
418 if (BlockOffset
> LbaLength
) {
419 return EFI_INVALID_PARAMETER
;
422 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
423 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
424 Status
= EFI_BAD_BUFFER_SIZE
;
427 CopyMem (Buffer
, (UINT8
*) (LbaAddress
+ BlockOffset
), (UINTN
) (*NumBytes
));
436 IN UINTN BlockOffset
,
437 IN OUT UINTN
*NumBytes
,
439 IN ESAL_FWB_GLOBAL
*Global
,
445 Writes specified number of bytes from the input buffer to the block
448 Instance - The FV instance to be written to
449 Lba - The starting logical block index to write to
450 BlockOffset - Offset into the block at which to begin writing
451 NumBytes - Pointer that on input contains the total size of
452 the buffer. On output, it contains the total number
453 of bytes actually written
454 Buffer - Pointer to a caller allocated buffer that contains
455 the source for the write
456 Global - Pointer to ESAL_FWB_GLOBAL that contains all
458 Virtual - Whether CPU is in virtual or physical mode
461 EFI_SUCCESS - The firmware volume was written successfully
462 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
463 NumBytes contains the total number of bytes
465 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
466 EFI_DEVICE_ERROR - The block device is not functioning correctly and
468 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
472 EFI_FVB_ATTRIBUTES_2 Attributes
;
478 // Check for invalid conditions
480 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
481 return EFI_INVALID_PARAMETER
;
484 if (*NumBytes
== 0) {
485 return EFI_INVALID_PARAMETER
;
488 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
489 if (EFI_ERROR (Status
)) {
493 // Check if the FV is write enabled
495 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
497 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
498 return EFI_ACCESS_DENIED
;
501 // Perform boundary checks and adjust NumBytes
503 if (BlockOffset
> LbaLength
) {
504 return EFI_INVALID_PARAMETER
;
507 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
508 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
509 Status
= EFI_BAD_BUFFER_SIZE
;
514 CopyMem ((UINT8
*) (LbaAddress
+ BlockOffset
), Buffer
, (UINTN
) (*NumBytes
));
523 IN ESAL_FWB_GLOBAL
*Global
,
529 Erases and initializes a firmware volume block
532 Instance - The FV instance to be erased
533 Lba - The logical block index to be erased
534 Global - Pointer to ESAL_FWB_GLOBAL that contains all
536 Virtual - Whether CPU is in virtual or physical mode
539 EFI_SUCCESS - The erase request was successfully completed
540 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
541 EFI_DEVICE_ERROR - The block device is not functioning correctly and
542 could not be written. Firmware device may have been
544 EFI_INVALID_PARAMETER - Instance not found
549 EFI_FVB_ATTRIBUTES_2 Attributes
;
556 // Check if the FV is write enabled
558 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
560 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
561 return EFI_ACCESS_DENIED
;
564 // Get the starting address of the block for erase.
566 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
568 if (EFI_ERROR (Status
)) {
572 if ((Attributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
578 SetMem ((UINT8
*) LbaAddress
, LbaLength
, Data
);
584 FvbSetVolumeAttributes (
586 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
587 IN ESAL_FWB_GLOBAL
*Global
,
593 Modifies the current settings of the firmware volume according to the
594 input parameter, and returns the new setting of the volume
597 Instance - The FV instance whose attributes is going to be
599 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
600 containing the desired firmware volume settings.
601 On successful return, it contains the new settings
602 of the firmware volume
603 Global - Pointer to ESAL_FWB_GLOBAL that contains all
605 Virtual - Whether CPU is in virtual or physical mode
608 EFI_SUCCESS - Successfully returns
609 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
610 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
611 in conflict with the capabilities as declared in the
612 firmware volume header
616 EFI_FW_VOL_INSTANCE
*FwhInstance
= NULL
;
617 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
618 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
623 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes
;
627 // Find the right instance of the FVB private data
629 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
630 ASSERT_EFI_ERROR (Status
);
632 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
633 OldAttributes
= *AttribPtr
;
634 Capabilities
= OldAttributes
& (EFI_FVB2_READ_DISABLED_CAP
| \
635 EFI_FVB2_READ_ENABLED_CAP
| \
636 EFI_FVB2_WRITE_DISABLED_CAP
| \
637 EFI_FVB2_WRITE_ENABLED_CAP
| \
641 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
642 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
643 UnchangedAttributes
= EFI_FVB2_READ_DISABLED_CAP
| \
644 EFI_FVB2_READ_ENABLED_CAP
| \
645 EFI_FVB2_WRITE_DISABLED_CAP
| \
646 EFI_FVB2_WRITE_ENABLED_CAP
| \
647 EFI_FVB2_LOCK_CAP
| \
648 EFI_FVB2_STICKY_WRITE
| \
649 EFI_FVB2_MEMORY_MAPPED
| \
650 EFI_FVB2_ERASE_POLARITY
| \
651 EFI_FVB2_READ_LOCK_CAP
| \
652 EFI_FVB2_WRITE_LOCK_CAP
| \
656 // Some attributes of FV is read only can *not* be set
658 if ((OldAttributes
& UnchangedAttributes
) ^ (*Attributes
& UnchangedAttributes
)) {
659 return EFI_INVALID_PARAMETER
;
663 // If firmware volume is locked, no status bit can be updated
665 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
666 if (OldStatus
^ NewStatus
) {
667 return EFI_ACCESS_DENIED
;
673 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
674 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
675 return EFI_INVALID_PARAMETER
;
681 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
682 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
683 return EFI_INVALID_PARAMETER
;
687 // Test write disable
689 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
690 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
691 return EFI_INVALID_PARAMETER
;
697 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
698 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
699 return EFI_INVALID_PARAMETER
;
705 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
706 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
707 return EFI_INVALID_PARAMETER
;
711 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
712 *AttribPtr
= (*AttribPtr
) | NewStatus
;
713 *Attributes
= *AttribPtr
;
722 FvbProtocolGetPhysicalAddress (
723 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
724 OUT EFI_PHYSICAL_ADDRESS
*Address
730 Retrieves the physical address of the device.
734 This - Calling context
735 Address - Output buffer containing the address.
740 EFI_SUCCESS - Successfully returns
744 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
746 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
748 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
753 FvbProtocolGetBlockSize (
754 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
756 OUT UINTN
*BlockSize
,
757 OUT UINTN
*NumOfBlocks
762 Retrieve the size of a logical block
765 This - Calling context
766 Lba - Indicates which block to return the size for.
767 BlockSize - A pointer to a caller allocated UINTN in which
768 the size of the block is returned
769 NumOfBlocks - a pointer to a caller allocated UINTN in which the
770 number of consecutive blocks starting with Lba is
771 returned. All blocks in this range have a size of
775 EFI_SUCCESS - The firmware volume was read successfully and
776 contents are in Buffer
780 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
782 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
784 return FvbGetLbaAddress (
797 FvbProtocolGetAttributes (
798 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
799 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
804 Retrieves Volume attributes. No polarity translations are done.
807 This - Calling context
808 Attributes - output buffer which contains attributes
811 EFI_SUCCESS - Successfully returns
815 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
817 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
819 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
824 FvbProtocolSetAttributes (
825 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
826 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
831 Sets Volume attributes. No polarity translations are done.
834 This - Calling context
835 Attributes - output buffer which contains attributes
838 EFI_SUCCESS - Successfully returns
842 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
844 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
846 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
851 FvbProtocolEraseBlocks (
852 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
859 The EraseBlock() function erases one or more blocks as denoted by the
860 variable argument list. The entire parameter list of blocks must be verified
861 prior to erasing any blocks. If a block is requested that does not exist
862 within the associated firmware volume (it has a larger index than the last
863 block of the firmware volume), the EraseBlock() function must return
864 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
867 This - Calling context
868 ... - Starting LBA followed by Number of Lba to erase.
869 a -1 to terminate the list.
872 EFI_SUCCESS - The erase request was successfully completed
873 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
874 EFI_DEVICE_ERROR - The block device is not functioning correctly and
875 could not be written. Firmware device may have been
880 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
881 EFI_FW_VOL_INSTANCE
*FwhInstance
= NULL
;
888 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
890 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
891 ASSERT_EFI_ERROR (Status
);
893 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
895 VA_START (args
, This
);
898 StartingLba
= VA_ARG (args
, EFI_LBA
);
899 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
903 NumOfLba
= VA_ARG (args
, UINTN
);
906 // Check input parameters
908 if (NumOfLba
== 0 || (StartingLba
+ NumOfLba
) > NumOfBlocks
) {
910 return EFI_INVALID_PARAMETER
;
916 VA_START (args
, This
);
918 StartingLba
= VA_ARG (args
, EFI_LBA
);
919 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
923 NumOfLba
= VA_ARG (args
, UINTN
);
925 while (NumOfLba
> 0) {
926 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
927 if (EFI_ERROR (Status
)) {
946 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
949 IN OUT UINTN
*NumBytes
,
956 Writes data beginning at Lba:Offset from FV. The write terminates either
957 when *NumBytes of data have been written, or when a block boundary is
958 reached. *NumBytes is updated to reflect the actual number of bytes
959 written. The write opertion does not include erase. This routine will
960 attempt to write only the specified bytes. If the writes do not stick,
961 it will return an error.
964 This - Calling context
965 Lba - Block in which to begin write
966 Offset - Offset in the block at which to begin write
967 NumBytes - On input, indicates the requested write size. On
968 output, indicates the actual number of bytes written
969 Buffer - Buffer containing source data for the write.
972 EFI_SUCCESS - The firmware volume was written successfully
973 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
974 NumBytes contains the total number of bytes
976 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
977 EFI_DEVICE_ERROR - The block device is not functioning correctly and
979 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
984 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
986 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
988 return FvbWriteBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
994 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
997 IN OUT UINTN
*NumBytes
,
1002 Routine Description:
1004 Reads data beginning at Lba:Offset from FV. The Read terminates either
1005 when *NumBytes of data have been read, or when a block boundary is
1006 reached. *NumBytes is updated to reflect the actual number of bytes
1007 written. The write opertion does not include erase. This routine will
1008 attempt to write only the specified bytes. If the writes do not stick,
1009 it will return an error.
1012 This - Calling context
1013 Lba - Block in which to begin Read
1014 Offset - Offset in the block at which to begin Read
1015 NumBytes - On input, indicates the requested write size. On
1016 output, indicates the actual number of bytes Read
1017 Buffer - Buffer containing source data for the Read.
1020 EFI_SUCCESS - The firmware volume was read successfully and
1021 contents are in Buffer
1022 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1023 NumBytes contains the total number of bytes returned
1025 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1026 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1028 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1033 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1035 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1037 return FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1041 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1045 Routine Description:
1046 Check the integrity of firmware volume header
1049 FwVolHeader - A pointer to a firmware volume header
1052 EFI_SUCCESS - The firmware volume is consistent
1053 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1058 UINT16 HeaderLength
;
1062 // Verify the header revision, header signature, length
1063 // Length of FvBlock cannot be 2**64-1
1064 // HeaderLength cannot be an odd number
1066 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1067 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1068 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
1069 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1071 return EFI_NOT_FOUND
;
1074 // Verify the header checksum
1076 HeaderLength
= (UINT16
) (FwVolHeader
->HeaderLength
/ 2);
1077 Ptr
= (UINT16
*) FwVolHeader
;
1079 while (HeaderLength
> 0) {
1080 Checksum
= Checksum
+ (*Ptr
);
1085 if (Checksum
!= 0) {
1086 return EFI_NOT_FOUND
;
1095 IN EFI_HANDLE ImageHandle
,
1096 IN EFI_SYSTEM_TABLE
*SystemTable
1100 Routine Description:
1101 This function does common initialization for FVB services
1110 EFI_FW_VOL_INSTANCE
*FwhInstance
= NULL
;
1111 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1112 EFI_DXE_SERVICES
*DxeServices
;
1113 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
1115 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1116 EFI_HANDLE FwbHandle
;
1117 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1118 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1119 EFI_DEVICE_PATH_PROTOCOL
*TempFwbDevicePath
;
1120 FV_DEVICE_PATH TempFvbDevicePathData
;
1122 EFI_PHYSICAL_ADDRESS BaseAddress
;
1125 EFI_PEI_HOB_POINTERS FvHob
;
1128 // Get the DXE services table
1133 // Allocate runtime services data for global variable, which contains
1134 // the private data of all firmware volume block instances
1136 Status
= gBS
->AllocatePool (
1137 EfiRuntimeServicesData
,
1138 sizeof (ESAL_FWB_GLOBAL
),
1139 (VOID
**) &mFvbModuleGlobal
1141 ASSERT_EFI_ERROR (Status
);
1144 // Calculate the total size for all firmware volume block instances
1148 FvHob
.Raw
= GetHobList ();
1149 while ((FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
)) != NULL
) {
1150 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1151 Length
= FvHob
.FirmwareVolume
->Length
;
1153 // Check if it is a "real" flash
1155 Status
= DxeServices
->GetMemorySpaceDescriptor (
1159 if (EFI_ERROR (Status
)) {
1163 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1164 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1168 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1169 Status
= ValidateFvHeader (FwVolHeader
);
1170 if (EFI_ERROR (Status
)) {
1174 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1175 if (EFI_ERROR (Status
)) {
1176 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1181 BufferSize
+= (sizeof (EFI_FW_VOL_INSTANCE
) + FwVolHeader
->HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1182 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1186 // Only need to allocate once. There is only one copy of physical memory for
1187 // the private data of each FV instance. But in virtual mode or in physical
1188 // mode, the address of the the physical memory may be different.
1190 Status
= gBS
->AllocatePool (
1191 EfiRuntimeServicesData
,
1193 (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
]
1195 ASSERT_EFI_ERROR (Status
);
1198 // Make a virtual copy of the FvInstance pointer.
1200 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1201 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1203 mFvbModuleGlobal
->NumFv
= 0;
1206 FvHob
.Raw
= GetHobList ();
1207 while (NULL
!= (FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
))) {
1208 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1209 Length
= FvHob
.FirmwareVolume
->Length
;
1211 // Check if it is a "real" flash
1213 Status
= DxeServices
->GetMemorySpaceDescriptor (
1217 if (EFI_ERROR (Status
)) {
1221 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1222 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1226 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1227 Status
= ValidateFvHeader (FwVolHeader
);
1228 if (EFI_ERROR (Status
)) {
1230 // Get FvbInfo to provide in FwhInstance.
1232 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1233 if (EFI_ERROR (Status
)) {
1234 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1238 // Write healthy FV header back.
1241 (VOID
*) (UINTN
) BaseAddress
,
1242 (VOID
*) FwVolHeader
,
1243 FwVolHeader
->HeaderLength
1247 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1248 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1250 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1251 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1252 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1256 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1258 // Get the maximum size of a block. The size will be used to allocate
1259 // buffer for Scratch space, the intermediate buffer for FVB extension
1262 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
1263 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1266 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1269 // The total number of blocks in the FV.
1271 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1274 // Add a FVB Protocol Instance
1276 Status
= gBS
->AllocatePool (
1277 EfiRuntimeServicesData
,
1278 sizeof (EFI_FW_VOL_BLOCK_DEVICE
),
1281 ASSERT_EFI_ERROR (Status
);
1283 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1285 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1286 mFvbModuleGlobal
->NumFv
++;
1289 // Set up the devicepath
1291 FvbDevice
->DevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
1292 FvbDevice
->DevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ (FwVolHeader
->FvLength
- 1);
1295 // Find a handle with a matching device path that has supports FW Block protocol
1297 TempFwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) &TempFvbDevicePathData
;
1298 CopyMem (TempFwbDevicePath
, &FvbDevice
->DevicePath
, sizeof (FV_DEVICE_PATH
));
1299 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &TempFwbDevicePath
, &FwbHandle
);
1300 if (EFI_ERROR (Status
)) {
1302 // LocateDevicePath fails so install a new interface and device path
1305 Status
= gBS
->InstallMultipleProtocolInterfaces (
1307 &gEfiFirmwareVolumeBlockProtocolGuid
,
1308 &FvbDevice
->FwVolBlockInstance
,
1309 &gEfiDevicePathProtocolGuid
,
1310 &FvbDevice
->DevicePath
,
1313 ASSERT_EFI_ERROR (Status
);
1314 } else if (IsDevicePathEnd (TempFwbDevicePath
)) {
1316 // Device allready exists, so reinstall the FVB protocol
1318 Status
= gBS
->HandleProtocol (
1320 &gEfiFirmwareVolumeBlockProtocolGuid
,
1321 (VOID
**)&OldFwbInterface
1323 ASSERT_EFI_ERROR (Status
);
1325 Status
= gBS
->ReinstallProtocolInterface (
1327 &gEfiFirmwareVolumeBlockProtocolGuid
,
1329 &FvbDevice
->FwVolBlockInstance
1331 ASSERT_EFI_ERROR (Status
);
1335 // There was a FVB protocol on an End Device Path node
1340 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1342 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1343 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1346 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);