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 <Protocol/DevicePath.h>
34 // The Library classes this module consumes
36 #include <Library/UefiLib.h>
37 #include <Library/UefiDriverEntryPoint.h>
38 #include <Library/BaseLib.h>
39 #include <Library/DxeServicesTableLib.h>
40 #include <Library/UefiRuntimeLib.h>
41 #include <Library/DebugLib.h>
42 #include <Library/HobLib.h>
43 #include <Library/BaseMemoryLib.h>
44 #include <Library/MemoryAllocationLib.h>
45 #include <Library/UefiBootServicesTableLib.h>
46 #include <Library/DevicePathLib.h>
48 #include "FWBlockService.h"
50 #define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
52 ESAL_FWB_GLOBAL
*mFvbModuleGlobal
;
54 FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate
= {
60 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
)),
61 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
) >> 8)
65 (EFI_PHYSICAL_ADDRESS
) 0,
66 (EFI_PHYSICAL_ADDRESS
) 0,
70 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
72 END_DEVICE_PATH_LENGTH
,
78 FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate
= {
84 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
)),
85 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
) >> 8)
92 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
94 END_DEVICE_PATH_LENGTH
,
100 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
101 FVB_DEVICE_SIGNATURE
,
105 FvbProtocolGetAttributes
,
106 FvbProtocolSetAttributes
,
107 FvbProtocolGetPhysicalAddress
,
108 FvbProtocolGetBlockSize
,
111 FvbProtocolEraseBlocks
,
120 FvbVirtualddressChangeEvent (
128 Fixup internal data so that EFI and SAL can be call in virtual mode.
129 Call the passed in Child Notify event and convert the mFvbModuleGlobal
130 date items to there virtual address.
132 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
133 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
138 (Standard EFI notify event - EFI_EVENT_NOTIFY)
146 EFI_FW_VOL_INSTANCE
*FwhInstance
;
149 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
152 // Convert the base address of all the instances
155 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
156 while (Index
< mFvbModuleGlobal
->NumFv
) {
157 EfiConvertPointer (0x0, (VOID
**) &FwhInstance
->FvBase
[FVB_VIRTUAL
]);
158 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
160 (UINTN
) ((UINT8
*) FwhInstance
) + FwhInstance
->VolumeHeader
.HeaderLength
+
161 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
166 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
]);
167 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
);
173 IN ESAL_FWB_GLOBAL
*Global
,
174 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
180 Retrieves the physical address of a memory mapped FV
183 Instance - The FV instance whose base address is going to be
185 Global - Pointer to ESAL_FWB_GLOBAL that contains all
187 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
188 Virtual - Whether CPU is in virtual or physical mode
191 EFI_SUCCESS - Successfully returns
192 EFI_INVALID_PARAMETER - Instance not found
196 EFI_FW_VOL_INSTANCE
*FwhRecord
;
198 if (Instance
>= Global
->NumFv
) {
199 return EFI_INVALID_PARAMETER
;
202 // Find the right instance of the FVB private data
204 FwhRecord
= Global
->FvInstance
[Virtual
];
205 while (Instance
> 0) {
206 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
208 (UINTN
) ((UINT8
*) FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
209 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
214 *FwhInstance
= FwhRecord
;
220 FvbGetPhysicalAddress (
222 OUT EFI_PHYSICAL_ADDRESS
*Address
,
223 IN ESAL_FWB_GLOBAL
*Global
,
229 Retrieves the physical address of a memory mapped FV
232 Instance - The FV instance whose base address is going to be
234 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
235 that on successful return, contains the base address
236 of the firmware volume.
237 Global - Pointer to ESAL_FWB_GLOBAL that contains all
239 Virtual - Whether CPU is in virtual or physical mode
242 EFI_SUCCESS - Successfully returns
243 EFI_INVALID_PARAMETER - Instance not found
247 EFI_FW_VOL_INSTANCE
*FwhInstance
;
251 // Find the right instance of the FVB private data
253 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
254 ASSERT_EFI_ERROR (Status
);
255 *Address
= FwhInstance
->FvBase
[Virtual
];
261 FvbGetVolumeAttributes (
263 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
264 IN ESAL_FWB_GLOBAL
*Global
,
270 Retrieves attributes, insures positive polarity of attribute bits, returns
271 resulting attributes in output parameter
274 Instance - The FV instance whose attributes is going to be
276 Attributes - Output buffer which contains attributes
277 Global - Pointer to ESAL_FWB_GLOBAL that contains all
279 Virtual - Whether CPU is in virtual or physical mode
282 EFI_SUCCESS - Successfully returns
283 EFI_INVALID_PARAMETER - Instance not found
287 EFI_FW_VOL_INSTANCE
*FwhInstance
;
291 // Find the right instance of the FVB private data
293 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
294 ASSERT_EFI_ERROR (Status
);
295 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
304 OUT UINTN
*LbaAddress
,
305 OUT UINTN
*LbaLength
,
306 OUT UINTN
*NumOfBlocks
,
307 IN ESAL_FWB_GLOBAL
*Global
,
313 Retrieves the starting address of an LBA in an FV
316 Instance - The FV instance which the Lba belongs to
317 Lba - The logical block address
318 LbaAddress - On output, contains the physical starting address
320 LbaLength - On output, contains the length of the block
321 NumOfBlocks - A pointer to a caller allocated UINTN in which the
322 number of consecutive blocks starting with Lba is
323 returned. All blocks in this range have a size of
325 Global - Pointer to ESAL_FWB_GLOBAL that contains all
327 Virtual - Whether CPU is in virtual or physical mode
330 EFI_SUCCESS - Successfully returns
331 EFI_INVALID_PARAMETER - Instance not found
340 EFI_FW_VOL_INSTANCE
*FwhInstance
;
341 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
345 // Find the right instance of the FVB private data
347 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
348 ASSERT_EFI_ERROR (Status
);
352 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
355 // Parse the blockmap of the FV to find which map entry the Lba belongs to
358 NumBlocks
= BlockMap
->NumBlocks
;
359 BlockLength
= BlockMap
->Length
;
361 if (NumBlocks
== 0 || BlockLength
== 0) {
362 return EFI_INVALID_PARAMETER
;
365 NextLba
= StartLba
+ NumBlocks
;
368 // The map entry found
370 if (Lba
>= StartLba
&& Lba
< NextLba
) {
371 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
372 if (LbaAddress
!= NULL
) {
373 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
376 if (LbaLength
!= NULL
) {
377 *LbaLength
= BlockLength
;
380 if (NumOfBlocks
!= NULL
) {
381 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
388 Offset
= Offset
+ NumBlocks
* BlockLength
;
397 IN UINTN BlockOffset
,
398 IN OUT UINTN
*NumBytes
,
400 IN ESAL_FWB_GLOBAL
*Global
,
406 Reads specified number of bytes into a buffer from the specified block
409 Instance - The FV instance to be read from
410 Lba - The logical block address to be read from
411 BlockOffset - Offset into the block at which to begin reading
412 NumBytes - Pointer that on input contains the total size of
413 the buffer. On output, it contains the total number
415 Buffer - Pointer to a caller allocated buffer that will be
416 used to hold the data read
417 Global - Pointer to ESAL_FWB_GLOBAL that contains all
419 Virtual - Whether CPU is in virtual or physical mode
422 EFI_SUCCESS - The firmware volume was read successfully and
423 contents are in Buffer
424 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
425 NumBytes contains the total number of bytes returned
427 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
428 EFI_DEVICE_ERROR - The block device is not functioning correctly and
430 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
434 EFI_FVB_ATTRIBUTES_2 Attributes
;
440 // Check for invalid conditions
442 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
443 return EFI_INVALID_PARAMETER
;
446 if (*NumBytes
== 0) {
447 return EFI_INVALID_PARAMETER
;
450 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
451 if (EFI_ERROR (Status
)) {
455 // Check if the FV is read enabled
457 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
459 if ((Attributes
& EFI_FVB2_READ_STATUS
) == 0) {
460 return EFI_ACCESS_DENIED
;
463 // Perform boundary checks and adjust NumBytes
465 if (BlockOffset
> LbaLength
) {
466 return EFI_INVALID_PARAMETER
;
469 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
470 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
471 Status
= EFI_BAD_BUFFER_SIZE
;
474 CopyMem (Buffer
, (UINT8
*) (LbaAddress
+ BlockOffset
), (UINTN
) (*NumBytes
));
483 IN UINTN BlockOffset
,
484 IN OUT UINTN
*NumBytes
,
486 IN ESAL_FWB_GLOBAL
*Global
,
492 Writes specified number of bytes from the input buffer to the block
495 Instance - The FV instance to be written to
496 Lba - The starting logical block index to write to
497 BlockOffset - Offset into the block at which to begin writing
498 NumBytes - Pointer that on input contains the total size of
499 the buffer. On output, it contains the total number
500 of bytes actually written
501 Buffer - Pointer to a caller allocated buffer that contains
502 the source for the write
503 Global - Pointer to ESAL_FWB_GLOBAL that contains all
505 Virtual - Whether CPU is in virtual or physical mode
508 EFI_SUCCESS - The firmware volume was written successfully
509 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
510 NumBytes contains the total number of bytes
512 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
513 EFI_DEVICE_ERROR - The block device is not functioning correctly and
515 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
519 EFI_FVB_ATTRIBUTES_2 Attributes
;
525 // Check for invalid conditions
527 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
528 return EFI_INVALID_PARAMETER
;
531 if (*NumBytes
== 0) {
532 return EFI_INVALID_PARAMETER
;
535 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
536 if (EFI_ERROR (Status
)) {
540 // Check if the FV is write enabled
542 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
544 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
545 return EFI_ACCESS_DENIED
;
548 // Perform boundary checks and adjust NumBytes
550 if (BlockOffset
> LbaLength
) {
551 return EFI_INVALID_PARAMETER
;
554 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
555 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
556 Status
= EFI_BAD_BUFFER_SIZE
;
561 CopyMem ((UINT8
*) (LbaAddress
+ BlockOffset
), Buffer
, (UINTN
) (*NumBytes
));
570 IN ESAL_FWB_GLOBAL
*Global
,
576 Erases and initializes a firmware volume block
579 Instance - The FV instance to be erased
580 Lba - The logical block index to be erased
581 Global - Pointer to ESAL_FWB_GLOBAL that contains all
583 Virtual - Whether CPU is in virtual or physical mode
586 EFI_SUCCESS - The erase request was successfully completed
587 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
588 EFI_DEVICE_ERROR - The block device is not functioning correctly and
589 could not be written. Firmware device may have been
591 EFI_INVALID_PARAMETER - Instance not found
596 EFI_FVB_ATTRIBUTES_2 Attributes
;
603 // Check if the FV is write enabled
605 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
607 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
608 return EFI_ACCESS_DENIED
;
611 // Get the starting address of the block for erase.
613 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
615 if (EFI_ERROR (Status
)) {
619 if ((Attributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
625 SetMem ((UINT8
*) LbaAddress
, LbaLength
, Data
);
631 FvbSetVolumeAttributes (
633 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
634 IN ESAL_FWB_GLOBAL
*Global
,
640 Modifies the current settings of the firmware volume according to the
641 input parameter, and returns the new setting of the volume
644 Instance - The FV instance whose attributes is going to be
646 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
647 containing the desired firmware volume settings.
648 On successful return, it contains the new settings
649 of the firmware volume
650 Global - Pointer to ESAL_FWB_GLOBAL that contains all
652 Virtual - Whether CPU is in virtual or physical mode
655 EFI_SUCCESS - Successfully returns
656 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
657 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
658 in conflict with the capabilities as declared in the
659 firmware volume header
663 EFI_FW_VOL_INSTANCE
*FwhInstance
;
664 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
665 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
670 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes
;
673 // Find the right instance of the FVB private data
675 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
676 ASSERT_EFI_ERROR (Status
);
678 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
679 OldAttributes
= *AttribPtr
;
680 Capabilities
= OldAttributes
& (EFI_FVB2_READ_DISABLED_CAP
| \
681 EFI_FVB2_READ_ENABLED_CAP
| \
682 EFI_FVB2_WRITE_DISABLED_CAP
| \
683 EFI_FVB2_WRITE_ENABLED_CAP
| \
686 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
687 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
689 UnchangedAttributes
= EFI_FVB2_READ_DISABLED_CAP
| \
690 EFI_FVB2_READ_ENABLED_CAP
| \
691 EFI_FVB2_WRITE_DISABLED_CAP
| \
692 EFI_FVB2_WRITE_ENABLED_CAP
| \
693 EFI_FVB2_LOCK_CAP
| \
694 EFI_FVB2_STICKY_WRITE
| \
695 EFI_FVB2_MEMORY_MAPPED
| \
696 EFI_FVB2_ERASE_POLARITY
| \
697 EFI_FVB2_READ_LOCK_CAP
| \
698 EFI_FVB2_WRITE_LOCK_CAP
| \
702 // Some attributes of FV is read only can *not* be set
704 if ((OldAttributes
& UnchangedAttributes
) ^ (*Attributes
& UnchangedAttributes
)) {
705 return EFI_INVALID_PARAMETER
;
708 // If firmware volume is locked, no status bit can be updated
710 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
711 if (OldStatus
^ NewStatus
) {
712 return EFI_ACCESS_DENIED
;
718 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
719 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
720 return EFI_INVALID_PARAMETER
;
726 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
727 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
728 return EFI_INVALID_PARAMETER
;
732 // Test write disable
734 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
735 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
736 return EFI_INVALID_PARAMETER
;
742 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
743 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
744 return EFI_INVALID_PARAMETER
;
750 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
751 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
752 return EFI_INVALID_PARAMETER
;
756 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
757 *AttribPtr
= (*AttribPtr
) | NewStatus
;
758 *Attributes
= *AttribPtr
;
767 FvbProtocolGetPhysicalAddress (
768 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
769 OUT EFI_PHYSICAL_ADDRESS
*Address
775 Retrieves the physical address of the device.
779 This - Calling context
780 Address - Output buffer containing the address.
785 EFI_SUCCESS - Successfully returns
789 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
791 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
793 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
798 FvbProtocolGetBlockSize (
799 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
800 IN CONST EFI_LBA Lba
,
801 OUT UINTN
*BlockSize
,
802 OUT UINTN
*NumOfBlocks
807 Retrieve the size of a logical block
810 This - Calling context
811 Lba - Indicates which block to return the size for.
812 BlockSize - A pointer to a caller allocated UINTN in which
813 the size of the block is returned
814 NumOfBlocks - a pointer to a caller allocated UINTN in which the
815 number of consecutive blocks starting with Lba is
816 returned. All blocks in this range have a size of
820 EFI_SUCCESS - The firmware volume was read successfully and
821 contents are in Buffer
825 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
827 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
829 return FvbGetLbaAddress (
842 FvbProtocolGetAttributes (
843 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
844 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
849 Retrieves Volume attributes. No polarity translations are done.
852 This - Calling context
853 Attributes - output buffer which contains attributes
856 EFI_SUCCESS - Successfully returns
860 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
862 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
864 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
869 FvbProtocolSetAttributes (
870 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
871 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
876 Sets Volume attributes. No polarity translations are done.
879 This - Calling context
880 Attributes - output buffer which contains attributes
883 EFI_SUCCESS - Successfully returns
887 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
889 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
891 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
896 FvbProtocolEraseBlocks (
897 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
904 The EraseBlock() function erases one or more blocks as denoted by the
905 variable argument list. The entire parameter list of blocks must be verified
906 prior to erasing any blocks. If a block is requested that does not exist
907 within the associated firmware volume (it has a larger index than the last
908 block of the firmware volume), the EraseBlock() function must return
909 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
912 This - Calling context
913 ... - Starting LBA followed by Number of Lba to erase.
914 a -1 to terminate the list.
917 EFI_SUCCESS - The erase request was successfully completed
918 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
919 EFI_DEVICE_ERROR - The block device is not functioning correctly and
920 could not be written. Firmware device may have been
925 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
926 EFI_FW_VOL_INSTANCE
*FwhInstance
;
933 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
935 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
936 ASSERT_EFI_ERROR (Status
);
938 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
940 VA_START (args
, This
);
943 StartingLba
= VA_ARG (args
, EFI_LBA
);
944 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
948 NumOfLba
= VA_ARG (args
, UINT32
);
951 // Check input parameters
955 return EFI_INVALID_PARAMETER
;
958 if ((StartingLba
+ NumOfLba
) > NumOfBlocks
) {
959 return EFI_INVALID_PARAMETER
;
965 VA_START (args
, This
);
967 StartingLba
= VA_ARG (args
, EFI_LBA
);
968 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
972 NumOfLba
= VA_ARG (args
, UINT32
);
974 while (NumOfLba
> 0) {
975 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
976 if (EFI_ERROR (Status
)) {
995 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
998 IN OUT UINTN
*NumBytes
,
1003 Routine Description:
1005 Writes data beginning at Lba:Offset from FV. The write terminates either
1006 when *NumBytes of data have been written, or when a block boundary is
1007 reached. *NumBytes is updated to reflect the actual number of bytes
1008 written. The write opertion does not include erase. This routine will
1009 attempt to write only the specified bytes. If the writes do not stick,
1010 it will return an error.
1013 This - Calling context
1014 Lba - Block in which to begin write
1015 Offset - Offset in the block at which to begin write
1016 NumBytes - On input, indicates the requested write size. On
1017 output, indicates the actual number of bytes written
1018 Buffer - Buffer containing source data for the write.
1021 EFI_SUCCESS - The firmware volume was written successfully
1022 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
1023 NumBytes contains the total number of bytes
1025 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1026 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1027 could not be written
1028 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1033 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1035 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1037 return FvbWriteBlock (FvbDevice
->Instance
, (EFI_LBA
)Lba
, (UINTN
)Offset
, NumBytes
, (UINT8
*)Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1043 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1044 IN CONST EFI_LBA Lba
,
1045 IN CONST UINTN Offset
,
1046 IN OUT UINTN
*NumBytes
,
1051 Routine Description:
1053 Reads data beginning at Lba:Offset from FV. The Read terminates either
1054 when *NumBytes of data have been read, or when a block boundary is
1055 reached. *NumBytes is updated to reflect the actual number of bytes
1056 written. The write opertion does not include erase. This routine will
1057 attempt to write only the specified bytes. If the writes do not stick,
1058 it will return an error.
1061 This - Calling context
1062 Lba - Block in which to begin Read
1063 Offset - Offset in the block at which to begin Read
1064 NumBytes - On input, indicates the requested write size. On
1065 output, indicates the actual number of bytes Read
1066 Buffer - Buffer containing source data for the Read.
1069 EFI_SUCCESS - The firmware volume was read successfully and
1070 contents are in Buffer
1071 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1072 NumBytes contains the total number of bytes returned
1074 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1075 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1077 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1082 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1084 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1086 return FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1091 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1095 Routine Description:
1096 Check the integrity of firmware volume header
1099 FwVolHeader - A pointer to a firmware volume header
1102 EFI_SUCCESS - The firmware volume is consistent
1103 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1108 UINT16 HeaderLength
;
1112 // Verify the header revision, header signature, length
1113 // Length of FvBlock cannot be 2**64-1
1114 // HeaderLength cannot be an odd number
1116 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1117 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1118 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
1119 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1121 return EFI_NOT_FOUND
;
1125 // Verify the header checksum
1127 HeaderLength
= (UINT16
) (FwVolHeader
->HeaderLength
/ 2);
1128 Ptr
= (UINT16
*) FwVolHeader
;
1130 while (HeaderLength
> 0) {
1131 Checksum
= (UINT16
)(Checksum
+ (*Ptr
));
1136 if (Checksum
!= 0) {
1137 return EFI_NOT_FOUND
;
1141 // PI specification defines the name guid of FV exists in extension header.
1143 if (FwVolHeader
->ExtHeaderOffset
== 0) {
1144 return EFI_NOT_FOUND
;
1153 IN EFI_HANDLE ImageHandle
,
1154 IN EFI_SYSTEM_TABLE
*SystemTable
1158 Routine Description:
1159 This function does common initialization for FVB services
1168 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1169 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1170 EFI_DXE_SERVICES
*DxeServices
;
1171 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
1173 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1174 EFI_HANDLE FwbHandle
;
1175 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1176 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1178 EFI_PHYSICAL_ADDRESS BaseAddress
;
1181 EFI_PEI_HOB_POINTERS FvHob
;
1184 // Get the DXE services table
1189 // Allocate runtime services data for global variable, which contains
1190 // the private data of all firmware volume block instances
1192 mFvbModuleGlobal
= AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL
));
1193 ASSERT (mFvbModuleGlobal
!= NULL
);
1196 // Calculate the total size for all firmware volume block instances
1200 FvHob
.Raw
= GetHobList ();
1201 while ((FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
)) != NULL
) {
1202 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1203 Length
= FvHob
.FirmwareVolume
->Length
;
1205 // Check if it is a "real" flash
1207 Status
= DxeServices
->GetMemorySpaceDescriptor (
1211 if (EFI_ERROR (Status
)) {
1215 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1216 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1220 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1221 Status
= ValidateFvHeader (FwVolHeader
);
1222 if (EFI_ERROR (Status
)) {
1226 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1227 if (EFI_ERROR (Status
)) {
1228 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1233 BufferSize
+= (sizeof (EFI_FW_VOL_INSTANCE
) + FwVolHeader
->HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1234 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1238 // Only need to allocate once. There is only one copy of physical memory for
1239 // the private data of each FV instance. But in virtual mode or in physical
1240 // mode, the address of the the physical memory may be different.
1242 mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] = AllocateRuntimePool (BufferSize
);
1243 ASSERT (mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] != NULL
);
1246 // Make a virtual copy of the FvInstance pointer.
1248 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1249 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1251 mFvbModuleGlobal
->NumFv
= 0;
1254 FvHob
.Raw
= GetHobList ();
1255 while (NULL
!= (FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
))) {
1256 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1257 Length
= FvHob
.FirmwareVolume
->Length
;
1259 // Check if it is a "real" flash
1261 Status
= DxeServices
->GetMemorySpaceDescriptor (
1265 if (EFI_ERROR (Status
)) {
1269 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1270 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1274 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1275 Status
= ValidateFvHeader (FwVolHeader
);
1276 if (EFI_ERROR (Status
)) {
1278 // Get FvbInfo to provide in FwhInstance.
1280 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1281 if (EFI_ERROR (Status
)) {
1282 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1286 // Write healthy FV header back.
1289 (VOID
*) (UINTN
) BaseAddress
,
1290 (VOID
*) FwVolHeader
,
1291 FwVolHeader
->HeaderLength
1295 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1296 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1298 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1299 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1300 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1304 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1306 // Get the maximum size of a block.
1308 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
1309 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1312 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1315 // The total number of blocks in the FV.
1317 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1320 // Add a FVB Protocol Instance
1322 FvbDevice
= AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1323 ASSERT (FvbDevice
!= NULL
);
1325 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1327 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1328 mFvbModuleGlobal
->NumFv
++;
1332 // Set up the devicepath
1334 if (FwVolHeader
->ExtHeaderOffset
== 0) {
1336 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
1338 FvbDevice
->DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH
), &mFvMemmapDevicePathTemplate
);
1339 ((FV_MEMMAP_DEVICE_PATH
*) FvbDevice
->DevicePath
)->MemMapDevPath
.StartingAddress
= BaseAddress
;
1340 ((FV_MEMMAP_DEVICE_PATH
*) FvbDevice
->DevicePath
)->MemMapDevPath
.EndingAddress
= BaseAddress
+ FwVolHeader
->FvLength
- 1;
1342 FvbDevice
->DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH
), &mFvPIWGDevicePathTemplate
);
1344 &((FV_PIWG_DEVICE_PATH
*)FvbDevice
->DevicePath
)->FvDevPath
.FvName
,
1345 (GUID
*)(UINTN
)(BaseAddress
+ FwVolHeader
->ExtHeaderOffset
)
1349 // Find a handle with a matching device path that has supports FW Block protocol
1351 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &FvbDevice
->DevicePath
, &FwbHandle
);
1352 if (EFI_ERROR (Status
)) {
1354 // LocateDevicePath fails so install a new interface and device path
1357 Status
= gBS
->InstallMultipleProtocolInterfaces (
1359 &gEfiFirmwareVolumeBlockProtocolGuid
,
1360 &FvbDevice
->FwVolBlockInstance
,
1361 &gEfiDevicePathProtocolGuid
,
1362 &FvbDevice
->DevicePath
,
1365 ASSERT_EFI_ERROR (Status
);
1366 } else if (IsDevicePathEnd (FvbDevice
->DevicePath
)) {
1368 // Device allready exists, so reinstall the FVB protocol
1370 Status
= gBS
->HandleProtocol (
1372 &gEfiFirmwareVolumeBlockProtocolGuid
,
1373 (VOID
**)&OldFwbInterface
1375 ASSERT_EFI_ERROR (Status
);
1377 Status
= gBS
->ReinstallProtocolInterface (
1379 &gEfiFirmwareVolumeBlockProtocolGuid
,
1381 &FvbDevice
->FwVolBlockInstance
1383 ASSERT_EFI_ERROR (Status
);
1387 // There was a FVB protocol on an End Device Path node
1392 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1394 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1395 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1398 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);