3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
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 mFvbModuleGlobal
= AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL
));
1256 ASSERT (mFvbModuleGlobal
!= NULL
);
1259 // Calculate the total size for all firmware volume block instances
1263 FvHob
.Raw
= GetHobList ();
1264 while ((FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
)) != NULL
) {
1265 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1266 Length
= FvHob
.FirmwareVolume
->Length
;
1268 // Check if it is a "real" flash
1270 Status
= DxeServices
->GetMemorySpaceDescriptor (
1274 if (EFI_ERROR (Status
)) {
1278 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1279 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1283 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1284 Status
= ValidateFvHeader (FwVolHeader
);
1285 if (EFI_ERROR (Status
)) {
1289 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1290 if (EFI_ERROR (Status
)) {
1291 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1296 BufferSize
+= (sizeof (EFI_FW_VOL_INSTANCE
) + FwVolHeader
->HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1297 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1301 // Only need to allocate once. There is only one copy of physical memory for
1302 // the private data of each FV instance. But in virtual mode or in physical
1303 // mode, the address of the the physical memory may be different.
1305 mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] = AllocateRuntimePool (BufferSize
);
1306 ASSERT (mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] != NULL
);
1309 // Make a virtual copy of the FvInstance pointer.
1311 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1312 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1314 mFvbModuleGlobal
->NumFv
= 0;
1317 FvHob
.Raw
= GetHobList ();
1318 while (NULL
!= (FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
))) {
1319 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1320 Length
= FvHob
.FirmwareVolume
->Length
;
1322 // Check if it is a "real" flash
1324 Status
= DxeServices
->GetMemorySpaceDescriptor (
1328 if (EFI_ERROR (Status
)) {
1332 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1333 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1337 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1338 Status
= ValidateFvHeader (FwVolHeader
);
1339 if (EFI_ERROR (Status
)) {
1341 // Get FvbInfo to provide in FwhInstance.
1343 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1344 if (EFI_ERROR (Status
)) {
1345 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1349 // Write healthy FV header back.
1352 (VOID
*) (UINTN
) BaseAddress
,
1353 (VOID
*) FwVolHeader
,
1354 FwVolHeader
->HeaderLength
1358 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1359 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1361 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1362 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1363 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1367 for (PtrBlockMapEntry
= FwVolHeader
->FvBlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1369 // Get the maximum size of a block. The size will be used to allocate
1370 // buffer for Scratch space, the intermediate buffer for FVB extension
1373 if (MaxLbaSize
< PtrBlockMapEntry
->BlockLength
) {
1374 MaxLbaSize
= PtrBlockMapEntry
->BlockLength
;
1377 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1380 // The total number of blocks in the FV.
1382 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1385 // Add a FVB Protocol Instance
1387 FvbDevice
= AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1388 ASSERT (FvbDevice
!= NULL
);
1390 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1392 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1393 mFvbModuleGlobal
->NumFv
++;
1396 // Set up the devicepath
1398 FvbDevice
->DevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
1399 FvbDevice
->DevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ (FwVolHeader
->FvLength
- 1);
1402 // Find a handle with a matching device path that has supports FW Block protocol
1404 TempFwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) &TempFvbDevicePathData
;
1405 CopyMem (TempFwbDevicePath
, &FvbDevice
->DevicePath
, sizeof (FV_DEVICE_PATH
));
1406 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &TempFwbDevicePath
, &FwbHandle
);
1407 if (EFI_ERROR (Status
)) {
1409 // LocateDevicePath fails so install a new interface and device path
1412 Status
= gBS
->InstallMultipleProtocolInterfaces (
1414 &gEfiFirmwareVolumeBlockProtocolGuid
,
1415 &FvbDevice
->FwVolBlockInstance
,
1416 &gEfiDevicePathProtocolGuid
,
1417 &FvbDevice
->DevicePath
,
1420 ASSERT_EFI_ERROR (Status
);
1421 } else if (EfiIsDevicePathEnd (TempFwbDevicePath
)) {
1423 // Device allready exists, so reinstall the FVB protocol
1425 Status
= gBS
->HandleProtocol (
1427 &gEfiFirmwareVolumeBlockProtocolGuid
,
1430 ASSERT_EFI_ERROR (Status
);
1432 Status
= gBS
->ReinstallProtocolInterface (
1434 &gEfiFirmwareVolumeBlockProtocolGuid
,
1436 &FvbDevice
->FwVolBlockInstance
1438 ASSERT_EFI_ERROR (Status
);
1442 // There was a FVB protocol on an End Device Path node
1447 // Install FVB Extension Protocol on the same handle
1449 Status
= gBS
->InstallMultipleProtocolInterfaces (
1451 &gEfiFvbExtensionProtocolGuid
,
1452 &FvbDevice
->FvbExtension
,
1453 &gEfiAlternateFvBlockGuid
,
1458 ASSERT_EFI_ERROR (Status
);
1460 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1462 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1463 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1466 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1470 // Allocate for scratch space, an intermediate buffer for FVB extention
1472 mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
] = AllocateRuntimePool (MaxLbaSize
);
1473 ASSERT (mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
] != NULL
);
1475 mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
] = mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
];