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/FirmwareVolumeBlock.h>
32 #include <Guid/AlternateFvBlock.h>
33 #include <Protocol/DevicePath.h>
35 // The Library classes this module consumes
37 #include <Library/UefiLib.h>
38 #include <Library/UefiDriverEntryPoint.h>
39 #include <Library/BaseLib.h>
40 #include <Library/DxeServicesTableLib.h>
41 #include <Library/UefiRuntimeLib.h>
42 #include <Library/DebugLib.h>
43 #include <Library/HobLib.h>
44 #include <Library/BaseMemoryLib.h>
45 #include <Library/MemoryAllocationLib.h>
46 #include <Library/UefiBootServicesTableLib.h>
47 #include <Library/DevicePathLib.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 FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate
= {
61 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
)),
62 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
) >> 8)
66 (EFI_PHYSICAL_ADDRESS
) 0,
67 (EFI_PHYSICAL_ADDRESS
) 0,
71 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
73 END_DEVICE_PATH_LENGTH
,
79 FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate
= {
85 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
)),
86 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
) >> 8)
93 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
95 END_DEVICE_PATH_LENGTH
,
101 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
102 FVB_DEVICE_SIGNATURE
,
106 FvbProtocolGetAttributes
,
107 FvbProtocolSetAttributes
,
108 FvbProtocolGetPhysicalAddress
,
109 FvbProtocolGetBlockSize
,
112 FvbProtocolEraseBlocks
,
121 FvbVirtualddressChangeEvent (
129 Fixup internal data so that EFI and SAL can be call in virtual mode.
130 Call the passed in Child Notify event and convert the mFvbModuleGlobal
131 date items to there virtual address.
133 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
134 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
139 (Standard EFI notify event - EFI_EVENT_NOTIFY)
147 EFI_FW_VOL_INSTANCE
*FwhInstance
;
150 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
153 // Convert the base address of all the instances
156 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
157 while (Index
< mFvbModuleGlobal
->NumFv
) {
158 EfiConvertPointer (0x0, (VOID
**) &FwhInstance
->FvBase
[FVB_VIRTUAL
]);
159 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
161 (UINTN
) ((UINT8
*) FwhInstance
) + FwhInstance
->VolumeHeader
.HeaderLength
+
162 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
167 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
]);
168 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
);
174 IN ESAL_FWB_GLOBAL
*Global
,
175 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
181 Retrieves the physical address of a memory mapped FV
184 Instance - The FV instance whose base address is going to be
186 Global - Pointer to ESAL_FWB_GLOBAL that contains all
188 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
189 Virtual - Whether CPU is in virtual or physical mode
192 EFI_SUCCESS - Successfully returns
193 EFI_INVALID_PARAMETER - Instance not found
197 EFI_FW_VOL_INSTANCE
*FwhRecord
;
199 if (Instance
>= Global
->NumFv
) {
200 return EFI_INVALID_PARAMETER
;
203 // Find the right instance of the FVB private data
205 FwhRecord
= Global
->FvInstance
[Virtual
];
206 while (Instance
> 0) {
207 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
209 (UINTN
) ((UINT8
*) FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
210 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
215 *FwhInstance
= FwhRecord
;
221 FvbGetPhysicalAddress (
223 OUT EFI_PHYSICAL_ADDRESS
*Address
,
224 IN ESAL_FWB_GLOBAL
*Global
,
230 Retrieves the physical address of a memory mapped FV
233 Instance - The FV instance whose base address is going to be
235 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
236 that on successful return, contains the base address
237 of the firmware volume.
238 Global - Pointer to ESAL_FWB_GLOBAL that contains all
240 Virtual - Whether CPU is in virtual or physical mode
243 EFI_SUCCESS - Successfully returns
244 EFI_INVALID_PARAMETER - Instance not found
248 EFI_FW_VOL_INSTANCE
*FwhInstance
;
252 // Find the right instance of the FVB private data
254 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
255 ASSERT_EFI_ERROR (Status
);
256 *Address
= FwhInstance
->FvBase
[Virtual
];
262 FvbGetVolumeAttributes (
264 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
265 IN ESAL_FWB_GLOBAL
*Global
,
271 Retrieves attributes, insures positive polarity of attribute bits, returns
272 resulting attributes in output parameter
275 Instance - The FV instance whose attributes is going to be
277 Attributes - Output buffer which contains attributes
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
288 EFI_FW_VOL_INSTANCE
*FwhInstance
;
292 // Find the right instance of the FVB private data
294 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
295 ASSERT_EFI_ERROR (Status
);
296 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
305 OUT UINTN
*LbaAddress
,
306 OUT UINTN
*LbaLength
,
307 OUT UINTN
*NumOfBlocks
,
308 IN ESAL_FWB_GLOBAL
*Global
,
314 Retrieves the starting address of an LBA in an FV
317 Instance - The FV instance which the Lba belongs to
318 Lba - The logical block address
319 LbaAddress - On output, contains the physical starting address
321 LbaLength - On output, contains the length of the block
322 NumOfBlocks - A pointer to a caller allocated UINTN in which the
323 number of consecutive blocks starting with Lba is
324 returned. All blocks in this range have a size of
326 Global - Pointer to ESAL_FWB_GLOBAL that contains all
328 Virtual - Whether CPU is in virtual or physical mode
331 EFI_SUCCESS - Successfully returns
332 EFI_INVALID_PARAMETER - Instance not found
341 EFI_FW_VOL_INSTANCE
*FwhInstance
;
342 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
346 // Find the right instance of the FVB private data
348 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
349 ASSERT_EFI_ERROR (Status
);
353 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
356 // Parse the blockmap of the FV to find which map entry the Lba belongs to
359 NumBlocks
= BlockMap
->NumBlocks
;
360 BlockLength
= BlockMap
->Length
;
362 if (NumBlocks
== 0 || BlockLength
== 0) {
363 return EFI_INVALID_PARAMETER
;
366 NextLba
= StartLba
+ NumBlocks
;
369 // The map entry found
371 if (Lba
>= StartLba
&& Lba
< NextLba
) {
372 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
373 if (LbaAddress
!= NULL
) {
374 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
377 if (LbaLength
!= NULL
) {
378 *LbaLength
= BlockLength
;
381 if (NumOfBlocks
!= NULL
) {
382 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
389 Offset
= Offset
+ NumBlocks
* BlockLength
;
398 IN UINTN BlockOffset
,
399 IN OUT UINTN
*NumBytes
,
401 IN ESAL_FWB_GLOBAL
*Global
,
407 Reads specified number of bytes into a buffer from the specified block
410 Instance - The FV instance to be read from
411 Lba - The logical block address to be read from
412 BlockOffset - Offset into the block at which to begin reading
413 NumBytes - Pointer that on input contains the total size of
414 the buffer. On output, it contains the total number
416 Buffer - Pointer to a caller allocated buffer that will be
417 used to hold the data read
418 Global - Pointer to ESAL_FWB_GLOBAL that contains all
420 Virtual - Whether CPU is in virtual or physical mode
423 EFI_SUCCESS - The firmware volume was read successfully and
424 contents are in Buffer
425 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
426 NumBytes contains the total number of bytes returned
428 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
429 EFI_DEVICE_ERROR - The block device is not functioning correctly and
431 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
435 EFI_FVB_ATTRIBUTES_2 Attributes
;
441 // Check for invalid conditions
443 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
444 return EFI_INVALID_PARAMETER
;
447 if (*NumBytes
== 0) {
448 return EFI_INVALID_PARAMETER
;
451 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
452 if (EFI_ERROR (Status
)) {
456 // Check if the FV is read enabled
458 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
460 if ((Attributes
& EFI_FVB2_READ_STATUS
) == 0) {
461 return EFI_ACCESS_DENIED
;
464 // Perform boundary checks and adjust NumBytes
466 if (BlockOffset
> LbaLength
) {
467 return EFI_INVALID_PARAMETER
;
470 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
471 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
472 Status
= EFI_BAD_BUFFER_SIZE
;
475 CopyMem (Buffer
, (UINT8
*) (LbaAddress
+ BlockOffset
), (UINTN
) (*NumBytes
));
484 IN UINTN BlockOffset
,
485 IN OUT UINTN
*NumBytes
,
487 IN ESAL_FWB_GLOBAL
*Global
,
493 Writes specified number of bytes from the input buffer to the block
496 Instance - The FV instance to be written to
497 Lba - The starting logical block index to write to
498 BlockOffset - Offset into the block at which to begin writing
499 NumBytes - Pointer that on input contains the total size of
500 the buffer. On output, it contains the total number
501 of bytes actually written
502 Buffer - Pointer to a caller allocated buffer that contains
503 the source for the write
504 Global - Pointer to ESAL_FWB_GLOBAL that contains all
506 Virtual - Whether CPU is in virtual or physical mode
509 EFI_SUCCESS - The firmware volume was written successfully
510 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
511 NumBytes contains the total number of bytes
513 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
514 EFI_DEVICE_ERROR - The block device is not functioning correctly and
516 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
520 EFI_FVB_ATTRIBUTES_2 Attributes
;
526 // Check for invalid conditions
528 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
529 return EFI_INVALID_PARAMETER
;
532 if (*NumBytes
== 0) {
533 return EFI_INVALID_PARAMETER
;
536 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
537 if (EFI_ERROR (Status
)) {
541 // Check if the FV is write enabled
543 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
545 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
546 return EFI_ACCESS_DENIED
;
549 // Perform boundary checks and adjust NumBytes
551 if (BlockOffset
> LbaLength
) {
552 return EFI_INVALID_PARAMETER
;
555 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
556 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
557 Status
= EFI_BAD_BUFFER_SIZE
;
562 CopyMem ((UINT8
*) (LbaAddress
+ BlockOffset
), Buffer
, (UINTN
) (*NumBytes
));
571 IN ESAL_FWB_GLOBAL
*Global
,
577 Erases and initializes a firmware volume block
580 Instance - The FV instance to be erased
581 Lba - The logical block index to be erased
582 Global - Pointer to ESAL_FWB_GLOBAL that contains all
584 Virtual - Whether CPU is in virtual or physical mode
587 EFI_SUCCESS - The erase request was successfully completed
588 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
589 EFI_DEVICE_ERROR - The block device is not functioning correctly and
590 could not be written. Firmware device may have been
592 EFI_INVALID_PARAMETER - Instance not found
597 EFI_FVB_ATTRIBUTES_2 Attributes
;
604 // Check if the FV is write enabled
606 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
608 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
609 return EFI_ACCESS_DENIED
;
612 // Get the starting address of the block for erase.
614 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
616 if (EFI_ERROR (Status
)) {
620 if ((Attributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
626 SetMem ((UINT8
*) LbaAddress
, LbaLength
, Data
);
632 FvbSetVolumeAttributes (
634 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
635 IN ESAL_FWB_GLOBAL
*Global
,
641 Modifies the current settings of the firmware volume according to the
642 input parameter, and returns the new setting of the volume
645 Instance - The FV instance whose attributes is going to be
647 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
648 containing the desired firmware volume settings.
649 On successful return, it contains the new settings
650 of the firmware volume
651 Global - Pointer to ESAL_FWB_GLOBAL that contains all
653 Virtual - Whether CPU is in virtual or physical mode
656 EFI_SUCCESS - Successfully returns
657 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
658 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
659 in conflict with the capabilities as declared in the
660 firmware volume header
664 EFI_FW_VOL_INSTANCE
*FwhInstance
;
665 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
666 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
671 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes
;
674 // Find the right instance of the FVB private data
676 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
677 ASSERT_EFI_ERROR (Status
);
679 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
680 OldAttributes
= *AttribPtr
;
681 Capabilities
= OldAttributes
& (EFI_FVB2_READ_DISABLED_CAP
| \
682 EFI_FVB2_READ_ENABLED_CAP
| \
683 EFI_FVB2_WRITE_DISABLED_CAP
| \
684 EFI_FVB2_WRITE_ENABLED_CAP
| \
687 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
688 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
690 UnchangedAttributes
= EFI_FVB2_READ_DISABLED_CAP
| \
691 EFI_FVB2_READ_ENABLED_CAP
| \
692 EFI_FVB2_WRITE_DISABLED_CAP
| \
693 EFI_FVB2_WRITE_ENABLED_CAP
| \
694 EFI_FVB2_LOCK_CAP
| \
695 EFI_FVB2_STICKY_WRITE
| \
696 EFI_FVB2_MEMORY_MAPPED
| \
697 EFI_FVB2_ERASE_POLARITY
| \
698 EFI_FVB2_READ_LOCK_CAP
| \
699 EFI_FVB2_WRITE_LOCK_CAP
| \
703 // Some attributes of FV is read only can *not* be set
705 if ((OldAttributes
& UnchangedAttributes
) ^ (*Attributes
& UnchangedAttributes
)) {
706 return EFI_INVALID_PARAMETER
;
709 // If firmware volume is locked, no status bit can be updated
711 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
712 if (OldStatus
^ NewStatus
) {
713 return EFI_ACCESS_DENIED
;
719 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
720 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
721 return EFI_INVALID_PARAMETER
;
727 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
728 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
729 return EFI_INVALID_PARAMETER
;
733 // Test write disable
735 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
736 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
737 return EFI_INVALID_PARAMETER
;
743 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
744 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
745 return EFI_INVALID_PARAMETER
;
751 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
752 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
753 return EFI_INVALID_PARAMETER
;
757 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
758 *AttribPtr
= (*AttribPtr
) | NewStatus
;
759 *Attributes
= *AttribPtr
;
768 FvbProtocolGetPhysicalAddress (
769 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
770 OUT EFI_PHYSICAL_ADDRESS
*Address
776 Retrieves the physical address of the device.
780 This - Calling context
781 Address - Output buffer containing the address.
786 EFI_SUCCESS - Successfully returns
790 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
792 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
794 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
799 FvbProtocolGetBlockSize (
800 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
801 IN CONST EFI_LBA Lba
,
802 OUT UINTN
*BlockSize
,
803 OUT UINTN
*NumOfBlocks
808 Retrieve the size of a logical block
811 This - Calling context
812 Lba - Indicates which block to return the size for.
813 BlockSize - A pointer to a caller allocated UINTN in which
814 the size of the block is returned
815 NumOfBlocks - a pointer to a caller allocated UINTN in which the
816 number of consecutive blocks starting with Lba is
817 returned. All blocks in this range have a size of
821 EFI_SUCCESS - The firmware volume was read successfully and
822 contents are in Buffer
826 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
828 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
830 return FvbGetLbaAddress (
843 FvbProtocolGetAttributes (
844 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
845 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
850 Retrieves Volume attributes. No polarity translations are done.
853 This - Calling context
854 Attributes - output buffer which contains attributes
857 EFI_SUCCESS - Successfully returns
861 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
863 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
865 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
870 FvbProtocolSetAttributes (
871 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
872 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
877 Sets Volume attributes. No polarity translations are done.
880 This - Calling context
881 Attributes - output buffer which contains attributes
884 EFI_SUCCESS - Successfully returns
888 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
890 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
892 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
897 FvbProtocolEraseBlocks (
898 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
905 The EraseBlock() function erases one or more blocks as denoted by the
906 variable argument list. The entire parameter list of blocks must be verified
907 prior to erasing any blocks. If a block is requested that does not exist
908 within the associated firmware volume (it has a larger index than the last
909 block of the firmware volume), the EraseBlock() function must return
910 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
913 This - Calling context
914 ... - Starting LBA followed by Number of Lba to erase.
915 a -1 to terminate the list.
918 EFI_SUCCESS - The erase request was successfully completed
919 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
920 EFI_DEVICE_ERROR - The block device is not functioning correctly and
921 could not be written. Firmware device may have been
926 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
927 EFI_FW_VOL_INSTANCE
*FwhInstance
;
934 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
936 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
937 ASSERT_EFI_ERROR (Status
);
939 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
941 VA_START (args
, This
);
944 StartingLba
= VA_ARG (args
, EFI_LBA
);
945 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
949 NumOfLba
= VA_ARG (args
, UINT32
);
952 // Check input parameters
956 return EFI_INVALID_PARAMETER
;
959 if ((StartingLba
+ NumOfLba
) > NumOfBlocks
) {
960 return EFI_INVALID_PARAMETER
;
966 VA_START (args
, This
);
968 StartingLba
= VA_ARG (args
, EFI_LBA
);
969 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
973 NumOfLba
= VA_ARG (args
, UINT32
);
975 while (NumOfLba
> 0) {
976 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
977 if (EFI_ERROR (Status
)) {
996 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
999 IN OUT UINTN
*NumBytes
,
1004 Routine Description:
1006 Writes data beginning at Lba:Offset from FV. The write terminates either
1007 when *NumBytes of data have been written, or when a block boundary is
1008 reached. *NumBytes is updated to reflect the actual number of bytes
1009 written. The write opertion does not include erase. This routine will
1010 attempt to write only the specified bytes. If the writes do not stick,
1011 it will return an error.
1014 This - Calling context
1015 Lba - Block in which to begin write
1016 Offset - Offset in the block at which to begin write
1017 NumBytes - On input, indicates the requested write size. On
1018 output, indicates the actual number of bytes written
1019 Buffer - Buffer containing source data for the write.
1022 EFI_SUCCESS - The firmware volume was written successfully
1023 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
1024 NumBytes contains the total number of bytes
1026 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1027 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1028 could not be written
1029 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1034 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1036 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1038 return FvbWriteBlock (FvbDevice
->Instance
, (EFI_LBA
)Lba
, (UINTN
)Offset
, NumBytes
, (UINT8
*)Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1044 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1045 IN CONST EFI_LBA Lba
,
1046 IN CONST UINTN Offset
,
1047 IN OUT UINTN
*NumBytes
,
1052 Routine Description:
1054 Reads data beginning at Lba:Offset from FV. The Read terminates either
1055 when *NumBytes of data have been read, or when a block boundary is
1056 reached. *NumBytes is updated to reflect the actual number of bytes
1057 written. The write opertion does not include erase. This routine will
1058 attempt to write only the specified bytes. If the writes do not stick,
1059 it will return an error.
1062 This - Calling context
1063 Lba - Block in which to begin Read
1064 Offset - Offset in the block at which to begin Read
1065 NumBytes - On input, indicates the requested write size. On
1066 output, indicates the actual number of bytes Read
1067 Buffer - Buffer containing source data for the Read.
1070 EFI_SUCCESS - The firmware volume was read successfully and
1071 contents are in Buffer
1072 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1073 NumBytes contains the total number of bytes returned
1075 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1076 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1078 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1083 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1085 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1087 return FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1092 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1096 Routine Description:
1097 Check the integrity of firmware volume header
1100 FwVolHeader - A pointer to a firmware volume header
1103 EFI_SUCCESS - The firmware volume is consistent
1104 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1109 UINT16 HeaderLength
;
1113 // Verify the header revision, header signature, length
1114 // Length of FvBlock cannot be 2**64-1
1115 // HeaderLength cannot be an odd number
1117 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1118 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1119 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
1120 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1122 return EFI_NOT_FOUND
;
1126 // Verify the header checksum
1128 HeaderLength
= (UINT16
) (FwVolHeader
->HeaderLength
/ 2);
1129 Ptr
= (UINT16
*) FwVolHeader
;
1131 while (HeaderLength
> 0) {
1132 Checksum
= (UINT16
)(Checksum
+ (*Ptr
));
1137 if (Checksum
!= 0) {
1138 return EFI_NOT_FOUND
;
1142 // PI specification defines the name guid of FV exists in extension header.
1144 if (FwVolHeader
->ExtHeaderOffset
== 0) {
1145 return EFI_NOT_FOUND
;
1154 IN EFI_HANDLE ImageHandle
,
1155 IN EFI_SYSTEM_TABLE
*SystemTable
1159 Routine Description:
1160 This function does common initialization for FVB services
1169 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1170 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1171 EFI_DXE_SERVICES
*DxeServices
;
1172 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
1174 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1175 EFI_HANDLE FwbHandle
;
1176 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1177 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1179 EFI_PHYSICAL_ADDRESS BaseAddress
;
1182 EFI_PEI_HOB_POINTERS FvHob
;
1185 // Get the DXE services table
1190 // Allocate runtime services data for global variable, which contains
1191 // the private data of all firmware volume block instances
1193 mFvbModuleGlobal
= AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL
));
1194 ASSERT (mFvbModuleGlobal
!= NULL
);
1197 // Calculate the total size for all firmware volume block instances
1201 FvHob
.Raw
= GetHobList ();
1202 while ((FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
)) != NULL
) {
1203 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1204 Length
= FvHob
.FirmwareVolume
->Length
;
1206 // Check if it is a "real" flash
1208 Status
= DxeServices
->GetMemorySpaceDescriptor (
1212 if (EFI_ERROR (Status
)) {
1216 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1217 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1221 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1222 Status
= ValidateFvHeader (FwVolHeader
);
1223 if (EFI_ERROR (Status
)) {
1227 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1228 if (EFI_ERROR (Status
)) {
1229 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1234 BufferSize
+= (sizeof (EFI_FW_VOL_INSTANCE
) + FwVolHeader
->HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1235 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1239 // Only need to allocate once. There is only one copy of physical memory for
1240 // the private data of each FV instance. But in virtual mode or in physical
1241 // mode, the address of the the physical memory may be different.
1243 mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] = AllocateRuntimePool (BufferSize
);
1244 ASSERT (mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] != NULL
);
1247 // Make a virtual copy of the FvInstance pointer.
1249 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1250 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1252 mFvbModuleGlobal
->NumFv
= 0;
1255 FvHob
.Raw
= GetHobList ();
1256 while (NULL
!= (FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
))) {
1257 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1258 Length
= FvHob
.FirmwareVolume
->Length
;
1260 // Check if it is a "real" flash
1262 Status
= DxeServices
->GetMemorySpaceDescriptor (
1266 if (EFI_ERROR (Status
)) {
1270 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1271 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1275 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1276 Status
= ValidateFvHeader (FwVolHeader
);
1277 if (EFI_ERROR (Status
)) {
1279 // Get FvbInfo to provide in FwhInstance.
1281 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1282 if (EFI_ERROR (Status
)) {
1283 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1287 // Write healthy FV header back.
1290 (VOID
*) (UINTN
) BaseAddress
,
1291 (VOID
*) FwVolHeader
,
1292 FwVolHeader
->HeaderLength
1296 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1297 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1299 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1300 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1301 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1305 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1307 // Get the maximum size of a block.
1309 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
1310 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1313 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1316 // The total number of blocks in the FV.
1318 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1321 // Add a FVB Protocol Instance
1323 FvbDevice
= AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1324 ASSERT (FvbDevice
!= NULL
);
1326 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1328 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1329 mFvbModuleGlobal
->NumFv
++;
1333 // Set up the devicepath
1335 if (FwVolHeader
->ExtHeaderOffset
== 0) {
1337 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
1339 FvbDevice
->DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH
), &mFvMemmapDevicePathTemplate
);
1340 ((FV_MEMMAP_DEVICE_PATH
*) FvbDevice
->DevicePath
)->MemMapDevPath
.StartingAddress
= BaseAddress
;
1341 ((FV_MEMMAP_DEVICE_PATH
*) FvbDevice
->DevicePath
)->MemMapDevPath
.EndingAddress
= BaseAddress
+ FwVolHeader
->FvLength
- 1;
1343 FvbDevice
->DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH
), &mFvPIWGDevicePathTemplate
);
1345 &((FV_PIWG_DEVICE_PATH
*)FvbDevice
->DevicePath
)->FvDevPath
.FvName
,
1346 (GUID
*)(UINTN
)(BaseAddress
+ FwVolHeader
->ExtHeaderOffset
)
1350 // Find a handle with a matching device path that has supports FW Block protocol
1352 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &FvbDevice
->DevicePath
, &FwbHandle
);
1353 if (EFI_ERROR (Status
)) {
1355 // LocateDevicePath fails so install a new interface and device path
1358 Status
= gBS
->InstallMultipleProtocolInterfaces (
1360 &gEfiFirmwareVolumeBlockProtocolGuid
,
1361 &FvbDevice
->FwVolBlockInstance
,
1362 &gEfiDevicePathProtocolGuid
,
1363 &FvbDevice
->DevicePath
,
1366 ASSERT_EFI_ERROR (Status
);
1367 } else if (IsDevicePathEnd (FvbDevice
->DevicePath
)) {
1369 // Device allready exists, so reinstall the FVB protocol
1371 Status
= gBS
->HandleProtocol (
1373 &gEfiFirmwareVolumeBlockProtocolGuid
,
1374 (VOID
**)&OldFwbInterface
1376 ASSERT_EFI_ERROR (Status
);
1378 Status
= gBS
->ReinstallProtocolInterface (
1380 &gEfiFirmwareVolumeBlockProtocolGuid
,
1382 &FvbDevice
->FwVolBlockInstance
1384 ASSERT_EFI_ERROR (Status
);
1388 // There was a FVB protocol on an End Device Path node
1393 Status
= gBS
->InstallMultipleProtocolInterfaces (
1395 &gEfiAlternateFvBlockGuid
,
1400 ASSERT_EFI_ERROR (Status
);
1402 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1404 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1405 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1408 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);