3 Copyright (c) 2006, 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.
22 #include "FWBlockService.h"
24 ESAL_FWB_GLOBAL
*mFvbModuleGlobal
;
26 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
34 sizeof (MEMMAP_DEVICE_PATH
),
44 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
46 sizeof (EFI_DEVICE_PATH_PROTOCOL
),
53 FvbProtocolGetAttributes
,
54 FvbProtocolSetAttributes
,
55 FvbProtocolGetPhysicalAddress
,
56 FvbProtocolGetBlockSize
,
59 FvbProtocolEraseBlocks
,
63 FvbExtendProtocolEraseCustomBlockRange
71 FvbVirtualddressChangeEvent (
79 Fixup internal data so that EFI and SAL can be call in virtual mode.
80 Call the passed in Child Notify event and convert the mFvbModuleGlobal
81 date items to there virtual address.
83 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
84 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
89 (Standard EFI notify event - EFI_EVENT_NOTIFY)
97 EFI_FW_VOL_INSTANCE
*FwhInstance
;
100 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
103 // Convert the base address of all the instances
106 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
107 while (Index
< mFvbModuleGlobal
->NumFv
) {
108 EfiConvertPointer (0x0, (VOID
**) &FwhInstance
->FvBase
[FVB_VIRTUAL
]);
109 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
111 (UINTN
) ((UINT8
*) FwhInstance
) + FwhInstance
->VolumeHeader
.HeaderLength
+
112 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
117 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
]);
118 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
);
124 IN ESAL_FWB_GLOBAL
*Global
,
125 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
131 Retrieves the physical address of a memory mapped FV
134 Instance - The FV instance whose base address is going to be
136 Global - Pointer to ESAL_FWB_GLOBAL that contains all
138 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
139 Virtual - Whether CPU is in virtual or physical mode
142 EFI_SUCCESS - Successfully returns
143 EFI_INVALID_PARAMETER - Instance not found
147 EFI_FW_VOL_INSTANCE
*FwhRecord
;
149 if (Instance
>= Global
->NumFv
) {
150 return EFI_INVALID_PARAMETER
;
153 // Find the right instance of the FVB private data
155 FwhRecord
= Global
->FvInstance
[Virtual
];
156 while (Instance
> 0) {
157 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
159 (UINTN
) ((UINT8
*) FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
160 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
165 *FwhInstance
= FwhRecord
;
171 FvbGetPhysicalAddress (
173 OUT EFI_PHYSICAL_ADDRESS
*Address
,
174 IN ESAL_FWB_GLOBAL
*Global
,
180 Retrieves the physical address of a memory mapped FV
183 Instance - The FV instance whose base address is going to be
185 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
186 that on successful return, contains the base address
187 of the firmware volume.
188 Global - Pointer to ESAL_FWB_GLOBAL that contains all
190 Virtual - Whether CPU is in virtual or physical mode
193 EFI_SUCCESS - Successfully returns
194 EFI_INVALID_PARAMETER - Instance not found
198 EFI_FW_VOL_INSTANCE
*FwhInstance
;
202 // Find the right instance of the FVB private data
204 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
205 ASSERT_EFI_ERROR (Status
);
206 *Address
= FwhInstance
->FvBase
[Virtual
];
212 FvbGetVolumeAttributes (
214 OUT EFI_FVB_ATTRIBUTES
*Attributes
,
215 IN ESAL_FWB_GLOBAL
*Global
,
221 Retrieves attributes, insures positive polarity of attribute bits, returns
222 resulting attributes in output parameter
225 Instance - The FV instance whose attributes is going to be
227 Attributes - Output buffer which contains attributes
228 Global - Pointer to ESAL_FWB_GLOBAL that contains all
230 Virtual - Whether CPU is in virtual or physical mode
233 EFI_SUCCESS - Successfully returns
234 EFI_INVALID_PARAMETER - Instance not found
238 EFI_FW_VOL_INSTANCE
*FwhInstance
;
242 // Find the right instance of the FVB private data
244 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
245 ASSERT_EFI_ERROR (Status
);
246 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
255 OUT UINTN
*LbaAddress
,
256 OUT UINTN
*LbaLength
,
257 OUT UINTN
*NumOfBlocks
,
258 IN ESAL_FWB_GLOBAL
*Global
,
264 Retrieves the starting address of an LBA in an FV
267 Instance - The FV instance which the Lba belongs to
268 Lba - The logical block address
269 LbaAddress - On output, contains the physical starting address
271 LbaLength - On output, contains the length of the block
272 NumOfBlocks - A pointer to a caller allocated UINTN in which the
273 number of consecutive blocks starting with Lba is
274 returned. All blocks in this range have a size of
276 Global - Pointer to ESAL_FWB_GLOBAL that contains all
278 Virtual - Whether CPU is in virtual or physical mode
281 EFI_SUCCESS - Successfully returns
282 EFI_INVALID_PARAMETER - Instance not found
291 EFI_FW_VOL_INSTANCE
*FwhInstance
;
292 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
296 // Find the right instance of the FVB private data
298 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
299 ASSERT_EFI_ERROR (Status
);
303 BlockMap
= &(FwhInstance
->VolumeHeader
.FvBlockMap
[0]);
306 // Parse the blockmap of the FV to find which map entry the Lba belongs to
309 NumBlocks
= BlockMap
->NumBlocks
;
310 BlockLength
= BlockMap
->BlockLength
;
312 if (NumBlocks
== 0 || BlockLength
== 0) {
313 return EFI_INVALID_PARAMETER
;
316 NextLba
= StartLba
+ NumBlocks
;
319 // The map entry found
321 if (Lba
>= StartLba
&& Lba
< NextLba
) {
322 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
323 if (LbaAddress
!= NULL
) {
324 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
327 if (LbaLength
!= NULL
) {
328 *LbaLength
= BlockLength
;
331 if (NumOfBlocks
!= NULL
) {
332 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
339 Offset
= Offset
+ NumBlocks
* BlockLength
;
348 IN UINTN BlockOffset
,
349 IN OUT UINTN
*NumBytes
,
351 IN ESAL_FWB_GLOBAL
*Global
,
357 Reads specified number of bytes into a buffer from the specified block
360 Instance - The FV instance to be read from
361 Lba - The logical block address to be read from
362 BlockOffset - Offset into the block at which to begin reading
363 NumBytes - Pointer that on input contains the total size of
364 the buffer. On output, it contains the total number
366 Buffer - Pointer to a caller allocated buffer that will be
367 used to hold the data read
368 Global - Pointer to ESAL_FWB_GLOBAL that contains all
370 Virtual - Whether CPU is in virtual or physical mode
373 EFI_SUCCESS - The firmware volume was read successfully and
374 contents are in Buffer
375 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
376 NumBytes contains the total number of bytes returned
378 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
379 EFI_DEVICE_ERROR - The block device is not functioning correctly and
381 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
385 EFI_FVB_ATTRIBUTES Attributes
;
391 // Check for invalid conditions
393 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
394 return EFI_INVALID_PARAMETER
;
397 if (*NumBytes
== 0) {
398 return EFI_INVALID_PARAMETER
;
401 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
402 if (EFI_ERROR (Status
)) {
406 // Check if the FV is read enabled
408 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
410 if ((Attributes
& EFI_FVB_READ_STATUS
) == 0) {
411 return EFI_ACCESS_DENIED
;
414 // Perform boundary checks and adjust NumBytes
416 if (BlockOffset
> LbaLength
) {
417 return EFI_INVALID_PARAMETER
;
420 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
421 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
422 Status
= EFI_BAD_BUFFER_SIZE
;
425 CopyMem (Buffer
, (UINT8
*) (LbaAddress
+ BlockOffset
), (UINTN
) (*NumBytes
));
434 IN UINTN BlockOffset
,
435 IN OUT UINTN
*NumBytes
,
437 IN ESAL_FWB_GLOBAL
*Global
,
443 Writes specified number of bytes from the input buffer to the block
446 Instance - The FV instance to be written to
447 Lba - The starting logical block index to write to
448 BlockOffset - Offset into the block at which to begin writing
449 NumBytes - Pointer that on input contains the total size of
450 the buffer. On output, it contains the total number
451 of bytes actually written
452 Buffer - Pointer to a caller allocated buffer that contains
453 the source for the write
454 Global - Pointer to ESAL_FWB_GLOBAL that contains all
456 Virtual - Whether CPU is in virtual or physical mode
459 EFI_SUCCESS - The firmware volume was written successfully
460 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
461 NumBytes contains the total number of bytes
463 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
464 EFI_DEVICE_ERROR - The block device is not functioning correctly and
466 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
470 EFI_FVB_ATTRIBUTES Attributes
;
476 // Check for invalid conditions
478 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
479 return EFI_INVALID_PARAMETER
;
482 if (*NumBytes
== 0) {
483 return EFI_INVALID_PARAMETER
;
486 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
487 if (EFI_ERROR (Status
)) {
491 // Check if the FV is write enabled
493 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
495 if ((Attributes
& EFI_FVB_WRITE_STATUS
) == 0) {
496 return EFI_ACCESS_DENIED
;
499 // Perform boundary checks and adjust NumBytes
501 if (BlockOffset
> LbaLength
) {
502 return EFI_INVALID_PARAMETER
;
505 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
506 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
507 Status
= EFI_BAD_BUFFER_SIZE
;
512 CopyMem ((UINT8
*) (LbaAddress
+ BlockOffset
), Buffer
, (UINTN
) (*NumBytes
));
521 IN ESAL_FWB_GLOBAL
*Global
,
527 Erases and initializes a firmware volume block
530 Instance - The FV instance to be erased
531 Lba - The logical block index to be erased
532 Global - Pointer to ESAL_FWB_GLOBAL that contains all
534 Virtual - Whether CPU is in virtual or physical mode
537 EFI_SUCCESS - The erase request was successfully completed
538 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
539 EFI_DEVICE_ERROR - The block device is not functioning correctly and
540 could not be written. Firmware device may have been
542 EFI_INVALID_PARAMETER - Instance not found
547 EFI_FVB_ATTRIBUTES Attributes
;
554 // Check if the FV is write enabled
556 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
558 if ((Attributes
& EFI_FVB_WRITE_STATUS
) == 0) {
559 return EFI_ACCESS_DENIED
;
562 // Get the starting address of the block for erase.
564 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
566 if (EFI_ERROR (Status
)) {
570 if ((Attributes
& EFI_FVB_ERASE_POLARITY
) != 0) {
576 SetMem ((UINT8
*) LbaAddress
, LbaLength
, Data
);
582 FvbEraseCustomBlockRange (
585 IN UINTN OffsetStartLba
,
587 IN UINTN OffsetLastLba
,
588 IN ESAL_FWB_GLOBAL
*Global
,
594 Erases and initializes a specified range of a firmware volume
597 Instance - The FV instance to be erased
598 StartLba - The starting logical block index to be erased
599 OffsetStartLba - Offset into the starting block at which to
601 LastLba - The last logical block index to be erased
602 OffsetStartLba - Offset into the last block at which to end erasing
603 Global - Pointer to ESAL_FWB_GLOBAL that contains all
605 Virtual - Whether CPU is in virtual or physical mode
608 EFI_SUCCESS - The firmware volume was erased successfully
609 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
610 EFI_DEVICE_ERROR - The block device is not functioning correctly and
611 could not be written. Firmware device may have been
613 EFI_INVALID_PARAMETER - Instance not found
619 UINTN ScratchLbaSizeData
;
624 FvbGetLbaAddress (Instance
, StartLba
, NULL
, &LbaSize
, NULL
, Global
, Virtual
);
627 // Use the scratch space as the intermediate buffer to transfer data
628 // Back up the first LBA in scratch space.
630 FvbReadBlock (Instance
, StartLba
, 0, &LbaSize
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
635 FvbEraseBlock (Instance
, StartLba
, Global
, Virtual
);
636 ScratchLbaSizeData
= OffsetStartLba
;
639 // write the data back to the first block
641 if (ScratchLbaSizeData
> 0) {
642 FvbWriteBlock (Instance
, StartLba
, 0, &ScratchLbaSizeData
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
647 if (LastLba
> (StartLba
+ 1)) {
648 for (Index
= (StartLba
+ 1); Index
<= (LastLba
- 1); Index
++) {
649 FvbEraseBlock (Instance
, Index
, Global
, Virtual
);
653 // Last LBAs, the same as first LBAs
655 if (LastLba
> StartLba
) {
656 FvbGetLbaAddress (Instance
, LastLba
, NULL
, &LbaSize
, NULL
, Global
, Virtual
);
657 FvbReadBlock (Instance
, LastLba
, 0, &LbaSize
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
658 FvbEraseBlock (Instance
, LastLba
, Global
, Virtual
);
661 ScratchLbaSizeData
= LbaSize
- (OffsetStartLba
+ 1);
663 return FvbWriteBlock (
668 Global
->FvbScratchSpace
[Virtual
],
675 FvbSetVolumeAttributes (
677 IN OUT EFI_FVB_ATTRIBUTES
*Attributes
,
678 IN ESAL_FWB_GLOBAL
*Global
,
684 Modifies the current settings of the firmware volume according to the
685 input parameter, and returns the new setting of the volume
688 Instance - The FV instance whose attributes is going to be
690 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES
691 containing the desired firmware volume settings.
692 On successful return, it contains the new settings
693 of the firmware volume
694 Global - Pointer to ESAL_FWB_GLOBAL that contains all
696 Virtual - Whether CPU is in virtual or physical mode
699 EFI_SUCCESS - Successfully returns
700 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
701 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
702 in conflict with the capabilities as declared in the
703 firmware volume header
707 EFI_FW_VOL_INSTANCE
*FwhInstance
;
708 EFI_FVB_ATTRIBUTES OldAttributes
;
709 EFI_FVB_ATTRIBUTES
*AttribPtr
;
716 // Find the right instance of the FVB private data
718 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
719 ASSERT_EFI_ERROR (Status
);
721 AttribPtr
= (EFI_FVB_ATTRIBUTES
*) &(FwhInstance
->VolumeHeader
.Attributes
);
722 OldAttributes
= *AttribPtr
;
723 Capabilities
= OldAttributes
& EFI_FVB_CAPABILITIES
;
724 OldStatus
= OldAttributes
& EFI_FVB_STATUS
;
725 NewStatus
= *Attributes
& EFI_FVB_STATUS
;
728 // If firmware volume is locked, no status bit can be updated
730 if (OldAttributes
& EFI_FVB_LOCK_STATUS
) {
731 if (OldStatus
^ NewStatus
) {
732 return EFI_ACCESS_DENIED
;
738 if ((Capabilities
& EFI_FVB_READ_DISABLED_CAP
) == 0) {
739 if ((NewStatus
& EFI_FVB_READ_STATUS
) == 0) {
740 return EFI_INVALID_PARAMETER
;
746 if ((Capabilities
& EFI_FVB_READ_ENABLED_CAP
) == 0) {
747 if (NewStatus
& EFI_FVB_READ_STATUS
) {
748 return EFI_INVALID_PARAMETER
;
752 // Test write disable
754 if ((Capabilities
& EFI_FVB_WRITE_DISABLED_CAP
) == 0) {
755 if ((NewStatus
& EFI_FVB_WRITE_STATUS
) == 0) {
756 return EFI_INVALID_PARAMETER
;
762 if ((Capabilities
& EFI_FVB_WRITE_ENABLED_CAP
) == 0) {
763 if (NewStatus
& EFI_FVB_WRITE_STATUS
) {
764 return EFI_INVALID_PARAMETER
;
770 if ((Capabilities
& EFI_FVB_LOCK_CAP
) == 0) {
771 if (NewStatus
& EFI_FVB_LOCK_STATUS
) {
772 return EFI_INVALID_PARAMETER
;
776 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB_STATUS
));
777 *AttribPtr
= (*AttribPtr
) | NewStatus
;
778 *Attributes
= *AttribPtr
;
787 FvbProtocolGetPhysicalAddress (
788 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
789 OUT EFI_PHYSICAL_ADDRESS
*Address
795 Retrieves the physical address of the device.
799 This - Calling context
800 Address - Output buffer containing the address.
805 EFI_SUCCESS - Successfully returns
809 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
811 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
813 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
818 FvbProtocolGetBlockSize (
819 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
821 OUT UINTN
*BlockSize
,
822 OUT UINTN
*NumOfBlocks
827 Retrieve the size of a logical block
830 This - Calling context
831 Lba - Indicates which block to return the size for.
832 BlockSize - A pointer to a caller allocated UINTN in which
833 the size of the block is returned
834 NumOfBlocks - a pointer to a caller allocated UINTN in which the
835 number of consecutive blocks starting with Lba is
836 returned. All blocks in this range have a size of
840 EFI_SUCCESS - The firmware volume was read successfully and
841 contents are in Buffer
845 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
847 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
849 return FvbGetLbaAddress (
862 FvbProtocolGetAttributes (
863 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
864 OUT EFI_FVB_ATTRIBUTES
*Attributes
869 Retrieves Volume attributes. No polarity translations are done.
872 This - Calling context
873 Attributes - output buffer which contains attributes
876 EFI_SUCCESS - Successfully returns
880 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
882 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
884 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
889 FvbProtocolSetAttributes (
890 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
891 IN OUT EFI_FVB_ATTRIBUTES
*Attributes
896 Sets Volume attributes. No polarity translations are done.
899 This - Calling context
900 Attributes - output buffer which contains attributes
903 EFI_SUCCESS - Successfully returns
907 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
909 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
911 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
916 FvbProtocolEraseBlocks (
917 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
924 The EraseBlock() function erases one or more blocks as denoted by the
925 variable argument list. The entire parameter list of blocks must be verified
926 prior to erasing any blocks. If a block is requested that does not exist
927 within the associated firmware volume (it has a larger index than the last
928 block of the firmware volume), the EraseBlock() function must return
929 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
932 This - Calling context
933 ... - Starting LBA followed by Number of Lba to erase.
934 a -1 to terminate the list.
937 EFI_SUCCESS - The erase request was successfully completed
938 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
939 EFI_DEVICE_ERROR - The block device is not functioning correctly and
940 could not be written. Firmware device may have been
945 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
946 EFI_FW_VOL_INSTANCE
*FwhInstance
;
953 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
955 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
956 ASSERT_EFI_ERROR (Status
);
958 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
960 VA_START (args
, This
);
963 StartingLba
= VA_ARG (args
, EFI_LBA
);
964 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
968 NumOfLba
= VA_ARG (args
, UINT32
);
971 // Check input parameters
975 return EFI_INVALID_PARAMETER
;
978 if ((StartingLba
+ NumOfLba
) > NumOfBlocks
) {
979 return EFI_INVALID_PARAMETER
;
985 VA_START (args
, This
);
987 StartingLba
= VA_ARG (args
, EFI_LBA
);
988 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
992 NumOfLba
= VA_ARG (args
, UINT32
);
994 while (NumOfLba
> 0) {
995 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
996 if (EFI_ERROR (Status
)) {
1015 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1018 IN OUT UINTN
*NumBytes
,
1023 Routine Description:
1025 Writes data beginning at Lba:Offset from FV. The write terminates either
1026 when *NumBytes of data have been written, or when a block boundary is
1027 reached. *NumBytes is updated to reflect the actual number of bytes
1028 written. The write opertion does not include erase. This routine will
1029 attempt to write only the specified bytes. If the writes do not stick,
1030 it will return an error.
1033 This - Calling context
1034 Lba - Block in which to begin write
1035 Offset - Offset in the block at which to begin write
1036 NumBytes - On input, indicates the requested write size. On
1037 output, indicates the actual number of bytes written
1038 Buffer - Buffer containing source data for the write.
1041 EFI_SUCCESS - The firmware volume was written successfully
1042 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
1043 NumBytes contains the total number of bytes
1045 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1046 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1047 could not be written
1048 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1053 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1055 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1057 return FvbWriteBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1063 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1066 IN OUT UINTN
*NumBytes
,
1071 Routine Description:
1073 Reads data beginning at Lba:Offset from FV. The Read terminates either
1074 when *NumBytes of data have been read, or when a block boundary is
1075 reached. *NumBytes is updated to reflect the actual number of bytes
1076 written. The write opertion does not include erase. This routine will
1077 attempt to write only the specified bytes. If the writes do not stick,
1078 it will return an error.
1081 This - Calling context
1082 Lba - Block in which to begin Read
1083 Offset - Offset in the block at which to begin Read
1084 NumBytes - On input, indicates the requested write size. On
1085 output, indicates the actual number of bytes Read
1086 Buffer - Buffer containing source data for the Read.
1089 EFI_SUCCESS - The firmware volume was read successfully and
1090 contents are in Buffer
1091 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1092 NumBytes contains the total number of bytes returned
1094 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1095 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1097 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1102 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1104 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1106 return FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1109 // FVB Extension Protocols
1113 FvbExtendProtocolEraseCustomBlockRange (
1114 IN EFI_FVB_EXTENSION_PROTOCOL
*This
,
1115 IN EFI_LBA StartLba
,
1116 IN UINTN OffsetStartLba
,
1118 IN UINTN OffsetLastLba
1122 Routine Description:
1123 Erases and initializes a specified range of a firmware volume
1126 This - Calling context
1127 StartLba - The starting logical block index to be erased
1128 OffsetStartLba - Offset into the starting block at which to
1130 LastLba - The last logical block index to be erased
1131 OffsetStartLba - Offset into the last block at which to end erasing
1134 EFI_SUCCESS - The firmware volume was erased successfully
1135 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1136 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1137 could not be written. Firmware device may have been
1142 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1144 FvbDevice
= FVB_EXTEND_DEVICE_FROM_THIS (This
);
1146 return FvbEraseCustomBlockRange (
1147 FvbDevice
->Instance
,
1160 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1164 Routine Description:
1165 Check the integrity of firmware volume header
1168 FwVolHeader - A pointer to a firmware volume header
1171 EFI_SUCCESS - The firmware volume is consistent
1172 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1177 UINT16 HeaderLength
;
1181 // Verify the header revision, header signature, length
1182 // Length of FvBlock cannot be 2**64-1
1183 // HeaderLength cannot be an odd number
1185 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1186 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1187 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
1188 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1190 return EFI_NOT_FOUND
;
1193 // Verify the header checksum
1195 HeaderLength
= (UINT16
) (FwVolHeader
->HeaderLength
/ 2);
1196 Ptr
= (UINT16
*) FwVolHeader
;
1198 while (HeaderLength
> 0) {
1203 if (Checksum
!= 0) {
1204 return EFI_NOT_FOUND
;
1213 IN EFI_HANDLE ImageHandle
,
1214 IN EFI_SYSTEM_TABLE
*SystemTable
1218 Routine Description:
1219 This function does common initialization for FVB services
1228 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1229 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1230 EFI_DXE_SERVICES
*DxeServices
;
1231 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
1233 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1234 EFI_HANDLE FwbHandle
;
1235 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1236 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1237 EFI_DEVICE_PATH_PROTOCOL
*TempFwbDevicePath
;
1238 FV_DEVICE_PATH TempFvbDevicePathData
;
1240 EFI_PHYSICAL_ADDRESS BaseAddress
;
1243 EFI_PEI_HOB_POINTERS FvHob
;
1246 // Get the DXE services table
1251 // Allocate runtime services data for global variable, which contains
1252 // the private data of all firmware volume block instances
1254 Status
= gBS
->AllocatePool (
1255 EfiRuntimeServicesData
,
1256 sizeof (ESAL_FWB_GLOBAL
),
1259 ASSERT_EFI_ERROR (Status
);
1262 // Calculate the total size for all firmware volume block instances
1266 FvHob
.Raw
= GetHobList ();
1267 while ((FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
)) != NULL
) {
1268 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1269 Length
= FvHob
.FirmwareVolume
->Length
;
1271 // Check if it is a "real" flash
1273 Status
= DxeServices
->GetMemorySpaceDescriptor (
1277 if (EFI_ERROR (Status
)) {
1281 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1282 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1286 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1287 Status
= ValidateFvHeader (FwVolHeader
);
1288 if (EFI_ERROR (Status
)) {
1292 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1293 if (EFI_ERROR (Status
)) {
1294 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1299 BufferSize
+= (sizeof (EFI_FW_VOL_INSTANCE
) + FwVolHeader
->HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1300 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1304 // Only need to allocate once. There is only one copy of physical memory for
1305 // the private data of each FV instance. But in virtual mode or in physical
1306 // mode, the address of the the physical memory may be different.
1308 Status
= gBS
->AllocatePool (
1309 EfiRuntimeServicesData
,
1311 &mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
]
1313 ASSERT_EFI_ERROR (Status
);
1316 // Make a virtual copy of the FvInstance pointer.
1318 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1319 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1321 mFvbModuleGlobal
->NumFv
= 0;
1324 FvHob
.Raw
= GetHobList ();
1325 while (NULL
!= (FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
))) {
1326 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1327 Length
= FvHob
.FirmwareVolume
->Length
;
1329 // Check if it is a "real" flash
1331 Status
= DxeServices
->GetMemorySpaceDescriptor (
1335 if (EFI_ERROR (Status
)) {
1339 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1340 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1344 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1345 Status
= ValidateFvHeader (FwVolHeader
);
1346 if (EFI_ERROR (Status
)) {
1348 // Get FvbInfo to provide in FwhInstance.
1350 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1351 if (EFI_ERROR (Status
)) {
1352 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1356 // Write healthy FV header back.
1359 (VOID
*) (UINTN
) BaseAddress
,
1360 (VOID
*) FwVolHeader
,
1361 FwVolHeader
->HeaderLength
1365 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1366 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1368 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1369 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1370 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), EFI_TPL_HIGH_LEVEL
);
1374 for (PtrBlockMapEntry
= FwVolHeader
->FvBlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1376 // Get the maximum size of a block. The size will be used to allocate
1377 // buffer for Scratch space, the intermediate buffer for FVB extension
1380 if (MaxLbaSize
< PtrBlockMapEntry
->BlockLength
) {
1381 MaxLbaSize
= PtrBlockMapEntry
->BlockLength
;
1384 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1387 // The total number of blocks in the FV.
1389 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1392 // Add a FVB Protocol Instance
1394 Status
= gBS
->AllocatePool (
1395 EfiRuntimeServicesData
,
1396 sizeof (EFI_FW_VOL_BLOCK_DEVICE
),
1399 ASSERT_EFI_ERROR (Status
);
1401 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1403 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1404 mFvbModuleGlobal
->NumFv
++;
1407 // Set up the devicepath
1409 FvbDevice
->DevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
1410 FvbDevice
->DevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ (FwVolHeader
->FvLength
- 1);
1413 // Find a handle with a matching device path that has supports FW Block protocol
1415 TempFwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) &TempFvbDevicePathData
;
1416 CopyMem (TempFwbDevicePath
, &FvbDevice
->DevicePath
, sizeof (FV_DEVICE_PATH
));
1417 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &TempFwbDevicePath
, &FwbHandle
);
1418 if (EFI_ERROR (Status
)) {
1420 // LocateDevicePath fails so install a new interface and device path
1423 Status
= gBS
->InstallMultipleProtocolInterfaces (
1425 &gEfiFirmwareVolumeBlockProtocolGuid
,
1426 &FvbDevice
->FwVolBlockInstance
,
1427 &gEfiDevicePathProtocolGuid
,
1428 &FvbDevice
->DevicePath
,
1431 ASSERT_EFI_ERROR (Status
);
1432 } else if (EfiIsDevicePathEnd (TempFwbDevicePath
)) {
1434 // Device allready exists, so reinstall the FVB protocol
1436 Status
= gBS
->HandleProtocol (
1438 &gEfiFirmwareVolumeBlockProtocolGuid
,
1441 ASSERT_EFI_ERROR (Status
);
1443 Status
= gBS
->ReinstallProtocolInterface (
1445 &gEfiFirmwareVolumeBlockProtocolGuid
,
1447 &FvbDevice
->FwVolBlockInstance
1449 ASSERT_EFI_ERROR (Status
);
1453 // There was a FVB protocol on an End Device Path node
1458 // Install FVB Extension Protocol on the same handle
1460 Status
= gBS
->InstallMultipleProtocolInterfaces (
1462 &gEfiFvbExtensionProtocolGuid
,
1463 &FvbDevice
->FvbExtension
,
1464 &gEfiAlternateFvBlockGuid
,
1469 ASSERT_EFI_ERROR (Status
);
1471 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1473 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1474 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1477 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1481 // Allocate for scratch space, an intermediate buffer for FVB extention
1483 Status
= gBS
->AllocatePool (
1484 EfiRuntimeServicesData
,
1486 &mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
]
1488 ASSERT_EFI_ERROR (Status
);
1490 mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
] = mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
];