2 Copyright (c) 2007, Intel Corporation
3 All rights reserved. This program and the accompanying materials
4 are licensed and made available under the terms and conditions of the BSD License
5 which accompanies this distribution. The full text of the license may be found at
6 http://opensource.org/licenses/bsd-license.php
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 #include "FWBlockService.h"
21 #include "EfiFlashMap.h"
23 #include "FlashLayout.h"
25 ESAL_FWB_GLOBAL
*mFvbModuleGlobal
;
26 VOID
*mSFSRegistration
;
27 #define TRY_ASSIGN(var, value) if(var != NULL) {*var = value;}
29 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
37 sizeof (MEMMAP_DEVICE_PATH
),
47 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
49 sizeof (EFI_DEVICE_PATH_PROTOCOL
),
56 FvbProtocolGetAttributes
,
57 FvbProtocolSetAttributes
,
58 FvbProtocolGetPhysicalAddress
,
59 FvbProtocolGetBlockSize
,
62 FvbProtocolEraseBlocks
,
71 IN EFI_FW_VOL_INSTANCE
*FwhInstance
,
72 IN OUT UINTN
*NumBytes
,
78 Writes specified number of bytes from the input buffer to the address
93 CopyMem ((VOID
*) Address
, Buffer
, *NumBytes
);
95 if (!EfiAtRuntime () && (FwhInstance
->Device
!= NULL
)) {
96 Status
= FileOpen (FwhInstance
->Device
, FwhInstance
->MappedFile
, &File
, EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
);
97 ASSERT_EFI_ERROR (Status
);
98 if (!EFI_ERROR (Status
)) {
99 if (Address
- FwhInstance
->FvBase
[FVB_PHYSICAL
] < FwhInstance
->Offset
) {
101 BufferForFile
= FwhInstance
->FvBase
[FVB_PHYSICAL
] + FwhInstance
->Offset
;
102 Length
= *NumBytes
- (FwhInstance
->Offset
- (Address
- FwhInstance
->FvBase
[FVB_PHYSICAL
]));
104 FileOffset
= Address
- FwhInstance
->FvBase
[FVB_PHYSICAL
] - FwhInstance
->Offset
;
105 BufferForFile
= Address
;
109 Status
= FileWrite (File
, FileOffset
, BufferForFile
, Length
);
110 ASSERT_EFI_ERROR (Status
);
120 IN EFI_FW_VOL_INSTANCE
*FwhInstance
,
126 Erase a certain block from address LbaWriteAddress
140 Status
= EFI_SUCCESS
;
142 SetMem ((VOID
*)Address
, LbaLength
, 0xff);
144 if (!EfiAtRuntime () && (FwhInstance
->Device
!= NULL
)) {
145 Status
= FileOpen (FwhInstance
->Device
, FwhInstance
->MappedFile
, &File
, EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
);
146 ASSERT_EFI_ERROR (Status
);
147 if (!EFI_ERROR (Status
)) {
148 if (Address
- FwhInstance
->FvBase
[FVB_PHYSICAL
] < FwhInstance
->Offset
) {
150 BufferForFile
= FwhInstance
->FvBase
[FVB_PHYSICAL
] + FwhInstance
->Offset
;
151 Length
= LbaLength
- (FwhInstance
->Offset
- (Address
- FwhInstance
->FvBase
[FVB_PHYSICAL
]));
153 FileOffset
= Address
- FwhInstance
->FvBase
[FVB_PHYSICAL
] - FwhInstance
->Offset
;
154 BufferForFile
= Address
;
158 Status
= FileWrite (File
, FileOffset
, BufferForFile
, Length
);
159 ASSERT_EFI_ERROR (Status
);
168 FvbVirtualddressChangeEvent (
176 Fixup internal data so that EFI and SAL can be call in virtual mode.
177 Call the passed in Child Notify event and convert the mFvbModuleGlobal
178 date items to there virtual address.
180 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
181 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
186 (Standard EFI notify event - EFI_EVENT_NOTIFY)
194 EFI_FW_VOL_INSTANCE
*FwhInstance
;
197 EfiConvertPointer (0, (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
200 // Convert the base address of all the instances
203 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
204 while (Index
< mFvbModuleGlobal
->NumFv
) {
205 EfiConvertPointer (0, (VOID
**) &FwhInstance
->FvBase
[FVB_VIRTUAL
]);
206 FwhInstance
= (EFI_FW_VOL_INSTANCE
*) ((UINTN
)((UINT8
*)FwhInstance
) + FwhInstance
->VolumeHeader
.HeaderLength
207 + (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
)));
211 EfiConvertPointer (0, (VOID
**) &mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
]);
212 EfiConvertPointer (0, (VOID
**) &mFvbModuleGlobal
);
218 IN ESAL_FWB_GLOBAL
*Global
,
219 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
225 Retrieves the physical address of a memory mapped FV
228 Instance - The FV instance whose base address is going to be
230 Global - Pointer to ESAL_FWB_GLOBAL that contains all
232 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
233 Virtual - Whether CPU is in virtual or physical mode
236 EFI_SUCCESS - Successfully returns
237 EFI_INVALID_PARAMETER - Instance not found
241 EFI_FW_VOL_INSTANCE
*FwhRecord
;
243 if (Instance
>= Global
->NumFv
) {
244 return EFI_INVALID_PARAMETER
;
247 // Find the right instance of the FVB private data
249 FwhRecord
= Global
->FvInstance
[Virtual
];
250 while (Instance
> 0) {
251 FwhRecord
= (EFI_FW_VOL_INSTANCE
*) ((UINTN
)((UINT8
*)FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
252 + (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
)));
256 *FwhInstance
= FwhRecord
;
262 FvbGetPhysicalAddress (
264 OUT EFI_PHYSICAL_ADDRESS
*Address
,
265 IN ESAL_FWB_GLOBAL
*Global
,
271 Retrieves the physical address of a memory mapped FV
274 Instance - The FV instance whose base address is going to be
276 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
277 that on successful return, contains the base address
278 of the firmware volume.
279 Global - Pointer to ESAL_FWB_GLOBAL that contains all
281 Virtual - Whether CPU is in virtual or physical mode
284 EFI_SUCCESS - Successfully returns
285 EFI_INVALID_PARAMETER - Instance not found
289 EFI_FW_VOL_INSTANCE
*FwhInstance
;
293 // Find the right instance of the FVB private data
295 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
296 ASSERT_EFI_ERROR (Status
);
297 *Address
= FwhInstance
->FvBase
[Virtual
];
303 FvbGetVolumeAttributes (
305 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
306 IN ESAL_FWB_GLOBAL
*Global
,
312 Retrieves attributes, insures positive polarity of attribute bits, returns
313 resulting attributes in output parameter
316 Instance - The FV instance whose attributes is going to be
318 Attributes - Output buffer which contains attributes
319 Global - Pointer to ESAL_FWB_GLOBAL that contains all
321 Virtual - Whether CPU is in virtual or physical mode
324 EFI_SUCCESS - Successfully returns
325 EFI_INVALID_PARAMETER - Instance not found
329 EFI_FW_VOL_INSTANCE
*FwhInstance
;
333 // Find the right instance of the FVB private data
335 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
336 ASSERT_EFI_ERROR (Status
);
337 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
346 OUT UINTN
*LbaAddress OPTIONAL
,
347 OUT UINTN
*LbaLength OPTIONAL
,
348 OUT UINTN
*NumOfBlocks OPTIONAL
,
349 IN ESAL_FWB_GLOBAL
*Global
,
355 Retrieves the starting address of an LBA in an FV
358 Instance - The FV instance which the Lba belongs to
359 Lba - The logical block address
360 LbaAddress - On output, contains the physical starting address
361 of the Lba for writing
362 LbaLength - On output, contains the length of the block
363 NumOfBlocks - A pointer to a caller allocated UINTN in which the
364 number of consecutive blocks starting with Lba is
365 returned. All blocks in this range have a size of
367 Global - Pointer to ESAL_FWB_GLOBAL that contains all
369 Virtual - Whether CPU is in virtual or physical mode
372 EFI_SUCCESS - Successfully returns
373 EFI_INVALID_PARAMETER - Instance not found
382 EFI_FW_VOL_INSTANCE
*FwhInstance
;
383 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
387 // Find the right instance of the FVB private data
389 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
390 ASSERT_EFI_ERROR (Status
);
394 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
397 // Parse the blockmap of the FV to find which map entry the Lba belongs to
400 NumBlocks
= BlockMap
->NumBlocks
;
401 BlockLength
= BlockMap
->Length
;
403 if (NumBlocks
== 0 || BlockLength
== 0) {
404 return EFI_INVALID_PARAMETER
;
407 NextLba
= StartLba
+ NumBlocks
;
410 // The map entry found
412 if (Lba
>= StartLba
&& Lba
< NextLba
) {
413 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
416 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
420 *LbaLength
= BlockLength
;
424 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
431 Offset
= Offset
+ NumBlocks
* BlockLength
;
440 IN UINTN BlockOffset
,
441 IN OUT UINTN
*NumBytes
,
443 IN ESAL_FWB_GLOBAL
*Global
,
449 Reads specified number of bytes into a buffer from the specified block
452 Instance - The FV instance to be read from
453 Lba - The logical block address to be read from
454 BlockOffset - Offset into the block at which to begin reading
455 NumBytes - Pointer that on input contains the total size of
456 the buffer. On output, it contains the total number
458 Buffer - Pointer to a caller allocated buffer that will be
459 used to hold the data read
460 Global - Pointer to ESAL_FWB_GLOBAL that contains all
462 Virtual - Whether CPU is in virtual or physical mode
465 EFI_SUCCESS - The firmware volume was read successfully and
466 contents are in Buffer
467 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
468 NumBytes contains the total number of bytes returned
470 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
471 EFI_DEVICE_ERROR - The block device is not functioning correctly and
473 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
477 EFI_FVB_ATTRIBUTES_2 Attributes
;
483 // Check for invalid conditions
485 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
486 return EFI_INVALID_PARAMETER
;
489 if (*NumBytes
== 0) {
490 return EFI_INVALID_PARAMETER
;
493 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
494 if (EFI_ERROR (Status
)) {
498 // Check if the FV is read enabled
500 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
502 if ((Attributes
& EFI_FVB2_READ_STATUS
) == 0) {
503 return EFI_ACCESS_DENIED
;
506 // Perform boundary checks and adjust NumBytes
508 if (BlockOffset
> LbaLength
) {
509 return EFI_INVALID_PARAMETER
;
512 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
513 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
514 Status
= EFI_BAD_BUFFER_SIZE
;
517 CopyMem (Buffer
, (VOID
*) (LbaAddress
+ BlockOffset
), (UINTN
) *NumBytes
);
525 IN UINTN BlockOffset
,
526 IN OUT UINTN
*NumBytes
,
528 IN ESAL_FWB_GLOBAL
*Global
,
534 Writes specified number of bytes from the input buffer to the block
537 Instance - The FV instance to be written to
538 Lba - The starting logical block index to write to
539 BlockOffset - Offset into the block at which to begin writing
540 NumBytes - Pointer that on input contains the total size of
541 the buffer. On output, it contains the total number
542 of bytes actually written
543 Buffer - Pointer to a caller allocated buffer that contains
544 the source for the write
545 Global - Pointer to ESAL_FWB_GLOBAL that contains all
547 Virtual - Whether CPU is in virtual or physical mode
550 EFI_SUCCESS - The firmware volume was written successfully
551 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
552 NumBytes contains the total number of bytes
554 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
555 EFI_DEVICE_ERROR - The block device is not functioning correctly and
557 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
561 EFI_FVB_ATTRIBUTES_2 Attributes
;
564 EFI_FW_VOL_INSTANCE
*FwhInstance
;
566 EFI_STATUS ReturnStatus
;
569 // Find the right instance of the FVB private data
571 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
572 ASSERT_EFI_ERROR (Status
);
575 // Writes are enabled in the init routine itself
577 if (!FwhInstance
->WriteEnabled
) {
578 return EFI_ACCESS_DENIED
;
581 // Check for invalid conditions
583 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
584 return EFI_INVALID_PARAMETER
;
587 if (*NumBytes
== 0) {
588 return EFI_INVALID_PARAMETER
;
591 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
592 if (EFI_ERROR (Status
)) {
596 // Check if the FV is write enabled
598 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
600 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
601 return EFI_ACCESS_DENIED
;
604 // Perform boundary checks and adjust NumBytes
606 if (BlockOffset
> LbaLength
) {
607 return EFI_INVALID_PARAMETER
;
610 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
611 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
612 Status
= EFI_BAD_BUFFER_SIZE
;
615 ReturnStatus
= FlashFdWrite (
616 LbaAddress
+ BlockOffset
,
621 if (EFI_ERROR (ReturnStatus
)) {
632 IN ESAL_FWB_GLOBAL
*Global
,
638 Erases and initializes a firmware volume block
641 Instance - The FV instance to be erased
642 Lba - The logical block index to be erased
643 Global - Pointer to ESAL_FWB_GLOBAL that contains all
645 Virtual - Whether CPU is in virtual or physical mode
648 EFI_SUCCESS - The erase request was successfully completed
649 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
650 EFI_DEVICE_ERROR - The block device is not functioning correctly and
651 could not be written. Firmware device may have been
653 EFI_INVALID_PARAMETER - Instance not found
658 EFI_FVB_ATTRIBUTES_2 Attributes
;
660 EFI_FW_VOL_INSTANCE
*FwhInstance
;
665 // Find the right instance of the FVB private data
667 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
668 ASSERT_EFI_ERROR (Status
);
671 // Writes are enabled in the init routine itself
673 if (!FwhInstance
->WriteEnabled
) {
674 return EFI_ACCESS_DENIED
;
677 // Check if the FV is write enabled
679 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
681 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
682 return EFI_ACCESS_DENIED
;
685 // Get the starting address of the block for erase. For debug reasons,
686 // LbaWriteAddress may not be the same as LbaAddress.
688 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
689 if (EFI_ERROR (Status
)) {
693 return FlashFdErase (
701 FvbSetVolumeAttributes (
703 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
704 IN ESAL_FWB_GLOBAL
*Global
,
710 Modifies the current settings of the firmware volume according to the
711 input parameter, and returns the new setting of the volume
714 Instance - The FV instance whose attributes is going to be
716 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
717 containing the desired firmware volume settings.
718 On successful return, it contains the new settings
719 of the firmware volume
720 Global - Pointer to ESAL_FWB_GLOBAL that contains all
722 Virtual - Whether CPU is in virtual or physical mode
725 EFI_SUCCESS - Successfully returns
726 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
727 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
728 in conflict with the capabilities as declared in the
729 firmware volume header
733 EFI_FW_VOL_INSTANCE
*FwhInstance
;
734 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
735 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
742 // Find the right instance of the FVB private data
744 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
745 ASSERT_EFI_ERROR (Status
);
747 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
748 OldAttributes
= *AttribPtr
;
749 Capabilities
= OldAttributes
& EFI_FVB2_CAPABILITIES
;
750 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
751 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
754 // If firmware volume is locked, no status bit can be updated
756 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
757 if (OldStatus
^ NewStatus
) {
758 return EFI_ACCESS_DENIED
;
764 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
765 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
766 return EFI_INVALID_PARAMETER
;
772 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
773 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
774 return EFI_INVALID_PARAMETER
;
778 // Test write disable
780 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
781 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
782 return EFI_INVALID_PARAMETER
;
788 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
789 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
790 return EFI_INVALID_PARAMETER
;
796 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
797 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
798 return EFI_INVALID_PARAMETER
;
802 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
803 *AttribPtr
= (*AttribPtr
) | NewStatus
;
804 *Attributes
= *AttribPtr
;
813 FvbProtocolGetPhysicalAddress (
814 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
815 OUT EFI_PHYSICAL_ADDRESS
*Address
821 Retrieves the physical address of the device.
825 This - Calling context
826 Address - Output buffer containing the address.
831 EFI_SUCCESS - Successfully returns
835 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
837 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
839 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
844 FvbProtocolGetBlockSize (
845 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
847 OUT UINTN
*BlockSize
,
848 OUT UINTN
*NumOfBlocks
853 Retrieve the size of a logical block
856 This - Calling context
857 Lba - Indicates which block to return the size for.
858 BlockSize - A pointer to a caller allocated UINTN in which
859 the size of the block is returned
860 NumOfBlocks - a pointer to a caller allocated UINTN in which the
861 number of consecutive blocks starting with Lba is
862 returned. All blocks in this range have a size of
866 EFI_SUCCESS - The firmware volume was read successfully and
867 contents are in Buffer
871 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
873 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
875 return FvbGetLbaAddress (
888 FvbProtocolGetAttributes (
889 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
890 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
895 Retrieves Volume attributes. No polarity translations are done.
898 This - Calling context
899 Attributes - output buffer which contains attributes
902 EFI_SUCCESS - Successfully returns
906 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
908 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
910 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
915 FvbProtocolSetAttributes (
916 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
917 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
922 Sets Volume attributes. No polarity translations are done.
925 This - Calling context
926 Attributes - output buffer which contains attributes
929 EFI_SUCCESS - Successfully returns
933 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
935 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
937 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
942 FvbProtocolEraseBlocks (
943 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
950 The EraseBlock() function erases one or more blocks as denoted by the
951 variable argument list. The entire parameter list of blocks must be verified
952 prior to erasing any blocks. If a block is requested that does not exist
953 within the associated firmware volume (it has a larger index than the last
954 block of the firmware volume), the EraseBlock() function must return
955 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
958 This - Calling context
959 ... - Starting LBA followed by Number of Lba to erase.
960 a -1 to terminate the list.
963 EFI_SUCCESS - The erase request was successfully completed
964 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
965 EFI_DEVICE_ERROR - The block device is not functioning correctly and
966 could not be written. Firmware device may have been
971 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
972 EFI_FW_VOL_INSTANCE
*FwhInstance
;
979 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
981 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
982 ASSERT_EFI_ERROR (Status
);
984 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
986 VA_START (args
, This
);
989 StartingLba
= VA_ARG (args
, EFI_LBA
);
990 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
994 NumOfLba
= VA_ARG (args
, UINT32
);
997 // Check input parameters
999 if ((NumOfLba
== 0) || ((StartingLba
+ NumOfLba
) > NumOfBlocks
)) {
1001 return EFI_INVALID_PARAMETER
;
1007 VA_START (args
, This
);
1009 StartingLba
= VA_ARG (args
, EFI_LBA
);
1010 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
1014 NumOfLba
= VA_ARG (args
, UINT32
);
1016 while (NumOfLba
> 0) {
1017 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
1018 if (EFI_ERROR (Status
)) {
1037 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1040 IN OUT UINTN
*NumBytes
,
1045 Routine Description:
1047 Writes data beginning at Lba:Offset from FV. The write terminates either
1048 when *NumBytes of data have been written, or when a block boundary is
1049 reached. *NumBytes is updated to reflect the actual number of bytes
1050 written. The write opertion does not include erase. This routine will
1051 attempt to write only the specified bytes. If the writes do not stick,
1052 it will return an error.
1055 This - Calling context
1056 Lba - Block in which to begin write
1057 Offset - Offset in the block at which to begin write
1058 NumBytes - On input, indicates the requested write size. On
1059 output, indicates the actual number of bytes written
1060 Buffer - Buffer containing source data for the write.
1063 EFI_SUCCESS - The firmware volume was written successfully
1064 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
1065 NumBytes contains the total number of bytes
1067 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1068 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1069 could not be written
1070 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1075 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1077 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1079 return FvbWriteBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1085 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1088 IN OUT UINTN
*NumBytes
,
1093 Routine Description:
1095 Reads data beginning at Lba:Offset from FV. The Read terminates either
1096 when *NumBytes of data have been read, or when a block boundary is
1097 reached. *NumBytes is updated to reflect the actual number of bytes
1098 written. The write opertion does not include erase. This routine will
1099 attempt to write only the specified bytes. If the writes do not stick,
1100 it will return an error.
1103 This - Calling context
1104 Lba - Block in which to begin Read
1105 Offset - Offset in the block at which to begin Read
1106 NumBytes - On input, indicates the requested write size. On
1107 output, indicates the actual number of bytes Read
1108 Buffer - Buffer containing source data for the Read.
1111 EFI_SUCCESS - The firmware volume was read successfully and
1112 contents are in Buffer
1113 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1114 NumBytes contains the total number of bytes returned
1116 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1117 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1119 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1124 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1126 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1128 return FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1133 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1137 Routine Description:
1138 Check the integrity of firmware volume header
1141 FwVolHeader - A pointer to a firmware volume header
1144 EFI_SUCCESS - The firmware volume is consistent
1145 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1150 UINT16 HeaderLength
;
1154 // Verify the header revision, header signature, length
1155 // Length of FvBlock cannot be 2**64-1
1156 // HeaderLength cannot be an odd number
1158 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1159 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1160 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
1161 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1163 return EFI_NOT_FOUND
;
1166 // Verify the header checksum
1168 HeaderLength
= (UINT16
) (FwVolHeader
->HeaderLength
/ 2);
1169 Ptr
= (UINT16
*) FwVolHeader
;
1171 while (HeaderLength
> 0) {
1172 Checksum
= Checksum
+ (*Ptr
);
1177 if (Checksum
!= 0) {
1178 return EFI_NOT_FOUND
;
1187 IN OUT EFI_PEI_HOB_POINTERS
*HobList
,
1188 OUT EFI_FIRMWARE_VOLUME_HEADER
**FwVolHeader
,
1189 OUT EFI_PHYSICAL_ADDRESS
*BaseAddress OPTIONAL
,
1190 OUT UINT32
*VolumeId OPTIONAL
,
1191 OUT CHAR16
**MappedFile OPTIONAL
,
1192 OUT UINT32
*ActuralSize OPTIONAL
,
1193 OUT UINT32
*Offset OPTIONAL
,
1194 OUT BOOLEAN
*WriteBack OPTIONAL
1198 EFI_FLASH_MAP_FS_ENTRY_DATA
*FlashMapEntry
;
1199 EFI_FLASH_SUBAREA_ENTRY
*FlashMapSubEntry
;
1201 Status
= EFI_SUCCESS
;
1202 *FwVolHeader
= NULL
;
1203 TRY_ASSIGN (WriteBack
, FALSE
);
1205 DEBUG ((EFI_D_INFO
, "Hob start is 0x%x\n", (UINTN
)(*HobList
).Raw
));
1206 (*HobList
).Raw
= GetNextGuidHob (&gEfiFlashMapHobGuid
, (*HobList
).Raw
);
1207 if ((*HobList
).Raw
== NULL
) {
1208 return EFI_NOT_FOUND
;
1211 FlashMapEntry
= (EFI_FLASH_MAP_FS_ENTRY_DATA
*) GET_GUID_HOB_DATA ((*HobList
).Guid
);
1212 FlashMapSubEntry
= &FlashMapEntry
->Entries
[0];
1215 // Check if it is a "FVB" area
1217 if (!CompareGuid (&FlashMapSubEntry
->FileSystem
, &gEfiFirmwareVolumeBlockProtocolGuid
)) {
1221 // Check if it is a "real" flash
1223 if (FlashMapSubEntry
->Attributes
!= (EFI_FLASH_AREA_FV
| EFI_FLASH_AREA_MEMMAPPED_FV
)) {
1227 TRY_ASSIGN (BaseAddress
, FlashMapSubEntry
->Base
);
1230 // Cast buffer to FLASH_AREA_INFO to get extra information related to the special FVB driver
1232 TRY_ASSIGN (VolumeId
, FlashMapEntry
->VolumeId
);
1233 TRY_ASSIGN (ActuralSize
, FlashMapEntry
->ActuralSize
);
1234 TRY_ASSIGN (MappedFile
, ((CHAR16
*) FlashMapEntry
->FilePath
));
1235 TRY_ASSIGN (Offset
, FlashMapEntry
->Offset
);
1239 "FlashMap HOB: BaseAddress = 0x%x, Length = 0x%x, ActuralLength = 0x%x, Offset = 0x%x\n",
1240 (UINTN
) FlashMapSubEntry
->Base
, (UINTN
) FlashMapSubEntry
->Length
,
1241 (UINTN
) FlashMapEntry
->ActuralSize
, (UINTN
) FlashMapEntry
->Offset
1245 "FlashMap HOB: VolumeId = 0x%lx, MappedFile = %s\n",
1246 (UINTN
) FlashMapEntry
->VolumeId
, (UINTN
) FlashMapEntry
->FilePath
1248 *FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) (FlashMapSubEntry
->Base
);
1249 Status
= ValidateFvHeader (*FwVolHeader
);
1250 if (EFI_ERROR (Status
)) {
1254 TRY_ASSIGN (WriteBack
, TRUE
);
1255 Status
= GetFvbInfo (FlashMapSubEntry
->Length
, FwVolHeader
);
1256 DEBUG ((EFI_D_ERROR
, "Fvb: FV header invalid, GetFvbInfo - %r\n", Status
));
1257 ASSERT_EFI_ERROR (Status
);
1265 OnSimpleFileSystemInstall (
1274 EFI_DEVICE_PATH_PROTOCOL
*Device
;
1276 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1278 HandleSize
= sizeof (EFI_HANDLE
);
1279 Status
= gBS
->LocateHandle (
1286 if (Status
== EFI_NOT_FOUND
) {
1289 DEBUG ((EFI_D_ERROR
, "Fwh: New FileSystem Installed!\n"));
1290 ASSERT_EFI_ERROR (Status
);
1292 // Check if this is the storage we care about, and store it in FwhInstance
1294 for (Instance
= 0; Instance
< mFvbModuleGlobal
->NumFv
; ++Instance
) {
1295 Status
= GetFvbInstance (Instance
, mFvbModuleGlobal
, &FwhInstance
, FALSE
);
1296 ASSERT_EFI_ERROR (Status
);
1298 if (FwhInstance
->MappedFile
[0] == L
'\0') {
1300 // The instance of FVB isn't mapped to file.
1305 if ((FwhInstance
->Device
!= NULL
) &&
1306 !EFI_ERROR (CheckStoreExists (FwhInstance
->Device
))
1309 // The instance of FVB has already associated to a device
1310 // and the device is not removed from system.
1313 EFI_D_ERROR
, "Fwh: MappedFile FVB (0x%x:0x%x) - Already mapped, Skip!\n",
1314 (UINTN
) FwhInstance
->FvBase
[FVB_PHYSICAL
],
1315 (UINTN
) FwhInstance
->Offset
1320 Status
= CheckStore (Handle
, FwhInstance
->VolumeId
, &Device
);
1321 if (!EFI_ERROR (Status
)) {
1323 // Write back memory content to file
1325 Status
= FileOpen (Device
, FwhInstance
->MappedFile
, &File
, EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_READ
| EFI_FILE_MODE_CREATE
);
1326 ASSERT_EFI_ERROR (Status
);
1327 if (!EFI_ERROR (Status
)) {
1329 EFI_D_ERROR
, "Fwh: MappedFile FVB (0x%x:0x%x) - Write back to mapped file!\n",
1330 (UINTN
) FwhInstance
->FvBase
[FVB_PHYSICAL
],
1331 (UINTN
) FwhInstance
->Offset
1333 Status
= FileWrite (
1336 FwhInstance
->FvBase
[FVB_PHYSICAL
] + FwhInstance
->Offset
,
1337 FwhInstance
->ActuralSize
- FwhInstance
->Offset
1339 ASSERT_EFI_ERROR (Status
);
1340 if (!EFI_ERROR (Status
)) {
1341 if (FwhInstance
->Device
!= NULL
) {
1342 gBS
->FreePool (FwhInstance
->Device
);
1344 FwhInstance
->Device
= Device
;
1346 EFI_D_ERROR
, "Fwh: MappedFile FVB (0x%x:0x%x) - Mapped!\n",
1347 (UINTN
) FwhInstance
->FvBase
[FVB_PHYSICAL
],
1348 (UINTN
) FwhInstance
->Offset
1359 FvbInstallSfsNotify (
1366 Status
= gBS
->CreateEvent (
1369 OnSimpleFileSystemInstall
,
1373 ASSERT_EFI_ERROR (Status
);
1375 Status
= gBS
->RegisterProtocolNotify (
1376 &gEfiSimpleFileSystemProtocolGuid
,
1380 ASSERT_EFI_ERROR (Status
);
1387 IN EFI_HANDLE ImageHandle
,
1388 IN EFI_SYSTEM_TABLE
*SystemTable
1392 Routine Description:
1393 This function does common initialization for FVB services
1402 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1403 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1404 EFI_PEI_HOB_POINTERS FirmwareVolumeHobList
;
1406 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1408 EFI_HANDLE FwbHandle
;
1409 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1410 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1411 EFI_DEVICE_PATH_PROTOCOL
*TempFwbDevicePath
;
1412 FV_DEVICE_PATH TempFvbDevicePathData
;
1414 EFI_PHYSICAL_ADDRESS BaseAddress
;
1422 BOOLEAN InstallSfsNotify
;
1425 InstallSfsNotify
= FALSE
;
1428 // Allocate runtime services data for global variable, which contains
1429 // the private data of all firmware volume block instances
1431 Status
= gBS
->AllocatePool (
1432 EfiRuntimeServicesData
,
1433 sizeof (ESAL_FWB_GLOBAL
),
1436 ASSERT_EFI_ERROR (Status
);
1438 // Calculate the total size for all firmware volume block instances
1441 FirmwareVolumeHobList
.Raw
= GetHobList();
1443 Status
= GetFvbHeader (&FirmwareVolumeHobList
, &FwVolHeader
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1444 if (EFI_ERROR (Status
)) {
1447 FirmwareVolumeHobList
.Raw
= GET_NEXT_HOB (FirmwareVolumeHobList
);
1450 BufferSize
+= (FwVolHeader
->HeaderLength
+ sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1455 // Only need to allocate once. There is only one copy of physical memory for
1456 // the private data of each FV instance. But in virtual mode or in physical
1457 // mode, the address of the the physical memory may be different.
1459 Status
= gBS
->AllocatePool (
1460 EfiRuntimeServicesData
,
1462 &mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
]
1464 ASSERT_EFI_ERROR (Status
);
1467 // Make a virtual copy of the FvInstance pointer.
1469 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1470 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1472 mFvbModuleGlobal
->NumFv
= 0;
1473 FirmwareVolumeHobList
.Raw
= GetHobList();
1477 // Fill in the private data of each firmware volume block instance
1480 Status
= GetFvbHeader (
1481 &FirmwareVolumeHobList
, &FwVolHeader
,
1482 &BaseAddress
, &VolumeId
, &MappedFile
, &ActuralSize
, &Offset
,
1485 if (EFI_ERROR (Status
)) {
1488 FirmwareVolumeHobList
.Raw
= GET_NEXT_HOB (FirmwareVolumeHobList
);
1494 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1495 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1497 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1498 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1499 FwhInstance
->Device
= NULL
;
1500 FwhInstance
->Offset
= Offset
;
1502 if (*MappedFile
!= '\0') {
1503 FwhInstance
->VolumeId
= VolumeId
;
1504 FwhInstance
->ActuralSize
= ActuralSize
;
1505 StrCpy (FwhInstance
->MappedFile
, MappedFile
);
1507 InstallSfsNotify
= TRUE
;
1509 FwhInstance
->VolumeId
= (UINT32
) -1;
1510 FwhInstance
->ActuralSize
= (UINT32
) -1;
1511 FwhInstance
->MappedFile
[0] = L
'\0';
1514 DEBUG ((EFI_D_INFO
, "FirmVolume Found! BaseAddress=0x%lx, VolumeId=0x%x, MappedFile=%s, Size=0x%x\n",
1515 (UINTN
) BaseAddress
, VolumeId
, MappedFile
, ActuralSize
));
1517 // We may expose readonly FVB in future.
1519 FwhInstance
->WriteEnabled
= TRUE
; // Ken: Why enable write?
1520 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1522 LbaAddress
= (UINTN
) FwhInstance
->FvBase
[0];
1525 if (FwhInstance
->WriteEnabled
) {
1526 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1528 LbaAddress
+= PtrBlockMapEntry
->NumBlocks
* PtrBlockMapEntry
->Length
;
1530 // Get the maximum size of a block. The size will be used to allocate
1531 // buffer for Scratch space, the intermediate buffer for FVB extension
1534 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
1535 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1538 NumOfBlocks
+= PtrBlockMapEntry
->NumBlocks
;
1541 // Write back a healthy FV header
1544 Status
= FlashFdErase (
1545 (UINTN
) FwhInstance
->FvBase
[0],
1547 FwVolHeader
->BlockMap
->Length
1550 HeaderLength
= (UINTN
) FwVolHeader
->HeaderLength
;
1552 Status
= FlashFdWrite (
1553 (UINTN
) FwhInstance
->FvBase
[0],
1555 (UINTN
*) &HeaderLength
,
1556 (UINT8
*) FwVolHeader
1559 FwVolHeader
->HeaderLength
= (UINT16
) HeaderLength
;
1561 DEBUG ((EFI_D_ERROR
, "Fvb (0x%x): FV header invalid, write back - %r\n", (UINTN
) FwhInstance
->FvBase
[0], Status
));
1565 // The total number of blocks in the FV.
1567 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1570 // Add a FVB Protocol Instance
1572 Status
= gBS
->AllocatePool (
1573 EfiRuntimeServicesData
,
1574 sizeof (EFI_FW_VOL_BLOCK_DEVICE
),
1577 ASSERT_EFI_ERROR (Status
);
1579 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1581 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1582 mFvbModuleGlobal
->NumFv
++;
1585 // Set up the devicepath
1587 FvbDevice
->DevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
1588 FvbDevice
->DevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ (FwVolHeader
->FvLength
- 1);
1591 // Find a handle with a matching device path that has supports FW Block protocol
1593 TempFwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) &TempFvbDevicePathData
;
1594 CopyMem (TempFwbDevicePath
, &FvbDevice
->DevicePath
, sizeof (FV_DEVICE_PATH
));
1595 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &TempFwbDevicePath
, &FwbHandle
);
1596 if (EFI_ERROR (Status
)) {
1598 // LocateDevicePath fails so install a new interface and device path
1601 Status
= gBS
->InstallMultipleProtocolInterfaces (
1603 &gEfiFirmwareVolumeBlockProtocolGuid
,
1604 &FvbDevice
->FwVolBlockInstance
,
1605 &gEfiDevicePathProtocolGuid
,
1606 &FvbDevice
->DevicePath
,
1609 ASSERT_EFI_ERROR (Status
);
1610 } else if (IsDevicePathEnd (TempFwbDevicePath
)) {
1612 // Device allready exists, so reinstall the FVB protocol
1614 Status
= gBS
->HandleProtocol (
1616 &gEfiFirmwareVolumeBlockProtocolGuid
,
1619 ASSERT_EFI_ERROR (Status
);
1621 Status
= gBS
->ReinstallProtocolInterface (
1623 &gEfiFirmwareVolumeBlockProtocolGuid
,
1625 &FvbDevice
->FwVolBlockInstance
1627 ASSERT_EFI_ERROR (Status
);
1631 // There was a FVB protocol on an End Device Path node
1636 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1638 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1639 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1644 // Allocate for scratch space, an intermediate buffer for FVB extention
1646 Status
= gBS
->AllocatePool (
1647 EfiRuntimeServicesData
,
1649 &mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
]
1651 ASSERT_EFI_ERROR (Status
);
1653 mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
] = mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
];
1655 if (InstallSfsNotify
) {
1656 FvbInstallSfsNotify ();