3 Copyright (c) 2006 - 2008, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
23 #include <Guid/EventGroup.h>
24 #include <Protocol/FvbExtension.h>
25 #include <Protocol/FirmwareVolumeBlock.h>
26 #include <Guid/AlternateFvBlock.h>
27 #include <Protocol/DevicePath.h>
29 #include <Library/UefiLib.h>
30 #include <Library/UefiDriverEntryPoint.h>
31 #include <Library/BaseLib.h>
32 #include <Library/DxeServicesTableLib.h>
33 #include <Library/UefiRuntimeLib.h>
34 #include <Library/DebugLib.h>
35 #include <Library/HobLib.h>
36 #include <Library/BaseMemoryLib.h>
37 #include <Library/MemoryAllocationLib.h>
38 #include <Library/UefiBootServicesTableLib.h>
39 #include <Library/DevicePathLib.h>
41 #include "FwBlockService.h"
43 ESAL_FWB_GLOBAL
*mFvbModuleGlobal
;
45 #define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
47 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
55 sizeof (MEMMAP_DEVICE_PATH
),
65 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
67 sizeof (EFI_DEVICE_PATH_PROTOCOL
),
74 FvbProtocolGetAttributes
,
75 FvbProtocolSetAttributes
,
76 FvbProtocolGetPhysicalAddress
,
77 FvbProtocolGetBlockSize
,
80 FvbProtocolEraseBlocks
,
84 FvbExtendProtocolEraseCustomBlockRange
92 FvbVirtualddressChangeEvent (
100 Fixup internal data so that EFI and SAL can be call in virtual mode.
101 Call the passed in Child Notify event and convert the mFvbModuleGlobal
102 date items to there virtual address.
104 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
105 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
110 (Standard EFI notify event - EFI_EVENT_NOTIFY)
118 EFI_FW_VOL_INSTANCE
*FwhInstance
;
121 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
124 // Convert the base address of all the instances
127 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
128 while (Index
< mFvbModuleGlobal
->NumFv
) {
129 EfiConvertPointer (0x0, (VOID
**) &FwhInstance
->FvBase
[FVB_VIRTUAL
]);
130 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
132 (UINTN
) ((UINT8
*) FwhInstance
) + FwhInstance
->VolumeHeader
.HeaderLength
+
133 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
138 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
]);
139 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
);
145 IN ESAL_FWB_GLOBAL
*Global
,
146 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
152 Retrieves the physical address of a memory mapped FV
155 Instance - The FV instance whose base address is going to be
157 Global - Pointer to ESAL_FWB_GLOBAL that contains all
159 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
160 Virtual - Whether CPU is in virtual or physical mode
163 EFI_SUCCESS - Successfully returns
164 EFI_INVALID_PARAMETER - Instance not found
168 EFI_FW_VOL_INSTANCE
*FwhRecord
;
170 if (Instance
>= Global
->NumFv
) {
171 return EFI_INVALID_PARAMETER
;
174 // Find the right instance of the FVB private data
176 FwhRecord
= Global
->FvInstance
[Virtual
];
177 while (Instance
> 0) {
178 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
180 (UINTN
) ((UINT8
*) FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
181 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
186 *FwhInstance
= FwhRecord
;
192 FvbGetPhysicalAddress (
194 OUT EFI_PHYSICAL_ADDRESS
*Address
,
195 IN ESAL_FWB_GLOBAL
*Global
,
201 Retrieves the physical address of a memory mapped FV
204 Instance - The FV instance whose base address is going to be
206 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
207 that on successful return, contains the base address
208 of the firmware volume.
209 Global - Pointer to ESAL_FWB_GLOBAL that contains all
211 Virtual - Whether CPU is in virtual or physical mode
214 EFI_SUCCESS - Successfully returns
215 EFI_INVALID_PARAMETER - Instance not found
219 EFI_FW_VOL_INSTANCE
*FwhInstance
;
223 // Find the right instance of the FVB private data
225 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
226 ASSERT_EFI_ERROR (Status
);
227 *Address
= FwhInstance
->FvBase
[Virtual
];
233 FvbGetVolumeAttributes (
235 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
236 IN ESAL_FWB_GLOBAL
*Global
,
242 Retrieves attributes, insures positive polarity of attribute bits, returns
243 resulting attributes in output parameter
246 Instance - The FV instance whose attributes is going to be
248 Attributes - Output buffer which contains attributes
249 Global - Pointer to ESAL_FWB_GLOBAL that contains all
251 Virtual - Whether CPU is in virtual or physical mode
254 EFI_SUCCESS - Successfully returns
255 EFI_INVALID_PARAMETER - Instance not found
259 EFI_FW_VOL_INSTANCE
*FwhInstance
;
263 // Find the right instance of the FVB private data
265 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
266 ASSERT_EFI_ERROR (Status
);
267 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
276 OUT UINTN
*LbaAddress
,
277 OUT UINTN
*LbaLength
,
278 OUT UINTN
*NumOfBlocks
,
279 IN ESAL_FWB_GLOBAL
*Global
,
285 Retrieves the starting address of an LBA in an FV
288 Instance - The FV instance which the Lba belongs to
289 Lba - The logical block address
290 LbaAddress - On output, contains the physical starting address
292 LbaLength - On output, contains the length of the block
293 NumOfBlocks - A pointer to a caller allocated UINTN in which the
294 number of consecutive blocks starting with Lba is
295 returned. All blocks in this range have a size of
297 Global - Pointer to ESAL_FWB_GLOBAL that contains all
299 Virtual - Whether CPU is in virtual or physical mode
302 EFI_SUCCESS - Successfully returns
303 EFI_INVALID_PARAMETER - Instance not found
312 EFI_FW_VOL_INSTANCE
*FwhInstance
;
313 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
317 // Find the right instance of the FVB private data
319 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
320 ASSERT_EFI_ERROR (Status
);
324 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
327 // Parse the blockmap of the FV to find which map entry the Lba belongs to
330 NumBlocks
= BlockMap
->NumBlocks
;
331 BlockLength
= BlockMap
->Length
;
333 if (NumBlocks
== 0 || BlockLength
== 0) {
334 return EFI_INVALID_PARAMETER
;
337 NextLba
= StartLba
+ NumBlocks
;
340 // The map entry found
342 if (Lba
>= StartLba
&& Lba
< NextLba
) {
343 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
344 if (LbaAddress
!= NULL
) {
345 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
348 if (LbaLength
!= NULL
) {
349 *LbaLength
= BlockLength
;
352 if (NumOfBlocks
!= NULL
) {
353 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
360 Offset
= Offset
+ NumBlocks
* BlockLength
;
369 IN UINTN BlockOffset
,
370 IN OUT UINTN
*NumBytes
,
372 IN ESAL_FWB_GLOBAL
*Global
,
378 Reads specified number of bytes into a buffer from the specified block
381 Instance - The FV instance to be read from
382 Lba - The logical block address to be read from
383 BlockOffset - Offset into the block at which to begin reading
384 NumBytes - Pointer that on input contains the total size of
385 the buffer. On output, it contains the total number
387 Buffer - Pointer to a caller allocated buffer that will be
388 used to hold the data read
389 Global - Pointer to ESAL_FWB_GLOBAL that contains all
391 Virtual - Whether CPU is in virtual or physical mode
394 EFI_SUCCESS - The firmware volume was read successfully and
395 contents are in Buffer
396 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
397 NumBytes contains the total number of bytes returned
399 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
400 EFI_DEVICE_ERROR - The block device is not functioning correctly and
402 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
406 EFI_FVB_ATTRIBUTES_2 Attributes
;
412 // Check for invalid conditions
414 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
415 return EFI_INVALID_PARAMETER
;
418 if (*NumBytes
== 0) {
419 return EFI_INVALID_PARAMETER
;
422 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
423 if (EFI_ERROR (Status
)) {
427 // Check if the FV is read enabled
429 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
431 if ((Attributes
& EFI_FVB2_READ_STATUS
) == 0) {
432 return EFI_ACCESS_DENIED
;
435 // Perform boundary checks and adjust NumBytes
437 if (BlockOffset
> LbaLength
) {
438 return EFI_INVALID_PARAMETER
;
441 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
442 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
443 Status
= EFI_BAD_BUFFER_SIZE
;
446 CopyMem (Buffer
, (UINT8
*) (LbaAddress
+ BlockOffset
), (UINTN
) (*NumBytes
));
455 IN UINTN BlockOffset
,
456 IN OUT UINTN
*NumBytes
,
458 IN ESAL_FWB_GLOBAL
*Global
,
464 Writes specified number of bytes from the input buffer to the block
467 Instance - The FV instance to be written to
468 Lba - The starting logical block index to write to
469 BlockOffset - Offset into the block at which to begin writing
470 NumBytes - Pointer that on input contains the total size of
471 the buffer. On output, it contains the total number
472 of bytes actually written
473 Buffer - Pointer to a caller allocated buffer that contains
474 the source for the write
475 Global - Pointer to ESAL_FWB_GLOBAL that contains all
477 Virtual - Whether CPU is in virtual or physical mode
480 EFI_SUCCESS - The firmware volume was written successfully
481 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
482 NumBytes contains the total number of bytes
484 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
485 EFI_DEVICE_ERROR - The block device is not functioning correctly and
487 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
491 EFI_FVB_ATTRIBUTES_2 Attributes
;
497 // Check for invalid conditions
499 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
500 return EFI_INVALID_PARAMETER
;
503 if (*NumBytes
== 0) {
504 return EFI_INVALID_PARAMETER
;
507 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
508 if (EFI_ERROR (Status
)) {
512 // Check if the FV is write enabled
514 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
516 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
517 return EFI_ACCESS_DENIED
;
520 // Perform boundary checks and adjust NumBytes
522 if (BlockOffset
> LbaLength
) {
523 return EFI_INVALID_PARAMETER
;
526 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
527 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
528 Status
= EFI_BAD_BUFFER_SIZE
;
533 CopyMem ((UINT8
*) (LbaAddress
+ BlockOffset
), Buffer
, (UINTN
) (*NumBytes
));
542 IN ESAL_FWB_GLOBAL
*Global
,
548 Erases and initializes a firmware volume block
551 Instance - The FV instance to be erased
552 Lba - The logical block index to be erased
553 Global - Pointer to ESAL_FWB_GLOBAL that contains all
555 Virtual - Whether CPU is in virtual or physical mode
558 EFI_SUCCESS - The erase request was successfully completed
559 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
560 EFI_DEVICE_ERROR - The block device is not functioning correctly and
561 could not be written. Firmware device may have been
563 EFI_INVALID_PARAMETER - Instance not found
568 EFI_FVB_ATTRIBUTES_2 Attributes
;
575 // Check if the FV is write enabled
577 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
579 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
580 return EFI_ACCESS_DENIED
;
583 // Get the starting address of the block for erase.
585 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
587 if (EFI_ERROR (Status
)) {
591 if ((Attributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
597 SetMem ((UINT8
*) LbaAddress
, LbaLength
, Data
);
603 FvbEraseCustomBlockRange (
606 IN UINTN OffsetStartLba
,
608 IN UINTN OffsetLastLba
,
609 IN ESAL_FWB_GLOBAL
*Global
,
615 Erases and initializes a specified range of a firmware volume
618 Instance - The FV instance to be erased
619 StartLba - The starting logical block index to be erased
620 OffsetStartLba - Offset into the starting block at which to
622 LastLba - The last logical block index to be erased
623 OffsetStartLba - Offset into the last block at which to end erasing
624 Global - Pointer to ESAL_FWB_GLOBAL that contains all
626 Virtual - Whether CPU is in virtual or physical mode
629 EFI_SUCCESS - The firmware volume was erased successfully
630 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
631 EFI_DEVICE_ERROR - The block device is not functioning correctly and
632 could not be written. Firmware device may have been
634 EFI_INVALID_PARAMETER - Instance not found
640 UINTN ScratchLbaSizeData
;
646 Status
= FvbGetLbaAddress (Instance
, StartLba
, NULL
, &LbaSize
, NULL
, Global
, Virtual
);
647 if (EFI_ERROR (Status
)) {
652 // Use the scratch space as the intermediate buffer to transfer data
653 // Back up the first LBA in scratch space.
655 FvbReadBlock (Instance
, StartLba
, 0, &LbaSize
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
660 FvbEraseBlock (Instance
, StartLba
, Global
, Virtual
);
661 ScratchLbaSizeData
= OffsetStartLba
;
664 // write the data back to the first block
666 if (ScratchLbaSizeData
> 0) {
667 Status
= FvbWriteBlock (Instance
, StartLba
, 0, &ScratchLbaSizeData
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
668 if (EFI_ERROR (Status
)) {
675 if (LastLba
> (StartLba
+ 1)) {
676 for (Index
= (StartLba
+ 1); Index
<= (LastLba
- 1); Index
++) {
677 FvbEraseBlock (Instance
, Index
, Global
, Virtual
);
681 // Last LBAs, the same as first LBAs
683 if (LastLba
> StartLba
) {
684 Status
= FvbGetLbaAddress (Instance
, LastLba
, NULL
, &LbaSize
, NULL
, Global
, Virtual
);
685 if (EFI_ERROR (Status
)) {
688 FvbReadBlock (Instance
, LastLba
, 0, &LbaSize
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
689 FvbEraseBlock (Instance
, LastLba
, Global
, Virtual
);
692 ScratchLbaSizeData
= LbaSize
- (OffsetLastLba
+ 1);
694 if (ScratchLbaSizeData
> 0) {
695 Status
= FvbWriteBlock (
700 Global
->FvbScratchSpace
[Virtual
] + OffsetLastLba
+ 1,
710 FvbSetVolumeAttributes (
712 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
713 IN ESAL_FWB_GLOBAL
*Global
,
719 Modifies the current settings of the firmware volume according to the
720 input parameter, and returns the new setting of the volume
723 Instance - The FV instance whose attributes is going to be
725 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
726 containing the desired firmware volume settings.
727 On successful return, it contains the new settings
728 of the firmware volume
729 Global - Pointer to ESAL_FWB_GLOBAL that contains all
731 Virtual - Whether CPU is in virtual or physical mode
734 EFI_SUCCESS - Successfully returns
735 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
736 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
737 in conflict with the capabilities as declared in the
738 firmware volume header
742 EFI_FW_VOL_INSTANCE
*FwhInstance
;
743 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
744 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
749 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes
;
753 // Find the right instance of the FVB private data
755 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
756 ASSERT_EFI_ERROR (Status
);
758 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
759 OldAttributes
= *AttribPtr
;
760 Capabilities
= OldAttributes
& (EFI_FVB2_READ_DISABLED_CAP
| \
761 EFI_FVB2_READ_ENABLED_CAP
| \
762 EFI_FVB2_WRITE_DISABLED_CAP
| \
763 EFI_FVB2_WRITE_ENABLED_CAP
| \
767 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
768 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
769 UnchangedAttributes
= EFI_FVB2_READ_DISABLED_CAP
| \
770 EFI_FVB2_READ_ENABLED_CAP
| \
771 EFI_FVB2_WRITE_DISABLED_CAP
| \
772 EFI_FVB2_WRITE_ENABLED_CAP
| \
773 EFI_FVB2_LOCK_CAP
| \
774 EFI_FVB2_STICKY_WRITE
| \
775 EFI_FVB2_MEMORY_MAPPED
| \
776 EFI_FVB2_ERASE_POLARITY
| \
777 EFI_FVB2_READ_LOCK_CAP
| \
778 EFI_FVB2_WRITE_LOCK_CAP
| \
782 // Some attributes of FV is read only can *not* be set
784 if ((OldAttributes
& UnchangedAttributes
) ^ (*Attributes
& UnchangedAttributes
)) {
785 return EFI_INVALID_PARAMETER
;
789 // If firmware volume is locked, no status bit can be updated
791 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
792 if (OldStatus
^ NewStatus
) {
793 return EFI_ACCESS_DENIED
;
799 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
800 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
801 return EFI_INVALID_PARAMETER
;
807 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
808 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
809 return EFI_INVALID_PARAMETER
;
813 // Test write disable
815 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
816 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
817 return EFI_INVALID_PARAMETER
;
823 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
824 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
825 return EFI_INVALID_PARAMETER
;
831 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
832 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
833 return EFI_INVALID_PARAMETER
;
837 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
838 *AttribPtr
= (*AttribPtr
) | NewStatus
;
839 *Attributes
= *AttribPtr
;
848 FvbProtocolGetPhysicalAddress (
849 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
850 OUT EFI_PHYSICAL_ADDRESS
*Address
856 Retrieves the physical address of the device.
860 This - Calling context
861 Address - Output buffer containing the address.
866 EFI_SUCCESS - Successfully returns
870 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
872 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
874 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
879 FvbProtocolGetBlockSize (
880 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
882 OUT UINTN
*BlockSize
,
883 OUT UINTN
*NumOfBlocks
888 Retrieve the size of a logical block
891 This - Calling context
892 Lba - Indicates which block to return the size for.
893 BlockSize - A pointer to a caller allocated UINTN in which
894 the size of the block is returned
895 NumOfBlocks - a pointer to a caller allocated UINTN in which the
896 number of consecutive blocks starting with Lba is
897 returned. All blocks in this range have a size of
901 EFI_SUCCESS - The firmware volume was read successfully and
902 contents are in Buffer
906 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
908 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
910 return FvbGetLbaAddress (
923 FvbProtocolGetAttributes (
924 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
925 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
930 Retrieves Volume attributes. No polarity translations are done.
933 This - Calling context
934 Attributes - output buffer which contains attributes
937 EFI_SUCCESS - Successfully returns
941 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
943 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
945 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
950 FvbProtocolSetAttributes (
951 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
952 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
957 Sets Volume attributes. No polarity translations are done.
960 This - Calling context
961 Attributes - output buffer which contains attributes
964 EFI_SUCCESS - Successfully returns
968 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
970 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
972 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
977 FvbProtocolEraseBlocks (
978 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
985 The EraseBlock() function erases one or more blocks as denoted by the
986 variable argument list. The entire parameter list of blocks must be verified
987 prior to erasing any blocks. If a block is requested that does not exist
988 within the associated firmware volume (it has a larger index than the last
989 block of the firmware volume), the EraseBlock() function must return
990 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
993 This - Calling context
994 ... - Starting LBA followed by Number of Lba to erase.
995 a -1 to terminate the list.
998 EFI_SUCCESS - The erase request was successfully completed
999 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1000 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1001 could not be written. Firmware device may have been
1006 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1007 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1010 EFI_LBA StartingLba
;
1014 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1016 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
1017 ASSERT_EFI_ERROR (Status
);
1019 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
1021 VA_START (args
, This
);
1024 StartingLba
= VA_ARG (args
, EFI_LBA
);
1025 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
1029 NumOfLba
= VA_ARG (args
, UINT32
);
1032 // Check input parameters
1034 if (NumOfLba
== 0) {
1036 return EFI_INVALID_PARAMETER
;
1039 if ((StartingLba
+ NumOfLba
) > NumOfBlocks
) {
1040 return EFI_INVALID_PARAMETER
;
1046 VA_START (args
, This
);
1048 StartingLba
= VA_ARG (args
, EFI_LBA
);
1049 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
1053 NumOfLba
= VA_ARG (args
, UINT32
);
1055 while (NumOfLba
> 0) {
1056 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
1057 if (EFI_ERROR (Status
)) {
1076 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1079 IN OUT UINTN
*NumBytes
,
1084 Routine Description:
1086 Writes data beginning at Lba:Offset from FV. The write terminates either
1087 when *NumBytes of data have been written, or when a block boundary is
1088 reached. *NumBytes is updated to reflect the actual number of bytes
1089 written. The write opertion does not include erase. This routine will
1090 attempt to write only the specified bytes. If the writes do not stick,
1091 it will return an error.
1094 This - Calling context
1095 Lba - Block in which to begin write
1096 Offset - Offset in the block at which to begin write
1097 NumBytes - On input, indicates the requested write size. On
1098 output, indicates the actual number of bytes written
1099 Buffer - Buffer containing source data for the write.
1102 EFI_SUCCESS - The firmware volume was written successfully
1103 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
1104 NumBytes contains the total number of bytes
1106 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1107 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1108 could not be written
1109 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1114 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1116 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1118 return FvbWriteBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1124 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1127 IN OUT UINTN
*NumBytes
,
1132 Routine Description:
1134 Reads data beginning at Lba:Offset from FV. The Read terminates either
1135 when *NumBytes of data have been read, or when a block boundary is
1136 reached. *NumBytes is updated to reflect the actual number of bytes
1137 written. The write opertion does not include erase. This routine will
1138 attempt to write only the specified bytes. If the writes do not stick,
1139 it will return an error.
1142 This - Calling context
1143 Lba - Block in which to begin Read
1144 Offset - Offset in the block at which to begin Read
1145 NumBytes - On input, indicates the requested write size. On
1146 output, indicates the actual number of bytes Read
1147 Buffer - Buffer containing source data for the Read.
1150 EFI_SUCCESS - The firmware volume was read successfully and
1151 contents are in Buffer
1152 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1153 NumBytes contains the total number of bytes returned
1155 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1156 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1158 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1163 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1165 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1167 return FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1170 // FVB Extension Protocols
1174 FvbExtendProtocolEraseCustomBlockRange (
1175 IN EFI_FVB_EXTENSION_PROTOCOL
*This
,
1176 IN EFI_LBA StartLba
,
1177 IN UINTN OffsetStartLba
,
1179 IN UINTN OffsetLastLba
1183 Routine Description:
1184 Erases and initializes a specified range of a firmware volume
1187 This - Calling context
1188 StartLba - The starting logical block index to be erased
1189 OffsetStartLba - Offset into the starting block at which to
1191 LastLba - The last logical block index to be erased
1192 OffsetStartLba - Offset into the last block at which to end erasing
1195 EFI_SUCCESS - The firmware volume was erased successfully
1196 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1197 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1198 could not be written. Firmware device may have been
1203 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1205 FvbDevice
= FVB_EXTEND_DEVICE_FROM_THIS (This
);
1207 return FvbEraseCustomBlockRange (
1208 FvbDevice
->Instance
,
1220 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1224 Routine Description:
1225 Check the integrity of firmware volume header
1228 FwVolHeader - A pointer to a firmware volume header
1231 EFI_SUCCESS - The firmware volume is consistent
1232 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1237 UINT16 HeaderLength
;
1241 // Verify the header revision, header signature, length
1242 // Length of FvBlock cannot be 2**64-1
1243 // HeaderLength cannot be an odd number
1245 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1246 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1247 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
1248 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1250 return EFI_NOT_FOUND
;
1253 // Verify the header checksum
1255 HeaderLength
= (UINT16
) (FwVolHeader
->HeaderLength
/ 2);
1256 Ptr
= (UINT16
*) FwVolHeader
;
1258 while (HeaderLength
> 0) {
1259 Checksum
= Checksum
+ (*Ptr
);
1264 if (Checksum
!= 0) {
1265 return EFI_NOT_FOUND
;
1274 IN EFI_HANDLE ImageHandle
,
1275 IN EFI_SYSTEM_TABLE
*SystemTable
1279 Routine Description:
1280 This function does common initialization for FVB services
1289 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1290 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1291 EFI_DXE_SERVICES
*DxeServices
;
1292 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
1294 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1295 EFI_HANDLE FwbHandle
;
1296 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1297 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1298 EFI_DEVICE_PATH_PROTOCOL
*TempFwbDevicePath
;
1299 FV_DEVICE_PATH TempFvbDevicePathData
;
1301 EFI_PHYSICAL_ADDRESS BaseAddress
;
1304 EFI_PEI_HOB_POINTERS FvHob
;
1307 // Get the DXE services table
1312 // Allocate runtime services data for global variable, which contains
1313 // the private data of all firmware volume block instances
1315 Status
= gBS
->AllocatePool (
1316 EfiRuntimeServicesData
,
1317 sizeof (ESAL_FWB_GLOBAL
),
1318 (VOID
**) &mFvbModuleGlobal
1320 ASSERT_EFI_ERROR (Status
);
1323 // Calculate the total size for all firmware volume block instances
1327 FvHob
.Raw
= GetHobList ();
1328 while ((FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
)) != NULL
) {
1329 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1330 Length
= FvHob
.FirmwareVolume
->Length
;
1332 // Check if it is a "real" flash
1334 Status
= DxeServices
->GetMemorySpaceDescriptor (
1338 if (EFI_ERROR (Status
)) {
1342 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1343 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1347 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1348 Status
= ValidateFvHeader (FwVolHeader
);
1349 if (EFI_ERROR (Status
)) {
1353 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1354 if (EFI_ERROR (Status
)) {
1355 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1360 BufferSize
+= (sizeof (EFI_FW_VOL_INSTANCE
) + FwVolHeader
->HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1361 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1365 // Only need to allocate once. There is only one copy of physical memory for
1366 // the private data of each FV instance. But in virtual mode or in physical
1367 // mode, the address of the the physical memory may be different.
1369 Status
= gBS
->AllocatePool (
1370 EfiRuntimeServicesData
,
1372 (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
]
1374 ASSERT_EFI_ERROR (Status
);
1377 // Make a virtual copy of the FvInstance pointer.
1379 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1380 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1382 mFvbModuleGlobal
->NumFv
= 0;
1385 FvHob
.Raw
= GetHobList ();
1386 while (NULL
!= (FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
))) {
1387 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1388 Length
= FvHob
.FirmwareVolume
->Length
;
1390 // Check if it is a "real" flash
1392 Status
= DxeServices
->GetMemorySpaceDescriptor (
1396 if (EFI_ERROR (Status
)) {
1400 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1401 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1405 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1406 Status
= ValidateFvHeader (FwVolHeader
);
1407 if (EFI_ERROR (Status
)) {
1409 // Get FvbInfo to provide in FwhInstance.
1411 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1412 if (EFI_ERROR (Status
)) {
1413 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1417 // Write healthy FV header back.
1420 (VOID
*) (UINTN
) BaseAddress
,
1421 (VOID
*) FwVolHeader
,
1422 FwVolHeader
->HeaderLength
1426 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1427 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1429 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1430 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1431 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1435 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1437 // Get the maximum size of a block. The size will be used to allocate
1438 // buffer for Scratch space, the intermediate buffer for FVB extension
1441 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
1442 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1445 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1448 // The total number of blocks in the FV.
1450 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1453 // Add a FVB Protocol Instance
1455 Status
= gBS
->AllocatePool (
1456 EfiRuntimeServicesData
,
1457 sizeof (EFI_FW_VOL_BLOCK_DEVICE
),
1460 ASSERT_EFI_ERROR (Status
);
1462 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1464 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1465 mFvbModuleGlobal
->NumFv
++;
1468 // Set up the devicepath
1470 FvbDevice
->DevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
1471 FvbDevice
->DevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ (FwVolHeader
->FvLength
- 1);
1474 // Find a handle with a matching device path that has supports FW Block protocol
1476 TempFwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) &TempFvbDevicePathData
;
1477 CopyMem (TempFwbDevicePath
, &FvbDevice
->DevicePath
, sizeof (FV_DEVICE_PATH
));
1478 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &TempFwbDevicePath
, &FwbHandle
);
1479 if (EFI_ERROR (Status
)) {
1481 // LocateDevicePath fails so install a new interface and device path
1484 Status
= gBS
->InstallMultipleProtocolInterfaces (
1486 &gEfiFirmwareVolumeBlockProtocolGuid
,
1487 &FvbDevice
->FwVolBlockInstance
,
1488 &gEfiDevicePathProtocolGuid
,
1489 &FvbDevice
->DevicePath
,
1492 ASSERT_EFI_ERROR (Status
);
1493 } else if (IsDevicePathEnd (TempFwbDevicePath
)) {
1495 // Device allready exists, so reinstall the FVB protocol
1497 Status
= gBS
->HandleProtocol (
1499 &gEfiFirmwareVolumeBlockProtocolGuid
,
1500 (VOID
**)&OldFwbInterface
1502 ASSERT_EFI_ERROR (Status
);
1504 Status
= gBS
->ReinstallProtocolInterface (
1506 &gEfiFirmwareVolumeBlockProtocolGuid
,
1508 &FvbDevice
->FwVolBlockInstance
1510 ASSERT_EFI_ERROR (Status
);
1514 // There was a FVB protocol on an End Device Path node
1519 // Install FVB Extension Protocol on the same handle
1521 Status
= gBS
->InstallMultipleProtocolInterfaces (
1523 &gEfiFvbExtensionProtocolGuid
,
1524 &FvbDevice
->FvbExtension
,
1525 &gEfiAlternateFvBlockGuid
,
1530 ASSERT_EFI_ERROR (Status
);
1532 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1534 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1535 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1538 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1542 // Allocate for scratch space, an intermediate buffer for FVB extention
1544 Status
= gBS
->AllocatePool (
1545 EfiRuntimeServicesData
,
1547 (VOID
**)&mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
]
1549 ASSERT_EFI_ERROR (Status
);
1551 mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
] = mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
];