3 Copyright (c) 2013-2016 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
594 WriteAddress
-= (PcdGet32 (PcdFlashAreaBaseAddress
));
595 if (mInSmmMode
== 0 ) { // !(EfiInManagementInterrupt ())) {
596 Status
= mFvbModuleGlobal
->SpiProtocol
->Execute (
597 mFvbModuleGlobal
->SpiProtocol
,
598 SPI_OPCODE_ERASE_INDEX
, // OpcodeIndex
599 0, // PrefixOpcodeIndex
603 WriteAddress
, // Address
606 EnumSpiRegionBios
// SPI_REGION_TYPE
609 Status
= mFvbModuleGlobal
->SmmSpiProtocol
->Execute (
610 mFvbModuleGlobal
->SmmSpiProtocol
,
611 SPI_OPCODE_ERASE_INDEX
, // OpcodeIndex
612 0, // PrefixOpcodeIndex
616 WriteAddress
, // Address
619 EnumSpiRegionBios
// SPI_REGION_TYPE
632 IN UINTN BlockOffset
,
633 IN OUT UINTN
*NumBytes
,
635 IN ESAL_FWB_GLOBAL
*Global
,
641 Writes specified number of bytes from the input buffer to the block
644 Instance - The FV instance to be written to
645 Lba - The starting logical block index to write to
646 BlockOffset - Offset into the block at which to begin writing
647 NumBytes - Pointer that on input contains the total size of
648 the buffer. On output, it contains the total number
649 of bytes actually written
650 Buffer - Pointer to a caller allocated buffer that contains
651 the source for the write
652 Global - Pointer to ESAL_FWB_GLOBAL that contains all
654 Virtual - Whether CPU is in virtual or physical mode
657 EFI_SUCCESS - The firmware volume was written successfully
658 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
659 NumBytes contains the total number of bytes
661 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
662 EFI_DEVICE_ERROR - The block device is not functioning correctly and
664 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
668 EFI_FVB_ATTRIBUTES_2 Attributes
;
670 UINTN LbaWriteAddress
;
672 EFI_FW_VOL_INSTANCE
*FwhInstance
;
674 EFI_STATUS ReturnStatus
;
679 // Find the right instance of the FVB private data
681 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
682 ASSERT_EFI_ERROR (Status
);
685 // Writes are enabled in the init routine itself
687 if (!FwhInstance
->WriteEnabled
) {
688 return EFI_ACCESS_DENIED
;
691 // Check for invalid conditions
693 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
694 return EFI_INVALID_PARAMETER
;
697 if (*NumBytes
== 0) {
698 return EFI_INVALID_PARAMETER
;
701 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaWriteAddress
, &LbaLength
, NULL
, Global
, Virtual
);
702 if (EFI_ERROR (Status
)) {
706 // Check if the FV is write enabled
708 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
710 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
711 return EFI_ACCESS_DENIED
;
714 // Perform boundary checks and adjust NumBytes
716 if (BlockOffset
> LbaLength
) {
717 return EFI_INVALID_PARAMETER
;
720 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
721 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
722 Status
= EFI_BAD_BUFFER_SIZE
;
725 ReturnStatus
= FlashFdWrite (
726 LbaWriteAddress
+ BlockOffset
,
732 if (EFI_ERROR (ReturnStatus
)) {
743 IN ESAL_FWB_GLOBAL
*Global
,
749 Erases and initializes a firmware volume block
752 Instance - The FV instance to be erased
753 Lba - The logical block index to be erased
754 Global - Pointer to ESAL_FWB_GLOBAL that contains all
756 Virtual - Whether CPU is in virtual or physical mode
759 EFI_SUCCESS - The erase request was successfully completed
760 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
761 EFI_DEVICE_ERROR - The block device is not functioning correctly and
762 could not be written. Firmware device may have been
764 EFI_INVALID_PARAMETER - Instance not found
769 EFI_FVB_ATTRIBUTES_2 Attributes
;
771 UINTN LbaWriteAddress
;
772 EFI_FW_VOL_INSTANCE
*FwhInstance
;
781 // Find the right instance of the FVB private data
783 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
784 ASSERT_EFI_ERROR (Status
);
787 // Writes are enabled in the init routine itself
789 if (!FwhInstance
->WriteEnabled
) {
790 return EFI_ACCESS_DENIED
;
793 // Check if the FV is write enabled
795 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
797 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
798 return EFI_ACCESS_DENIED
;
801 // Get the starting address of the block for erase. For debug reasons,
802 // LbaWriteAddress may not be the same as LbaAddress.
804 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaWriteAddress
, &LbaLength
, NULL
, Global
, Virtual
);
805 if (EFI_ERROR (Status
)) {
809 SectorNum
= LbaLength
/ SPI_ERASE_SECTOR_SIZE
;
810 for (Index
= 0; Index
< SectorNum
; Index
++){
811 Status
= FlashFdErase (
812 LbaWriteAddress
+ Index
* SPI_ERASE_SECTOR_SIZE
,
814 SPI_ERASE_SECTOR_SIZE
816 if (Status
!= EFI_SUCCESS
){
825 FvbEraseCustomBlockRange (
828 IN UINTN OffsetStartLba
,
830 IN UINTN OffsetLastLba
,
831 IN ESAL_FWB_GLOBAL
*Global
,
837 Erases and initializes a specified range of a firmware volume
840 Instance - The FV instance to be erased
841 StartLba - The starting logical block index to be erased
842 OffsetStartLba - Offset into the starting block at which to
844 LastLba - The last logical block index to be erased
845 OffsetStartLba - Offset into the last block at which to end erasing
846 Global - Pointer to ESAL_FWB_GLOBAL that contains all
848 Virtual - Whether CPU is in virtual or physical mode
851 EFI_SUCCESS - The firmware volume was erased successfully
852 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
853 EFI_DEVICE_ERROR - The block device is not functioning correctly and
854 could not be written. Firmware device may have been
856 EFI_INVALID_PARAMETER - Instance not found
862 UINTN ScratchLbaSizeData
;
867 FvbGetLbaAddress (Instance
, StartLba
, NULL
, NULL
, &LbaSize
, NULL
, Global
, Virtual
);
870 // Use the scratch space as the intermediate buffer to transfer data
871 // Back up the first LBA in scratch space.
873 FvbReadBlock (Instance
, StartLba
, 0, &LbaSize
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
878 FvbEraseBlock (Instance
, StartLba
, Global
, Virtual
);
879 ScratchLbaSizeData
= OffsetStartLba
;
882 // write the data back to the first block
884 if (ScratchLbaSizeData
> 0) {
885 FvbWriteBlock (Instance
, StartLba
, 0, &ScratchLbaSizeData
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
890 if (LastLba
> (StartLba
+ 1)) {
891 for (Index
= (StartLba
+ 1); Index
<= (LastLba
- 1); Index
++) {
892 FvbEraseBlock (Instance
, Index
, Global
, Virtual
);
896 // Last LBAs, the same as first LBAs
898 if (LastLba
> StartLba
) {
899 FvbGetLbaAddress (Instance
, LastLba
, NULL
, NULL
, &LbaSize
, NULL
, Global
, Virtual
);
900 FvbReadBlock (Instance
, LastLba
, 0, &LbaSize
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
901 FvbEraseBlock (Instance
, LastLba
, Global
, Virtual
);
904 ScratchLbaSizeData
= LbaSize
- (OffsetStartLba
+ 1);
906 return FvbWriteBlock (
911 Global
->FvbScratchSpace
[Virtual
],
918 FvbSetVolumeAttributes (
920 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
921 IN ESAL_FWB_GLOBAL
*Global
,
927 Modifies the current settings of the firmware volume according to the
928 input parameter, and returns the new setting of the volume
931 Instance - The FV instance whose attributes is going to be
933 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
934 containing the desired firmware volume settings.
935 On successful return, it contains the new settings
936 of the firmware volume
937 Global - Pointer to ESAL_FWB_GLOBAL that contains all
939 Virtual - Whether CPU is in virtual or physical mode
942 EFI_SUCCESS - Successfully returns
943 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
944 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
945 in conflict with the capabilities as declared in the
946 firmware volume header
950 EFI_FW_VOL_INSTANCE
*FwhInstance
;
951 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
952 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
961 // Find the right instance of the FVB private data
963 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
964 ASSERT_EFI_ERROR (Status
);
966 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
967 OldAttributes
= *AttribPtr
;
968 Capabilities
= OldAttributes
& EFI_FVB2_CAPABILITIES
;
969 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
970 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
973 // If firmware volume is locked, no status bit can be updated
975 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
976 if (OldStatus
^ NewStatus
) {
977 return EFI_ACCESS_DENIED
;
983 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
984 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
985 return EFI_INVALID_PARAMETER
;
991 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
992 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
993 return EFI_INVALID_PARAMETER
;
997 // Test write disable
999 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
1000 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
1001 return EFI_INVALID_PARAMETER
;
1005 // Test write enable
1007 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
1008 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
1009 return EFI_INVALID_PARAMETER
;
1015 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
1016 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
1017 return EFI_INVALID_PARAMETER
;
1021 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
1022 *AttribPtr
= (*AttribPtr
) | NewStatus
;
1023 *Attributes
= *AttribPtr
;
1028 // FVB protocol APIs
1032 FvbProtocolGetPhysicalAddress (
1033 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1034 OUT EFI_PHYSICAL_ADDRESS
*Address
1038 Routine Description:
1040 Retrieves the physical address of the device.
1044 This - Calling context
1045 Address - Output buffer containing the address.
1050 EFI_SUCCESS - Successfully returns
1054 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1056 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1058 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
1062 FvbProtocolGetBlockSize (
1063 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1065 OUT UINTN
*BlockSize
,
1066 OUT UINTN
*NumOfBlocks
1070 Routine Description:
1071 Retrieve the size of a logical block
1074 This - Calling context
1075 Lba - Indicates which block to return the size for.
1076 BlockSize - A pointer to a caller allocated UINTN in which
1077 the size of the block is returned
1078 NumOfBlocks - a pointer to a caller allocated UINTN in which the
1079 number of consecutive blocks starting with Lba is
1080 returned. All blocks in this range have a size of
1084 EFI_SUCCESS - The firmware volume was read successfully and
1085 contents are in Buffer
1089 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1091 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1093 return FvbGetLbaAddress (
1094 FvbDevice
->Instance
,
1107 FvbProtocolGetAttributes (
1108 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1109 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
1113 Routine Description:
1114 Retrieves Volume attributes. No polarity translations are done.
1117 This - Calling context
1118 Attributes - output buffer which contains attributes
1121 EFI_SUCCESS - Successfully returns
1125 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1127 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1129 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
1134 FvbProtocolSetAttributes (
1135 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1136 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
1140 Routine Description:
1141 Sets Volume attributes. No polarity translations are done.
1144 This - Calling context
1145 Attributes - output buffer which contains attributes
1148 EFI_SUCCESS - Successfully returns
1152 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1154 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1156 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
1161 FvbProtocolEraseBlocks (
1162 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1167 Routine Description:
1169 The EraseBlock() function erases one or more blocks as denoted by the
1170 variable argument list. The entire parameter list of blocks must be verified
1171 prior to erasing any blocks. If a block is requested that does not exist
1172 within the associated firmware volume (it has a larger index than the last
1173 block of the firmware volume), the EraseBlock() function must return
1174 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
1177 This - Calling context
1178 ... - Starting LBA followed by Number of Lba to erase.
1179 a -1 to terminate the list.
1182 EFI_SUCCESS - The erase request was successfully completed
1183 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1184 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1185 could not be written. Firmware device may have been
1190 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1191 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1194 EFI_LBA StartingLba
;
1199 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1201 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
1202 ASSERT_EFI_ERROR (Status
);
1204 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
1206 VA_START (args
, This
);
1209 StartingLba
= VA_ARG (args
, EFI_LBA
);
1210 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
1214 NumOfLba
= VA_ARG (args
, UINT32
);
1217 // Check input parameters
1219 if (NumOfLba
== 0) {
1221 return EFI_INVALID_PARAMETER
;
1224 if ((StartingLba
+ NumOfLba
) > NumOfBlocks
) {
1225 return EFI_INVALID_PARAMETER
;
1231 VA_START (args
, This
);
1233 StartingLba
= VA_ARG (args
, EFI_LBA
);
1234 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
1238 NumOfLba
= VA_ARG (args
, UINT32
);
1240 while (NumOfLba
> 0) {
1241 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
1242 if (EFI_ERROR (Status
)) {
1261 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1264 IN OUT UINTN
*NumBytes
,
1269 Routine Description:
1271 Writes data beginning at Lba:Offset from FV. The write terminates either
1272 when *NumBytes of data have been written, or when a block boundary is
1273 reached. *NumBytes is updated to reflect the actual number of bytes
1274 written. The write opertion does not include erase. This routine will
1275 attempt to write only the specified bytes. If the writes do not stick,
1276 it will return an error.
1279 This - Calling context
1280 Lba - Block in which to begin write
1281 Offset - Offset in the block at which to begin write
1282 NumBytes - On input, indicates the requested write size. On
1283 output, indicates the actual number of bytes written
1284 Buffer - Buffer containing source data for the write.
1287 EFI_SUCCESS - The firmware volume was written successfully
1288 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
1289 NumBytes contains the total number of bytes
1291 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1292 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1293 could not be written
1294 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1299 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1301 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1303 return FvbWriteBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1309 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1312 IN OUT UINTN
*NumBytes
,
1317 Routine Description:
1319 Reads data beginning at Lba:Offset from FV. The Read terminates either
1320 when *NumBytes of data have been read, or when a block boundary is
1321 reached. *NumBytes is updated to reflect the actual number of bytes
1322 written. The write opertion does not include erase. This routine will
1323 attempt to write only the specified bytes. If the writes do not stick,
1324 it will return an error.
1327 This - Calling context
1328 Lba - Block in which to begin Read
1329 Offset - Offset in the block at which to begin Read
1330 NumBytes - On input, indicates the requested write size. On
1331 output, indicates the actual number of bytes Read
1332 Buffer - Buffer containing source data for the Read.
1335 EFI_SUCCESS - The firmware volume was read successfully and
1336 contents are in Buffer
1337 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1338 NumBytes contains the total number of bytes returned
1340 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1341 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1343 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1348 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1351 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1352 Status
= FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1359 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1363 Routine Description:
1364 Check the integrity of firmware volume header
1367 FwVolHeader - A pointer to a firmware volume header
1370 EFI_SUCCESS - The firmware volume is consistent
1371 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1376 UINT16 HeaderLength
;
1380 // Verify the header revision, header signature, length
1381 // Length of FvBlock cannot be 2**64-1
1382 // HeaderLength cannot be an odd number
1385 if (((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) && (FwVolHeader
->Revision
!= EFI_FVH_REVISION
)) ||
1387 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1389 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1390 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
1391 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1393 return EFI_NOT_FOUND
;
1396 // Verify the header checksum
1398 HeaderLength
= (UINT16
) (FwVolHeader
->HeaderLength
/ 2);
1399 Ptr
= (UINT16
*) FwVolHeader
;
1401 while (HeaderLength
> 0) {
1402 Checksum
= Checksum
+ (*Ptr
);
1407 if (Checksum
!= 0) {
1408 return EFI_NOT_FOUND
;
1417 OUT EFI_FIRMWARE_VOLUME_HEADER
**FwVolHeader
,
1418 OUT EFI_PHYSICAL_ADDRESS
*BaseAddress
,
1419 OUT BOOLEAN
*WriteBack
1424 Status
= EFI_SUCCESS
;
1427 if (*FwVolHeader
== NULL
) {
1428 *BaseAddress
= PcdGet32 (PcdFlashFvRecoveryBase
);
1429 } else if (*FwVolHeader
== (VOID
*)(UINTN
)PcdGet32 (PcdFlashFvRecoveryBase
)) {
1430 *BaseAddress
= PcdGet32 (PcdFlashFvMainBase
);
1431 } else if (*FwVolHeader
== (VOID
*)(UINTN
)PcdGet32 (PcdFlashFvMainBase
)) {
1432 *BaseAddress
= PcdGet32 (PcdFlashNvStorageVariableBase
);
1434 return EFI_NOT_FOUND
;
1437 DEBUG((EFI_D_INFO
, "Fvb base : %08x\n",*BaseAddress
));
1439 *FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) (*BaseAddress
);
1440 Status
= ValidateFvHeader (*FwVolHeader
);
1441 if (EFI_ERROR (Status
)) {
1447 Status
= GetFvbInfo (*BaseAddress
, FwVolHeader
);
1448 DEBUG(( DEBUG_ERROR
, "Through GetFvbInfo: %08x!\n",*BaseAddress
));
1450 ASSERT_EFI_ERROR (Status
);
1468 // Obtain a handle for ICH SPI Protocol
1470 ASSERT(mSmst
!= NULL
);
1471 if (mFvbModuleGlobal
->SmmSpiProtocol
== NULL
){
1472 Status
= mSmst
->SmmLocateProtocol (&gEfiSmmSpiProtocolGuid
, NULL
, (VOID
**) &mFvbModuleGlobal
->SmmSpiProtocol
);
1473 ASSERT_EFI_ERROR(Status
);
1476 // attempt to identify flash part and initialize spi table
1478 for (FlashIndex
= 0; FlashIndex
< EnumSpiFlashMax
; FlashIndex
++) {
1479 Status
= mFvbModuleGlobal
->SmmSpiProtocol
->Init (
1480 mFvbModuleGlobal
->SmmSpiProtocol
,
1481 &(mSpiInitTable
[FlashIndex
])
1483 if (!EFI_ERROR (Status
)) {
1485 // read vendor/device IDs to check if flash device is supported
1487 Status
= mFvbModuleGlobal
->SmmSpiProtocol
->Execute (
1488 mFvbModuleGlobal
->SmmSpiProtocol
,
1489 SPI_OPCODE_JEDEC_ID_INDEX
,
1499 if (!EFI_ERROR (Status
)) {
1500 if (((FlashID
[0] == mSpiInitTable
[FlashIndex
].VendorId
) &&
1501 (FlashID
[2] == mSpiInitTable
[FlashIndex
].DeviceId1
)) ||
1502 ((FlashID
[0] == SPI_AT26DF321_ID1
) &&
1503 (FlashID
[0] == mSpiInitTable
[FlashIndex
].VendorId
) &&
1504 (FlashID
[1] == mSpiInitTable
[FlashIndex
].DeviceId0
))) {
1506 // Supported SPI device found
1510 "Smm Mode: Supported SPI Flash device found, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1521 if (FlashIndex
>= EnumSpiFlashMax
) {
1522 Status
= EFI_UNSUPPORTED
;
1525 "ERROR - Unknown SPI Flash Device, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1530 ASSERT_EFI_ERROR (Status
);
1534 Status
= mFvbModuleGlobal
->SmmSpiProtocol
->Execute (
1535 mFvbModuleGlobal
->SmmSpiProtocol
,
1536 SPI_OPCODE_WRITE_S_INDEX
, // OpcodeIndex
1537 1, // PrefixOpcodeIndex
1544 EnumSpiRegionAll
// SPI_REGION_TYPE
1550 SmmSpiNotificationFunction (
1551 IN CONST EFI_GUID
*Protocol
,
1553 IN EFI_HANDLE Handle
1556 return SmmSpiInit();
1563 IN EFI_HANDLE ImageHandle
,
1564 IN EFI_SYSTEM_TABLE
*SystemTable
,
1565 OUT EFI_DEVICE_PATH_PROTOCOL
**CompleteFilePath
1569 Routine Description:
1571 Function is used to get the full device path for this driver.
1575 ImageHandle - The loaded image handle of this driver.
1576 SystemTable - The pointer of system table.
1577 CompleteFilePath - The pointer of returned full file path
1586 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
1587 EFI_DEVICE_PATH_PROTOCOL
*ImageDevicePath
;
1590 Status
= gBS
->HandleProtocol (
1592 &gEfiLoadedImageProtocolGuid
,
1593 (VOID
**) &LoadedImage
1595 ASSERT_EFI_ERROR (Status
);
1597 Status
= gBS
->HandleProtocol (
1598 LoadedImage
->DeviceHandle
,
1599 &gEfiDevicePathProtocolGuid
,
1600 (VOID
*) &ImageDevicePath
1602 ASSERT_EFI_ERROR (Status
);
1604 *CompleteFilePath
= AppendDevicePath (
1606 LoadedImage
->FilePath
1616 IN EFI_HANDLE ImageHandle
,
1617 IN EFI_SYSTEM_TABLE
*SystemTable
1621 Routine Description:
1622 This function does common initialization for FVB services
1631 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1632 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1633 EFI_FIRMWARE_VOLUME_HEADER
*TempFwVolHeader
;
1635 VOID
*FirmwareVolumeHobList
;
1637 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1638 BOOLEAN WriteEnabled
;
1639 BOOLEAN WriteLocked
;
1640 EFI_HANDLE FwbHandle
;
1641 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1642 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1643 EFI_DEVICE_PATH_PROTOCOL
*FwbDevicePath
;
1644 EFI_DEVICE_PATH_PROTOCOL
*TempFwbDevicePath
;
1646 EFI_PHYSICAL_ADDRESS BaseAddress
;
1653 EFI_DEVICE_PATH_PROTOCOL
*CompleteFilePath
;
1654 UINT8 PrefixOpcodeIndex
;
1656 EFI_SMM_BASE2_PROTOCOL
*mSmmBase2
;
1662 CompleteFilePath
= NULL
;
1663 GetFullDriverPath (ImageHandle
, SystemTable
, &CompleteFilePath
);
1665 Status
= EfiGetSystemConfigurationTable (&gEfiHobListGuid
, &HobList
);
1670 ASSERT_EFI_ERROR (Status
);
1674 // Allocate runtime services data for global variable, which contains
1675 // the private data of all firmware volume block instances
1677 mFvbModuleGlobal
= (ESAL_FWB_GLOBAL
*)AllocateRuntimeZeroPool(sizeof (ESAL_FWB_GLOBAL
));
1678 ASSERT(mFvbModuleGlobal
);
1680 Status
= gBS
->LocateProtocol (
1681 &gEfiSmmBase2ProtocolGuid
,
1683 (VOID
**) &mSmmBase2
1686 if (mSmmBase2
== NULL
) {
1689 mSmmBase2
->InSmm (mSmmBase2
, &InSmm
);
1690 mSmmBase2
->GetSmstLocation (mSmmBase2
, &mSmst
);
1697 // Obtain a handle for ICH SPI Protocol
1699 Status
= gBS
->LocateProtocol (&gEfiSpiProtocolGuid
, NULL
, (VOID
**) &mFvbModuleGlobal
->SpiProtocol
);
1700 ASSERT_EFI_ERROR (Status
);
1703 // attempt to identify flash part and initialize spi table
1705 for (FlashIndex
= 0; FlashIndex
< EnumSpiFlashMax
; FlashIndex
++) {
1706 Status
= mFvbModuleGlobal
->SpiProtocol
->Init (
1707 mFvbModuleGlobal
->SpiProtocol
,
1708 &(mSpiInitTable
[FlashIndex
])
1710 if (!EFI_ERROR (Status
)) {
1712 // read vendor/device IDs to check if flash device is supported
1714 Status
= mFvbModuleGlobal
->SpiProtocol
->Execute (
1715 mFvbModuleGlobal
->SpiProtocol
,
1716 SPI_OPCODE_JEDEC_ID_INDEX
,
1726 if (!EFI_ERROR (Status
)) {
1727 if (((FlashID
[0] == mSpiInitTable
[FlashIndex
].VendorId
) &&
1728 (FlashID
[2] == mSpiInitTable
[FlashIndex
].DeviceId1
)) ||
1729 ((FlashID
[0] == SPI_AT26DF321_ID1
) &&
1730 (FlashID
[0] == mSpiInitTable
[FlashIndex
].VendorId
) &&
1731 (FlashID
[1] == mSpiInitTable
[FlashIndex
].DeviceId0
))) {
1733 // Supported SPI device found
1737 "Supported SPI Flash device found, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1743 PublishFlashDeviceInfo (&mSpiInitTable
[FlashIndex
]);
1750 if (FlashIndex
>= EnumSpiFlashMax
) {
1751 Status
= EFI_UNSUPPORTED
;
1754 "ERROR - Unknown SPI Flash Device, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1759 ASSERT_EFI_ERROR (Status
);
1763 // Unlock all regions by writing to status register
1764 // This could be SPI device specific, need to follow the datasheet
1765 // To write to Write Status Register the Spi PrefixOpcode needs to be:
1766 // 0 for Atmel parts
1767 // 0 for Intel parts
1768 // 0 for Macronix parts
1769 // 0 for Winbond parts
1772 if (FlashID
[0] == SPI_SST25VF016B_ID1
) {
1773 PrefixOpcodeIndex
= 1;
1775 PrefixOpcodeIndex
= 0;
1777 Status
= mFvbModuleGlobal
->SpiProtocol
->Execute (
1778 mFvbModuleGlobal
->SpiProtocol
,
1779 SPI_OPCODE_WRITE_S_INDEX
, // OpcodeIndex
1780 PrefixOpcodeIndex
, // PrefixOpcodeIndex
1787 EnumSpiRegionAll
// SPI_REGION_TYPE
1794 Status
= mSmst
->SmmLocateProtocol (&gEfiSmmSpiProtocolGuid
, NULL
, (VOID
**) &mFvbModuleGlobal
->SmmSpiProtocol
);
1795 if (EFI_ERROR(Status
)) {
1796 Registration
= NULL
;
1797 Status
= mSmst
->SmmRegisterProtocolNotify (
1798 &gEfiSmmSpiProtocolGuid
,
1799 SmmSpiNotificationFunction
,
1803 Status
= SmmSpiInit();
1809 // Calculate the total size for all firmware volume block instances
1812 FirmwareVolumeHobList
= HobList
;
1815 Status
= GetFvbHeader (&FirmwareVolumeHobList
, &FwVolHeader
, &BaseAddress
, &WriteBack
);
1816 if (EFI_ERROR (Status
)) {
1821 BufferSize
+= (FwVolHeader
->HeaderLength
+ sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1826 // Only need to allocate once. There is only one copy of physical memory for
1827 // the private data of each FV instance. But in virtual mode or in physical
1828 // mode, the address of the the physical memory may be different.
1830 mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] = (EFI_FW_VOL_INSTANCE
*) AllocateRuntimeZeroPool (BufferSize
);
1831 ASSERT(mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
]);
1833 // Make a virtual copy of the FvInstance pointer.
1835 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1836 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1838 mFvbModuleGlobal
->NumFv
= 0;
1839 FirmwareVolumeHobList
= HobList
;
1840 TempFwVolHeader
= NULL
;
1845 // Fill in the private data of each firmware volume block instance
1847 // Foreach Fv HOB in the FirmwareVolumeHobList, loop
1850 Status
= GetFvbHeader (&FirmwareVolumeHobList
, &TempFwVolHeader
, &BaseAddress
, &WriteBack
);
1851 if (EFI_ERROR (Status
)) {
1854 FwVolHeader
= TempFwVolHeader
;
1861 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1862 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1864 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1865 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1868 // FwhInstance->FvWriteBase may not be the same as FwhInstance->FvBase
1870 FwhInstance
->FvWriteBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1871 WriteEnabled
= TRUE
;
1874 // Every pointer should have a virtual copy.
1876 FwhInstance
->FvWriteBase
[FVB_VIRTUAL
] = FwhInstance
->FvWriteBase
[FVB_PHYSICAL
];
1878 FwhInstance
->WriteEnabled
= WriteEnabled
;
1879 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1882 WriteLocked
= FALSE
;
1885 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1887 // Get the maximum size of a block. The size will be used to allocate
1888 // buffer for Scratch space, the intermediate buffer for FVB extension
1891 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
1892 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1895 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1898 // Write back a healthy FV header
1900 if (WriteBack
&& (!WriteLocked
)) {
1902 Status
= FlashFdErase (
1903 (UINTN
) FwhInstance
->FvWriteBase
[0],
1904 (UINTN
) BaseAddress
,
1905 FwVolHeader
->BlockMap
->Length
1908 HeaderLength
= (UINTN
) FwVolHeader
->HeaderLength
;
1909 Status
= FlashFdWrite (
1910 (UINTN
) FwhInstance
->FvWriteBase
[0],
1911 (UINTN
) BaseAddress
,
1913 (UINT8
*) FwVolHeader
,
1914 FwVolHeader
->BlockMap
->Length
1920 // The total number of blocks in the FV.
1922 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1925 // If the FV is write locked, set the appropriate attributes
1931 FwhInstance
->VolumeHeader
.Attributes
&= ~EFI_FVB2_WRITE_STATUS
;
1935 FwhInstance
->VolumeHeader
.Attributes
|= EFI_FVB2_LOCK_STATUS
;
1939 // Allocate and initialize FVB Device in a runtime data buffer
1941 FvbDevice
= AllocateRuntimeCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE
), &mFvbDeviceTemplate
);
1944 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1945 mFvbModuleGlobal
->NumFv
++;
1948 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
1950 if (FwVolHeader
->ExtHeaderOffset
== 0) {
1951 FvbDevice
->FvDevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
1952 FvbDevice
->FvDevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ (FwVolHeader
->FvLength
- 1);
1953 FwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)&FvbDevice
->FvDevicePath
;
1956 &FvbDevice
->UefiFvDevicePath
.FvDevPath
.FvName
,
1957 (EFI_GUID
*)(UINTN
)(BaseAddress
+ FwVolHeader
->ExtHeaderOffset
)
1959 FwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)&FvbDevice
->UefiFvDevicePath
;
1964 // Find a handle with a matching device path that has supports FW Block protocol
1966 TempFwbDevicePath
= FwbDevicePath
;
1967 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &TempFwbDevicePath
, &FwbHandle
);
1968 if (EFI_ERROR (Status
)) {
1970 // LocateDevicePath fails so install a new interface and device path
1973 Status
= gBS
->InstallMultipleProtocolInterfaces (
1975 &gEfiFirmwareVolumeBlockProtocolGuid
,
1976 &FvbDevice
->FwVolBlockInstance
,
1977 &gEfiDevicePathProtocolGuid
,
1981 ASSERT_EFI_ERROR (Status
);
1982 } else if (EfiIsDevicePathEnd (TempFwbDevicePath
)) {
1984 // Device already exists, so reinstall the FVB protocol
1986 Status
= gBS
->HandleProtocol (
1988 &gEfiFirmwareVolumeBlockProtocolGuid
,
1989 (VOID
**) &OldFwbInterface
1991 ASSERT_EFI_ERROR (Status
);
1993 Status
= gBS
->ReinstallProtocolInterface (
1995 &gEfiFirmwareVolumeBlockProtocolGuid
,
1997 &FvbDevice
->FwVolBlockInstance
1999 ASSERT_EFI_ERROR (Status
);
2003 // There was a FVB protocol on an End Device Path node
2009 Status
= mSmst
->SmmInstallProtocolInterface (
2011 &gEfiSmmFirmwareVolumeBlockProtocolGuid
,
2012 EFI_NATIVE_INTERFACE
,
2013 &FvbDevice
->FwVolBlockInstance
2015 ASSERT_EFI_ERROR (Status
);
2018 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
2020 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
2021 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
2026 // Allocate for scratch space, an intermediate buffer for FVB extention
2029 mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
] = AllocateRuntimeZeroPool (MaxLbaSize
);
2031 ASSERT (mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
]);
2033 mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
] = mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
];
2036 Status
= gBS
->CreateEventEx (
2039 FvbVirtualddressChangeEvent
,
2041 &gEfiEventVirtualAddressChangeGuid
,
2044 ASSERT_EFI_ERROR (Status
);
2047 // Inform other platform drivers that SPI device discovered and
2048 // SPI interface ready for use.
2051 Status
= gBS
->InstallProtocolInterface (
2053 &gEfiSmmSpiReadyProtocolGuid
,
2054 EFI_NATIVE_INTERFACE
,