3 Copyright (c) 2006 - 2008, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
23 #include <Guid/EventGroup.h>
24 #include <Protocol/FvbExtension.h>
25 #include <Protocol/FirmwareVolumeBlock.h>
26 #include <Guid/AlternateFvBlock.h>
27 #include <Protocol/DevicePath.h>
29 #include <Library/UefiLib.h>
30 #include <Library/UefiDriverEntryPoint.h>
31 #include <Library/BaseLib.h>
32 #include <Library/DxeServicesTableLib.h>
33 #include <Library/UefiRuntimeLib.h>
34 #include <Library/DebugLib.h>
35 #include <Library/HobLib.h>
36 #include <Library/BaseMemoryLib.h>
37 #include <Library/MemoryAllocationLib.h>
38 #include <Library/UefiBootServicesTableLib.h>
39 #include "FwBlockService.h"
41 ESAL_FWB_GLOBAL
*mFvbModuleGlobal
;
43 #define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
45 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
53 sizeof (MEMMAP_DEVICE_PATH
),
63 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
65 sizeof (EFI_DEVICE_PATH_PROTOCOL
),
72 FvbProtocolGetAttributes
,
73 FvbProtocolSetAttributes
,
74 FvbProtocolGetPhysicalAddress
,
75 FvbProtocolGetBlockSize
,
78 FvbProtocolEraseBlocks
,
82 FvbExtendProtocolEraseCustomBlockRange
90 FvbVirtualddressChangeEvent (
98 Fixup internal data so that EFI and SAL can be call in virtual mode.
99 Call the passed in Child Notify event and convert the mFvbModuleGlobal
100 date items to there virtual address.
102 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
103 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
108 (Standard EFI notify event - EFI_EVENT_NOTIFY)
116 EFI_FW_VOL_INSTANCE
*FwhInstance
;
119 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
122 // Convert the base address of all the instances
125 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
126 while (Index
< mFvbModuleGlobal
->NumFv
) {
127 EfiConvertPointer (0x0, (VOID
**) &FwhInstance
->FvBase
[FVB_VIRTUAL
]);
128 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
130 (UINTN
) ((UINT8
*) FwhInstance
) + FwhInstance
->VolumeHeader
.HeaderLength
+
131 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
136 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
]);
137 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
);
143 IN ESAL_FWB_GLOBAL
*Global
,
144 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
150 Retrieves the physical address of a memory mapped FV
153 Instance - The FV instance whose base address is going to be
155 Global - Pointer to ESAL_FWB_GLOBAL that contains all
157 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
158 Virtual - Whether CPU is in virtual or physical mode
161 EFI_SUCCESS - Successfully returns
162 EFI_INVALID_PARAMETER - Instance not found
166 EFI_FW_VOL_INSTANCE
*FwhRecord
;
168 if (Instance
>= Global
->NumFv
) {
169 return EFI_INVALID_PARAMETER
;
172 // Find the right instance of the FVB private data
174 FwhRecord
= Global
->FvInstance
[Virtual
];
175 while (Instance
> 0) {
176 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
178 (UINTN
) ((UINT8
*) FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
179 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
184 *FwhInstance
= FwhRecord
;
190 FvbGetPhysicalAddress (
192 OUT EFI_PHYSICAL_ADDRESS
*Address
,
193 IN ESAL_FWB_GLOBAL
*Global
,
199 Retrieves the physical address of a memory mapped FV
202 Instance - The FV instance whose base address is going to be
204 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
205 that on successful return, contains the base address
206 of the firmware volume.
207 Global - Pointer to ESAL_FWB_GLOBAL that contains all
209 Virtual - Whether CPU is in virtual or physical mode
212 EFI_SUCCESS - Successfully returns
213 EFI_INVALID_PARAMETER - Instance not found
217 EFI_FW_VOL_INSTANCE
*FwhInstance
;
221 // Find the right instance of the FVB private data
223 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
224 ASSERT_EFI_ERROR (Status
);
225 *Address
= FwhInstance
->FvBase
[Virtual
];
231 FvbGetVolumeAttributes (
233 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
234 IN ESAL_FWB_GLOBAL
*Global
,
240 Retrieves attributes, insures positive polarity of attribute bits, returns
241 resulting attributes in output parameter
244 Instance - The FV instance whose attributes is going to be
246 Attributes - Output buffer which contains attributes
247 Global - Pointer to ESAL_FWB_GLOBAL that contains all
249 Virtual - Whether CPU is in virtual or physical mode
252 EFI_SUCCESS - Successfully returns
253 EFI_INVALID_PARAMETER - Instance not found
257 EFI_FW_VOL_INSTANCE
*FwhInstance
;
261 // Find the right instance of the FVB private data
263 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
264 ASSERT_EFI_ERROR (Status
);
265 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
274 OUT UINTN
*LbaAddress
,
275 OUT UINTN
*LbaLength
,
276 OUT UINTN
*NumOfBlocks
,
277 IN ESAL_FWB_GLOBAL
*Global
,
283 Retrieves the starting address of an LBA in an FV
286 Instance - The FV instance which the Lba belongs to
287 Lba - The logical block address
288 LbaAddress - On output, contains the physical starting address
290 LbaLength - On output, contains the length of the block
291 NumOfBlocks - A pointer to a caller allocated UINTN in which the
292 number of consecutive blocks starting with Lba is
293 returned. All blocks in this range have a size of
295 Global - Pointer to ESAL_FWB_GLOBAL that contains all
297 Virtual - Whether CPU is in virtual or physical mode
300 EFI_SUCCESS - Successfully returns
301 EFI_INVALID_PARAMETER - Instance not found
310 EFI_FW_VOL_INSTANCE
*FwhInstance
;
311 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
315 // Find the right instance of the FVB private data
317 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
318 ASSERT_EFI_ERROR (Status
);
322 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
325 // Parse the blockmap of the FV to find which map entry the Lba belongs to
328 NumBlocks
= BlockMap
->NumBlocks
;
329 BlockLength
= BlockMap
->Length
;
331 if (NumBlocks
== 0 || BlockLength
== 0) {
332 return EFI_INVALID_PARAMETER
;
335 NextLba
= StartLba
+ NumBlocks
;
338 // The map entry found
340 if (Lba
>= StartLba
&& Lba
< NextLba
) {
341 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
342 if (LbaAddress
!= NULL
) {
343 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
346 if (LbaLength
!= NULL
) {
347 *LbaLength
= BlockLength
;
350 if (NumOfBlocks
!= NULL
) {
351 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
358 Offset
= Offset
+ NumBlocks
* BlockLength
;
367 IN UINTN BlockOffset
,
368 IN OUT UINTN
*NumBytes
,
370 IN ESAL_FWB_GLOBAL
*Global
,
376 Reads specified number of bytes into a buffer from the specified block
379 Instance - The FV instance to be read from
380 Lba - The logical block address to be read from
381 BlockOffset - Offset into the block at which to begin reading
382 NumBytes - Pointer that on input contains the total size of
383 the buffer. On output, it contains the total number
385 Buffer - Pointer to a caller allocated buffer that will be
386 used to hold the data read
387 Global - Pointer to ESAL_FWB_GLOBAL that contains all
389 Virtual - Whether CPU is in virtual or physical mode
392 EFI_SUCCESS - The firmware volume was read successfully and
393 contents are in Buffer
394 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
395 NumBytes contains the total number of bytes returned
397 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
398 EFI_DEVICE_ERROR - The block device is not functioning correctly and
400 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
404 EFI_FVB_ATTRIBUTES_2 Attributes
;
410 // Check for invalid conditions
412 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
413 return EFI_INVALID_PARAMETER
;
416 if (*NumBytes
== 0) {
417 return EFI_INVALID_PARAMETER
;
420 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
421 if (EFI_ERROR (Status
)) {
425 // Check if the FV is read enabled
427 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
429 if ((Attributes
& EFI_FVB2_READ_STATUS
) == 0) {
430 return EFI_ACCESS_DENIED
;
433 // Perform boundary checks and adjust NumBytes
435 if (BlockOffset
> LbaLength
) {
436 return EFI_INVALID_PARAMETER
;
439 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
440 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
441 Status
= EFI_BAD_BUFFER_SIZE
;
444 CopyMem (Buffer
, (UINT8
*) (LbaAddress
+ BlockOffset
), (UINTN
) (*NumBytes
));
453 IN UINTN BlockOffset
,
454 IN OUT UINTN
*NumBytes
,
456 IN ESAL_FWB_GLOBAL
*Global
,
462 Writes specified number of bytes from the input buffer to the block
465 Instance - The FV instance to be written to
466 Lba - The starting logical block index to write to
467 BlockOffset - Offset into the block at which to begin writing
468 NumBytes - Pointer that on input contains the total size of
469 the buffer. On output, it contains the total number
470 of bytes actually written
471 Buffer - Pointer to a caller allocated buffer that contains
472 the source for the write
473 Global - Pointer to ESAL_FWB_GLOBAL that contains all
475 Virtual - Whether CPU is in virtual or physical mode
478 EFI_SUCCESS - The firmware volume was written successfully
479 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
480 NumBytes contains the total number of bytes
482 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
483 EFI_DEVICE_ERROR - The block device is not functioning correctly and
485 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
489 EFI_FVB_ATTRIBUTES_2 Attributes
;
495 // Check for invalid conditions
497 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
498 return EFI_INVALID_PARAMETER
;
501 if (*NumBytes
== 0) {
502 return EFI_INVALID_PARAMETER
;
505 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
506 if (EFI_ERROR (Status
)) {
510 // Check if the FV is write enabled
512 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
514 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
515 return EFI_ACCESS_DENIED
;
518 // Perform boundary checks and adjust NumBytes
520 if (BlockOffset
> LbaLength
) {
521 return EFI_INVALID_PARAMETER
;
524 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
525 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
526 Status
= EFI_BAD_BUFFER_SIZE
;
531 CopyMem ((UINT8
*) (LbaAddress
+ BlockOffset
), Buffer
, (UINTN
) (*NumBytes
));
540 IN ESAL_FWB_GLOBAL
*Global
,
546 Erases and initializes a firmware volume block
549 Instance - The FV instance to be erased
550 Lba - The logical block index to be erased
551 Global - Pointer to ESAL_FWB_GLOBAL that contains all
553 Virtual - Whether CPU is in virtual or physical mode
556 EFI_SUCCESS - The erase request was successfully completed
557 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
558 EFI_DEVICE_ERROR - The block device is not functioning correctly and
559 could not be written. Firmware device may have been
561 EFI_INVALID_PARAMETER - Instance not found
566 EFI_FVB_ATTRIBUTES_2 Attributes
;
573 // Check if the FV is write enabled
575 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
577 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
578 return EFI_ACCESS_DENIED
;
581 // Get the starting address of the block for erase.
583 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
585 if (EFI_ERROR (Status
)) {
589 if ((Attributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
595 SetMem ((UINT8
*) LbaAddress
, LbaLength
, Data
);
601 FvbEraseCustomBlockRange (
604 IN UINTN OffsetStartLba
,
606 IN UINTN OffsetLastLba
,
607 IN ESAL_FWB_GLOBAL
*Global
,
613 Erases and initializes a specified range of a firmware volume
616 Instance - The FV instance to be erased
617 StartLba - The starting logical block index to be erased
618 OffsetStartLba - Offset into the starting block at which to
620 LastLba - The last logical block index to be erased
621 OffsetStartLba - Offset into the last block at which to end erasing
622 Global - Pointer to ESAL_FWB_GLOBAL that contains all
624 Virtual - Whether CPU is in virtual or physical mode
627 EFI_SUCCESS - The firmware volume was erased successfully
628 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
629 EFI_DEVICE_ERROR - The block device is not functioning correctly and
630 could not be written. Firmware device may have been
632 EFI_INVALID_PARAMETER - Instance not found
638 UINTN ScratchLbaSizeData
;
644 Status
= FvbGetLbaAddress (Instance
, StartLba
, NULL
, &LbaSize
, NULL
, Global
, Virtual
);
645 if (EFI_ERROR (Status
)) {
650 // Use the scratch space as the intermediate buffer to transfer data
651 // Back up the first LBA in scratch space.
653 FvbReadBlock (Instance
, StartLba
, 0, &LbaSize
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
658 FvbEraseBlock (Instance
, StartLba
, Global
, Virtual
);
659 ScratchLbaSizeData
= OffsetStartLba
;
662 // write the data back to the first block
664 if (ScratchLbaSizeData
> 0) {
665 Status
= FvbWriteBlock (Instance
, StartLba
, 0, &ScratchLbaSizeData
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
666 if (EFI_ERROR (Status
)) {
673 if (LastLba
> (StartLba
+ 1)) {
674 for (Index
= (StartLba
+ 1); Index
<= (LastLba
- 1); Index
++) {
675 FvbEraseBlock (Instance
, Index
, Global
, Virtual
);
679 // Last LBAs, the same as first LBAs
681 if (LastLba
> StartLba
) {
682 Status
= FvbGetLbaAddress (Instance
, LastLba
, NULL
, &LbaSize
, NULL
, Global
, Virtual
);
683 if (EFI_ERROR (Status
)) {
686 FvbReadBlock (Instance
, LastLba
, 0, &LbaSize
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
687 FvbEraseBlock (Instance
, LastLba
, Global
, Virtual
);
690 ScratchLbaSizeData
= LbaSize
- (OffsetLastLba
+ 1);
692 if (ScratchLbaSizeData
> 0) {
693 Status
= FvbWriteBlock (
698 Global
->FvbScratchSpace
[Virtual
] + OffsetLastLba
+ 1,
708 FvbSetVolumeAttributes (
710 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
711 IN ESAL_FWB_GLOBAL
*Global
,
717 Modifies the current settings of the firmware volume according to the
718 input parameter, and returns the new setting of the volume
721 Instance - The FV instance whose attributes is going to be
723 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
724 containing the desired firmware volume settings.
725 On successful return, it contains the new settings
726 of the firmware volume
727 Global - Pointer to ESAL_FWB_GLOBAL that contains all
729 Virtual - Whether CPU is in virtual or physical mode
732 EFI_SUCCESS - Successfully returns
733 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
734 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
735 in conflict with the capabilities as declared in the
736 firmware volume header
740 EFI_FW_VOL_INSTANCE
*FwhInstance
;
741 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
742 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
747 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes
;
751 // Find the right instance of the FVB private data
753 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
754 ASSERT_EFI_ERROR (Status
);
756 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
757 OldAttributes
= *AttribPtr
;
758 Capabilities
= OldAttributes
& (EFI_FVB2_READ_DISABLED_CAP
| \
759 EFI_FVB2_READ_ENABLED_CAP
| \
760 EFI_FVB2_WRITE_DISABLED_CAP
| \
761 EFI_FVB2_WRITE_ENABLED_CAP
| \
765 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
766 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
767 UnchangedAttributes
= EFI_FVB2_READ_DISABLED_CAP
| \
768 EFI_FVB2_READ_ENABLED_CAP
| \
769 EFI_FVB2_WRITE_DISABLED_CAP
| \
770 EFI_FVB2_WRITE_ENABLED_CAP
| \
771 EFI_FVB2_LOCK_CAP
| \
772 EFI_FVB2_STICKY_WRITE
| \
773 EFI_FVB2_MEMORY_MAPPED
| \
774 EFI_FVB2_ERASE_POLARITY
| \
775 EFI_FVB2_READ_LOCK_CAP
| \
776 EFI_FVB2_WRITE_LOCK_CAP
| \
780 // Some attributes of FV is read only can *not* be set
782 if ((OldAttributes
& UnchangedAttributes
) ^ (*Attributes
& UnchangedAttributes
)) {
783 return EFI_INVALID_PARAMETER
;
787 // If firmware volume is locked, no status bit can be updated
789 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
790 if (OldStatus
^ NewStatus
) {
791 return EFI_ACCESS_DENIED
;
797 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
798 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
799 return EFI_INVALID_PARAMETER
;
805 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
806 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
807 return EFI_INVALID_PARAMETER
;
811 // Test write disable
813 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
814 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
815 return EFI_INVALID_PARAMETER
;
821 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
822 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
823 return EFI_INVALID_PARAMETER
;
829 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
830 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
831 return EFI_INVALID_PARAMETER
;
835 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
836 *AttribPtr
= (*AttribPtr
) | NewStatus
;
837 *Attributes
= *AttribPtr
;
846 FvbProtocolGetPhysicalAddress (
847 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
848 OUT EFI_PHYSICAL_ADDRESS
*Address
854 Retrieves the physical address of the device.
858 This - Calling context
859 Address - Output buffer containing the address.
864 EFI_SUCCESS - Successfully returns
868 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
870 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
872 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
877 FvbProtocolGetBlockSize (
878 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
880 OUT UINTN
*BlockSize
,
881 OUT UINTN
*NumOfBlocks
886 Retrieve the size of a logical block
889 This - Calling context
890 Lba - Indicates which block to return the size for.
891 BlockSize - A pointer to a caller allocated UINTN in which
892 the size of the block is returned
893 NumOfBlocks - a pointer to a caller allocated UINTN in which the
894 number of consecutive blocks starting with Lba is
895 returned. All blocks in this range have a size of
899 EFI_SUCCESS - The firmware volume was read successfully and
900 contents are in Buffer
904 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
906 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
908 return FvbGetLbaAddress (
921 FvbProtocolGetAttributes (
922 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
923 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
928 Retrieves Volume attributes. No polarity translations are done.
931 This - Calling context
932 Attributes - output buffer which contains attributes
935 EFI_SUCCESS - Successfully returns
939 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
941 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
943 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
948 FvbProtocolSetAttributes (
949 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
950 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
955 Sets Volume attributes. No polarity translations are done.
958 This - Calling context
959 Attributes - output buffer which contains attributes
962 EFI_SUCCESS - Successfully returns
966 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
968 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
970 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
975 FvbProtocolEraseBlocks (
976 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
983 The EraseBlock() function erases one or more blocks as denoted by the
984 variable argument list. The entire parameter list of blocks must be verified
985 prior to erasing any blocks. If a block is requested that does not exist
986 within the associated firmware volume (it has a larger index than the last
987 block of the firmware volume), the EraseBlock() function must return
988 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
991 This - Calling context
992 ... - Starting LBA followed by Number of Lba to erase.
993 a -1 to terminate the list.
996 EFI_SUCCESS - The erase request was successfully completed
997 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
998 EFI_DEVICE_ERROR - The block device is not functioning correctly and
999 could not be written. Firmware device may have been
1004 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1005 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1008 EFI_LBA StartingLba
;
1012 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1014 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
1015 ASSERT_EFI_ERROR (Status
);
1017 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
1019 VA_START (args
, This
);
1022 StartingLba
= VA_ARG (args
, EFI_LBA
);
1023 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
1027 NumOfLba
= VA_ARG (args
, UINT32
);
1030 // Check input parameters
1032 if (NumOfLba
== 0) {
1034 return EFI_INVALID_PARAMETER
;
1037 if ((StartingLba
+ NumOfLba
) > NumOfBlocks
) {
1038 return EFI_INVALID_PARAMETER
;
1044 VA_START (args
, This
);
1046 StartingLba
= VA_ARG (args
, EFI_LBA
);
1047 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
1051 NumOfLba
= VA_ARG (args
, UINT32
);
1053 while (NumOfLba
> 0) {
1054 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
1055 if (EFI_ERROR (Status
)) {
1074 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1077 IN OUT UINTN
*NumBytes
,
1082 Routine Description:
1084 Writes data beginning at Lba:Offset from FV. The write terminates either
1085 when *NumBytes of data have been written, or when a block boundary is
1086 reached. *NumBytes is updated to reflect the actual number of bytes
1087 written. The write opertion does not include erase. This routine will
1088 attempt to write only the specified bytes. If the writes do not stick,
1089 it will return an error.
1092 This - Calling context
1093 Lba - Block in which to begin write
1094 Offset - Offset in the block at which to begin write
1095 NumBytes - On input, indicates the requested write size. On
1096 output, indicates the actual number of bytes written
1097 Buffer - Buffer containing source data for the write.
1100 EFI_SUCCESS - The firmware volume was written successfully
1101 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
1102 NumBytes contains the total number of bytes
1104 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1105 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1106 could not be written
1107 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1112 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1114 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1116 return FvbWriteBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1122 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1125 IN OUT UINTN
*NumBytes
,
1130 Routine Description:
1132 Reads data beginning at Lba:Offset from FV. The Read terminates either
1133 when *NumBytes of data have been read, or when a block boundary is
1134 reached. *NumBytes is updated to reflect the actual number of bytes
1135 written. The write opertion does not include erase. This routine will
1136 attempt to write only the specified bytes. If the writes do not stick,
1137 it will return an error.
1140 This - Calling context
1141 Lba - Block in which to begin Read
1142 Offset - Offset in the block at which to begin Read
1143 NumBytes - On input, indicates the requested write size. On
1144 output, indicates the actual number of bytes Read
1145 Buffer - Buffer containing source data for the Read.
1148 EFI_SUCCESS - The firmware volume was read successfully and
1149 contents are in Buffer
1150 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1151 NumBytes contains the total number of bytes returned
1153 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1154 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1156 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1161 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1163 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1165 return FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1168 // FVB Extension Protocols
1172 FvbExtendProtocolEraseCustomBlockRange (
1173 IN EFI_FVB_EXTENSION_PROTOCOL
*This
,
1174 IN EFI_LBA StartLba
,
1175 IN UINTN OffsetStartLba
,
1177 IN UINTN OffsetLastLba
1181 Routine Description:
1182 Erases and initializes a specified range of a firmware volume
1185 This - Calling context
1186 StartLba - The starting logical block index to be erased
1187 OffsetStartLba - Offset into the starting block at which to
1189 LastLba - The last logical block index to be erased
1190 OffsetStartLba - Offset into the last block at which to end erasing
1193 EFI_SUCCESS - The firmware volume was erased successfully
1194 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1195 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1196 could not be written. Firmware device may have been
1201 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1203 FvbDevice
= FVB_EXTEND_DEVICE_FROM_THIS (This
);
1205 return FvbEraseCustomBlockRange (
1206 FvbDevice
->Instance
,
1219 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1223 Routine Description:
1224 Check the integrity of firmware volume header
1227 FwVolHeader - A pointer to a firmware volume header
1230 EFI_SUCCESS - The firmware volume is consistent
1231 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1236 UINT16 HeaderLength
;
1240 // Verify the header revision, header signature, length
1241 // Length of FvBlock cannot be 2**64-1
1242 // HeaderLength cannot be an odd number
1244 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1245 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1246 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
1247 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1249 return EFI_NOT_FOUND
;
1252 // Verify the header checksum
1254 HeaderLength
= (UINT16
) (FwVolHeader
->HeaderLength
/ 2);
1255 Ptr
= (UINT16
*) FwVolHeader
;
1257 while (HeaderLength
> 0) {
1258 Checksum
= Checksum
+ (*Ptr
);
1263 if (Checksum
!= 0) {
1264 return EFI_NOT_FOUND
;
1273 IN EFI_HANDLE ImageHandle
,
1274 IN EFI_SYSTEM_TABLE
*SystemTable
1278 Routine Description:
1279 This function does common initialization for FVB services
1288 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1289 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1290 EFI_DXE_SERVICES
*DxeServices
;
1291 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
1293 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1294 EFI_HANDLE FwbHandle
;
1295 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1296 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1297 EFI_DEVICE_PATH_PROTOCOL
*TempFwbDevicePath
;
1298 FV_DEVICE_PATH TempFvbDevicePathData
;
1300 EFI_PHYSICAL_ADDRESS BaseAddress
;
1303 EFI_PEI_HOB_POINTERS FvHob
;
1306 // Get the DXE services table
1311 // Allocate runtime services data for global variable, which contains
1312 // the private data of all firmware volume block instances
1314 Status
= gBS
->AllocatePool (
1315 EfiRuntimeServicesData
,
1316 sizeof (ESAL_FWB_GLOBAL
),
1317 (VOID
**) &mFvbModuleGlobal
1319 ASSERT_EFI_ERROR (Status
);
1322 // Calculate the total size for all firmware volume block instances
1326 FvHob
.Raw
= GetHobList ();
1327 while ((FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
)) != NULL
) {
1328 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1329 Length
= FvHob
.FirmwareVolume
->Length
;
1331 // Check if it is a "real" flash
1333 Status
= DxeServices
->GetMemorySpaceDescriptor (
1337 if (EFI_ERROR (Status
)) {
1341 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1342 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1346 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1347 Status
= ValidateFvHeader (FwVolHeader
);
1348 if (EFI_ERROR (Status
)) {
1352 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1353 if (EFI_ERROR (Status
)) {
1354 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1359 BufferSize
+= (sizeof (EFI_FW_VOL_INSTANCE
) + FwVolHeader
->HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1360 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1364 // Only need to allocate once. There is only one copy of physical memory for
1365 // the private data of each FV instance. But in virtual mode or in physical
1366 // mode, the address of the the physical memory may be different.
1368 Status
= gBS
->AllocatePool (
1369 EfiRuntimeServicesData
,
1371 (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
]
1373 ASSERT_EFI_ERROR (Status
);
1376 // Make a virtual copy of the FvInstance pointer.
1378 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1379 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1381 mFvbModuleGlobal
->NumFv
= 0;
1384 FvHob
.Raw
= GetHobList ();
1385 while (NULL
!= (FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
))) {
1386 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1387 Length
= FvHob
.FirmwareVolume
->Length
;
1389 // Check if it is a "real" flash
1391 Status
= DxeServices
->GetMemorySpaceDescriptor (
1395 if (EFI_ERROR (Status
)) {
1399 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1400 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1404 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1405 Status
= ValidateFvHeader (FwVolHeader
);
1406 if (EFI_ERROR (Status
)) {
1408 // Get FvbInfo to provide in FwhInstance.
1410 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1411 if (EFI_ERROR (Status
)) {
1412 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1416 // Write healthy FV header back.
1419 (VOID
*) (UINTN
) BaseAddress
,
1420 (VOID
*) FwVolHeader
,
1421 FwVolHeader
->HeaderLength
1425 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1426 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1428 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1429 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1430 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1434 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1436 // Get the maximum size of a block. The size will be used to allocate
1437 // buffer for Scratch space, the intermediate buffer for FVB extension
1440 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
1441 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1444 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1447 // The total number of blocks in the FV.
1449 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1452 // Add a FVB Protocol Instance
1454 Status
= gBS
->AllocatePool (
1455 EfiRuntimeServicesData
,
1456 sizeof (EFI_FW_VOL_BLOCK_DEVICE
),
1459 ASSERT_EFI_ERROR (Status
);
1461 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1463 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1464 mFvbModuleGlobal
->NumFv
++;
1467 // Set up the devicepath
1469 FvbDevice
->DevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
1470 FvbDevice
->DevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ (FwVolHeader
->FvLength
- 1);
1473 // Find a handle with a matching device path that has supports FW Block protocol
1475 TempFwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) &TempFvbDevicePathData
;
1476 CopyMem (TempFwbDevicePath
, &FvbDevice
->DevicePath
, sizeof (FV_DEVICE_PATH
));
1477 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &TempFwbDevicePath
, &FwbHandle
);
1478 if (EFI_ERROR (Status
)) {
1480 // LocateDevicePath fails so install a new interface and device path
1483 Status
= gBS
->InstallMultipleProtocolInterfaces (
1485 &gEfiFirmwareVolumeBlockProtocolGuid
,
1486 &FvbDevice
->FwVolBlockInstance
,
1487 &gEfiDevicePathProtocolGuid
,
1488 &FvbDevice
->DevicePath
,
1491 ASSERT_EFI_ERROR (Status
);
1492 } else if (EfiIsDevicePathEnd (TempFwbDevicePath
)) {
1494 // Device allready exists, so reinstall the FVB protocol
1496 Status
= gBS
->HandleProtocol (
1498 &gEfiFirmwareVolumeBlockProtocolGuid
,
1499 (VOID
**)&OldFwbInterface
1501 ASSERT_EFI_ERROR (Status
);
1503 Status
= gBS
->ReinstallProtocolInterface (
1505 &gEfiFirmwareVolumeBlockProtocolGuid
,
1507 &FvbDevice
->FwVolBlockInstance
1509 ASSERT_EFI_ERROR (Status
);
1513 // There was a FVB protocol on an End Device Path node
1518 // Install FVB Extension Protocol on the same handle
1520 Status
= gBS
->InstallMultipleProtocolInterfaces (
1522 &gEfiFvbExtensionProtocolGuid
,
1523 &FvbDevice
->FvbExtension
,
1524 &gEfiAlternateFvBlockGuid
,
1529 ASSERT_EFI_ERROR (Status
);
1531 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1533 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1534 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1537 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1541 // Allocate for scratch space, an intermediate buffer for FVB extention
1543 Status
= gBS
->AllocatePool (
1544 EfiRuntimeServicesData
,
1546 (VOID
**)&mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
]
1548 ASSERT_EFI_ERROR (Status
);
1550 mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
] = mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
];