3 Copyright (c) 2013-2016 Intel Corporation.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "FwBlockService.h"
12 ESAL_FWB_GLOBAL
*mFvbModuleGlobal
;
14 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
15 FVB_DEVICE_SIGNATURE
, // Signature
17 // FV_DEVICE_PATH FvDevicePath
25 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
)),
26 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
) >> 8)
30 (EFI_PHYSICAL_ADDRESS
) 0,
31 (EFI_PHYSICAL_ADDRESS
) 0
35 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
37 END_DEVICE_PATH_LENGTH
,
43 // UEFI_FV_DEVICE_PATH UefiFvDevicePath
51 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
)),
52 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
) >> 8)
59 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
61 END_DEVICE_PATH_LENGTH
,
68 // EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance
71 FvbProtocolGetAttributes
,
72 FvbProtocolSetAttributes
,
73 FvbProtocolGetPhysicalAddress
,
74 FvbProtocolGetBlockSize
,
77 FvbProtocolEraseBlocks
,
82 UINT32 mInSmmMode
= 0;
83 EFI_SMM_SYSTEM_TABLE2
* mSmst
= NULL
;
86 PublishFlashDeviceInfo (
87 IN SPI_INIT_TABLE
*Found
93 Publish info on found flash device to other drivers via PcdSpiFlashDeviceSize.
96 Found - Pointer to entry in mSpiInitTable for found flash part.
106 // Publish Byte Size of found flash device.
108 Status
= PcdSet32S (PcdSpiFlashDeviceSize
, (UINT32
)(Found
->BiosStartOffset
+ Found
->BiosSize
));
109 ASSERT_EFI_ERROR (Status
);
113 FvbVirtualddressChangeEvent (
121 Fixup internal data so that EFI and SAL can be call in virtual mode.
122 Call the passed in Child Notify event and convert the mFvbModuleGlobal
123 date items to there virtual address.
125 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
126 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
131 (Standard EFI notify event - EFI_EVENT_NOTIFY)
139 EFI_FW_VOL_INSTANCE
*FwhInstance
;
142 gRT
->ConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
145 // Convert the base address of all the instances
148 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
149 while (Index
< mFvbModuleGlobal
->NumFv
) {
151 gRT
->ConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &FwhInstance
->FvBase
[FVB_VIRTUAL
]);
153 // SpiWrite and SpiErase always use Physical Address instead of
154 // Virtual Address, even in Runtime. So we need not convert pointer
155 // for FvWriteBase[FVB_VIRTUAL]
157 // EfiConvertPointer (0, (VOID **) &FwhInstance->FvWriteBase[FVB_VIRTUAL]);
159 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
161 (UINTN
) ((UINT8
*) FwhInstance
) + FwhInstance
->VolumeHeader
.HeaderLength
+
162 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
167 gRT
->ConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
]);
169 // Convert SPI_PROTOCOL instance for runtime
171 gRT
->ConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &mFvbModuleGlobal
->SpiProtocol
);
172 gRT
->ConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &mFvbModuleGlobal
);
181 MmioWrite8 ((UINTN
)Dest
, Byte
);
189 IN ESAL_FWB_GLOBAL
*Global
,
190 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
196 Retrieves the physical address of a memory mapped FV
199 Instance - The FV instance whose base address is going to be
201 Global - Pointer to ESAL_FWB_GLOBAL that contains all
203 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
204 Virtual - Whether CPU is in virtual or physical mode
207 EFI_SUCCESS - Successfully returns
208 EFI_INVALID_PARAMETER - Instance not found
212 EFI_FW_VOL_INSTANCE
*FwhRecord
;
214 if (Instance
>= Global
->NumFv
) {
215 return EFI_INVALID_PARAMETER
;
218 // Find the right instance of the FVB private data
220 FwhRecord
= Global
->FvInstance
[Virtual
];
221 while (Instance
> 0) {
222 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
224 (UINTN
) ((UINT8
*) FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
225 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
230 *FwhInstance
= FwhRecord
;
236 FvbGetPhysicalAddress (
238 OUT EFI_PHYSICAL_ADDRESS
*Address
,
239 IN ESAL_FWB_GLOBAL
*Global
,
245 Retrieves the physical address of a memory mapped FV
248 Instance - The FV instance whose base address is going to be
250 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
251 that on successful return, contains the base address
252 of the firmware volume.
253 Global - Pointer to ESAL_FWB_GLOBAL that contains all
255 Virtual - Whether CPU is in virtual or physical mode
258 EFI_SUCCESS - Successfully returns
259 EFI_INVALID_PARAMETER - Instance not found
263 EFI_FW_VOL_INSTANCE
*FwhInstance
;
269 // Find the right instance of the FVB private data
271 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
272 ASSERT_EFI_ERROR (Status
);
273 *Address
= FwhInstance
->FvBase
[Virtual
];
279 FvbGetVolumeAttributes (
281 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
282 IN ESAL_FWB_GLOBAL
*Global
,
288 Retrieves attributes, insures positive polarity of attribute bits, returns
289 resulting attributes in output parameter
292 Instance - The FV instance whose attributes is going to be
294 Attributes - Output buffer which contains attributes
295 Global - Pointer to ESAL_FWB_GLOBAL that contains all
297 Virtual - Whether CPU is in virtual or physical mode
300 EFI_SUCCESS - Successfully returns
301 EFI_INVALID_PARAMETER - Instance not found
305 EFI_FW_VOL_INSTANCE
*FwhInstance
;
311 // Find the right instance of the FVB private data
313 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
314 ASSERT_EFI_ERROR (Status
);
315 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
324 OUT UINTN
*LbaAddress
,
325 OUT UINTN
*LbaWriteAddress
,
326 OUT UINTN
*LbaLength
,
327 OUT UINTN
*NumOfBlocks
,
328 IN ESAL_FWB_GLOBAL
*Global
,
334 Retrieves the starting address of an LBA in an FV
337 Instance - The FV instance which the Lba belongs to
338 Lba - The logical block address
339 LbaAddress - On output, contains the physical starting address
341 LbaWriteAddress - On output, contains the physical starting address
342 of the Lba for writing
343 LbaLength - On output, contains the length of the block
344 NumOfBlocks - A pointer to a caller allocated UINTN in which the
345 number of consecutive blocks starting with Lba is
346 returned. All blocks in this range have a size of
348 Global - Pointer to ESAL_FWB_GLOBAL that contains all
350 Virtual - Whether CPU is in virtual or physical mode
353 EFI_SUCCESS - Successfully returns
354 EFI_INVALID_PARAMETER - Instance not found
363 EFI_FW_VOL_INSTANCE
*FwhInstance
;
364 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
370 // Find the right instance of the FVB private data
372 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
373 ASSERT_EFI_ERROR (Status
);
377 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
380 // Parse the blockmap of the FV to find which map entry the Lba belongs to
383 NumBlocks
= BlockMap
->NumBlocks
;
384 BlockLength
= BlockMap
->Length
;
386 if ((NumBlocks
== 0) || (BlockLength
== 0)) {
387 return EFI_INVALID_PARAMETER
;
390 NextLba
= StartLba
+ NumBlocks
;
393 // The map entry found
395 if (Lba
>= StartLba
&& Lba
< NextLba
) {
396 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
398 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
401 if (LbaWriteAddress
) {
402 *LbaWriteAddress
= FwhInstance
->FvWriteBase
[Virtual
] + Offset
;
406 *LbaLength
= BlockLength
;
410 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
417 Offset
= Offset
+ NumBlocks
* BlockLength
;
426 IN UINTN BlockOffset
,
427 IN OUT UINTN
*NumBytes
,
429 IN ESAL_FWB_GLOBAL
*Global
,
435 Reads specified number of bytes into a buffer from the specified block
438 Instance - The FV instance to be read from
439 Lba - The logical block address to be read from
440 BlockOffset - Offset into the block at which to begin reading
441 NumBytes - Pointer that on input contains the total size of
442 the buffer. On output, it contains the total number
444 Buffer - Pointer to a caller allocated buffer that will be
445 used to hold the data read
446 Global - Pointer to ESAL_FWB_GLOBAL that contains all
448 Virtual - Whether CPU is in virtual or physical mode
451 EFI_SUCCESS - The firmware volume was read successfully and
452 contents are in Buffer
453 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
454 NumBytes contains the total number of bytes returned
456 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
457 EFI_DEVICE_ERROR - The block device is not functioning correctly and
459 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
463 EFI_FVB_ATTRIBUTES_2 Attributes
;
469 // Check for invalid conditions
471 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
472 return EFI_INVALID_PARAMETER
;
475 if (*NumBytes
== 0) {
476 return EFI_INVALID_PARAMETER
;
479 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, NULL
, &LbaLength
, NULL
, Global
, Virtual
);
480 if (EFI_ERROR (Status
)) {
484 // Check if the FV is read enabled
486 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
488 if ((Attributes
& EFI_FVB2_READ_STATUS
) == 0) {
489 return EFI_ACCESS_DENIED
;
492 // Perform boundary checks and adjust NumBytes
494 if (BlockOffset
> LbaLength
) {
495 return EFI_INVALID_PARAMETER
;
498 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
499 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
500 Status
= EFI_BAD_BUFFER_SIZE
;
503 MmioReadBuffer8 (LbaAddress
+ BlockOffset
, (UINTN
) *NumBytes
, Buffer
);
510 IN UINTN WriteAddress
,
512 IN OUT UINTN
*NumBytes
,
519 Writes specified number of bytes from the input buffer to the address
529 Status
= EFI_SUCCESS
;
532 // TODO: Suggested that this code be "critical section"
534 WriteAddress
-= ( PcdGet32 (PcdFlashAreaBaseAddress
) );
535 if (mInSmmMode
== 0) { // !(EfiInManagementInterrupt ())) {
536 Status
= mFvbModuleGlobal
->SpiProtocol
->Execute (
537 mFvbModuleGlobal
->SpiProtocol
,
538 SPI_OPCODE_WRITE_INDEX
, // OpcodeIndex
539 0, // PrefixOpcodeIndex
543 WriteAddress
, // Address
544 (UINT32
) (*NumBytes
), // Data Number
550 Status
= mFvbModuleGlobal
->SmmSpiProtocol
->Execute (
551 mFvbModuleGlobal
->SmmSpiProtocol
,
552 SPI_OPCODE_WRITE_INDEX
, // OpcodeIndex
553 0, // PrefixOpcodeIndex
557 WriteAddress
, // Address
558 (UINT32
) (*NumBytes
), // Data Number
571 IN UINTN WriteAddress
,
578 Erase a certain block from address LbaWriteAddress
588 WriteAddress
-= (PcdGet32 (PcdFlashAreaBaseAddress
));
589 if (mInSmmMode
== 0 ) { // !(EfiInManagementInterrupt ())) {
590 Status
= mFvbModuleGlobal
->SpiProtocol
->Execute (
591 mFvbModuleGlobal
->SpiProtocol
,
592 SPI_OPCODE_ERASE_INDEX
, // OpcodeIndex
593 0, // PrefixOpcodeIndex
597 WriteAddress
, // Address
600 EnumSpiRegionBios
// SPI_REGION_TYPE
603 Status
= mFvbModuleGlobal
->SmmSpiProtocol
->Execute (
604 mFvbModuleGlobal
->SmmSpiProtocol
,
605 SPI_OPCODE_ERASE_INDEX
, // OpcodeIndex
606 0, // PrefixOpcodeIndex
610 WriteAddress
, // Address
613 EnumSpiRegionBios
// SPI_REGION_TYPE
626 IN UINTN BlockOffset
,
627 IN OUT UINTN
*NumBytes
,
629 IN ESAL_FWB_GLOBAL
*Global
,
635 Writes specified number of bytes from the input buffer to the block
638 Instance - The FV instance to be written to
639 Lba - The starting logical block index to write to
640 BlockOffset - Offset into the block at which to begin writing
641 NumBytes - Pointer that on input contains the total size of
642 the buffer. On output, it contains the total number
643 of bytes actually written
644 Buffer - Pointer to a caller allocated buffer that contains
645 the source for the write
646 Global - Pointer to ESAL_FWB_GLOBAL that contains all
648 Virtual - Whether CPU is in virtual or physical mode
651 EFI_SUCCESS - The firmware volume was written successfully
652 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
653 NumBytes contains the total number of bytes
655 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
656 EFI_DEVICE_ERROR - The block device is not functioning correctly and
658 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
662 EFI_FVB_ATTRIBUTES_2 Attributes
;
664 UINTN LbaWriteAddress
;
666 EFI_FW_VOL_INSTANCE
*FwhInstance
;
668 EFI_STATUS ReturnStatus
;
673 // Find the right instance of the FVB private data
675 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
676 ASSERT_EFI_ERROR (Status
);
679 // Writes are enabled in the init routine itself
681 if (!FwhInstance
->WriteEnabled
) {
682 return EFI_ACCESS_DENIED
;
685 // Check for invalid conditions
687 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
688 return EFI_INVALID_PARAMETER
;
691 if (*NumBytes
== 0) {
692 return EFI_INVALID_PARAMETER
;
695 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaWriteAddress
, &LbaLength
, NULL
, Global
, Virtual
);
696 if (EFI_ERROR (Status
)) {
700 // Check if the FV is write enabled
702 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
704 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
705 return EFI_ACCESS_DENIED
;
708 // Perform boundary checks and adjust NumBytes
710 if (BlockOffset
> LbaLength
) {
711 return EFI_INVALID_PARAMETER
;
714 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
715 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
716 Status
= EFI_BAD_BUFFER_SIZE
;
719 ReturnStatus
= FlashFdWrite (
720 LbaWriteAddress
+ BlockOffset
,
726 if (EFI_ERROR (ReturnStatus
)) {
737 IN ESAL_FWB_GLOBAL
*Global
,
743 Erases and initializes a firmware volume block
746 Instance - The FV instance to be erased
747 Lba - The logical block index to be erased
748 Global - Pointer to ESAL_FWB_GLOBAL that contains all
750 Virtual - Whether CPU is in virtual or physical mode
753 EFI_SUCCESS - The erase request was successfully completed
754 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
755 EFI_DEVICE_ERROR - The block device is not functioning correctly and
756 could not be written. Firmware device may have been
758 EFI_INVALID_PARAMETER - Instance not found
763 EFI_FVB_ATTRIBUTES_2 Attributes
;
765 UINTN LbaWriteAddress
;
766 EFI_FW_VOL_INSTANCE
*FwhInstance
;
775 // Find the right instance of the FVB private data
777 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
778 ASSERT_EFI_ERROR (Status
);
781 // Writes are enabled in the init routine itself
783 if (!FwhInstance
->WriteEnabled
) {
784 return EFI_ACCESS_DENIED
;
787 // Check if the FV is write enabled
789 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
791 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
792 return EFI_ACCESS_DENIED
;
795 // Get the starting address of the block for erase. For debug reasons,
796 // LbaWriteAddress may not be the same as LbaAddress.
798 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaWriteAddress
, &LbaLength
, NULL
, Global
, Virtual
);
799 if (EFI_ERROR (Status
)) {
803 SectorNum
= LbaLength
/ SPI_ERASE_SECTOR_SIZE
;
804 for (Index
= 0; Index
< SectorNum
; Index
++){
805 Status
= FlashFdErase (
806 LbaWriteAddress
+ Index
* SPI_ERASE_SECTOR_SIZE
,
808 SPI_ERASE_SECTOR_SIZE
810 if (Status
!= EFI_SUCCESS
){
819 FvbEraseCustomBlockRange (
822 IN UINTN OffsetStartLba
,
824 IN UINTN OffsetLastLba
,
825 IN ESAL_FWB_GLOBAL
*Global
,
831 Erases and initializes a specified range of a firmware volume
834 Instance - The FV instance to be erased
835 StartLba - The starting logical block index to be erased
836 OffsetStartLba - Offset into the starting block at which to
838 LastLba - The last logical block index to be erased
839 OffsetStartLba - Offset into the last block at which to end erasing
840 Global - Pointer to ESAL_FWB_GLOBAL that contains all
842 Virtual - Whether CPU is in virtual or physical mode
845 EFI_SUCCESS - The firmware volume was erased successfully
846 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
847 EFI_DEVICE_ERROR - The block device is not functioning correctly and
848 could not be written. Firmware device may have been
850 EFI_INVALID_PARAMETER - Instance not found
856 UINTN ScratchLbaSizeData
;
861 FvbGetLbaAddress (Instance
, StartLba
, NULL
, NULL
, &LbaSize
, NULL
, Global
, Virtual
);
864 // Use the scratch space as the intermediate buffer to transfer data
865 // Back up the first LBA in scratch space.
867 FvbReadBlock (Instance
, StartLba
, 0, &LbaSize
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
872 FvbEraseBlock (Instance
, StartLba
, Global
, Virtual
);
873 ScratchLbaSizeData
= OffsetStartLba
;
876 // write the data back to the first block
878 if (ScratchLbaSizeData
> 0) {
879 FvbWriteBlock (Instance
, StartLba
, 0, &ScratchLbaSizeData
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
884 if (LastLba
> (StartLba
+ 1)) {
885 for (Index
= (StartLba
+ 1); Index
<= (LastLba
- 1); Index
++) {
886 FvbEraseBlock (Instance
, Index
, Global
, Virtual
);
890 // Last LBAs, the same as first LBAs
892 if (LastLba
> StartLba
) {
893 FvbGetLbaAddress (Instance
, LastLba
, NULL
, NULL
, &LbaSize
, NULL
, Global
, Virtual
);
894 FvbReadBlock (Instance
, LastLba
, 0, &LbaSize
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
895 FvbEraseBlock (Instance
, LastLba
, Global
, Virtual
);
898 ScratchLbaSizeData
= LbaSize
- (OffsetStartLba
+ 1);
900 return FvbWriteBlock (
905 Global
->FvbScratchSpace
[Virtual
],
912 FvbSetVolumeAttributes (
914 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
915 IN ESAL_FWB_GLOBAL
*Global
,
921 Modifies the current settings of the firmware volume according to the
922 input parameter, and returns the new setting of the volume
925 Instance - The FV instance whose attributes is going to be
927 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
928 containing the desired firmware volume settings.
929 On successful return, it contains the new settings
930 of the firmware volume
931 Global - Pointer to ESAL_FWB_GLOBAL that contains all
933 Virtual - Whether CPU is in virtual or physical mode
936 EFI_SUCCESS - Successfully returns
937 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
938 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
939 in conflict with the capabilities as declared in the
940 firmware volume header
944 EFI_FW_VOL_INSTANCE
*FwhInstance
;
945 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
946 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
955 // Find the right instance of the FVB private data
957 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
958 ASSERT_EFI_ERROR (Status
);
960 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
961 OldAttributes
= *AttribPtr
;
962 Capabilities
= OldAttributes
& EFI_FVB2_CAPABILITIES
;
963 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
964 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
967 // If firmware volume is locked, no status bit can be updated
969 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
970 if (OldStatus
^ NewStatus
) {
971 return EFI_ACCESS_DENIED
;
977 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
978 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
979 return EFI_INVALID_PARAMETER
;
985 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
986 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
987 return EFI_INVALID_PARAMETER
;
991 // Test write disable
993 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
994 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
995 return EFI_INVALID_PARAMETER
;
1001 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
1002 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
1003 return EFI_INVALID_PARAMETER
;
1009 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
1010 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
1011 return EFI_INVALID_PARAMETER
;
1015 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
1016 *AttribPtr
= (*AttribPtr
) | NewStatus
;
1017 *Attributes
= *AttribPtr
;
1022 // FVB protocol APIs
1026 FvbProtocolGetPhysicalAddress (
1027 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1028 OUT EFI_PHYSICAL_ADDRESS
*Address
1032 Routine Description:
1034 Retrieves the physical address of the device.
1038 This - Calling context
1039 Address - Output buffer containing the address.
1044 EFI_SUCCESS - Successfully returns
1048 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1050 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1052 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
1056 FvbProtocolGetBlockSize (
1057 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1059 OUT UINTN
*BlockSize
,
1060 OUT UINTN
*NumOfBlocks
1064 Routine Description:
1065 Retrieve the size of a logical block
1068 This - Calling context
1069 Lba - Indicates which block to return the size for.
1070 BlockSize - A pointer to a caller allocated UINTN in which
1071 the size of the block is returned
1072 NumOfBlocks - a pointer to a caller allocated UINTN in which the
1073 number of consecutive blocks starting with Lba is
1074 returned. All blocks in this range have a size of
1078 EFI_SUCCESS - The firmware volume was read successfully and
1079 contents are in Buffer
1083 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1085 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1087 return FvbGetLbaAddress (
1088 FvbDevice
->Instance
,
1101 FvbProtocolGetAttributes (
1102 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1103 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
1107 Routine Description:
1108 Retrieves Volume attributes. No polarity translations are done.
1111 This - Calling context
1112 Attributes - output buffer which contains attributes
1115 EFI_SUCCESS - Successfully returns
1119 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1121 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1123 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
1128 FvbProtocolSetAttributes (
1129 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1130 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
1134 Routine Description:
1135 Sets Volume attributes. No polarity translations are done.
1138 This - Calling context
1139 Attributes - output buffer which contains attributes
1142 EFI_SUCCESS - Successfully returns
1146 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1148 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1150 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
1155 FvbProtocolEraseBlocks (
1156 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1161 Routine Description:
1163 The EraseBlock() function erases one or more blocks as denoted by the
1164 variable argument list. The entire parameter list of blocks must be verified
1165 prior to erasing any blocks. If a block is requested that does not exist
1166 within the associated firmware volume (it has a larger index than the last
1167 block of the firmware volume), the EraseBlock() function must return
1168 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
1171 This - Calling context
1172 ... - Starting LBA followed by Number of Lba to erase.
1173 a -1 to terminate the list.
1176 EFI_SUCCESS - The erase request was successfully completed
1177 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1178 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1179 could not be written. Firmware device may have been
1184 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1185 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1188 EFI_LBA StartingLba
;
1193 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1195 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
1196 ASSERT_EFI_ERROR (Status
);
1198 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
1200 VA_START (args
, This
);
1203 StartingLba
= VA_ARG (args
, EFI_LBA
);
1204 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
1208 NumOfLba
= VA_ARG (args
, UINTN
);
1211 // Check input parameters
1213 if (NumOfLba
== 0) {
1215 return EFI_INVALID_PARAMETER
;
1218 if ((StartingLba
+ NumOfLba
) > NumOfBlocks
) {
1219 return EFI_INVALID_PARAMETER
;
1225 VA_START (args
, This
);
1227 StartingLba
= VA_ARG (args
, EFI_LBA
);
1228 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
1232 NumOfLba
= VA_ARG (args
, UINTN
);
1234 while (NumOfLba
> 0) {
1235 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
1236 if (EFI_ERROR (Status
)) {
1255 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1258 IN OUT UINTN
*NumBytes
,
1263 Routine Description:
1265 Writes data beginning at Lba:Offset from FV. The write terminates either
1266 when *NumBytes of data have been written, or when a block boundary is
1267 reached. *NumBytes is updated to reflect the actual number of bytes
1268 written. The write opertion does not include erase. This routine will
1269 attempt to write only the specified bytes. If the writes do not stick,
1270 it will return an error.
1273 This - Calling context
1274 Lba - Block in which to begin write
1275 Offset - Offset in the block at which to begin write
1276 NumBytes - On input, indicates the requested write size. On
1277 output, indicates the actual number of bytes written
1278 Buffer - Buffer containing source data for the write.
1281 EFI_SUCCESS - The firmware volume was written successfully
1282 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
1283 NumBytes contains the total number of bytes
1285 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1286 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1287 could not be written
1288 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1293 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1295 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1297 return FvbWriteBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1303 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1306 IN OUT UINTN
*NumBytes
,
1311 Routine Description:
1313 Reads data beginning at Lba:Offset from FV. The Read terminates either
1314 when *NumBytes of data have been read, or when a block boundary is
1315 reached. *NumBytes is updated to reflect the actual number of bytes
1316 written. The write opertion does not include erase. This routine will
1317 attempt to write only the specified bytes. If the writes do not stick,
1318 it will return an error.
1321 This - Calling context
1322 Lba - Block in which to begin Read
1323 Offset - Offset in the block at which to begin Read
1324 NumBytes - On input, indicates the requested write size. On
1325 output, indicates the actual number of bytes Read
1326 Buffer - Buffer containing source data for the Read.
1329 EFI_SUCCESS - The firmware volume was read successfully and
1330 contents are in Buffer
1331 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1332 NumBytes contains the total number of bytes returned
1334 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1335 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1337 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1342 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1345 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1346 Status
= FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1353 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1357 Routine Description:
1358 Check the integrity of firmware volume header
1361 FwVolHeader - A pointer to a firmware volume header
1364 EFI_SUCCESS - The firmware volume is consistent
1365 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1370 UINT16 HeaderLength
;
1374 // Verify the header revision, header signature, length
1375 // Length of FvBlock cannot be 2**64-1
1376 // HeaderLength cannot be an odd number
1379 if (((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) && (FwVolHeader
->Revision
!= EFI_FVH_REVISION
)) ||
1381 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1383 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1384 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
1385 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1387 return EFI_NOT_FOUND
;
1390 // Verify the header checksum
1392 HeaderLength
= (UINT16
) (FwVolHeader
->HeaderLength
/ 2);
1393 Ptr
= (UINT16
*) FwVolHeader
;
1395 while (HeaderLength
> 0) {
1396 Checksum
= Checksum
+ (*Ptr
);
1401 if (Checksum
!= 0) {
1402 return EFI_NOT_FOUND
;
1411 OUT EFI_FIRMWARE_VOLUME_HEADER
**FwVolHeader
,
1412 OUT EFI_PHYSICAL_ADDRESS
*BaseAddress
,
1413 OUT BOOLEAN
*WriteBack
1418 Status
= EFI_SUCCESS
;
1421 if (*FwVolHeader
== NULL
) {
1422 *BaseAddress
= PcdGet32 (PcdFlashFvRecoveryBase
);
1423 } else if (*FwVolHeader
== (VOID
*)(UINTN
)PcdGet32 (PcdFlashFvRecoveryBase
)) {
1424 *BaseAddress
= PcdGet32 (PcdFlashFvMainBase
);
1425 } else if (*FwVolHeader
== (VOID
*)(UINTN
)PcdGet32 (PcdFlashFvMainBase
)) {
1426 *BaseAddress
= PcdGet32 (PcdFlashNvStorageVariableBase
);
1428 return EFI_NOT_FOUND
;
1431 DEBUG((EFI_D_INFO
, "Fvb base : %08x\n",*BaseAddress
));
1433 *FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) (*BaseAddress
);
1434 Status
= ValidateFvHeader (*FwVolHeader
);
1435 if (EFI_ERROR (Status
)) {
1441 Status
= GetFvbInfo (*BaseAddress
, FwVolHeader
);
1442 DEBUG(( DEBUG_ERROR
, "Through GetFvbInfo: %08x!\n",*BaseAddress
));
1444 ASSERT_EFI_ERROR (Status
);
1462 // Obtain a handle for ICH SPI Protocol
1464 ASSERT(mSmst
!= NULL
);
1465 if (mFvbModuleGlobal
->SmmSpiProtocol
== NULL
){
1466 Status
= mSmst
->SmmLocateProtocol (&gEfiSmmSpiProtocolGuid
, NULL
, (VOID
**) &mFvbModuleGlobal
->SmmSpiProtocol
);
1467 ASSERT_EFI_ERROR(Status
);
1470 // attempt to identify flash part and initialize spi table
1472 for (FlashIndex
= 0; FlashIndex
< EnumSpiFlashMax
; FlashIndex
++) {
1473 Status
= mFvbModuleGlobal
->SmmSpiProtocol
->Init (
1474 mFvbModuleGlobal
->SmmSpiProtocol
,
1475 &(mSpiInitTable
[FlashIndex
])
1477 if (!EFI_ERROR (Status
)) {
1479 // read vendor/device IDs to check if flash device is supported
1481 Status
= mFvbModuleGlobal
->SmmSpiProtocol
->Execute (
1482 mFvbModuleGlobal
->SmmSpiProtocol
,
1483 SPI_OPCODE_JEDEC_ID_INDEX
,
1493 if (!EFI_ERROR (Status
)) {
1494 if (((FlashID
[0] == mSpiInitTable
[FlashIndex
].VendorId
) &&
1495 (FlashID
[2] == mSpiInitTable
[FlashIndex
].DeviceId1
)) ||
1496 ((FlashID
[0] == SPI_AT26DF321_ID1
) &&
1497 (FlashID
[0] == mSpiInitTable
[FlashIndex
].VendorId
) &&
1498 (FlashID
[1] == mSpiInitTable
[FlashIndex
].DeviceId0
))) {
1500 // Supported SPI device found
1504 "Smm Mode: Supported SPI Flash device found, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1515 if (FlashIndex
>= EnumSpiFlashMax
) {
1516 Status
= EFI_UNSUPPORTED
;
1519 "ERROR - Unknown SPI Flash Device, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1524 ASSERT_EFI_ERROR (Status
);
1528 Status
= mFvbModuleGlobal
->SmmSpiProtocol
->Execute (
1529 mFvbModuleGlobal
->SmmSpiProtocol
,
1530 SPI_OPCODE_WRITE_S_INDEX
, // OpcodeIndex
1531 1, // PrefixOpcodeIndex
1538 EnumSpiRegionAll
// SPI_REGION_TYPE
1544 SmmSpiNotificationFunction (
1545 IN CONST EFI_GUID
*Protocol
,
1547 IN EFI_HANDLE Handle
1550 return SmmSpiInit();
1557 IN EFI_HANDLE ImageHandle
,
1558 IN EFI_SYSTEM_TABLE
*SystemTable
,
1559 OUT EFI_DEVICE_PATH_PROTOCOL
**CompleteFilePath
1563 Routine Description:
1565 Function is used to get the full device path for this driver.
1569 ImageHandle - The loaded image handle of this driver.
1570 SystemTable - The pointer of system table.
1571 CompleteFilePath - The pointer of returned full file path
1580 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
1581 EFI_DEVICE_PATH_PROTOCOL
*ImageDevicePath
;
1584 Status
= gBS
->HandleProtocol (
1586 &gEfiLoadedImageProtocolGuid
,
1587 (VOID
**) &LoadedImage
1589 ASSERT_EFI_ERROR (Status
);
1591 Status
= gBS
->HandleProtocol (
1592 LoadedImage
->DeviceHandle
,
1593 &gEfiDevicePathProtocolGuid
,
1594 (VOID
*) &ImageDevicePath
1596 ASSERT_EFI_ERROR (Status
);
1598 *CompleteFilePath
= AppendDevicePath (
1600 LoadedImage
->FilePath
1610 IN EFI_HANDLE ImageHandle
,
1611 IN EFI_SYSTEM_TABLE
*SystemTable
1615 Routine Description:
1616 This function does common initialization for FVB services
1625 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1626 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1627 EFI_FIRMWARE_VOLUME_HEADER
*TempFwVolHeader
;
1629 VOID
*FirmwareVolumeHobList
;
1631 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1632 BOOLEAN WriteEnabled
;
1633 BOOLEAN WriteLocked
;
1634 EFI_HANDLE FwbHandle
;
1635 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1636 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1637 EFI_DEVICE_PATH_PROTOCOL
*FwbDevicePath
;
1638 EFI_DEVICE_PATH_PROTOCOL
*TempFwbDevicePath
;
1640 EFI_PHYSICAL_ADDRESS BaseAddress
;
1647 EFI_DEVICE_PATH_PROTOCOL
*CompleteFilePath
;
1648 UINT8 PrefixOpcodeIndex
;
1650 EFI_SMM_BASE2_PROTOCOL
*mSmmBase2
;
1656 CompleteFilePath
= NULL
;
1657 GetFullDriverPath (ImageHandle
, SystemTable
, &CompleteFilePath
);
1659 Status
= EfiGetSystemConfigurationTable (&gEfiHobListGuid
, &HobList
);
1664 ASSERT_EFI_ERROR (Status
);
1668 // Allocate runtime services data for global variable, which contains
1669 // the private data of all firmware volume block instances
1671 mFvbModuleGlobal
= (ESAL_FWB_GLOBAL
*)AllocateRuntimeZeroPool(sizeof (ESAL_FWB_GLOBAL
));
1672 ASSERT(mFvbModuleGlobal
);
1674 Status
= gBS
->LocateProtocol (
1675 &gEfiSmmBase2ProtocolGuid
,
1677 (VOID
**) &mSmmBase2
1680 if (mSmmBase2
== NULL
) {
1683 mSmmBase2
->InSmm (mSmmBase2
, &InSmm
);
1684 mSmmBase2
->GetSmstLocation (mSmmBase2
, &mSmst
);
1691 // Obtain a handle for ICH SPI Protocol
1693 Status
= gBS
->LocateProtocol (&gEfiSpiProtocolGuid
, NULL
, (VOID
**) &mFvbModuleGlobal
->SpiProtocol
);
1694 ASSERT_EFI_ERROR (Status
);
1697 // attempt to identify flash part and initialize spi table
1699 for (FlashIndex
= 0; FlashIndex
< EnumSpiFlashMax
; FlashIndex
++) {
1700 Status
= mFvbModuleGlobal
->SpiProtocol
->Init (
1701 mFvbModuleGlobal
->SpiProtocol
,
1702 &(mSpiInitTable
[FlashIndex
])
1704 if (!EFI_ERROR (Status
)) {
1706 // read vendor/device IDs to check if flash device is supported
1708 Status
= mFvbModuleGlobal
->SpiProtocol
->Execute (
1709 mFvbModuleGlobal
->SpiProtocol
,
1710 SPI_OPCODE_JEDEC_ID_INDEX
,
1720 if (!EFI_ERROR (Status
)) {
1721 if (((FlashID
[0] == mSpiInitTable
[FlashIndex
].VendorId
) &&
1722 (FlashID
[2] == mSpiInitTable
[FlashIndex
].DeviceId1
)) ||
1723 ((FlashID
[0] == SPI_AT26DF321_ID1
) &&
1724 (FlashID
[0] == mSpiInitTable
[FlashIndex
].VendorId
) &&
1725 (FlashID
[1] == mSpiInitTable
[FlashIndex
].DeviceId0
))) {
1727 // Supported SPI device found
1731 "Supported SPI Flash device found, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1737 PublishFlashDeviceInfo (&mSpiInitTable
[FlashIndex
]);
1744 if (FlashIndex
>= EnumSpiFlashMax
) {
1745 Status
= EFI_UNSUPPORTED
;
1748 "ERROR - Unknown SPI Flash Device, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1753 ASSERT_EFI_ERROR (Status
);
1757 // Unlock all regions by writing to status register
1758 // This could be SPI device specific, need to follow the datasheet
1759 // To write to Write Status Register the Spi PrefixOpcode needs to be:
1760 // 0 for Atmel parts
1761 // 0 for Intel parts
1762 // 0 for Macronix parts
1763 // 0 for Winbond parts
1766 if (FlashID
[0] == SPI_SST25VF016B_ID1
) {
1767 PrefixOpcodeIndex
= 1;
1769 PrefixOpcodeIndex
= 0;
1771 Status
= mFvbModuleGlobal
->SpiProtocol
->Execute (
1772 mFvbModuleGlobal
->SpiProtocol
,
1773 SPI_OPCODE_WRITE_S_INDEX
, // OpcodeIndex
1774 PrefixOpcodeIndex
, // PrefixOpcodeIndex
1781 EnumSpiRegionAll
// SPI_REGION_TYPE
1788 Status
= mSmst
->SmmLocateProtocol (&gEfiSmmSpiProtocolGuid
, NULL
, (VOID
**) &mFvbModuleGlobal
->SmmSpiProtocol
);
1789 if (EFI_ERROR(Status
)) {
1790 Registration
= NULL
;
1791 Status
= mSmst
->SmmRegisterProtocolNotify (
1792 &gEfiSmmSpiProtocolGuid
,
1793 SmmSpiNotificationFunction
,
1797 Status
= SmmSpiInit();
1803 // Calculate the total size for all firmware volume block instances
1806 FirmwareVolumeHobList
= HobList
;
1809 Status
= GetFvbHeader (&FirmwareVolumeHobList
, &FwVolHeader
, &BaseAddress
, &WriteBack
);
1810 if (EFI_ERROR (Status
)) {
1815 BufferSize
+= (FwVolHeader
->HeaderLength
+ sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1820 // Only need to allocate once. There is only one copy of physical memory for
1821 // the private data of each FV instance. But in virtual mode or in physical
1822 // mode, the address of the the physical memory may be different.
1824 mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] = (EFI_FW_VOL_INSTANCE
*) AllocateRuntimeZeroPool (BufferSize
);
1825 ASSERT(mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
]);
1827 // Make a virtual copy of the FvInstance pointer.
1829 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1830 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1832 mFvbModuleGlobal
->NumFv
= 0;
1833 FirmwareVolumeHobList
= HobList
;
1834 TempFwVolHeader
= NULL
;
1839 // Fill in the private data of each firmware volume block instance
1841 // Foreach Fv HOB in the FirmwareVolumeHobList, loop
1844 Status
= GetFvbHeader (&FirmwareVolumeHobList
, &TempFwVolHeader
, &BaseAddress
, &WriteBack
);
1845 if (EFI_ERROR (Status
)) {
1848 FwVolHeader
= TempFwVolHeader
;
1855 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1856 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1858 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1859 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1862 // FwhInstance->FvWriteBase may not be the same as FwhInstance->FvBase
1864 FwhInstance
->FvWriteBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1865 WriteEnabled
= TRUE
;
1868 // Every pointer should have a virtual copy.
1870 FwhInstance
->FvWriteBase
[FVB_VIRTUAL
] = FwhInstance
->FvWriteBase
[FVB_PHYSICAL
];
1872 FwhInstance
->WriteEnabled
= WriteEnabled
;
1873 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1876 WriteLocked
= FALSE
;
1879 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1881 // Get the maximum size of a block. The size will be used to allocate
1882 // buffer for Scratch space, the intermediate buffer for FVB extension
1885 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
1886 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1889 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1892 // Write back a healthy FV header
1894 if (WriteBack
&& (!WriteLocked
)) {
1896 Status
= FlashFdErase (
1897 (UINTN
) FwhInstance
->FvWriteBase
[0],
1898 (UINTN
) BaseAddress
,
1899 FwVolHeader
->BlockMap
->Length
1902 HeaderLength
= (UINTN
) FwVolHeader
->HeaderLength
;
1903 Status
= FlashFdWrite (
1904 (UINTN
) FwhInstance
->FvWriteBase
[0],
1905 (UINTN
) BaseAddress
,
1907 (UINT8
*) FwVolHeader
,
1908 FwVolHeader
->BlockMap
->Length
1914 // The total number of blocks in the FV.
1916 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1919 // If the FV is write locked, set the appropriate attributes
1925 FwhInstance
->VolumeHeader
.Attributes
&= ~EFI_FVB2_WRITE_STATUS
;
1929 FwhInstance
->VolumeHeader
.Attributes
|= EFI_FVB2_LOCK_STATUS
;
1933 // Allocate and initialize FVB Device in a runtime data buffer
1935 FvbDevice
= AllocateRuntimeCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE
), &mFvbDeviceTemplate
);
1938 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1939 mFvbModuleGlobal
->NumFv
++;
1942 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
1944 if (FwVolHeader
->ExtHeaderOffset
== 0) {
1945 FvbDevice
->FvDevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
1946 FvbDevice
->FvDevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ (FwVolHeader
->FvLength
- 1);
1947 FwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)&FvbDevice
->FvDevicePath
;
1950 &FvbDevice
->UefiFvDevicePath
.FvDevPath
.FvName
,
1951 (EFI_GUID
*)(UINTN
)(BaseAddress
+ FwVolHeader
->ExtHeaderOffset
)
1953 FwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)&FvbDevice
->UefiFvDevicePath
;
1958 // Find a handle with a matching device path that has supports FW Block protocol
1960 TempFwbDevicePath
= FwbDevicePath
;
1961 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &TempFwbDevicePath
, &FwbHandle
);
1962 if (EFI_ERROR (Status
)) {
1964 // LocateDevicePath fails so install a new interface and device path
1967 Status
= gBS
->InstallMultipleProtocolInterfaces (
1969 &gEfiFirmwareVolumeBlockProtocolGuid
,
1970 &FvbDevice
->FwVolBlockInstance
,
1971 &gEfiDevicePathProtocolGuid
,
1975 ASSERT_EFI_ERROR (Status
);
1976 } else if (EfiIsDevicePathEnd (TempFwbDevicePath
)) {
1978 // Device already exists, so reinstall the FVB protocol
1980 Status
= gBS
->HandleProtocol (
1982 &gEfiFirmwareVolumeBlockProtocolGuid
,
1983 (VOID
**) &OldFwbInterface
1985 ASSERT_EFI_ERROR (Status
);
1987 Status
= gBS
->ReinstallProtocolInterface (
1989 &gEfiFirmwareVolumeBlockProtocolGuid
,
1991 &FvbDevice
->FwVolBlockInstance
1993 ASSERT_EFI_ERROR (Status
);
1997 // There was a FVB protocol on an End Device Path node
2003 Status
= mSmst
->SmmInstallProtocolInterface (
2005 &gEfiSmmFirmwareVolumeBlockProtocolGuid
,
2006 EFI_NATIVE_INTERFACE
,
2007 &FvbDevice
->FwVolBlockInstance
2009 ASSERT_EFI_ERROR (Status
);
2012 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
2014 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
2015 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
2020 // Allocate for scratch space, an intermediate buffer for FVB extention
2023 mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
] = AllocateRuntimeZeroPool (MaxLbaSize
);
2025 ASSERT (mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
]);
2027 mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
] = mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
];
2030 Status
= gBS
->CreateEventEx (
2033 FvbVirtualddressChangeEvent
,
2035 &gEfiEventVirtualAddressChangeGuid
,
2038 ASSERT_EFI_ERROR (Status
);
2041 // Inform other platform drivers that SPI device discovered and
2042 // SPI interface ready for use.
2045 Status
= gBS
->InstallProtocolInterface (
2047 &gEfiSmmSpiReadyProtocolGuid
,
2048 EFI_NATIVE_INTERFACE
,