3 Copyright (c) 2006 - 2007, 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 // The package level header files this module uses
28 // The protocols, PPI and GUID defintions for this module
30 #include <Guid/EventGroup.h>
31 #include <Protocol/FvbExtension.h>
32 #include <Protocol/FirmwareVolumeBlock.h>
33 #include <Guid/AlternateFvBlock.h>
34 #include <Protocol/DevicePath.h>
36 // The Library classes this module consumes
38 #include <Library/UefiLib.h>
39 #include <Library/UefiDriverEntryPoint.h>
40 #include <Library/BaseLib.h>
41 #include <Library/DxeServicesTableLib.h>
42 #include <Library/UefiRuntimeLib.h>
43 #include <Library/DebugLib.h>
44 #include <Library/HobLib.h>
45 #include <Library/BaseMemoryLib.h>
46 #include <Library/MemoryAllocationLib.h>
47 #include <Library/UefiBootServicesTableLib.h>
49 #include "FWBlockService.h"
51 #define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
53 ESAL_FWB_GLOBAL
*mFvbModuleGlobal
;
55 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
63 sizeof (MEMMAP_DEVICE_PATH
),
73 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
75 sizeof (EFI_DEVICE_PATH_PROTOCOL
),
82 FvbProtocolGetAttributes
,
83 FvbProtocolSetAttributes
,
84 FvbProtocolGetPhysicalAddress
,
85 FvbProtocolGetBlockSize
,
88 FvbProtocolEraseBlocks
,
92 FvbExtendProtocolEraseCustomBlockRange
100 FvbVirtualddressChangeEvent (
108 Fixup internal data so that EFI and SAL can be call in virtual mode.
109 Call the passed in Child Notify event and convert the mFvbModuleGlobal
110 date items to there virtual address.
112 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
113 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
118 (Standard EFI notify event - EFI_EVENT_NOTIFY)
126 EFI_FW_VOL_INSTANCE
*FwhInstance
;
129 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
132 // Convert the base address of all the instances
135 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
136 while (Index
< mFvbModuleGlobal
->NumFv
) {
137 EfiConvertPointer (0x0, (VOID
**) &FwhInstance
->FvBase
[FVB_VIRTUAL
]);
138 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
140 (UINTN
) ((UINT8
*) FwhInstance
) + FwhInstance
->VolumeHeader
.HeaderLength
+
141 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
146 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
]);
147 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
);
153 IN ESAL_FWB_GLOBAL
*Global
,
154 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
160 Retrieves the physical address of a memory mapped FV
163 Instance - The FV instance whose base address is going to be
165 Global - Pointer to ESAL_FWB_GLOBAL that contains all
167 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
168 Virtual - Whether CPU is in virtual or physical mode
171 EFI_SUCCESS - Successfully returns
172 EFI_INVALID_PARAMETER - Instance not found
176 EFI_FW_VOL_INSTANCE
*FwhRecord
;
178 if (Instance
>= Global
->NumFv
) {
179 return EFI_INVALID_PARAMETER
;
182 // Find the right instance of the FVB private data
184 FwhRecord
= Global
->FvInstance
[Virtual
];
185 while (Instance
> 0) {
186 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
188 (UINTN
) ((UINT8
*) FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
189 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
194 *FwhInstance
= FwhRecord
;
200 FvbGetPhysicalAddress (
202 OUT EFI_PHYSICAL_ADDRESS
*Address
,
203 IN ESAL_FWB_GLOBAL
*Global
,
209 Retrieves the physical address of a memory mapped FV
212 Instance - The FV instance whose base address is going to be
214 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
215 that on successful return, contains the base address
216 of the firmware volume.
217 Global - Pointer to ESAL_FWB_GLOBAL that contains all
219 Virtual - Whether CPU is in virtual or physical mode
222 EFI_SUCCESS - Successfully returns
223 EFI_INVALID_PARAMETER - Instance not found
227 EFI_FW_VOL_INSTANCE
*FwhInstance
;
231 // Find the right instance of the FVB private data
233 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
234 ASSERT_EFI_ERROR (Status
);
235 *Address
= FwhInstance
->FvBase
[Virtual
];
241 FvbGetVolumeAttributes (
243 OUT EFI_FVB_ATTRIBUTES
*Attributes
,
244 IN ESAL_FWB_GLOBAL
*Global
,
250 Retrieves attributes, insures positive polarity of attribute bits, returns
251 resulting attributes in output parameter
254 Instance - The FV instance whose attributes is going to be
256 Attributes - Output buffer which contains attributes
257 Global - Pointer to ESAL_FWB_GLOBAL that contains all
259 Virtual - Whether CPU is in virtual or physical mode
262 EFI_SUCCESS - Successfully returns
263 EFI_INVALID_PARAMETER - Instance not found
267 EFI_FW_VOL_INSTANCE
*FwhInstance
;
271 // Find the right instance of the FVB private data
273 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
274 ASSERT_EFI_ERROR (Status
);
275 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
284 OUT UINTN
*LbaAddress
,
285 OUT UINTN
*LbaLength
,
286 OUT UINTN
*NumOfBlocks
,
287 IN ESAL_FWB_GLOBAL
*Global
,
293 Retrieves the starting address of an LBA in an FV
296 Instance - The FV instance which the Lba belongs to
297 Lba - The logical block address
298 LbaAddress - On output, contains the physical starting address
300 LbaLength - On output, contains the length of the block
301 NumOfBlocks - A pointer to a caller allocated UINTN in which the
302 number of consecutive blocks starting with Lba is
303 returned. All blocks in this range have a size of
305 Global - Pointer to ESAL_FWB_GLOBAL that contains all
307 Virtual - Whether CPU is in virtual or physical mode
310 EFI_SUCCESS - Successfully returns
311 EFI_INVALID_PARAMETER - Instance not found
320 EFI_FW_VOL_INSTANCE
*FwhInstance
;
321 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
325 // Find the right instance of the FVB private data
327 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
328 ASSERT_EFI_ERROR (Status
);
332 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
335 // Parse the blockmap of the FV to find which map entry the Lba belongs to
338 NumBlocks
= BlockMap
->NumBlocks
;
339 BlockLength
= BlockMap
->Length
;
341 if (NumBlocks
== 0 || BlockLength
== 0) {
342 return EFI_INVALID_PARAMETER
;
345 NextLba
= StartLba
+ NumBlocks
;
348 // The map entry found
350 if (Lba
>= StartLba
&& Lba
< NextLba
) {
351 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
352 if (LbaAddress
!= NULL
) {
353 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
356 if (LbaLength
!= NULL
) {
357 *LbaLength
= BlockLength
;
360 if (NumOfBlocks
!= NULL
) {
361 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
368 Offset
= Offset
+ NumBlocks
* BlockLength
;
377 IN UINTN BlockOffset
,
378 IN OUT UINTN
*NumBytes
,
380 IN ESAL_FWB_GLOBAL
*Global
,
386 Reads specified number of bytes into a buffer from the specified block
389 Instance - The FV instance to be read from
390 Lba - The logical block address to be read from
391 BlockOffset - Offset into the block at which to begin reading
392 NumBytes - Pointer that on input contains the total size of
393 the buffer. On output, it contains the total number
395 Buffer - Pointer to a caller allocated buffer that will be
396 used to hold the data read
397 Global - Pointer to ESAL_FWB_GLOBAL that contains all
399 Virtual - Whether CPU is in virtual or physical mode
402 EFI_SUCCESS - The firmware volume was read successfully and
403 contents are in Buffer
404 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
405 NumBytes contains the total number of bytes returned
407 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
408 EFI_DEVICE_ERROR - The block device is not functioning correctly and
410 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
414 EFI_FVB_ATTRIBUTES Attributes
;
420 // Check for invalid conditions
422 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
423 return EFI_INVALID_PARAMETER
;
426 if (*NumBytes
== 0) {
427 return EFI_INVALID_PARAMETER
;
430 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
431 if (EFI_ERROR (Status
)) {
435 // Check if the FV is read enabled
437 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
439 if ((Attributes
& EFI_FVB2_READ_STATUS
) == 0) {
440 return EFI_ACCESS_DENIED
;
443 // Perform boundary checks and adjust NumBytes
445 if (BlockOffset
> LbaLength
) {
446 return EFI_INVALID_PARAMETER
;
449 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
450 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
451 Status
= EFI_BAD_BUFFER_SIZE
;
454 CopyMem (Buffer
, (UINT8
*) (LbaAddress
+ BlockOffset
), (UINTN
) (*NumBytes
));
463 IN UINTN BlockOffset
,
464 IN OUT UINTN
*NumBytes
,
466 IN ESAL_FWB_GLOBAL
*Global
,
472 Writes specified number of bytes from the input buffer to the block
475 Instance - The FV instance to be written to
476 Lba - The starting logical block index to write to
477 BlockOffset - Offset into the block at which to begin writing
478 NumBytes - Pointer that on input contains the total size of
479 the buffer. On output, it contains the total number
480 of bytes actually written
481 Buffer - Pointer to a caller allocated buffer that contains
482 the source for the write
483 Global - Pointer to ESAL_FWB_GLOBAL that contains all
485 Virtual - Whether CPU is in virtual or physical mode
488 EFI_SUCCESS - The firmware volume was written successfully
489 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
490 NumBytes contains the total number of bytes
492 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
493 EFI_DEVICE_ERROR - The block device is not functioning correctly and
495 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
499 EFI_FVB_ATTRIBUTES Attributes
;
505 // Check for invalid conditions
507 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
508 return EFI_INVALID_PARAMETER
;
511 if (*NumBytes
== 0) {
512 return EFI_INVALID_PARAMETER
;
515 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
516 if (EFI_ERROR (Status
)) {
520 // Check if the FV is write enabled
522 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
524 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
525 return EFI_ACCESS_DENIED
;
528 // Perform boundary checks and adjust NumBytes
530 if (BlockOffset
> LbaLength
) {
531 return EFI_INVALID_PARAMETER
;
534 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
535 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
536 Status
= EFI_BAD_BUFFER_SIZE
;
541 CopyMem ((UINT8
*) (LbaAddress
+ BlockOffset
), Buffer
, (UINTN
) (*NumBytes
));
550 IN ESAL_FWB_GLOBAL
*Global
,
556 Erases and initializes a firmware volume block
559 Instance - The FV instance to be erased
560 Lba - The logical block index to be erased
561 Global - Pointer to ESAL_FWB_GLOBAL that contains all
563 Virtual - Whether CPU is in virtual or physical mode
566 EFI_SUCCESS - The erase request was successfully completed
567 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
568 EFI_DEVICE_ERROR - The block device is not functioning correctly and
569 could not be written. Firmware device may have been
571 EFI_INVALID_PARAMETER - Instance not found
576 EFI_FVB_ATTRIBUTES Attributes
;
583 // Check if the FV is write enabled
585 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
587 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
588 return EFI_ACCESS_DENIED
;
591 // Get the starting address of the block for erase.
593 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
595 if (EFI_ERROR (Status
)) {
599 if ((Attributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
605 SetMem ((UINT8
*) LbaAddress
, LbaLength
, Data
);
611 FvbEraseCustomBlockRange (
614 IN UINTN OffsetStartLba
,
616 IN UINTN OffsetLastLba
,
617 IN ESAL_FWB_GLOBAL
*Global
,
623 Erases and initializes a specified range of a firmware volume
626 Instance - The FV instance to be erased
627 StartLba - The starting logical block index to be erased
628 OffsetStartLba - Offset into the starting block at which to
630 LastLba - The last logical block index to be erased
631 OffsetStartLba - Offset into the last block at which to end erasing
632 Global - Pointer to ESAL_FWB_GLOBAL that contains all
634 Virtual - Whether CPU is in virtual or physical mode
637 EFI_SUCCESS - The firmware volume was erased successfully
638 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
639 EFI_DEVICE_ERROR - The block device is not functioning correctly and
640 could not be written. Firmware device may have been
642 EFI_INVALID_PARAMETER - Instance not found
648 UINTN ScratchLbaSizeData
;
653 FvbGetLbaAddress (Instance
, StartLba
, NULL
, &LbaSize
, NULL
, Global
, Virtual
);
656 // Use the scratch space as the intermediate buffer to transfer data
657 // Back up the first LBA in scratch space.
659 FvbReadBlock (Instance
, StartLba
, 0, &LbaSize
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
664 FvbEraseBlock (Instance
, StartLba
, Global
, Virtual
);
665 ScratchLbaSizeData
= OffsetStartLba
;
668 // write the data back to the first block
670 if (ScratchLbaSizeData
> 0) {
671 FvbWriteBlock (Instance
, StartLba
, 0, &ScratchLbaSizeData
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
676 if (LastLba
> (StartLba
+ 1)) {
677 for (Index
= (StartLba
+ 1); Index
<= (LastLba
- 1); Index
++) {
678 FvbEraseBlock (Instance
, Index
, Global
, Virtual
);
682 // Last LBAs, the same as first LBAs
684 if (LastLba
> StartLba
) {
685 FvbGetLbaAddress (Instance
, LastLba
, NULL
, &LbaSize
, NULL
, Global
, Virtual
);
686 FvbReadBlock (Instance
, LastLba
, 0, &LbaSize
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
687 FvbEraseBlock (Instance
, LastLba
, Global
, Virtual
);
690 ScratchLbaSizeData
= LbaSize
- (OffsetStartLba
+ 1);
692 return FvbWriteBlock (
697 Global
->FvbScratchSpace
[Virtual
],
704 FvbSetVolumeAttributes (
706 IN OUT EFI_FVB_ATTRIBUTES
*Attributes
,
707 IN ESAL_FWB_GLOBAL
*Global
,
713 Modifies the current settings of the firmware volume according to the
714 input parameter, and returns the new setting of the volume
717 Instance - The FV instance whose attributes is going to be
719 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES
720 containing the desired firmware volume settings.
721 On successful return, it contains the new settings
722 of the firmware volume
723 Global - Pointer to ESAL_FWB_GLOBAL that contains all
725 Virtual - Whether CPU is in virtual or physical mode
728 EFI_SUCCESS - Successfully returns
729 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
730 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
731 in conflict with the capabilities as declared in the
732 firmware volume header
736 EFI_FW_VOL_INSTANCE
*FwhInstance
;
737 EFI_FVB_ATTRIBUTES OldAttributes
;
738 EFI_FVB_ATTRIBUTES
*AttribPtr
;
743 EFI_FVB_ATTRIBUTES UnchangedAttributes
;
746 // Find the right instance of the FVB private data
748 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
749 ASSERT_EFI_ERROR (Status
);
751 AttribPtr
= (EFI_FVB_ATTRIBUTES
*) &(FwhInstance
->VolumeHeader
.Attributes
);
752 OldAttributes
= *AttribPtr
;
753 Capabilities
= OldAttributes
& (EFI_FVB2_READ_DISABLED_CAP
| \
754 EFI_FVB2_READ_ENABLED_CAP
| \
755 EFI_FVB2_WRITE_DISABLED_CAP
| \
756 EFI_FVB2_WRITE_ENABLED_CAP
| \
759 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
760 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
762 UnchangedAttributes
= EFI_FVB2_READ_DISABLED_CAP
| \
763 EFI_FVB2_READ_ENABLED_CAP
| \
764 EFI_FVB2_WRITE_DISABLED_CAP
| \
765 EFI_FVB2_WRITE_ENABLED_CAP
| \
766 EFI_FVB2_LOCK_CAP
| \
767 EFI_FVB2_STICKY_WRITE
| \
768 EFI_FVB2_MEMORY_MAPPED
| \
769 EFI_FVB2_ERASE_POLARITY
| \
770 EFI_FVB2_READ_LOCK_CAP
| \
771 EFI_FVB2_WRITE_LOCK_CAP
| \
775 // Some attributes of FV is read only can *not* be set
777 if ((OldAttributes
& UnchangedAttributes
) ^ (*Attributes
& UnchangedAttributes
)) {
778 return EFI_INVALID_PARAMETER
;
781 // If firmware volume is locked, no status bit can be updated
783 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
784 if (OldStatus
^ NewStatus
) {
785 return EFI_ACCESS_DENIED
;
791 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
792 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
793 return EFI_INVALID_PARAMETER
;
799 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
800 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
801 return EFI_INVALID_PARAMETER
;
805 // Test write disable
807 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
808 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
809 return EFI_INVALID_PARAMETER
;
815 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
816 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
817 return EFI_INVALID_PARAMETER
;
823 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
824 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
825 return EFI_INVALID_PARAMETER
;
829 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
830 *AttribPtr
= (*AttribPtr
) | NewStatus
;
831 *Attributes
= *AttribPtr
;
840 FvbProtocolGetPhysicalAddress (
841 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
842 OUT EFI_PHYSICAL_ADDRESS
*Address
848 Retrieves the physical address of the device.
852 This - Calling context
853 Address - Output buffer containing the address.
858 EFI_SUCCESS - Successfully returns
862 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
864 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
866 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
871 FvbProtocolGetBlockSize (
872 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
873 IN CONST EFI_LBA Lba
,
874 OUT UINTN
*BlockSize
,
875 OUT UINTN
*NumOfBlocks
880 Retrieve the size of a logical block
883 This - Calling context
884 Lba - Indicates which block to return the size for.
885 BlockSize - A pointer to a caller allocated UINTN in which
886 the size of the block is returned
887 NumOfBlocks - a pointer to a caller allocated UINTN in which the
888 number of consecutive blocks starting with Lba is
889 returned. All blocks in this range have a size of
893 EFI_SUCCESS - The firmware volume was read successfully and
894 contents are in Buffer
898 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
900 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
902 return FvbGetLbaAddress (
915 FvbProtocolGetAttributes (
916 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
917 OUT EFI_FVB_ATTRIBUTES
*Attributes
922 Retrieves Volume attributes. No polarity translations are done.
925 This - Calling context
926 Attributes - output buffer which contains attributes
929 EFI_SUCCESS - Successfully returns
933 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
935 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
937 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
942 FvbProtocolSetAttributes (
943 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
944 IN OUT EFI_FVB_ATTRIBUTES
*Attributes
949 Sets Volume attributes. No polarity translations are done.
952 This - Calling context
953 Attributes - output buffer which contains attributes
956 EFI_SUCCESS - Successfully returns
960 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
962 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
964 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
969 FvbProtocolEraseBlocks (
970 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
977 The EraseBlock() function erases one or more blocks as denoted by the
978 variable argument list. The entire parameter list of blocks must be verified
979 prior to erasing any blocks. If a block is requested that does not exist
980 within the associated firmware volume (it has a larger index than the last
981 block of the firmware volume), the EraseBlock() function must return
982 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
985 This - Calling context
986 ... - Starting LBA followed by Number of Lba to erase.
987 a -1 to terminate the list.
990 EFI_SUCCESS - The erase request was successfully completed
991 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
992 EFI_DEVICE_ERROR - The block device is not functioning correctly and
993 could not be written. Firmware device may have been
998 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
999 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1002 EFI_LBA StartingLba
;
1006 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1008 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
1009 ASSERT_EFI_ERROR (Status
);
1011 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
1013 VA_START (args
, This
);
1016 StartingLba
= VA_ARG (args
, EFI_LBA
);
1017 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
1021 NumOfLba
= VA_ARG (args
, UINT32
);
1024 // Check input parameters
1026 if (NumOfLba
== 0) {
1028 return EFI_INVALID_PARAMETER
;
1031 if ((StartingLba
+ NumOfLba
) > NumOfBlocks
) {
1032 return EFI_INVALID_PARAMETER
;
1038 VA_START (args
, This
);
1040 StartingLba
= VA_ARG (args
, EFI_LBA
);
1041 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
1045 NumOfLba
= VA_ARG (args
, UINT32
);
1047 while (NumOfLba
> 0) {
1048 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
1049 if (EFI_ERROR (Status
)) {
1068 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1069 IN CONST EFI_LBA Lba
,
1070 IN CONST UINTN Offset
,
1071 IN OUT UINTN
*NumBytes
,
1072 IN CONST UINT8
*Buffer
1076 Routine Description:
1078 Writes data beginning at Lba:Offset from FV. The write terminates either
1079 when *NumBytes of data have been written, or when a block boundary is
1080 reached. *NumBytes is updated to reflect the actual number of bytes
1081 written. The write opertion does not include erase. This routine will
1082 attempt to write only the specified bytes. If the writes do not stick,
1083 it will return an error.
1086 This - Calling context
1087 Lba - Block in which to begin write
1088 Offset - Offset in the block at which to begin write
1089 NumBytes - On input, indicates the requested write size. On
1090 output, indicates the actual number of bytes written
1091 Buffer - Buffer containing source data for the write.
1094 EFI_SUCCESS - The firmware volume was written successfully
1095 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
1096 NumBytes contains the total number of bytes
1098 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1099 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1100 could not be written
1101 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1106 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1108 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1110 return FvbWriteBlock (FvbDevice
->Instance
, (EFI_LBA
)Lba
, (UINTN
)Offset
, NumBytes
, (UINT8
*)Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1116 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1117 IN CONST EFI_LBA Lba
,
1118 IN CONST UINTN Offset
,
1119 IN OUT UINTN
*NumBytes
,
1124 Routine Description:
1126 Reads data beginning at Lba:Offset from FV. The Read terminates either
1127 when *NumBytes of data have been read, or when a block boundary is
1128 reached. *NumBytes is updated to reflect the actual number of bytes
1129 written. The write opertion does not include erase. This routine will
1130 attempt to write only the specified bytes. If the writes do not stick,
1131 it will return an error.
1134 This - Calling context
1135 Lba - Block in which to begin Read
1136 Offset - Offset in the block at which to begin Read
1137 NumBytes - On input, indicates the requested write size. On
1138 output, indicates the actual number of bytes Read
1139 Buffer - Buffer containing source data for the Read.
1142 EFI_SUCCESS - The firmware volume was read successfully and
1143 contents are in Buffer
1144 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1145 NumBytes contains the total number of bytes returned
1147 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1148 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1150 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1155 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1157 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1159 return FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1162 // FVB Extension Protocols
1166 FvbExtendProtocolEraseCustomBlockRange (
1167 IN EFI_FVB_EXTENSION_PROTOCOL
*This
,
1168 IN EFI_LBA StartLba
,
1169 IN UINTN OffsetStartLba
,
1171 IN UINTN OffsetLastLba
1175 Routine Description:
1176 Erases and initializes a specified range of a firmware volume
1179 This - Calling context
1180 StartLba - The starting logical block index to be erased
1181 OffsetStartLba - Offset into the starting block at which to
1183 LastLba - The last logical block index to be erased
1184 OffsetStartLba - Offset into the last block at which to end erasing
1187 EFI_SUCCESS - The firmware volume was erased successfully
1188 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1189 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1190 could not be written. Firmware device may have been
1195 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1197 FvbDevice
= FVB_EXTEND_DEVICE_FROM_THIS (This
);
1199 return FvbEraseCustomBlockRange (
1200 FvbDevice
->Instance
,
1213 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1217 Routine Description:
1218 Check the integrity of firmware volume header
1221 FwVolHeader - A pointer to a firmware volume header
1224 EFI_SUCCESS - The firmware volume is consistent
1225 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1230 UINT16 HeaderLength
;
1234 // Verify the header revision, header signature, length
1235 // Length of FvBlock cannot be 2**64-1
1236 // HeaderLength cannot be an odd number
1238 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1239 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1240 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
1241 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1243 return EFI_NOT_FOUND
;
1246 // Verify the header checksum
1248 HeaderLength
= (UINT16
) (FwVolHeader
->HeaderLength
/ 2);
1249 Ptr
= (UINT16
*) FwVolHeader
;
1251 while (HeaderLength
> 0) {
1252 Checksum
= Checksum
+ (*Ptr
);
1257 if (Checksum
!= 0) {
1258 return EFI_NOT_FOUND
;
1267 IN EFI_HANDLE ImageHandle
,
1268 IN EFI_SYSTEM_TABLE
*SystemTable
1272 Routine Description:
1273 This function does common initialization for FVB services
1282 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1283 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1284 EFI_DXE_SERVICES
*DxeServices
;
1285 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
1287 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1288 EFI_HANDLE FwbHandle
;
1289 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1290 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1291 EFI_DEVICE_PATH_PROTOCOL
*TempFwbDevicePath
;
1292 FV_DEVICE_PATH TempFvbDevicePathData
;
1294 EFI_PHYSICAL_ADDRESS BaseAddress
;
1297 EFI_PEI_HOB_POINTERS FvHob
;
1300 // Get the DXE services table
1305 // Allocate runtime services data for global variable, which contains
1306 // the private data of all firmware volume block instances
1308 mFvbModuleGlobal
= AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL
));
1309 ASSERT (mFvbModuleGlobal
!= NULL
);
1312 // Calculate the total size for all firmware volume block instances
1316 FvHob
.Raw
= GetHobList ();
1317 while ((FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
)) != NULL
) {
1318 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1319 Length
= FvHob
.FirmwareVolume
->Length
;
1321 // Check if it is a "real" flash
1323 Status
= DxeServices
->GetMemorySpaceDescriptor (
1327 if (EFI_ERROR (Status
)) {
1331 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1332 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1336 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1337 Status
= ValidateFvHeader (FwVolHeader
);
1338 if (EFI_ERROR (Status
)) {
1342 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1343 if (EFI_ERROR (Status
)) {
1344 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1349 BufferSize
+= (sizeof (EFI_FW_VOL_INSTANCE
) + FwVolHeader
->HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1350 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1354 // Only need to allocate once. There is only one copy of physical memory for
1355 // the private data of each FV instance. But in virtual mode or in physical
1356 // mode, the address of the the physical memory may be different.
1358 mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] = AllocateRuntimePool (BufferSize
);
1359 ASSERT (mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] != NULL
);
1362 // Make a virtual copy of the FvInstance pointer.
1364 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1365 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1367 mFvbModuleGlobal
->NumFv
= 0;
1370 FvHob
.Raw
= GetHobList ();
1371 while (NULL
!= (FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
))) {
1372 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1373 Length
= FvHob
.FirmwareVolume
->Length
;
1375 // Check if it is a "real" flash
1377 Status
= DxeServices
->GetMemorySpaceDescriptor (
1381 if (EFI_ERROR (Status
)) {
1385 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1386 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1390 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1391 Status
= ValidateFvHeader (FwVolHeader
);
1392 if (EFI_ERROR (Status
)) {
1394 // Get FvbInfo to provide in FwhInstance.
1396 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1397 if (EFI_ERROR (Status
)) {
1398 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1402 // Write healthy FV header back.
1405 (VOID
*) (UINTN
) BaseAddress
,
1406 (VOID
*) FwVolHeader
,
1407 FwVolHeader
->HeaderLength
1411 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1412 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1414 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1415 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1416 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1420 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1422 // Get the maximum size of a block. The size will be used to allocate
1423 // buffer for Scratch space, the intermediate buffer for FVB extension
1426 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
1427 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1430 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1433 // The total number of blocks in the FV.
1435 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1438 // Add a FVB Protocol Instance
1440 FvbDevice
= AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1441 ASSERT (FvbDevice
!= NULL
);
1443 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1445 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1446 mFvbModuleGlobal
->NumFv
++;
1449 // Set up the devicepath
1451 FvbDevice
->DevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
1452 FvbDevice
->DevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ (FwVolHeader
->FvLength
- 1);
1455 // Find a handle with a matching device path that has supports FW Block protocol
1457 TempFwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) &TempFvbDevicePathData
;
1458 CopyMem (TempFwbDevicePath
, &FvbDevice
->DevicePath
, sizeof (FV_DEVICE_PATH
));
1459 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &TempFwbDevicePath
, &FwbHandle
);
1460 if (EFI_ERROR (Status
)) {
1462 // LocateDevicePath fails so install a new interface and device path
1465 Status
= gBS
->InstallMultipleProtocolInterfaces (
1467 &gEfiFirmwareVolumeBlockProtocolGuid
,
1468 &FvbDevice
->FwVolBlockInstance
,
1469 &gEfiDevicePathProtocolGuid
,
1470 &FvbDevice
->DevicePath
,
1473 ASSERT_EFI_ERROR (Status
);
1474 } else if (EfiIsDevicePathEnd (TempFwbDevicePath
)) {
1476 // Device allready exists, so reinstall the FVB protocol
1478 Status
= gBS
->HandleProtocol (
1480 &gEfiFirmwareVolumeBlockProtocolGuid
,
1483 ASSERT_EFI_ERROR (Status
);
1485 Status
= gBS
->ReinstallProtocolInterface (
1487 &gEfiFirmwareVolumeBlockProtocolGuid
,
1489 &FvbDevice
->FwVolBlockInstance
1491 ASSERT_EFI_ERROR (Status
);
1495 // There was a FVB protocol on an End Device Path node
1500 // Install FVB Extension Protocol on the same handle
1502 Status
= gBS
->InstallMultipleProtocolInterfaces (
1504 &gEfiFvbExtensionProtocolGuid
,
1505 &FvbDevice
->FvbExtension
,
1506 &gEfiAlternateFvBlockGuid
,
1511 ASSERT_EFI_ERROR (Status
);
1513 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1515 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1516 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1519 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1523 // Allocate for scratch space, an intermediate buffer for FVB extention
1525 mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
] = AllocateRuntimePool (MaxLbaSize
);
1526 ASSERT (mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
] != NULL
);
1528 mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
] = mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
];