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) {
1199 Checksum
= Checksum
+ (*Ptr
);
1204 if (Checksum
!= 0) {
1205 return EFI_NOT_FOUND
;
1214 IN EFI_HANDLE ImageHandle
,
1215 IN EFI_SYSTEM_TABLE
*SystemTable
1219 Routine Description:
1220 This function does common initialization for FVB services
1229 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1230 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1231 EFI_DXE_SERVICES
*DxeServices
;
1232 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
1234 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1235 EFI_HANDLE FwbHandle
;
1236 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1237 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1238 EFI_DEVICE_PATH_PROTOCOL
*TempFwbDevicePath
;
1239 FV_DEVICE_PATH TempFvbDevicePathData
;
1241 EFI_PHYSICAL_ADDRESS BaseAddress
;
1244 EFI_PEI_HOB_POINTERS FvHob
;
1247 // Get the DXE services table
1252 // Allocate runtime services data for global variable, which contains
1253 // the private data of all firmware volume block instances
1255 Status
= gBS
->AllocatePool (
1256 EfiRuntimeServicesData
,
1257 sizeof (ESAL_FWB_GLOBAL
),
1258 (VOID
**) &mFvbModuleGlobal
1260 ASSERT_EFI_ERROR (Status
);
1263 // Calculate the total size for all firmware volume block instances
1267 FvHob
.Raw
= GetHobList ();
1268 while ((FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
)) != NULL
) {
1269 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1270 Length
= FvHob
.FirmwareVolume
->Length
;
1272 // Check if it is a "real" flash
1274 Status
= DxeServices
->GetMemorySpaceDescriptor (
1278 if (EFI_ERROR (Status
)) {
1282 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1283 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1287 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1288 Status
= ValidateFvHeader (FwVolHeader
);
1289 if (EFI_ERROR (Status
)) {
1293 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1294 if (EFI_ERROR (Status
)) {
1295 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1300 BufferSize
+= (sizeof (EFI_FW_VOL_INSTANCE
) + FwVolHeader
->HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1301 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1305 // Only need to allocate once. There is only one copy of physical memory for
1306 // the private data of each FV instance. But in virtual mode or in physical
1307 // mode, the address of the the physical memory may be different.
1309 Status
= gBS
->AllocatePool (
1310 EfiRuntimeServicesData
,
1312 (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
]
1314 ASSERT_EFI_ERROR (Status
);
1317 // Make a virtual copy of the FvInstance pointer.
1319 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1320 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1322 mFvbModuleGlobal
->NumFv
= 0;
1325 FvHob
.Raw
= GetHobList ();
1326 while (NULL
!= (FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
))) {
1327 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1328 Length
= FvHob
.FirmwareVolume
->Length
;
1330 // Check if it is a "real" flash
1332 Status
= DxeServices
->GetMemorySpaceDescriptor (
1336 if (EFI_ERROR (Status
)) {
1340 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1341 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1345 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1346 Status
= ValidateFvHeader (FwVolHeader
);
1347 if (EFI_ERROR (Status
)) {
1349 // Get FvbInfo to provide in FwhInstance.
1351 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1352 if (EFI_ERROR (Status
)) {
1353 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1357 // Write healthy FV header back.
1360 (VOID
*) (UINTN
) BaseAddress
,
1361 (VOID
*) FwVolHeader
,
1362 FwVolHeader
->HeaderLength
1366 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1367 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1369 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1370 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1371 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1375 for (PtrBlockMapEntry
= FwVolHeader
->FvBlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1377 // Get the maximum size of a block. The size will be used to allocate
1378 // buffer for Scratch space, the intermediate buffer for FVB extension
1381 if (MaxLbaSize
< PtrBlockMapEntry
->BlockLength
) {
1382 MaxLbaSize
= PtrBlockMapEntry
->BlockLength
;
1385 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1388 // The total number of blocks in the FV.
1390 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1393 // Add a FVB Protocol Instance
1395 Status
= gBS
->AllocatePool (
1396 EfiRuntimeServicesData
,
1397 sizeof (EFI_FW_VOL_BLOCK_DEVICE
),
1400 ASSERT_EFI_ERROR (Status
);
1402 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1404 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1405 mFvbModuleGlobal
->NumFv
++;
1408 // Set up the devicepath
1410 FvbDevice
->DevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
1411 FvbDevice
->DevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ (FwVolHeader
->FvLength
- 1);
1414 // Find a handle with a matching device path that has supports FW Block protocol
1416 TempFwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) &TempFvbDevicePathData
;
1417 CopyMem (TempFwbDevicePath
, &FvbDevice
->DevicePath
, sizeof (FV_DEVICE_PATH
));
1418 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &TempFwbDevicePath
, &FwbHandle
);
1419 if (EFI_ERROR (Status
)) {
1421 // LocateDevicePath fails so install a new interface and device path
1424 Status
= gBS
->InstallMultipleProtocolInterfaces (
1426 &gEfiFirmwareVolumeBlockProtocolGuid
,
1427 &FvbDevice
->FwVolBlockInstance
,
1428 &gEfiDevicePathProtocolGuid
,
1429 &FvbDevice
->DevicePath
,
1432 ASSERT_EFI_ERROR (Status
);
1433 } else if (EfiIsDevicePathEnd (TempFwbDevicePath
)) {
1435 // Device allready exists, so reinstall the FVB protocol
1437 Status
= gBS
->HandleProtocol (
1439 &gEfiFirmwareVolumeBlockProtocolGuid
,
1440 (VOID
**)&OldFwbInterface
1442 ASSERT_EFI_ERROR (Status
);
1444 Status
= gBS
->ReinstallProtocolInterface (
1446 &gEfiFirmwareVolumeBlockProtocolGuid
,
1448 &FvbDevice
->FwVolBlockInstance
1450 ASSERT_EFI_ERROR (Status
);
1454 // There was a FVB protocol on an End Device Path node
1459 // Install FVB Extension Protocol on the same handle
1461 Status
= gBS
->InstallMultipleProtocolInterfaces (
1463 &gEfiFvbExtensionProtocolGuid
,
1464 &FvbDevice
->FvbExtension
,
1465 &gEfiAlternateFvBlockGuid
,
1470 ASSERT_EFI_ERROR (Status
);
1472 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1474 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1475 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1478 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1482 // Allocate for scratch space, an intermediate buffer for FVB extention
1484 Status
= gBS
->AllocatePool (
1485 EfiRuntimeServicesData
,
1487 (VOID
**)&mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
]
1489 ASSERT_EFI_ERROR (Status
);
1491 mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
] = mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
];