3 Copyright (c) 2013-2015 Intel Corporation.
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "FwBlockService.h"
18 ESAL_FWB_GLOBAL
*mFvbModuleGlobal
;
20 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
21 FVB_DEVICE_SIGNATURE
, // Signature
23 // FV_DEVICE_PATH FvDevicePath
31 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
)),
32 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
) >> 8)
36 (EFI_PHYSICAL_ADDRESS
) 0,
37 (EFI_PHYSICAL_ADDRESS
) 0
41 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
43 END_DEVICE_PATH_LENGTH
,
49 // UEFI_FV_DEVICE_PATH UefiFvDevicePath
57 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
)),
58 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
) >> 8)
65 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
67 END_DEVICE_PATH_LENGTH
,
74 // EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance
77 FvbProtocolGetAttributes
,
78 FvbProtocolSetAttributes
,
79 FvbProtocolGetPhysicalAddress
,
80 FvbProtocolGetBlockSize
,
83 FvbProtocolEraseBlocks
,
88 UINT32 mInSmmMode
= 0;
89 EFI_SMM_SYSTEM_TABLE2
* mSmst
= NULL
;
92 PublishFlashDeviceInfo (
93 IN SPI_INIT_TABLE
*Found
99 Publish info on found flash device to other drivers via PcdSpiFlashDeviceSize.
102 Found - Pointer to entry in mSpiInitTable for found flash part.
112 // Publish Byte Size of found flash device.
114 Status
= PcdSet32S (PcdSpiFlashDeviceSize
, (UINT32
)(Found
->BiosStartOffset
+ Found
->BiosSize
));
115 ASSERT_EFI_ERROR (Status
);
119 FvbVirtualddressChangeEvent (
127 Fixup internal data so that EFI and SAL can be call in virtual mode.
128 Call the passed in Child Notify event and convert the mFvbModuleGlobal
129 date items to there virtual address.
131 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
132 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
137 (Standard EFI notify event - EFI_EVENT_NOTIFY)
145 EFI_FW_VOL_INSTANCE
*FwhInstance
;
148 gRT
->ConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
151 // Convert the base address of all the instances
154 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
155 while (Index
< mFvbModuleGlobal
->NumFv
) {
157 gRT
->ConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &FwhInstance
->FvBase
[FVB_VIRTUAL
]);
159 // SpiWrite and SpiErase always use Physical Address instead of
160 // Virtual Address, even in Runtime. So we need not convert pointer
161 // for FvWriteBase[FVB_VIRTUAL]
163 // EfiConvertPointer (0, (VOID **) &FwhInstance->FvWriteBase[FVB_VIRTUAL]);
165 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
167 (UINTN
) ((UINT8
*) FwhInstance
) + FwhInstance
->VolumeHeader
.HeaderLength
+
168 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
173 gRT
->ConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
]);
175 // Convert SPI_PROTOCOL instance for runtime
177 gRT
->ConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &mFvbModuleGlobal
->SpiProtocol
);
178 gRT
->ConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &mFvbModuleGlobal
);
187 MmioWrite8 ((UINTN
)Dest
, Byte
);
195 IN ESAL_FWB_GLOBAL
*Global
,
196 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
202 Retrieves the physical address of a memory mapped FV
205 Instance - The FV instance whose base address is going to be
207 Global - Pointer to ESAL_FWB_GLOBAL that contains all
209 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
210 Virtual - Whether CPU is in virtual or physical mode
213 EFI_SUCCESS - Successfully returns
214 EFI_INVALID_PARAMETER - Instance not found
218 EFI_FW_VOL_INSTANCE
*FwhRecord
;
220 if (Instance
>= Global
->NumFv
) {
221 return EFI_INVALID_PARAMETER
;
224 // Find the right instance of the FVB private data
226 FwhRecord
= Global
->FvInstance
[Virtual
];
227 while (Instance
> 0) {
228 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
230 (UINTN
) ((UINT8
*) FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
231 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
236 *FwhInstance
= FwhRecord
;
242 FvbGetPhysicalAddress (
244 OUT EFI_PHYSICAL_ADDRESS
*Address
,
245 IN ESAL_FWB_GLOBAL
*Global
,
251 Retrieves the physical address of a memory mapped FV
254 Instance - The FV instance whose base address is going to be
256 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
257 that on successful return, contains the base address
258 of the firmware volume.
259 Global - Pointer to ESAL_FWB_GLOBAL that contains all
261 Virtual - Whether CPU is in virtual or physical mode
264 EFI_SUCCESS - Successfully returns
265 EFI_INVALID_PARAMETER - Instance not found
269 EFI_FW_VOL_INSTANCE
*FwhInstance
;
275 // Find the right instance of the FVB private data
277 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
278 ASSERT_EFI_ERROR (Status
);
279 *Address
= FwhInstance
->FvBase
[Virtual
];
285 FvbGetVolumeAttributes (
287 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
288 IN ESAL_FWB_GLOBAL
*Global
,
294 Retrieves attributes, insures positive polarity of attribute bits, returns
295 resulting attributes in output parameter
298 Instance - The FV instance whose attributes is going to be
300 Attributes - Output buffer which contains attributes
301 Global - Pointer to ESAL_FWB_GLOBAL that contains all
303 Virtual - Whether CPU is in virtual or physical mode
306 EFI_SUCCESS - Successfully returns
307 EFI_INVALID_PARAMETER - Instance not found
311 EFI_FW_VOL_INSTANCE
*FwhInstance
;
317 // Find the right instance of the FVB private data
319 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
320 ASSERT_EFI_ERROR (Status
);
321 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
330 OUT UINTN
*LbaAddress
,
331 OUT UINTN
*LbaWriteAddress
,
332 OUT UINTN
*LbaLength
,
333 OUT UINTN
*NumOfBlocks
,
334 IN ESAL_FWB_GLOBAL
*Global
,
340 Retrieves the starting address of an LBA in an FV
343 Instance - The FV instance which the Lba belongs to
344 Lba - The logical block address
345 LbaAddress - On output, contains the physical starting address
347 LbaWriteAddress - On output, contains the physical starting address
348 of the Lba for writing
349 LbaLength - On output, contains the length of the block
350 NumOfBlocks - A pointer to a caller allocated UINTN in which the
351 number of consecutive blocks starting with Lba is
352 returned. All blocks in this range have a size of
354 Global - Pointer to ESAL_FWB_GLOBAL that contains all
356 Virtual - Whether CPU is in virtual or physical mode
359 EFI_SUCCESS - Successfully returns
360 EFI_INVALID_PARAMETER - Instance not found
369 EFI_FW_VOL_INSTANCE
*FwhInstance
;
370 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
376 // Find the right instance of the FVB private data
378 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
379 ASSERT_EFI_ERROR (Status
);
383 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
386 // Parse the blockmap of the FV to find which map entry the Lba belongs to
389 NumBlocks
= BlockMap
->NumBlocks
;
390 BlockLength
= BlockMap
->Length
;
392 if ((NumBlocks
== 0) || (BlockLength
== 0)) {
393 return EFI_INVALID_PARAMETER
;
396 NextLba
= StartLba
+ NumBlocks
;
399 // The map entry found
401 if (Lba
>= StartLba
&& Lba
< NextLba
) {
402 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
404 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
407 if (LbaWriteAddress
) {
408 *LbaWriteAddress
= FwhInstance
->FvWriteBase
[Virtual
] + Offset
;
412 *LbaLength
= BlockLength
;
416 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
423 Offset
= Offset
+ NumBlocks
* BlockLength
;
432 IN UINTN BlockOffset
,
433 IN OUT UINTN
*NumBytes
,
435 IN ESAL_FWB_GLOBAL
*Global
,
441 Reads specified number of bytes into a buffer from the specified block
444 Instance - The FV instance to be read from
445 Lba - The logical block address to be read from
446 BlockOffset - Offset into the block at which to begin reading
447 NumBytes - Pointer that on input contains the total size of
448 the buffer. On output, it contains the total number
450 Buffer - Pointer to a caller allocated buffer that will be
451 used to hold the data read
452 Global - Pointer to ESAL_FWB_GLOBAL that contains all
454 Virtual - Whether CPU is in virtual or physical mode
457 EFI_SUCCESS - The firmware volume was read successfully and
458 contents are in Buffer
459 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
460 NumBytes contains the total number of bytes returned
462 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
463 EFI_DEVICE_ERROR - The block device is not functioning correctly and
465 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
469 EFI_FVB_ATTRIBUTES_2 Attributes
;
475 // Check for invalid conditions
477 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
478 return EFI_INVALID_PARAMETER
;
481 if (*NumBytes
== 0) {
482 return EFI_INVALID_PARAMETER
;
485 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, NULL
, &LbaLength
, NULL
, Global
, Virtual
);
486 if (EFI_ERROR (Status
)) {
490 // Check if the FV is read enabled
492 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
494 if ((Attributes
& EFI_FVB2_READ_STATUS
) == 0) {
495 return EFI_ACCESS_DENIED
;
498 // Perform boundary checks and adjust NumBytes
500 if (BlockOffset
> LbaLength
) {
501 return EFI_INVALID_PARAMETER
;
504 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
505 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
506 Status
= EFI_BAD_BUFFER_SIZE
;
509 MmioReadBuffer8 (LbaAddress
+ BlockOffset
, (UINTN
) *NumBytes
, Buffer
);
516 IN UINTN WriteAddress
,
518 IN OUT UINTN
*NumBytes
,
525 Writes specified number of bytes from the input buffer to the address
535 Status
= EFI_SUCCESS
;
538 // TODO: Suggested that this code be "critical section"
540 WriteAddress
-= ( PcdGet32 (PcdFlashAreaBaseAddress
) );
541 if (mInSmmMode
== 0) { // !(EfiInManagementInterrupt ())) {
542 Status
= mFvbModuleGlobal
->SpiProtocol
->Execute (
543 mFvbModuleGlobal
->SpiProtocol
,
544 SPI_OPCODE_WRITE_INDEX
, // OpcodeIndex
545 0, // PrefixOpcodeIndex
549 WriteAddress
, // Address
550 (UINT32
) (*NumBytes
), // Data Number
556 Status
= mFvbModuleGlobal
->SmmSpiProtocol
->Execute (
557 mFvbModuleGlobal
->SmmSpiProtocol
,
558 SPI_OPCODE_WRITE_INDEX
, // OpcodeIndex
559 0, // PrefixOpcodeIndex
563 WriteAddress
, // Address
564 (UINT32
) (*NumBytes
), // Data Number
577 IN UINTN WriteAddress
,
584 Erase a certain block from address LbaWriteAddress
595 NumBytes
= LbaLength
;
597 WriteAddress
-= (PcdGet32 (PcdFlashAreaBaseAddress
));
598 if (mInSmmMode
== 0 ) { // !(EfiInManagementInterrupt ())) {
599 Status
= mFvbModuleGlobal
->SpiProtocol
->Execute (
600 mFvbModuleGlobal
->SpiProtocol
,
601 SPI_OPCODE_ERASE_INDEX
, // OpcodeIndex
602 0, // PrefixOpcodeIndex
606 WriteAddress
, // Address
609 EnumSpiRegionBios
// SPI_REGION_TYPE
612 Status
= mFvbModuleGlobal
->SmmSpiProtocol
->Execute (
613 mFvbModuleGlobal
->SmmSpiProtocol
,
614 SPI_OPCODE_ERASE_INDEX
, // OpcodeIndex
615 0, // PrefixOpcodeIndex
619 WriteAddress
, // Address
622 EnumSpiRegionBios
// SPI_REGION_TYPE
635 IN UINTN BlockOffset
,
636 IN OUT UINTN
*NumBytes
,
638 IN ESAL_FWB_GLOBAL
*Global
,
644 Writes specified number of bytes from the input buffer to the block
647 Instance - The FV instance to be written to
648 Lba - The starting logical block index to write to
649 BlockOffset - Offset into the block at which to begin writing
650 NumBytes - Pointer that on input contains the total size of
651 the buffer. On output, it contains the total number
652 of bytes actually written
653 Buffer - Pointer to a caller allocated buffer that contains
654 the source for the write
655 Global - Pointer to ESAL_FWB_GLOBAL that contains all
657 Virtual - Whether CPU is in virtual or physical mode
660 EFI_SUCCESS - The firmware volume was written successfully
661 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
662 NumBytes contains the total number of bytes
664 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
665 EFI_DEVICE_ERROR - The block device is not functioning correctly and
667 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
671 EFI_FVB_ATTRIBUTES_2 Attributes
;
673 UINTN LbaWriteAddress
;
675 EFI_FW_VOL_INSTANCE
*FwhInstance
;
677 EFI_STATUS ReturnStatus
;
682 // Find the right instance of the FVB private data
684 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
685 ASSERT_EFI_ERROR (Status
);
688 // Writes are enabled in the init routine itself
690 if (!FwhInstance
->WriteEnabled
) {
691 return EFI_ACCESS_DENIED
;
694 // Check for invalid conditions
696 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
697 return EFI_INVALID_PARAMETER
;
700 if (*NumBytes
== 0) {
701 return EFI_INVALID_PARAMETER
;
704 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaWriteAddress
, &LbaLength
, NULL
, Global
, Virtual
);
705 if (EFI_ERROR (Status
)) {
709 // Check if the FV is write enabled
711 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
713 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
714 return EFI_ACCESS_DENIED
;
717 // Perform boundary checks and adjust NumBytes
719 if (BlockOffset
> LbaLength
) {
720 return EFI_INVALID_PARAMETER
;
723 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
724 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
725 Status
= EFI_BAD_BUFFER_SIZE
;
728 ReturnStatus
= FlashFdWrite (
729 LbaWriteAddress
+ BlockOffset
,
735 if (EFI_ERROR (ReturnStatus
)) {
746 IN ESAL_FWB_GLOBAL
*Global
,
752 Erases and initializes a firmware volume block
755 Instance - The FV instance to be erased
756 Lba - The logical block index to be erased
757 Global - Pointer to ESAL_FWB_GLOBAL that contains all
759 Virtual - Whether CPU is in virtual or physical mode
762 EFI_SUCCESS - The erase request was successfully completed
763 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
764 EFI_DEVICE_ERROR - The block device is not functioning correctly and
765 could not be written. Firmware device may have been
767 EFI_INVALID_PARAMETER - Instance not found
772 EFI_FVB_ATTRIBUTES_2 Attributes
;
774 UINTN LbaWriteAddress
;
775 EFI_FW_VOL_INSTANCE
*FwhInstance
;
784 // Find the right instance of the FVB private data
786 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
787 ASSERT_EFI_ERROR (Status
);
790 // Writes are enabled in the init routine itself
792 if (!FwhInstance
->WriteEnabled
) {
793 return EFI_ACCESS_DENIED
;
796 // Check if the FV is write enabled
798 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
800 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
801 return EFI_ACCESS_DENIED
;
804 // Get the starting address of the block for erase. For debug reasons,
805 // LbaWriteAddress may not be the same as LbaAddress.
807 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaWriteAddress
, &LbaLength
, NULL
, Global
, Virtual
);
808 if (EFI_ERROR (Status
)) {
812 SectorNum
= LbaLength
/ SPI_ERASE_SECTOR_SIZE
;
813 for (Index
= 0; Index
< SectorNum
; Index
++){
814 Status
= FlashFdErase (
815 LbaWriteAddress
+ Index
* SPI_ERASE_SECTOR_SIZE
,
817 SPI_ERASE_SECTOR_SIZE
819 if (Status
!= EFI_SUCCESS
){
828 FvbEraseCustomBlockRange (
831 IN UINTN OffsetStartLba
,
833 IN UINTN OffsetLastLba
,
834 IN ESAL_FWB_GLOBAL
*Global
,
840 Erases and initializes a specified range of a firmware volume
843 Instance - The FV instance to be erased
844 StartLba - The starting logical block index to be erased
845 OffsetStartLba - Offset into the starting block at which to
847 LastLba - The last logical block index to be erased
848 OffsetStartLba - Offset into the last block at which to end erasing
849 Global - Pointer to ESAL_FWB_GLOBAL that contains all
851 Virtual - Whether CPU is in virtual or physical mode
854 EFI_SUCCESS - The firmware volume was erased successfully
855 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
856 EFI_DEVICE_ERROR - The block device is not functioning correctly and
857 could not be written. Firmware device may have been
859 EFI_INVALID_PARAMETER - Instance not found
865 UINTN ScratchLbaSizeData
;
870 FvbGetLbaAddress (Instance
, StartLba
, NULL
, NULL
, &LbaSize
, NULL
, Global
, Virtual
);
873 // Use the scratch space as the intermediate buffer to transfer data
874 // Back up the first LBA in scratch space.
876 FvbReadBlock (Instance
, StartLba
, 0, &LbaSize
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
881 FvbEraseBlock (Instance
, StartLba
, Global
, Virtual
);
882 ScratchLbaSizeData
= OffsetStartLba
;
885 // write the data back to the first block
887 if (ScratchLbaSizeData
> 0) {
888 FvbWriteBlock (Instance
, StartLba
, 0, &ScratchLbaSizeData
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
893 if (LastLba
> (StartLba
+ 1)) {
894 for (Index
= (StartLba
+ 1); Index
<= (LastLba
- 1); Index
++) {
895 FvbEraseBlock (Instance
, Index
, Global
, Virtual
);
899 // Last LBAs, the same as first LBAs
901 if (LastLba
> StartLba
) {
902 FvbGetLbaAddress (Instance
, LastLba
, NULL
, NULL
, &LbaSize
, NULL
, Global
, Virtual
);
903 FvbReadBlock (Instance
, LastLba
, 0, &LbaSize
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
904 FvbEraseBlock (Instance
, LastLba
, Global
, Virtual
);
907 ScratchLbaSizeData
= LbaSize
- (OffsetStartLba
+ 1);
909 return FvbWriteBlock (
914 Global
->FvbScratchSpace
[Virtual
],
921 FvbSetVolumeAttributes (
923 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
924 IN ESAL_FWB_GLOBAL
*Global
,
930 Modifies the current settings of the firmware volume according to the
931 input parameter, and returns the new setting of the volume
934 Instance - The FV instance whose attributes is going to be
936 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
937 containing the desired firmware volume settings.
938 On successful return, it contains the new settings
939 of the firmware volume
940 Global - Pointer to ESAL_FWB_GLOBAL that contains all
942 Virtual - Whether CPU is in virtual or physical mode
945 EFI_SUCCESS - Successfully returns
946 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
947 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
948 in conflict with the capabilities as declared in the
949 firmware volume header
953 EFI_FW_VOL_INSTANCE
*FwhInstance
;
954 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
955 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
964 // Find the right instance of the FVB private data
966 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
967 ASSERT_EFI_ERROR (Status
);
969 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
970 OldAttributes
= *AttribPtr
;
971 Capabilities
= OldAttributes
& EFI_FVB2_CAPABILITIES
;
972 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
973 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
976 // If firmware volume is locked, no status bit can be updated
978 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
979 if (OldStatus
^ NewStatus
) {
980 return EFI_ACCESS_DENIED
;
986 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
987 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
988 return EFI_INVALID_PARAMETER
;
994 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
995 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
996 return EFI_INVALID_PARAMETER
;
1000 // Test write disable
1002 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
1003 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
1004 return EFI_INVALID_PARAMETER
;
1008 // Test write enable
1010 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
1011 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
1012 return EFI_INVALID_PARAMETER
;
1018 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
1019 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
1020 return EFI_INVALID_PARAMETER
;
1024 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
1025 *AttribPtr
= (*AttribPtr
) | NewStatus
;
1026 *Attributes
= *AttribPtr
;
1031 // FVB protocol APIs
1035 FvbProtocolGetPhysicalAddress (
1036 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1037 OUT EFI_PHYSICAL_ADDRESS
*Address
1041 Routine Description:
1043 Retrieves the physical address of the device.
1047 This - Calling context
1048 Address - Output buffer containing the address.
1053 EFI_SUCCESS - Successfully returns
1057 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1059 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1061 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
1065 FvbProtocolGetBlockSize (
1066 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1068 OUT UINTN
*BlockSize
,
1069 OUT UINTN
*NumOfBlocks
1073 Routine Description:
1074 Retrieve the size of a logical block
1077 This - Calling context
1078 Lba - Indicates which block to return the size for.
1079 BlockSize - A pointer to a caller allocated UINTN in which
1080 the size of the block is returned
1081 NumOfBlocks - a pointer to a caller allocated UINTN in which the
1082 number of consecutive blocks starting with Lba is
1083 returned. All blocks in this range have a size of
1087 EFI_SUCCESS - The firmware volume was read successfully and
1088 contents are in Buffer
1092 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1094 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1096 return FvbGetLbaAddress (
1097 FvbDevice
->Instance
,
1110 FvbProtocolGetAttributes (
1111 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1112 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
1116 Routine Description:
1117 Retrieves Volume attributes. No polarity translations are done.
1120 This - Calling context
1121 Attributes - output buffer which contains attributes
1124 EFI_SUCCESS - Successfully returns
1128 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1130 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1132 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
1137 FvbProtocolSetAttributes (
1138 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1139 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
1143 Routine Description:
1144 Sets Volume attributes. No polarity translations are done.
1147 This - Calling context
1148 Attributes - output buffer which contains attributes
1151 EFI_SUCCESS - Successfully returns
1155 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1157 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1159 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
1164 FvbProtocolEraseBlocks (
1165 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1170 Routine Description:
1172 The EraseBlock() function erases one or more blocks as denoted by the
1173 variable argument list. The entire parameter list of blocks must be verified
1174 prior to erasing any blocks. If a block is requested that does not exist
1175 within the associated firmware volume (it has a larger index than the last
1176 block of the firmware volume), the EraseBlock() function must return
1177 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
1180 This - Calling context
1181 ... - Starting LBA followed by Number of Lba to erase.
1182 a -1 to terminate the list.
1185 EFI_SUCCESS - The erase request was successfully completed
1186 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1187 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1188 could not be written. Firmware device may have been
1193 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1194 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1197 EFI_LBA StartingLba
;
1202 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1204 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
1205 ASSERT_EFI_ERROR (Status
);
1207 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
1209 VA_START (args
, This
);
1212 StartingLba
= VA_ARG (args
, EFI_LBA
);
1213 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
1217 NumOfLba
= VA_ARG (args
, UINT32
);
1220 // Check input parameters
1222 if (NumOfLba
== 0) {
1224 return EFI_INVALID_PARAMETER
;
1227 if ((StartingLba
+ NumOfLba
) > NumOfBlocks
) {
1228 return EFI_INVALID_PARAMETER
;
1234 VA_START (args
, This
);
1236 StartingLba
= VA_ARG (args
, EFI_LBA
);
1237 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
1241 NumOfLba
= VA_ARG (args
, UINT32
);
1243 while (NumOfLba
> 0) {
1244 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
1245 if (EFI_ERROR (Status
)) {
1264 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1267 IN OUT UINTN
*NumBytes
,
1272 Routine Description:
1274 Writes data beginning at Lba:Offset from FV. The write terminates either
1275 when *NumBytes of data have been written, or when a block boundary is
1276 reached. *NumBytes is updated to reflect the actual number of bytes
1277 written. The write opertion does not include erase. This routine will
1278 attempt to write only the specified bytes. If the writes do not stick,
1279 it will return an error.
1282 This - Calling context
1283 Lba - Block in which to begin write
1284 Offset - Offset in the block at which to begin write
1285 NumBytes - On input, indicates the requested write size. On
1286 output, indicates the actual number of bytes written
1287 Buffer - Buffer containing source data for the write.
1290 EFI_SUCCESS - The firmware volume was written successfully
1291 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
1292 NumBytes contains the total number of bytes
1294 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1295 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1296 could not be written
1297 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1302 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1304 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1306 return FvbWriteBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1312 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1315 IN OUT UINTN
*NumBytes
,
1320 Routine Description:
1322 Reads data beginning at Lba:Offset from FV. The Read terminates either
1323 when *NumBytes of data have been read, or when a block boundary is
1324 reached. *NumBytes is updated to reflect the actual number of bytes
1325 written. The write opertion does not include erase. This routine will
1326 attempt to write only the specified bytes. If the writes do not stick,
1327 it will return an error.
1330 This - Calling context
1331 Lba - Block in which to begin Read
1332 Offset - Offset in the block at which to begin Read
1333 NumBytes - On input, indicates the requested write size. On
1334 output, indicates the actual number of bytes Read
1335 Buffer - Buffer containing source data for the Read.
1338 EFI_SUCCESS - The firmware volume was read successfully and
1339 contents are in Buffer
1340 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1341 NumBytes contains the total number of bytes returned
1343 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1344 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1346 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1351 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1354 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1355 Status
= FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1362 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1366 Routine Description:
1367 Check the integrity of firmware volume header
1370 FwVolHeader - A pointer to a firmware volume header
1373 EFI_SUCCESS - The firmware volume is consistent
1374 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1379 UINT16 HeaderLength
;
1383 // Verify the header revision, header signature, length
1384 // Length of FvBlock cannot be 2**64-1
1385 // HeaderLength cannot be an odd number
1388 if (((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) && (FwVolHeader
->Revision
!= EFI_FVH_REVISION
)) ||
1390 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1392 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1393 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
1394 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1396 return EFI_NOT_FOUND
;
1399 // Verify the header checksum
1401 HeaderLength
= (UINT16
) (FwVolHeader
->HeaderLength
/ 2);
1402 Ptr
= (UINT16
*) FwVolHeader
;
1404 while (HeaderLength
> 0) {
1405 Checksum
= Checksum
+ (*Ptr
);
1410 if (Checksum
!= 0) {
1411 return EFI_NOT_FOUND
;
1420 OUT EFI_FIRMWARE_VOLUME_HEADER
**FwVolHeader
,
1421 OUT EFI_PHYSICAL_ADDRESS
*BaseAddress
,
1422 OUT BOOLEAN
*WriteBack
1427 Status
= EFI_SUCCESS
;
1430 if (*FwVolHeader
== NULL
) {
1431 *BaseAddress
= PcdGet32 (PcdFlashFvRecoveryBase
);
1432 } else if (*FwVolHeader
== (VOID
*)(UINTN
)PcdGet32 (PcdFlashFvRecoveryBase
)) {
1433 *BaseAddress
= PcdGet32 (PcdFlashFvMainBase
);
1434 } else if (*FwVolHeader
== (VOID
*)(UINTN
)PcdGet32 (PcdFlashFvMainBase
)) {
1435 *BaseAddress
= PcdGet32 (PcdFlashNvStorageVariableBase
);
1437 return EFI_NOT_FOUND
;
1440 DEBUG((EFI_D_INFO
, "Fvb base : %08x\n",*BaseAddress
));
1442 *FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) (*BaseAddress
);
1443 Status
= ValidateFvHeader (*FwVolHeader
);
1444 if (EFI_ERROR (Status
)) {
1450 Status
= GetFvbInfo (*BaseAddress
, FwVolHeader
);
1451 DEBUG(( DEBUG_ERROR
, "Through GetFvbInfo: %08x!\n",*BaseAddress
));
1453 ASSERT_EFI_ERROR (Status
);
1471 // Obtain a handle for ICH SPI Protocol
1473 ASSERT(mSmst
!= NULL
);
1474 if (mFvbModuleGlobal
->SmmSpiProtocol
== NULL
){
1475 Status
= mSmst
->SmmLocateProtocol (&gEfiSmmSpiProtocolGuid
, NULL
, (VOID
**) &mFvbModuleGlobal
->SmmSpiProtocol
);
1476 ASSERT_EFI_ERROR(Status
);
1479 // attempt to identify flash part and initialize spi table
1481 for (FlashIndex
= 0; FlashIndex
< EnumSpiFlashMax
; FlashIndex
++) {
1482 Status
= mFvbModuleGlobal
->SmmSpiProtocol
->Init (
1483 mFvbModuleGlobal
->SmmSpiProtocol
,
1484 &(mSpiInitTable
[FlashIndex
])
1486 if (!EFI_ERROR (Status
)) {
1488 // read vendor/device IDs to check if flash device is supported
1490 Status
= mFvbModuleGlobal
->SmmSpiProtocol
->Execute (
1491 mFvbModuleGlobal
->SmmSpiProtocol
,
1492 SPI_OPCODE_JEDEC_ID_INDEX
,
1502 if (!EFI_ERROR (Status
)) {
1503 if (((FlashID
[0] == mSpiInitTable
[FlashIndex
].VendorId
) &&
1504 (FlashID
[2] == mSpiInitTable
[FlashIndex
].DeviceId1
)) ||
1505 ((FlashID
[0] == SPI_AT26DF321_ID1
) &&
1506 (FlashID
[0] == mSpiInitTable
[FlashIndex
].VendorId
) &&
1507 (FlashID
[1] == mSpiInitTable
[FlashIndex
].DeviceId0
))) {
1509 // Supported SPI device found
1513 "Smm Mode: Supported SPI Flash device found, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1524 if (FlashIndex
>= EnumSpiFlashMax
) {
1525 Status
= EFI_UNSUPPORTED
;
1528 "ERROR - Unknown SPI Flash Device, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1533 ASSERT_EFI_ERROR (Status
);
1537 Status
= mFvbModuleGlobal
->SmmSpiProtocol
->Execute (
1538 mFvbModuleGlobal
->SmmSpiProtocol
,
1539 SPI_OPCODE_WRITE_S_INDEX
, // OpcodeIndex
1540 1, // PrefixOpcodeIndex
1547 EnumSpiRegionAll
// SPI_REGION_TYPE
1553 SmmSpiNotificationFunction (
1554 IN CONST EFI_GUID
*Protocol
,
1556 IN EFI_HANDLE Handle
1559 return SmmSpiInit();
1566 IN EFI_HANDLE ImageHandle
,
1567 IN EFI_SYSTEM_TABLE
*SystemTable
,
1568 OUT EFI_DEVICE_PATH_PROTOCOL
**CompleteFilePath
1572 Routine Description:
1574 Function is used to get the full device path for this driver.
1578 ImageHandle - The loaded image handle of this driver.
1579 SystemTable - The pointer of system table.
1580 CompleteFilePath - The pointer of returned full file path
1589 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
1590 EFI_DEVICE_PATH_PROTOCOL
*ImageDevicePath
;
1593 Status
= gBS
->HandleProtocol (
1595 &gEfiLoadedImageProtocolGuid
,
1596 (VOID
**) &LoadedImage
1598 ASSERT_EFI_ERROR (Status
);
1600 Status
= gBS
->HandleProtocol (
1601 LoadedImage
->DeviceHandle
,
1602 &gEfiDevicePathProtocolGuid
,
1603 (VOID
*) &ImageDevicePath
1605 ASSERT_EFI_ERROR (Status
);
1607 *CompleteFilePath
= AppendDevicePath (
1609 LoadedImage
->FilePath
1619 IN EFI_HANDLE ImageHandle
,
1620 IN EFI_SYSTEM_TABLE
*SystemTable
1624 Routine Description:
1625 This function does common initialization for FVB services
1634 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1635 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1636 EFI_FIRMWARE_VOLUME_HEADER
*TempFwVolHeader
;
1638 VOID
*FirmwareVolumeHobList
;
1640 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1642 BOOLEAN WriteEnabled
;
1643 BOOLEAN WriteLocked
;
1644 EFI_HANDLE FwbHandle
;
1645 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1646 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1647 EFI_DEVICE_PATH_PROTOCOL
*FwbDevicePath
;
1648 EFI_DEVICE_PATH_PROTOCOL
*TempFwbDevicePath
;
1650 EFI_PHYSICAL_ADDRESS BaseAddress
;
1657 EFI_DEVICE_PATH_PROTOCOL
*CompleteFilePath
;
1658 UINT8 PrefixOpcodeIndex
;
1660 EFI_SMM_BASE2_PROTOCOL
*mSmmBase2
;
1666 CompleteFilePath
= NULL
;
1667 GetFullDriverPath (ImageHandle
, SystemTable
, &CompleteFilePath
);
1669 Status
= EfiGetSystemConfigurationTable (&gEfiHobListGuid
, &HobList
);
1674 ASSERT_EFI_ERROR (Status
);
1678 // Allocate runtime services data for global variable, which contains
1679 // the private data of all firmware volume block instances
1681 mFvbModuleGlobal
= (ESAL_FWB_GLOBAL
*)AllocateRuntimeZeroPool(sizeof (ESAL_FWB_GLOBAL
));
1682 ASSERT(mFvbModuleGlobal
);
1684 Status
= gBS
->LocateProtocol (
1685 &gEfiSmmBase2ProtocolGuid
,
1687 (VOID
**) &mSmmBase2
1690 if (mSmmBase2
== NULL
) {
1693 mSmmBase2
->InSmm (mSmmBase2
, &InSmm
);
1694 mSmmBase2
->GetSmstLocation (mSmmBase2
, &mSmst
);
1701 // Obtain a handle for ICH SPI Protocol
1703 Status
= gBS
->LocateProtocol (&gEfiSpiProtocolGuid
, NULL
, (VOID
**) &mFvbModuleGlobal
->SpiProtocol
);
1704 ASSERT_EFI_ERROR (Status
);
1707 // attempt to identify flash part and initialize spi table
1709 for (FlashIndex
= 0; FlashIndex
< EnumSpiFlashMax
; FlashIndex
++) {
1710 Status
= mFvbModuleGlobal
->SpiProtocol
->Init (
1711 mFvbModuleGlobal
->SpiProtocol
,
1712 &(mSpiInitTable
[FlashIndex
])
1714 if (!EFI_ERROR (Status
)) {
1716 // read vendor/device IDs to check if flash device is supported
1718 Status
= mFvbModuleGlobal
->SpiProtocol
->Execute (
1719 mFvbModuleGlobal
->SpiProtocol
,
1720 SPI_OPCODE_JEDEC_ID_INDEX
,
1730 if (!EFI_ERROR (Status
)) {
1731 if (((FlashID
[0] == mSpiInitTable
[FlashIndex
].VendorId
) &&
1732 (FlashID
[2] == mSpiInitTable
[FlashIndex
].DeviceId1
)) ||
1733 ((FlashID
[0] == SPI_AT26DF321_ID1
) &&
1734 (FlashID
[0] == mSpiInitTable
[FlashIndex
].VendorId
) &&
1735 (FlashID
[1] == mSpiInitTable
[FlashIndex
].DeviceId0
))) {
1737 // Supported SPI device found
1741 "Supported SPI Flash device found, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1747 PublishFlashDeviceInfo (&mSpiInitTable
[FlashIndex
]);
1754 if (FlashIndex
>= EnumSpiFlashMax
) {
1755 Status
= EFI_UNSUPPORTED
;
1758 "ERROR - Unknown SPI Flash Device, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1763 ASSERT_EFI_ERROR (Status
);
1767 // Unlock all regions by writing to status register
1768 // This could be SPI device specific, need to follow the datasheet
1769 // To write to Write Status Register the Spi PrefixOpcode needs to be:
1770 // 0 for Atmel parts
1771 // 0 for Intel parts
1772 // 0 for Macronix parts
1773 // 0 for Winbond parts
1776 if (FlashID
[0] == SPI_SST25VF016B_ID1
) {
1777 PrefixOpcodeIndex
= 1;
1779 PrefixOpcodeIndex
= 0;
1781 Status
= mFvbModuleGlobal
->SpiProtocol
->Execute (
1782 mFvbModuleGlobal
->SpiProtocol
,
1783 SPI_OPCODE_WRITE_S_INDEX
, // OpcodeIndex
1784 PrefixOpcodeIndex
, // PrefixOpcodeIndex
1791 EnumSpiRegionAll
// SPI_REGION_TYPE
1798 Status
= mSmst
->SmmLocateProtocol (&gEfiSmmSpiProtocolGuid
, NULL
, (VOID
**) &mFvbModuleGlobal
->SmmSpiProtocol
);
1799 if (EFI_ERROR(Status
)) {
1800 Registration
= NULL
;
1801 Status
= mSmst
->SmmRegisterProtocolNotify (
1802 &gEfiSmmSpiProtocolGuid
,
1803 SmmSpiNotificationFunction
,
1807 Status
= SmmSpiInit();
1813 // Calculate the total size for all firmware volume block instances
1816 FirmwareVolumeHobList
= HobList
;
1819 Status
= GetFvbHeader (&FirmwareVolumeHobList
, &FwVolHeader
, &BaseAddress
, &WriteBack
);
1820 if (EFI_ERROR (Status
)) {
1825 BufferSize
+= (FwVolHeader
->HeaderLength
+ sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1830 // Only need to allocate once. There is only one copy of physical memory for
1831 // the private data of each FV instance. But in virtual mode or in physical
1832 // mode, the address of the the physical memory may be different.
1834 mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] = (EFI_FW_VOL_INSTANCE
*) AllocateRuntimeZeroPool (BufferSize
);
1835 ASSERT(mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
]);
1837 // Make a virtual copy of the FvInstance pointer.
1839 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1840 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1842 mFvbModuleGlobal
->NumFv
= 0;
1843 FirmwareVolumeHobList
= HobList
;
1844 TempFwVolHeader
= NULL
;
1849 // Fill in the private data of each firmware volume block instance
1851 // Foreach Fv HOB in the FirmwareVolumeHobList, loop
1854 Status
= GetFvbHeader (&FirmwareVolumeHobList
, &TempFwVolHeader
, &BaseAddress
, &WriteBack
);
1855 if (EFI_ERROR (Status
)) {
1858 FwVolHeader
= TempFwVolHeader
;
1865 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1866 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1868 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1869 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1872 // FwhInstance->FvWriteBase may not be the same as FwhInstance->FvBase
1874 FwhInstance
->FvWriteBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1875 WriteEnabled
= TRUE
;
1878 // Every pointer should have a virtual copy.
1880 FwhInstance
->FvWriteBase
[FVB_VIRTUAL
] = FwhInstance
->FvWriteBase
[FVB_PHYSICAL
];
1882 FwhInstance
->WriteEnabled
= WriteEnabled
;
1883 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1885 LbaAddress
= (UINTN
) FwhInstance
->FvWriteBase
[0];
1887 WriteLocked
= FALSE
;
1890 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1892 // Get the maximum size of a block. The size will be used to allocate
1893 // buffer for Scratch space, the intermediate buffer for FVB extension
1896 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
1897 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1900 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1903 // Write back a healthy FV header
1905 if (WriteBack
&& (!WriteLocked
)) {
1907 Status
= FlashFdErase (
1908 (UINTN
) FwhInstance
->FvWriteBase
[0],
1909 (UINTN
) BaseAddress
,
1910 FwVolHeader
->BlockMap
->Length
1913 HeaderLength
= (UINTN
) FwVolHeader
->HeaderLength
;
1914 Status
= FlashFdWrite (
1915 (UINTN
) FwhInstance
->FvWriteBase
[0],
1916 (UINTN
) BaseAddress
,
1918 (UINT8
*) FwVolHeader
,
1919 FwVolHeader
->BlockMap
->Length
1925 // The total number of blocks in the FV.
1927 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1930 // If the FV is write locked, set the appropriate attributes
1936 FwhInstance
->VolumeHeader
.Attributes
&= ~EFI_FVB2_WRITE_STATUS
;
1940 FwhInstance
->VolumeHeader
.Attributes
|= EFI_FVB2_LOCK_STATUS
;
1944 // Allocate and initialize FVB Device in a runtime data buffer
1946 FvbDevice
= AllocateRuntimeCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE
), &mFvbDeviceTemplate
);
1949 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1950 mFvbModuleGlobal
->NumFv
++;
1953 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
1955 if (FwVolHeader
->ExtHeaderOffset
== 0) {
1956 FvbDevice
->FvDevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
1957 FvbDevice
->FvDevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ (FwVolHeader
->FvLength
- 1);
1958 FwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)&FvbDevice
->FvDevicePath
;
1961 &FvbDevice
->UefiFvDevicePath
.FvDevPath
.FvName
,
1962 (EFI_GUID
*)(UINTN
)(BaseAddress
+ FwVolHeader
->ExtHeaderOffset
)
1964 FwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)&FvbDevice
->UefiFvDevicePath
;
1969 // Find a handle with a matching device path that has supports FW Block protocol
1971 TempFwbDevicePath
= FwbDevicePath
;
1972 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &TempFwbDevicePath
, &FwbHandle
);
1973 if (EFI_ERROR (Status
)) {
1975 // LocateDevicePath fails so install a new interface and device path
1978 Status
= gBS
->InstallMultipleProtocolInterfaces (
1980 &gEfiFirmwareVolumeBlockProtocolGuid
,
1981 &FvbDevice
->FwVolBlockInstance
,
1982 &gEfiDevicePathProtocolGuid
,
1986 ASSERT_EFI_ERROR (Status
);
1987 } else if (EfiIsDevicePathEnd (TempFwbDevicePath
)) {
1989 // Device already exists, so reinstall the FVB protocol
1991 Status
= gBS
->HandleProtocol (
1993 &gEfiFirmwareVolumeBlockProtocolGuid
,
1994 (VOID
**) &OldFwbInterface
1996 ASSERT_EFI_ERROR (Status
);
1998 Status
= gBS
->ReinstallProtocolInterface (
2000 &gEfiFirmwareVolumeBlockProtocolGuid
,
2002 &FvbDevice
->FwVolBlockInstance
2004 ASSERT_EFI_ERROR (Status
);
2008 // There was a FVB protocol on an End Device Path node
2014 Status
= mSmst
->SmmInstallProtocolInterface (
2016 &gEfiSmmFirmwareVolumeBlockProtocolGuid
,
2017 EFI_NATIVE_INTERFACE
,
2018 &FvbDevice
->FwVolBlockInstance
2020 ASSERT_EFI_ERROR (Status
);
2023 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
2025 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
2026 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
2031 // Allocate for scratch space, an intermediate buffer for FVB extention
2034 mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
] = AllocateRuntimeZeroPool (MaxLbaSize
);
2036 ASSERT (mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
]);
2038 mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
] = mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
];
2041 Status
= gBS
->CreateEventEx (
2044 FvbVirtualddressChangeEvent
,
2046 &gEfiEventVirtualAddressChangeGuid
,
2049 ASSERT_EFI_ERROR (Status
);
2052 // Inform other platform drivers that SPI device discovered and
2053 // SPI interface ready for use.
2056 Status
= gBS
->InstallProtocolInterface (
2058 &gEfiSmmSpiReadyProtocolGuid
,
2059 EFI_NATIVE_INTERFACE
,