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
;
19 EFI_GUID gEfiFirmwareVolumeBlockProtocolGuid
;
20 EFI_GUID gEfiSmmFirmwareVolumeBlockProtocolGuid
;
22 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
23 FVB_DEVICE_SIGNATURE
, // Signature
25 // FV_DEVICE_PATH FvDevicePath
33 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
)),
34 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
) >> 8)
38 (EFI_PHYSICAL_ADDRESS
) 0,
39 (EFI_PHYSICAL_ADDRESS
) 0
43 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
45 END_DEVICE_PATH_LENGTH
,
51 // UEFI_FV_DEVICE_PATH UefiFvDevicePath
59 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
)),
60 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
) >> 8)
67 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
69 END_DEVICE_PATH_LENGTH
,
76 // EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance
79 FvbProtocolGetAttributes
,
80 FvbProtocolSetAttributes
,
81 FvbProtocolGetPhysicalAddress
,
82 FvbProtocolGetBlockSize
,
85 FvbProtocolEraseBlocks
,
90 UINT32 mInSmmMode
= 0;
91 EFI_SMM_SYSTEM_TABLE2
* mSmst
= NULL
;
94 PublishFlashDeviceInfo (
95 IN SPI_INIT_TABLE
*Found
101 Publish info on found flash device to other drivers via PcdSpiFlashDeviceSize.
104 Found - Pointer to entry in mSpiInitTable for found flash part.
114 // Publish Byte Size of found flash device.
116 Status
= PcdSet32S (PcdSpiFlashDeviceSize
, (UINT32
)(Found
->BiosStartOffset
+ Found
->BiosSize
));
117 ASSERT_EFI_ERROR (Status
);
121 FvbVirtualddressChangeEvent (
129 Fixup internal data so that EFI and SAL can be call in virtual mode.
130 Call the passed in Child Notify event and convert the mFvbModuleGlobal
131 date items to there virtual address.
133 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
134 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
139 (Standard EFI notify event - EFI_EVENT_NOTIFY)
147 EFI_FW_VOL_INSTANCE
*FwhInstance
;
150 gRT
->ConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
153 // Convert the base address of all the instances
156 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
157 while (Index
< mFvbModuleGlobal
->NumFv
) {
159 gRT
->ConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &FwhInstance
->FvBase
[FVB_VIRTUAL
]);
161 // SpiWrite and SpiErase always use Physical Address instead of
162 // Virtual Address, even in Runtime. So we need not convert pointer
163 // for FvWriteBase[FVB_VIRTUAL]
165 // EfiConvertPointer (0, (VOID **) &FwhInstance->FvWriteBase[FVB_VIRTUAL]);
167 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
169 (UINTN
) ((UINT8
*) FwhInstance
) + FwhInstance
->VolumeHeader
.HeaderLength
+
170 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
175 gRT
->ConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
]);
177 // Convert SPI_PROTOCOL instance for runtime
179 gRT
->ConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &mFvbModuleGlobal
->SpiProtocol
);
180 gRT
->ConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &mFvbModuleGlobal
);
189 MmioWrite8 ((UINTN
)Dest
, Byte
);
197 IN ESAL_FWB_GLOBAL
*Global
,
198 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
204 Retrieves the physical address of a memory mapped FV
207 Instance - The FV instance whose base address is going to be
209 Global - Pointer to ESAL_FWB_GLOBAL that contains all
211 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
212 Virtual - Whether CPU is in virtual or physical mode
215 EFI_SUCCESS - Successfully returns
216 EFI_INVALID_PARAMETER - Instance not found
220 EFI_FW_VOL_INSTANCE
*FwhRecord
;
222 if (Instance
>= Global
->NumFv
) {
223 return EFI_INVALID_PARAMETER
;
226 // Find the right instance of the FVB private data
228 FwhRecord
= Global
->FvInstance
[Virtual
];
229 while (Instance
> 0) {
230 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
232 (UINTN
) ((UINT8
*) FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
233 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
238 *FwhInstance
= FwhRecord
;
244 FvbGetPhysicalAddress (
246 OUT EFI_PHYSICAL_ADDRESS
*Address
,
247 IN ESAL_FWB_GLOBAL
*Global
,
253 Retrieves the physical address of a memory mapped FV
256 Instance - The FV instance whose base address is going to be
258 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
259 that on successful return, contains the base address
260 of the firmware volume.
261 Global - Pointer to ESAL_FWB_GLOBAL that contains all
263 Virtual - Whether CPU is in virtual or physical mode
266 EFI_SUCCESS - Successfully returns
267 EFI_INVALID_PARAMETER - Instance not found
271 EFI_FW_VOL_INSTANCE
*FwhInstance
;
277 // Find the right instance of the FVB private data
279 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
280 ASSERT_EFI_ERROR (Status
);
281 *Address
= FwhInstance
->FvBase
[Virtual
];
287 FvbGetVolumeAttributes (
289 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
290 IN ESAL_FWB_GLOBAL
*Global
,
296 Retrieves attributes, insures positive polarity of attribute bits, returns
297 resulting attributes in output parameter
300 Instance - The FV instance whose attributes is going to be
302 Attributes - Output buffer which contains attributes
303 Global - Pointer to ESAL_FWB_GLOBAL that contains all
305 Virtual - Whether CPU is in virtual or physical mode
308 EFI_SUCCESS - Successfully returns
309 EFI_INVALID_PARAMETER - Instance not found
313 EFI_FW_VOL_INSTANCE
*FwhInstance
;
319 // Find the right instance of the FVB private data
321 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
322 ASSERT_EFI_ERROR (Status
);
323 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
332 OUT UINTN
*LbaAddress
,
333 OUT UINTN
*LbaWriteAddress
,
334 OUT UINTN
*LbaLength
,
335 OUT UINTN
*NumOfBlocks
,
336 IN ESAL_FWB_GLOBAL
*Global
,
342 Retrieves the starting address of an LBA in an FV
345 Instance - The FV instance which the Lba belongs to
346 Lba - The logical block address
347 LbaAddress - On output, contains the physical starting address
349 LbaWriteAddress - On output, contains the physical starting address
350 of the Lba for writing
351 LbaLength - On output, contains the length of the block
352 NumOfBlocks - A pointer to a caller allocated UINTN in which the
353 number of consecutive blocks starting with Lba is
354 returned. All blocks in this range have a size of
356 Global - Pointer to ESAL_FWB_GLOBAL that contains all
358 Virtual - Whether CPU is in virtual or physical mode
361 EFI_SUCCESS - Successfully returns
362 EFI_INVALID_PARAMETER - Instance not found
371 EFI_FW_VOL_INSTANCE
*FwhInstance
;
372 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
378 // Find the right instance of the FVB private data
380 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
381 ASSERT_EFI_ERROR (Status
);
385 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
388 // Parse the blockmap of the FV to find which map entry the Lba belongs to
391 NumBlocks
= BlockMap
->NumBlocks
;
392 BlockLength
= BlockMap
->Length
;
394 if ((NumBlocks
== 0) || (BlockLength
== 0)) {
395 return EFI_INVALID_PARAMETER
;
398 NextLba
= StartLba
+ NumBlocks
;
401 // The map entry found
403 if (Lba
>= StartLba
&& Lba
< NextLba
) {
404 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
406 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
409 if (LbaWriteAddress
) {
410 *LbaWriteAddress
= FwhInstance
->FvWriteBase
[Virtual
] + Offset
;
414 *LbaLength
= BlockLength
;
418 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
425 Offset
= Offset
+ NumBlocks
* BlockLength
;
434 IN UINTN BlockOffset
,
435 IN OUT UINTN
*NumBytes
,
437 IN ESAL_FWB_GLOBAL
*Global
,
443 Reads specified number of bytes into a buffer from the specified block
446 Instance - The FV instance to be read from
447 Lba - The logical block address to be read from
448 BlockOffset - Offset into the block at which to begin reading
449 NumBytes - Pointer that on input contains the total size of
450 the buffer. On output, it contains the total number
452 Buffer - Pointer to a caller allocated buffer that will be
453 used to hold the data read
454 Global - Pointer to ESAL_FWB_GLOBAL that contains all
456 Virtual - Whether CPU is in virtual or physical mode
459 EFI_SUCCESS - The firmware volume was read successfully and
460 contents are in Buffer
461 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
462 NumBytes contains the total number of bytes returned
464 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
465 EFI_DEVICE_ERROR - The block device is not functioning correctly and
467 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
471 EFI_FVB_ATTRIBUTES_2 Attributes
;
477 // Check for invalid conditions
479 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
480 return EFI_INVALID_PARAMETER
;
483 if (*NumBytes
== 0) {
484 return EFI_INVALID_PARAMETER
;
487 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, NULL
, &LbaLength
, NULL
, Global
, Virtual
);
488 if (EFI_ERROR (Status
)) {
492 // Check if the FV is read enabled
494 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
496 if ((Attributes
& EFI_FVB2_READ_STATUS
) == 0) {
497 return EFI_ACCESS_DENIED
;
500 // Perform boundary checks and adjust NumBytes
502 if (BlockOffset
> LbaLength
) {
503 return EFI_INVALID_PARAMETER
;
506 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
507 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
508 Status
= EFI_BAD_BUFFER_SIZE
;
511 MmioReadBuffer8 (LbaAddress
+ BlockOffset
, (UINTN
) *NumBytes
, Buffer
);
518 IN UINTN WriteAddress
,
520 IN OUT UINTN
*NumBytes
,
527 Writes specified number of bytes from the input buffer to the address
537 Status
= EFI_SUCCESS
;
540 // TODO: Suggested that this code be "critical section"
542 WriteAddress
-= ( PcdGet32 (PcdFlashAreaBaseAddress
) );
543 if (mInSmmMode
== 0) { // !(EfiInManagementInterrupt ())) {
544 Status
= mFvbModuleGlobal
->SpiProtocol
->Execute (
545 mFvbModuleGlobal
->SpiProtocol
,
546 SPI_OPCODE_WRITE_INDEX
, // OpcodeIndex
547 0, // PrefixOpcodeIndex
551 WriteAddress
, // Address
552 (UINT32
) (*NumBytes
), // Data Number
558 Status
= mFvbModuleGlobal
->SmmSpiProtocol
->Execute (
559 mFvbModuleGlobal
->SmmSpiProtocol
,
560 SPI_OPCODE_WRITE_INDEX
, // OpcodeIndex
561 0, // PrefixOpcodeIndex
565 WriteAddress
, // Address
566 (UINT32
) (*NumBytes
), // Data Number
579 IN UINTN WriteAddress
,
586 Erase a certain block from address LbaWriteAddress
597 NumBytes
= LbaLength
;
599 WriteAddress
-= (PcdGet32 (PcdFlashAreaBaseAddress
));
600 if (mInSmmMode
== 0 ) { // !(EfiInManagementInterrupt ())) {
601 Status
= mFvbModuleGlobal
->SpiProtocol
->Execute (
602 mFvbModuleGlobal
->SpiProtocol
,
603 SPI_OPCODE_ERASE_INDEX
, // OpcodeIndex
604 0, // PrefixOpcodeIndex
608 WriteAddress
, // Address
611 EnumSpiRegionBios
// SPI_REGION_TYPE
614 Status
= mFvbModuleGlobal
->SmmSpiProtocol
->Execute (
615 mFvbModuleGlobal
->SmmSpiProtocol
,
616 SPI_OPCODE_ERASE_INDEX
, // OpcodeIndex
617 0, // PrefixOpcodeIndex
621 WriteAddress
, // Address
624 EnumSpiRegionBios
// SPI_REGION_TYPE
637 IN UINTN BlockOffset
,
638 IN OUT UINTN
*NumBytes
,
640 IN ESAL_FWB_GLOBAL
*Global
,
646 Writes specified number of bytes from the input buffer to the block
649 Instance - The FV instance to be written to
650 Lba - The starting logical block index to write to
651 BlockOffset - Offset into the block at which to begin writing
652 NumBytes - Pointer that on input contains the total size of
653 the buffer. On output, it contains the total number
654 of bytes actually written
655 Buffer - Pointer to a caller allocated buffer that contains
656 the source for the write
657 Global - Pointer to ESAL_FWB_GLOBAL that contains all
659 Virtual - Whether CPU is in virtual or physical mode
662 EFI_SUCCESS - The firmware volume was written successfully
663 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
664 NumBytes contains the total number of bytes
666 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
667 EFI_DEVICE_ERROR - The block device is not functioning correctly and
669 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
673 EFI_FVB_ATTRIBUTES_2 Attributes
;
675 UINTN LbaWriteAddress
;
677 EFI_FW_VOL_INSTANCE
*FwhInstance
;
679 EFI_STATUS ReturnStatus
;
684 // Find the right instance of the FVB private data
686 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
687 ASSERT_EFI_ERROR (Status
);
690 // Writes are enabled in the init routine itself
692 if (!FwhInstance
->WriteEnabled
) {
693 return EFI_ACCESS_DENIED
;
696 // Check for invalid conditions
698 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
699 return EFI_INVALID_PARAMETER
;
702 if (*NumBytes
== 0) {
703 return EFI_INVALID_PARAMETER
;
706 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaWriteAddress
, &LbaLength
, NULL
, Global
, Virtual
);
707 if (EFI_ERROR (Status
)) {
711 // Check if the FV is write enabled
713 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
715 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
716 return EFI_ACCESS_DENIED
;
719 // Perform boundary checks and adjust NumBytes
721 if (BlockOffset
> LbaLength
) {
722 return EFI_INVALID_PARAMETER
;
725 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
726 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
727 Status
= EFI_BAD_BUFFER_SIZE
;
730 ReturnStatus
= FlashFdWrite (
731 LbaWriteAddress
+ BlockOffset
,
737 if (EFI_ERROR (ReturnStatus
)) {
748 IN ESAL_FWB_GLOBAL
*Global
,
754 Erases and initializes a firmware volume block
757 Instance - The FV instance to be erased
758 Lba - The logical block index to be erased
759 Global - Pointer to ESAL_FWB_GLOBAL that contains all
761 Virtual - Whether CPU is in virtual or physical mode
764 EFI_SUCCESS - The erase request was successfully completed
765 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
766 EFI_DEVICE_ERROR - The block device is not functioning correctly and
767 could not be written. Firmware device may have been
769 EFI_INVALID_PARAMETER - Instance not found
774 EFI_FVB_ATTRIBUTES_2 Attributes
;
776 UINTN LbaWriteAddress
;
777 EFI_FW_VOL_INSTANCE
*FwhInstance
;
786 // Find the right instance of the FVB private data
788 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
789 ASSERT_EFI_ERROR (Status
);
792 // Writes are enabled in the init routine itself
794 if (!FwhInstance
->WriteEnabled
) {
795 return EFI_ACCESS_DENIED
;
798 // Check if the FV is write enabled
800 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
802 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
803 return EFI_ACCESS_DENIED
;
806 // Get the starting address of the block for erase. For debug reasons,
807 // LbaWriteAddress may not be the same as LbaAddress.
809 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaWriteAddress
, &LbaLength
, NULL
, Global
, Virtual
);
810 if (EFI_ERROR (Status
)) {
814 SectorNum
= LbaLength
/ SPI_ERASE_SECTOR_SIZE
;
815 for (Index
= 0; Index
< SectorNum
; Index
++){
816 Status
= FlashFdErase (
817 LbaWriteAddress
+ Index
* SPI_ERASE_SECTOR_SIZE
,
819 SPI_ERASE_SECTOR_SIZE
821 if (Status
!= EFI_SUCCESS
){
830 FvbEraseCustomBlockRange (
833 IN UINTN OffsetStartLba
,
835 IN UINTN OffsetLastLba
,
836 IN ESAL_FWB_GLOBAL
*Global
,
842 Erases and initializes a specified range of a firmware volume
845 Instance - The FV instance to be erased
846 StartLba - The starting logical block index to be erased
847 OffsetStartLba - Offset into the starting block at which to
849 LastLba - The last logical block index to be erased
850 OffsetStartLba - Offset into the last block at which to end erasing
851 Global - Pointer to ESAL_FWB_GLOBAL that contains all
853 Virtual - Whether CPU is in virtual or physical mode
856 EFI_SUCCESS - The firmware volume was erased successfully
857 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
858 EFI_DEVICE_ERROR - The block device is not functioning correctly and
859 could not be written. Firmware device may have been
861 EFI_INVALID_PARAMETER - Instance not found
867 UINTN ScratchLbaSizeData
;
872 FvbGetLbaAddress (Instance
, StartLba
, NULL
, NULL
, &LbaSize
, NULL
, Global
, Virtual
);
875 // Use the scratch space as the intermediate buffer to transfer data
876 // Back up the first LBA in scratch space.
878 FvbReadBlock (Instance
, StartLba
, 0, &LbaSize
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
883 FvbEraseBlock (Instance
, StartLba
, Global
, Virtual
);
884 ScratchLbaSizeData
= OffsetStartLba
;
887 // write the data back to the first block
889 if (ScratchLbaSizeData
> 0) {
890 FvbWriteBlock (Instance
, StartLba
, 0, &ScratchLbaSizeData
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
895 if (LastLba
> (StartLba
+ 1)) {
896 for (Index
= (StartLba
+ 1); Index
<= (LastLba
- 1); Index
++) {
897 FvbEraseBlock (Instance
, Index
, Global
, Virtual
);
901 // Last LBAs, the same as first LBAs
903 if (LastLba
> StartLba
) {
904 FvbGetLbaAddress (Instance
, LastLba
, NULL
, NULL
, &LbaSize
, NULL
, Global
, Virtual
);
905 FvbReadBlock (Instance
, LastLba
, 0, &LbaSize
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
906 FvbEraseBlock (Instance
, LastLba
, Global
, Virtual
);
909 ScratchLbaSizeData
= LbaSize
- (OffsetStartLba
+ 1);
911 return FvbWriteBlock (
916 Global
->FvbScratchSpace
[Virtual
],
923 FvbSetVolumeAttributes (
925 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
926 IN ESAL_FWB_GLOBAL
*Global
,
932 Modifies the current settings of the firmware volume according to the
933 input parameter, and returns the new setting of the volume
936 Instance - The FV instance whose attributes is going to be
938 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
939 containing the desired firmware volume settings.
940 On successful return, it contains the new settings
941 of the firmware volume
942 Global - Pointer to ESAL_FWB_GLOBAL that contains all
944 Virtual - Whether CPU is in virtual or physical mode
947 EFI_SUCCESS - Successfully returns
948 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
949 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
950 in conflict with the capabilities as declared in the
951 firmware volume header
955 EFI_FW_VOL_INSTANCE
*FwhInstance
;
956 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
957 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
966 // Find the right instance of the FVB private data
968 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
969 ASSERT_EFI_ERROR (Status
);
971 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
972 OldAttributes
= *AttribPtr
;
973 Capabilities
= OldAttributes
& EFI_FVB2_CAPABILITIES
;
974 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
975 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
978 // If firmware volume is locked, no status bit can be updated
980 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
981 if (OldStatus
^ NewStatus
) {
982 return EFI_ACCESS_DENIED
;
988 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
989 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
990 return EFI_INVALID_PARAMETER
;
996 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
997 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
998 return EFI_INVALID_PARAMETER
;
1002 // Test write disable
1004 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
1005 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
1006 return EFI_INVALID_PARAMETER
;
1010 // Test write enable
1012 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
1013 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
1014 return EFI_INVALID_PARAMETER
;
1020 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
1021 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
1022 return EFI_INVALID_PARAMETER
;
1026 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
1027 *AttribPtr
= (*AttribPtr
) | NewStatus
;
1028 *Attributes
= *AttribPtr
;
1033 // FVB protocol APIs
1037 FvbProtocolGetPhysicalAddress (
1038 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1039 OUT EFI_PHYSICAL_ADDRESS
*Address
1043 Routine Description:
1045 Retrieves the physical address of the device.
1049 This - Calling context
1050 Address - Output buffer containing the address.
1055 EFI_SUCCESS - Successfully returns
1059 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1061 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1063 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
1067 FvbProtocolGetBlockSize (
1068 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1070 OUT UINTN
*BlockSize
,
1071 OUT UINTN
*NumOfBlocks
1075 Routine Description:
1076 Retrieve the size of a logical block
1079 This - Calling context
1080 Lba - Indicates which block to return the size for.
1081 BlockSize - A pointer to a caller allocated UINTN in which
1082 the size of the block is returned
1083 NumOfBlocks - a pointer to a caller allocated UINTN in which the
1084 number of consecutive blocks starting with Lba is
1085 returned. All blocks in this range have a size of
1089 EFI_SUCCESS - The firmware volume was read successfully and
1090 contents are in Buffer
1094 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1096 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1098 return FvbGetLbaAddress (
1099 FvbDevice
->Instance
,
1112 FvbProtocolGetAttributes (
1113 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1114 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
1118 Routine Description:
1119 Retrieves Volume attributes. No polarity translations are done.
1122 This - Calling context
1123 Attributes - output buffer which contains attributes
1126 EFI_SUCCESS - Successfully returns
1130 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1132 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1134 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
1139 FvbProtocolSetAttributes (
1140 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1141 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
1145 Routine Description:
1146 Sets Volume attributes. No polarity translations are done.
1149 This - Calling context
1150 Attributes - output buffer which contains attributes
1153 EFI_SUCCESS - Successfully returns
1157 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1159 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1161 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
1166 FvbProtocolEraseBlocks (
1167 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1172 Routine Description:
1174 The EraseBlock() function erases one or more blocks as denoted by the
1175 variable argument list. The entire parameter list of blocks must be verified
1176 prior to erasing any blocks. If a block is requested that does not exist
1177 within the associated firmware volume (it has a larger index than the last
1178 block of the firmware volume), the EraseBlock() function must return
1179 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
1182 This - Calling context
1183 ... - Starting LBA followed by Number of Lba to erase.
1184 a -1 to terminate the list.
1187 EFI_SUCCESS - The erase request was successfully completed
1188 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1189 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1190 could not be written. Firmware device may have been
1195 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1196 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1199 EFI_LBA StartingLba
;
1204 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1206 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
1207 ASSERT_EFI_ERROR (Status
);
1209 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
1211 VA_START (args
, This
);
1214 StartingLba
= VA_ARG (args
, EFI_LBA
);
1215 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
1219 NumOfLba
= VA_ARG (args
, UINT32
);
1222 // Check input parameters
1224 if (NumOfLba
== 0) {
1226 return EFI_INVALID_PARAMETER
;
1229 if ((StartingLba
+ NumOfLba
) > NumOfBlocks
) {
1230 return EFI_INVALID_PARAMETER
;
1236 VA_START (args
, This
);
1238 StartingLba
= VA_ARG (args
, EFI_LBA
);
1239 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
1243 NumOfLba
= VA_ARG (args
, UINT32
);
1245 while (NumOfLba
> 0) {
1246 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
1247 if (EFI_ERROR (Status
)) {
1266 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1269 IN OUT UINTN
*NumBytes
,
1274 Routine Description:
1276 Writes data beginning at Lba:Offset from FV. The write terminates either
1277 when *NumBytes of data have been written, or when a block boundary is
1278 reached. *NumBytes is updated to reflect the actual number of bytes
1279 written. The write opertion does not include erase. This routine will
1280 attempt to write only the specified bytes. If the writes do not stick,
1281 it will return an error.
1284 This - Calling context
1285 Lba - Block in which to begin write
1286 Offset - Offset in the block at which to begin write
1287 NumBytes - On input, indicates the requested write size. On
1288 output, indicates the actual number of bytes written
1289 Buffer - Buffer containing source data for the write.
1292 EFI_SUCCESS - The firmware volume was written successfully
1293 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
1294 NumBytes contains the total number of bytes
1296 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1297 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1298 could not be written
1299 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1304 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1306 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1308 return FvbWriteBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1314 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1317 IN OUT UINTN
*NumBytes
,
1322 Routine Description:
1324 Reads data beginning at Lba:Offset from FV. The Read terminates either
1325 when *NumBytes of data have been read, or when a block boundary is
1326 reached. *NumBytes is updated to reflect the actual number of bytes
1327 written. The write opertion does not include erase. This routine will
1328 attempt to write only the specified bytes. If the writes do not stick,
1329 it will return an error.
1332 This - Calling context
1333 Lba - Block in which to begin Read
1334 Offset - Offset in the block at which to begin Read
1335 NumBytes - On input, indicates the requested write size. On
1336 output, indicates the actual number of bytes Read
1337 Buffer - Buffer containing source data for the Read.
1340 EFI_SUCCESS - The firmware volume was read successfully and
1341 contents are in Buffer
1342 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1343 NumBytes contains the total number of bytes returned
1345 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1346 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1348 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1353 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1356 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1357 Status
= FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1364 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1368 Routine Description:
1369 Check the integrity of firmware volume header
1372 FwVolHeader - A pointer to a firmware volume header
1375 EFI_SUCCESS - The firmware volume is consistent
1376 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1381 UINT16 HeaderLength
;
1385 // Verify the header revision, header signature, length
1386 // Length of FvBlock cannot be 2**64-1
1387 // HeaderLength cannot be an odd number
1390 if (((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) && (FwVolHeader
->Revision
!= EFI_FVH_REVISION
)) ||
1392 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1394 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1395 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
1396 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1398 return EFI_NOT_FOUND
;
1401 // Verify the header checksum
1403 HeaderLength
= (UINT16
) (FwVolHeader
->HeaderLength
/ 2);
1404 Ptr
= (UINT16
*) FwVolHeader
;
1406 while (HeaderLength
> 0) {
1407 Checksum
= Checksum
+ (*Ptr
);
1412 if (Checksum
!= 0) {
1413 return EFI_NOT_FOUND
;
1422 OUT EFI_FIRMWARE_VOLUME_HEADER
**FwVolHeader
,
1423 OUT EFI_PHYSICAL_ADDRESS
*BaseAddress
,
1424 OUT BOOLEAN
*WriteBack
1429 Status
= EFI_SUCCESS
;
1432 if (*FwVolHeader
== NULL
) {
1433 *BaseAddress
= PcdGet32 (PcdFlashFvRecoveryBase
);
1434 } else if (*FwVolHeader
== (VOID
*)(UINTN
)PcdGet32 (PcdFlashFvRecoveryBase
)) {
1435 *BaseAddress
= PcdGet32 (PcdFlashFvMainBase
);
1436 } else if (*FwVolHeader
== (VOID
*)(UINTN
)PcdGet32 (PcdFlashFvMainBase
)) {
1437 *BaseAddress
= PcdGet32 (PcdFlashNvStorageVariableBase
);
1439 return EFI_NOT_FOUND
;
1442 DEBUG((EFI_D_INFO
, "Fvb base : %08x\n",*BaseAddress
));
1444 *FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) (*BaseAddress
);
1445 Status
= ValidateFvHeader (*FwVolHeader
);
1446 if (EFI_ERROR (Status
)) {
1452 Status
= GetFvbInfo (*BaseAddress
, FwVolHeader
);
1453 DEBUG(( DEBUG_ERROR
, "Through GetFvbInfo: %08x!\n",*BaseAddress
));
1455 ASSERT_EFI_ERROR (Status
);
1473 // Obtain a handle for ICH SPI Protocol
1475 ASSERT(mSmst
!= NULL
);
1476 if (mFvbModuleGlobal
->SmmSpiProtocol
== NULL
){
1477 Status
= mSmst
->SmmLocateProtocol (&gEfiSmmSpiProtocolGuid
, NULL
, (VOID
**) &mFvbModuleGlobal
->SmmSpiProtocol
);
1478 ASSERT_EFI_ERROR(Status
);
1481 // attempt to identify flash part and initialize spi table
1483 for (FlashIndex
= 0; FlashIndex
< EnumSpiFlashMax
; FlashIndex
++) {
1484 Status
= mFvbModuleGlobal
->SmmSpiProtocol
->Init (
1485 mFvbModuleGlobal
->SmmSpiProtocol
,
1486 &(mSpiInitTable
[FlashIndex
])
1488 if (!EFI_ERROR (Status
)) {
1490 // read vendor/device IDs to check if flash device is supported
1492 Status
= mFvbModuleGlobal
->SmmSpiProtocol
->Execute (
1493 mFvbModuleGlobal
->SmmSpiProtocol
,
1494 SPI_OPCODE_JEDEC_ID_INDEX
,
1504 if (!EFI_ERROR (Status
)) {
1505 if (((FlashID
[0] == mSpiInitTable
[FlashIndex
].VendorId
) &&
1506 (FlashID
[2] == mSpiInitTable
[FlashIndex
].DeviceId1
)) ||
1507 ((FlashID
[0] == SPI_AT26DF321_ID1
) &&
1508 (FlashID
[0] == mSpiInitTable
[FlashIndex
].VendorId
) &&
1509 (FlashID
[1] == mSpiInitTable
[FlashIndex
].DeviceId0
))) {
1511 // Supported SPI device found
1515 "Smm Mode: Supported SPI Flash device found, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1526 if (FlashIndex
>= EnumSpiFlashMax
) {
1527 Status
= EFI_UNSUPPORTED
;
1530 "ERROR - Unknown SPI Flash Device, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1535 ASSERT_EFI_ERROR (Status
);
1539 Status
= mFvbModuleGlobal
->SmmSpiProtocol
->Execute (
1540 mFvbModuleGlobal
->SmmSpiProtocol
,
1541 SPI_OPCODE_WRITE_S_INDEX
, // OpcodeIndex
1542 1, // PrefixOpcodeIndex
1549 EnumSpiRegionAll
// SPI_REGION_TYPE
1555 SmmSpiNotificationFunction (
1556 IN CONST EFI_GUID
*Protocol
,
1558 IN EFI_HANDLE Handle
1561 return SmmSpiInit();
1568 IN EFI_HANDLE ImageHandle
,
1569 IN EFI_SYSTEM_TABLE
*SystemTable
,
1570 OUT EFI_DEVICE_PATH_PROTOCOL
**CompleteFilePath
1574 Routine Description:
1576 Function is used to get the full device path for this driver.
1580 ImageHandle - The loaded image handle of this driver.
1581 SystemTable - The pointer of system table.
1582 CompleteFilePath - The pointer of returned full file path
1591 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
1592 EFI_DEVICE_PATH_PROTOCOL
*ImageDevicePath
;
1595 Status
= gBS
->HandleProtocol (
1597 &gEfiLoadedImageProtocolGuid
,
1598 (VOID
**) &LoadedImage
1600 ASSERT_EFI_ERROR (Status
);
1602 Status
= gBS
->HandleProtocol (
1603 LoadedImage
->DeviceHandle
,
1604 &gEfiDevicePathProtocolGuid
,
1605 (VOID
*) &ImageDevicePath
1607 ASSERT_EFI_ERROR (Status
);
1609 *CompleteFilePath
= AppendDevicePath (
1611 LoadedImage
->FilePath
1621 IN EFI_HANDLE ImageHandle
,
1622 IN EFI_SYSTEM_TABLE
*SystemTable
1626 Routine Description:
1627 This function does common initialization for FVB services
1636 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1637 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1638 EFI_FIRMWARE_VOLUME_HEADER
*TempFwVolHeader
;
1640 VOID
*FirmwareVolumeHobList
;
1642 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1644 BOOLEAN WriteEnabled
;
1645 BOOLEAN WriteLocked
;
1646 EFI_HANDLE FwbHandle
;
1647 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1648 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1649 EFI_DEVICE_PATH_PROTOCOL
*FwbDevicePath
;
1650 EFI_DEVICE_PATH_PROTOCOL
*TempFwbDevicePath
;
1652 EFI_PHYSICAL_ADDRESS BaseAddress
;
1659 EFI_DEVICE_PATH_PROTOCOL
*CompleteFilePath
;
1660 UINT8 PrefixOpcodeIndex
;
1662 EFI_SMM_BASE2_PROTOCOL
*mSmmBase2
;
1668 CompleteFilePath
= NULL
;
1669 GetFullDriverPath (ImageHandle
, SystemTable
, &CompleteFilePath
);
1671 Status
= EfiGetSystemConfigurationTable (&gEfiHobListGuid
, &HobList
);
1676 ASSERT_EFI_ERROR (Status
);
1680 // Allocate runtime services data for global variable, which contains
1681 // the private data of all firmware volume block instances
1683 mFvbModuleGlobal
= (ESAL_FWB_GLOBAL
*)AllocateRuntimeZeroPool(sizeof (ESAL_FWB_GLOBAL
));
1684 ASSERT(mFvbModuleGlobal
);
1686 Status
= gBS
->LocateProtocol (
1687 &gEfiSmmBase2ProtocolGuid
,
1689 (VOID
**) &mSmmBase2
1692 if (mSmmBase2
== NULL
) {
1695 mSmmBase2
->InSmm (mSmmBase2
, &InSmm
);
1696 mSmmBase2
->GetSmstLocation (mSmmBase2
, &mSmst
);
1703 // Obtain a handle for ICH SPI Protocol
1705 Status
= gBS
->LocateProtocol (&gEfiSpiProtocolGuid
, NULL
, (VOID
**) &mFvbModuleGlobal
->SpiProtocol
);
1706 ASSERT_EFI_ERROR (Status
);
1709 // attempt to identify flash part and initialize spi table
1711 for (FlashIndex
= 0; FlashIndex
< EnumSpiFlashMax
; FlashIndex
++) {
1712 Status
= mFvbModuleGlobal
->SpiProtocol
->Init (
1713 mFvbModuleGlobal
->SpiProtocol
,
1714 &(mSpiInitTable
[FlashIndex
])
1716 if (!EFI_ERROR (Status
)) {
1718 // read vendor/device IDs to check if flash device is supported
1720 Status
= mFvbModuleGlobal
->SpiProtocol
->Execute (
1721 mFvbModuleGlobal
->SpiProtocol
,
1722 SPI_OPCODE_JEDEC_ID_INDEX
,
1732 if (!EFI_ERROR (Status
)) {
1733 if (((FlashID
[0] == mSpiInitTable
[FlashIndex
].VendorId
) &&
1734 (FlashID
[2] == mSpiInitTable
[FlashIndex
].DeviceId1
)) ||
1735 ((FlashID
[0] == SPI_AT26DF321_ID1
) &&
1736 (FlashID
[0] == mSpiInitTable
[FlashIndex
].VendorId
) &&
1737 (FlashID
[1] == mSpiInitTable
[FlashIndex
].DeviceId0
))) {
1739 // Supported SPI device found
1743 "Supported SPI Flash device found, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1749 PublishFlashDeviceInfo (&mSpiInitTable
[FlashIndex
]);
1756 if (FlashIndex
>= EnumSpiFlashMax
) {
1757 Status
= EFI_UNSUPPORTED
;
1760 "ERROR - Unknown SPI Flash Device, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1765 ASSERT_EFI_ERROR (Status
);
1769 // Unlock all regions by writing to status register
1770 // This could be SPI device specific, need to follow the datasheet
1771 // To write to Write Status Register the Spi PrefixOpcode needs to be:
1772 // 0 for Atmel parts
1773 // 0 for Intel parts
1774 // 0 for Macronix parts
1775 // 0 for Winbond parts
1778 if (FlashID
[0] == SPI_SST25VF016B_ID1
) {
1779 PrefixOpcodeIndex
= 1;
1781 PrefixOpcodeIndex
= 0;
1783 Status
= mFvbModuleGlobal
->SpiProtocol
->Execute (
1784 mFvbModuleGlobal
->SpiProtocol
,
1785 SPI_OPCODE_WRITE_S_INDEX
, // OpcodeIndex
1786 PrefixOpcodeIndex
, // PrefixOpcodeIndex
1793 EnumSpiRegionAll
// SPI_REGION_TYPE
1800 Status
= mSmst
->SmmLocateProtocol (&gEfiSmmSpiProtocolGuid
, NULL
, (VOID
**) &mFvbModuleGlobal
->SmmSpiProtocol
);
1801 if (EFI_ERROR(Status
)) {
1802 Registration
= NULL
;
1803 Status
= mSmst
->SmmRegisterProtocolNotify (
1804 &gEfiSmmSpiProtocolGuid
,
1805 SmmSpiNotificationFunction
,
1809 Status
= SmmSpiInit();
1815 // Calculate the total size for all firmware volume block instances
1818 FirmwareVolumeHobList
= HobList
;
1821 Status
= GetFvbHeader (&FirmwareVolumeHobList
, &FwVolHeader
, &BaseAddress
, &WriteBack
);
1822 if (EFI_ERROR (Status
)) {
1827 BufferSize
+= (FwVolHeader
->HeaderLength
+ sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1832 // Only need to allocate once. There is only one copy of physical memory for
1833 // the private data of each FV instance. But in virtual mode or in physical
1834 // mode, the address of the the physical memory may be different.
1836 mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] = (EFI_FW_VOL_INSTANCE
*) AllocateRuntimeZeroPool (BufferSize
);
1837 ASSERT(mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
]);
1839 // Make a virtual copy of the FvInstance pointer.
1841 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1842 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1844 mFvbModuleGlobal
->NumFv
= 0;
1845 FirmwareVolumeHobList
= HobList
;
1846 TempFwVolHeader
= NULL
;
1851 // Fill in the private data of each firmware volume block instance
1853 // Foreach Fv HOB in the FirmwareVolumeHobList, loop
1856 Status
= GetFvbHeader (&FirmwareVolumeHobList
, &TempFwVolHeader
, &BaseAddress
, &WriteBack
);
1857 if (EFI_ERROR (Status
)) {
1860 FwVolHeader
= TempFwVolHeader
;
1867 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1868 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1870 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1871 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1874 // FwhInstance->FvWriteBase may not be the same as FwhInstance->FvBase
1876 FwhInstance
->FvWriteBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1877 WriteEnabled
= TRUE
;
1880 // Every pointer should have a virtual copy.
1882 FwhInstance
->FvWriteBase
[FVB_VIRTUAL
] = FwhInstance
->FvWriteBase
[FVB_PHYSICAL
];
1884 FwhInstance
->WriteEnabled
= WriteEnabled
;
1885 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1887 LbaAddress
= (UINTN
) FwhInstance
->FvWriteBase
[0];
1889 WriteLocked
= FALSE
;
1892 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1894 // Get the maximum size of a block. The size will be used to allocate
1895 // buffer for Scratch space, the intermediate buffer for FVB extension
1898 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
1899 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1902 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1905 // Write back a healthy FV header
1907 if (WriteBack
&& (!WriteLocked
)) {
1909 Status
= FlashFdErase (
1910 (UINTN
) FwhInstance
->FvWriteBase
[0],
1911 (UINTN
) BaseAddress
,
1912 FwVolHeader
->BlockMap
->Length
1915 HeaderLength
= (UINTN
) FwVolHeader
->HeaderLength
;
1916 Status
= FlashFdWrite (
1917 (UINTN
) FwhInstance
->FvWriteBase
[0],
1918 (UINTN
) BaseAddress
,
1920 (UINT8
*) FwVolHeader
,
1921 FwVolHeader
->BlockMap
->Length
1927 // The total number of blocks in the FV.
1929 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1932 // If the FV is write locked, set the appropriate attributes
1938 FwhInstance
->VolumeHeader
.Attributes
&= ~EFI_FVB2_WRITE_STATUS
;
1942 FwhInstance
->VolumeHeader
.Attributes
|= EFI_FVB2_LOCK_STATUS
;
1946 // Allocate and initialize FVB Device in a runtime data buffer
1948 FvbDevice
= AllocateRuntimeCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE
), &mFvbDeviceTemplate
);
1951 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1952 mFvbModuleGlobal
->NumFv
++;
1955 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
1957 if (FwVolHeader
->ExtHeaderOffset
== 0) {
1958 FvbDevice
->FvDevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
1959 FvbDevice
->FvDevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ (FwVolHeader
->FvLength
- 1);
1960 FwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)&FvbDevice
->FvDevicePath
;
1963 &FvbDevice
->UefiFvDevicePath
.FvDevPath
.FvName
,
1964 (EFI_GUID
*)(UINTN
)(BaseAddress
+ FwVolHeader
->ExtHeaderOffset
)
1966 FwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)&FvbDevice
->UefiFvDevicePath
;
1971 // Find a handle with a matching device path that has supports FW Block protocol
1973 TempFwbDevicePath
= FwbDevicePath
;
1974 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &TempFwbDevicePath
, &FwbHandle
);
1975 if (EFI_ERROR (Status
)) {
1977 // LocateDevicePath fails so install a new interface and device path
1980 Status
= gBS
->InstallMultipleProtocolInterfaces (
1982 &gEfiFirmwareVolumeBlockProtocolGuid
,
1983 &FvbDevice
->FwVolBlockInstance
,
1984 &gEfiDevicePathProtocolGuid
,
1988 ASSERT_EFI_ERROR (Status
);
1989 } else if (EfiIsDevicePathEnd (TempFwbDevicePath
)) {
1991 // Device already exists, so reinstall the FVB protocol
1993 Status
= gBS
->HandleProtocol (
1995 &gEfiFirmwareVolumeBlockProtocolGuid
,
1996 (VOID
**) &OldFwbInterface
1998 ASSERT_EFI_ERROR (Status
);
2000 Status
= gBS
->ReinstallProtocolInterface (
2002 &gEfiFirmwareVolumeBlockProtocolGuid
,
2004 &FvbDevice
->FwVolBlockInstance
2006 ASSERT_EFI_ERROR (Status
);
2010 // There was a FVB protocol on an End Device Path node
2016 Status
= mSmst
->SmmInstallProtocolInterface (
2018 &gEfiSmmFirmwareVolumeBlockProtocolGuid
,
2019 EFI_NATIVE_INTERFACE
,
2020 &FvbDevice
->FwVolBlockInstance
2022 ASSERT_EFI_ERROR (Status
);
2025 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
2027 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
2028 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
2033 // Allocate for scratch space, an intermediate buffer for FVB extention
2036 mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
] = AllocateRuntimeZeroPool (MaxLbaSize
);
2038 ASSERT (mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
]);
2040 mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
] = mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
];
2043 Status
= gBS
->CreateEventEx (
2046 FvbVirtualddressChangeEvent
,
2048 &gEfiEventVirtualAddressChangeGuid
,
2051 ASSERT_EFI_ERROR (Status
);
2054 // Inform other platform drivers that SPI device discovered and
2055 // SPI interface ready for use.
2058 Status
= gBS
->InstallProtocolInterface (
2060 &gEfiSmmSpiReadyProtocolGuid
,
2061 EFI_NATIVE_INTERFACE
,