3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
22 #include "FWBlockService.h"
23 #include "EfiFlashMap.h"
24 #include EFI_GUID_DEFINITION (FlashMapHob)
26 ESAL_FWB_GLOBAL
*mFvbModuleGlobal
;
28 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
36 sizeof (MEMMAP_DEVICE_PATH
),
46 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
48 sizeof (EFI_DEVICE_PATH_PROTOCOL
),
55 FvbProtocolGetAttributes
,
56 FvbProtocolSetAttributes
,
57 FvbProtocolGetPhysicalAddress
,
58 FvbProtocolGetBlockSize
,
61 FvbProtocolEraseBlocks
,
65 FvbExtendProtocolEraseCustomBlockRange
69 EFI_DRIVER_ENTRY_POINT (FvbInitialize
)
74 FvbVirtualddressChangeEvent (
82 Fixup internal data so that EFI and SAL can be call in virtual mode.
83 Call the passed in Child Notify event and convert the mFvbModuleGlobal
84 date items to there virtual address.
86 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
87 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
92 (Standard EFI notify event - EFI_EVENT_NOTIFY)
100 EFI_FW_VOL_INSTANCE
*FwhInstance
;
103 EfiConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
106 // Convert the base address of all the instances
109 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
110 while (Index
< mFvbModuleGlobal
->NumFv
) {
111 EfiConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &FwhInstance
->FvBase
[FVB_VIRTUAL
]);
112 EfiConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &FwhInstance
->FvWriteBase
[FVB_VIRTUAL
]);
113 FwhInstance
= (EFI_FW_VOL_INSTANCE
*) ((UINTN
)((UINT8
*)FwhInstance
) + FwhInstance
->VolumeHeader
.HeaderLength
114 + (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
)));
118 EfiConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
]);
119 EfiConvertPointer (EFI_INTERNAL_POINTER
, (VOID
**) &mFvbModuleGlobal
);
128 EfiMemWrite (EfiCpuIoWidthUint8
, Dest
, 1, &Byte
);
136 IN ESAL_FWB_GLOBAL
*Global
,
137 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
143 Retrieves the physical address of a memory mapped FV
146 Instance - The FV instance whose base address is going to be
148 Global - Pointer to ESAL_FWB_GLOBAL that contains all
150 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
151 Virtual - Whether CPU is in virtual or physical mode
154 EFI_SUCCESS - Successfully returns
155 EFI_INVALID_PARAMETER - Instance not found
159 EFI_FW_VOL_INSTANCE
*FwhRecord
;
161 if (Instance
>= Global
->NumFv
) {
162 return EFI_INVALID_PARAMETER
;
165 // Find the right instance of the FVB private data
167 FwhRecord
= Global
->FvInstance
[Virtual
];
168 while (Instance
> 0) {
169 FwhRecord
= (EFI_FW_VOL_INSTANCE
*) ((UINTN
)((UINT8
*)FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
170 + (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
)));
174 *FwhInstance
= FwhRecord
;
180 FvbGetPhysicalAddress (
182 OUT EFI_PHYSICAL_ADDRESS
*Address
,
183 IN ESAL_FWB_GLOBAL
*Global
,
189 Retrieves the physical address of a memory mapped FV
192 Instance - The FV instance whose base address is going to be
194 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
195 that on successful return, contains the base address
196 of the firmware volume.
197 Global - Pointer to ESAL_FWB_GLOBAL that contains all
199 Virtual - Whether CPU is in virtual or physical mode
202 EFI_SUCCESS - Successfully returns
203 EFI_INVALID_PARAMETER - Instance not found
207 EFI_FW_VOL_INSTANCE
*FwhInstance
;
211 // Find the right instance of the FVB private data
213 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
214 ASSERT_EFI_ERROR (Status
);
215 *Address
= FwhInstance
->FvBase
[Virtual
];
221 FvbGetVolumeAttributes (
223 OUT EFI_FVB_ATTRIBUTES
*Attributes
,
224 IN ESAL_FWB_GLOBAL
*Global
,
230 Retrieves attributes, insures positive polarity of attribute bits, returns
231 resulting attributes in output parameter
234 Instance - The FV instance whose attributes is going to be
236 Attributes - Output buffer which contains attributes
237 Global - Pointer to ESAL_FWB_GLOBAL that contains all
239 Virtual - Whether CPU is in virtual or physical mode
242 EFI_SUCCESS - Successfully returns
243 EFI_INVALID_PARAMETER - Instance not found
247 EFI_FW_VOL_INSTANCE
*FwhInstance
;
251 // Find the right instance of the FVB private data
253 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
254 ASSERT_EFI_ERROR (Status
);
255 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
264 OUT UINTN
*LbaAddress
,
265 OUT UINTN
*LbaWriteAddress
,
266 OUT UINTN
*LbaLength
,
267 OUT UINTN
*NumOfBlocks
,
268 IN ESAL_FWB_GLOBAL
*Global
,
274 Retrieves the starting address of an LBA in an FV
277 Instance - The FV instance which the Lba belongs to
278 Lba - The logical block address
279 LbaAddress - On output, contains the physical starting address
281 LbaWriteAddress - On output, contains the physical starting address
282 of the Lba for writing
283 LbaLength - On output, contains the length of the block
284 NumOfBlocks - A pointer to a caller allocated UINTN in which the
285 number of consecutive blocks starting with Lba is
286 returned. All blocks in this range have a size of
288 Global - Pointer to ESAL_FWB_GLOBAL that contains all
290 Virtual - Whether CPU is in virtual or physical mode
293 EFI_SUCCESS - Successfully returns
294 EFI_INVALID_PARAMETER - Instance not found
303 EFI_FW_VOL_INSTANCE
*FwhInstance
;
304 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
308 // Find the right instance of the FVB private data
310 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
311 ASSERT_EFI_ERROR (Status
);
315 BlockMap
= &(FwhInstance
->VolumeHeader
.FvBlockMap
[0]);
318 // Parse the blockmap of the FV to find which map entry the Lba belongs to
321 NumBlocks
= BlockMap
->NumBlocks
;
322 BlockLength
= BlockMap
->BlockLength
;
324 if (NumBlocks
== 0 || BlockLength
== 0) {
325 return EFI_INVALID_PARAMETER
;
328 NextLba
= StartLba
+ NumBlocks
;
331 // The map entry found
333 if (Lba
>= StartLba
&& Lba
< NextLba
) {
334 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
336 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
339 if (LbaWriteAddress
) {
340 *LbaWriteAddress
= FwhInstance
->FvWriteBase
[Virtual
] + Offset
;
344 *LbaLength
= BlockLength
;
348 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
355 Offset
= Offset
+ NumBlocks
* BlockLength
;
364 IN UINTN BlockOffset
,
365 IN OUT UINTN
*NumBytes
,
367 IN ESAL_FWB_GLOBAL
*Global
,
373 Reads specified number of bytes into a buffer from the specified block
376 Instance - The FV instance to be read from
377 Lba - The logical block address to be read from
378 BlockOffset - Offset into the block at which to begin reading
379 NumBytes - Pointer that on input contains the total size of
380 the buffer. On output, it contains the total number
382 Buffer - Pointer to a caller allocated buffer that will be
383 used to hold the data read
384 Global - Pointer to ESAL_FWB_GLOBAL that contains all
386 Virtual - Whether CPU is in virtual or physical mode
389 EFI_SUCCESS - The firmware volume was read successfully and
390 contents are in Buffer
391 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
392 NumBytes contains the total number of bytes returned
394 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
395 EFI_DEVICE_ERROR - The block device is not functioning correctly and
397 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
401 EFI_FVB_ATTRIBUTES Attributes
;
407 // Check for invalid conditions
409 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
410 return EFI_INVALID_PARAMETER
;
413 if (*NumBytes
== 0) {
414 return EFI_INVALID_PARAMETER
;
417 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, NULL
, &LbaLength
, NULL
, Global
, Virtual
);
418 if (EFI_ERROR (Status
)) {
422 // Check if the FV is read enabled
424 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
426 if ((Attributes
& EFI_FVB_READ_STATUS
) == 0) {
427 return EFI_ACCESS_DENIED
;
430 // Perform boundary checks and adjust NumBytes
432 if (BlockOffset
> LbaLength
) {
433 return EFI_INVALID_PARAMETER
;
436 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
437 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
438 Status
= EFI_BAD_BUFFER_SIZE
;
441 EfiMemRead (EfiCpuIoWidthUint8
, LbaAddress
+ BlockOffset
, (UINTN
) *NumBytes
, Buffer
);
448 IN UINTN WriteAddress
,
450 IN OUT UINTN
*NumBytes
,
457 Writes specified number of bytes from the input buffer to the address
473 Status
= EFI_SUCCESS
;
475 EnableFvbWrites (TRUE
);
478 // Grab the lock before entering critical code section
481 // Commented out since locking mechanisium is not correctly implemented
482 // on IA32 so that it will assert in runtime environment.
484 // EfiAcquireLock(&(FwhInstance->FvbDevLock));
486 // Write data one byte at a time, don't write if the src and dest bytes match
488 Dest
= (UINT8
*) WriteAddress
;
491 for (Count
= 0; Count
< *NumBytes
; Count
++, Dest
++, Src
++) {
493 HubCommand
= FWH_WRITE_SETUP_COMMAND
;
494 FvbMemWrite8 ((UINT64
) ((UINTN
) Dest
), HubCommand
);
495 FvbMemWrite8 ((UINT64
) ((UINTN
) Dest
), *Src
);
496 HubCommand
= FWH_READ_STATUS_COMMAND
;
497 FvbMemWrite8 ((UINT64
) ((UINTN
) Dest
), HubCommand
);
500 // Device error if time out occurs
503 while (RetryTimes
< FVB_MAX_RETRY_TIMES
) {
504 EfiMemRead (EfiCpuIoWidthUint8
, (UINT64
) ((UINTN
) Dest
), 0x1, &HubData
);
505 if (HubData
& FWH_WRITE_STATE_STATUS
) {
512 if (RetryTimes
>= FVB_MAX_RETRY_TIMES
) {
514 Status
= EFI_DEVICE_ERROR
;
519 // Clear status register
521 HubCommand
= FWH_CLEAR_STATUS_COMMAND
;
522 FvbMemWrite8 ((UINT64
) ((UINTN
) Dest
), HubCommand
);
525 // Issue read array command to return the FWH state machine to the
526 // normal operational state
528 HubCommand
= FWH_READ_ARRAY_COMMAND
;
529 FvbMemWrite8 ((UINT64
) ((UINTN
) WriteAddress
), HubCommand
);
531 // Flush the changed area to make the cache consistent
533 EfiCpuFlushCache (WriteAddress
, *NumBytes
);
536 // End of critical code section, release lock.
538 // EfiReleaseLock(&(FwhInstance->FvbDevLock));
540 EnableFvbWrites (FALSE
);
547 IN UINTN WriteAddress
,
554 Erase a certain block from address LbaWriteAddress
567 Status
= EFI_SUCCESS
;
569 EnableFvbWrites (TRUE
);
572 // Grab the lock before entering critical code section
574 // EfiAcquireLock(&(FwhInstance->FvbDevLock));
576 // Send erase commands to FWH
578 HubCommand
= FWH_BLOCK_ERASE_SETUP_COMMAND
;
579 FvbMemWrite8 ((UINT64
) WriteAddress
, HubCommand
);
580 HubCommand
= FWH_BLOCK_ERASE_CONFIRM_COMMAND
;
581 FvbMemWrite8 ((UINT64
) WriteAddress
, HubCommand
);
582 HubCommand
= FWH_READ_STATUS_COMMAND
;
583 FvbMemWrite8 ((UINT64
) WriteAddress
, HubCommand
);
586 // Wait for completion. Indicated by FWH_WRITE_STATE_STATUS bit becoming 0
587 // Device error if time out occurs
590 while (RetryTimes
< FVB_MAX_RETRY_TIMES
) {
591 EfiMemRead (EfiCpuIoWidthUint8
, (UINT64
) WriteAddress
, 0x1, &HubData
);
592 if (HubData
& FWH_WRITE_STATE_STATUS
) {
599 if (RetryTimes
>= FVB_MAX_RETRY_TIMES
) {
600 Status
= EFI_DEVICE_ERROR
;
603 // Clear status register
605 HubCommand
= FWH_CLEAR_STATUS_COMMAND
;
606 FvbMemWrite8 ((UINT64
) WriteAddress
, HubCommand
);
609 // Issue read array command to return the FWH state machine to the normal op state
611 HubCommand
= FWH_READ_ARRAY_COMMAND
;
612 FvbMemWrite8 ((UINT64
) ((UINTN
) WriteAddress
), HubCommand
);
614 EfiCpuFlushCache (Address
, LbaLength
);
617 // End of critical code section, release lock.
619 // EfiReleaseLock(&(FwhInstance->FvbDevLock));
621 EnableFvbWrites (FALSE
);
630 IN UINTN BlockOffset
,
631 IN OUT UINTN
*NumBytes
,
633 IN ESAL_FWB_GLOBAL
*Global
,
639 Writes specified number of bytes from the input buffer to the block
642 Instance - The FV instance to be written to
643 Lba - The starting logical block index to write to
644 BlockOffset - Offset into the block at which to begin writing
645 NumBytes - Pointer that on input contains the total size of
646 the buffer. On output, it contains the total number
647 of bytes actually written
648 Buffer - Pointer to a caller allocated buffer that contains
649 the source for the write
650 Global - Pointer to ESAL_FWB_GLOBAL that contains all
652 Virtual - Whether CPU is in virtual or physical mode
655 EFI_SUCCESS - The firmware volume was written successfully
656 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
657 NumBytes contains the total number of bytes
659 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
660 EFI_DEVICE_ERROR - The block device is not functioning correctly and
662 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
666 EFI_FVB_ATTRIBUTES Attributes
;
668 UINTN LbaWriteAddress
;
670 EFI_FW_VOL_INSTANCE
*FwhInstance
;
672 EFI_STATUS ReturnStatus
;
675 // Find the right instance of the FVB private data
677 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
678 ASSERT_EFI_ERROR (Status
);
681 // Writes are enabled in the init routine itself
683 if (!FwhInstance
->WriteEnabled
) {
684 return EFI_ACCESS_DENIED
;
687 // Check for invalid conditions
689 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
690 return EFI_INVALID_PARAMETER
;
693 if (*NumBytes
== 0) {
694 return EFI_INVALID_PARAMETER
;
697 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaWriteAddress
, &LbaLength
, NULL
, Global
, Virtual
);
698 if (EFI_ERROR (Status
)) {
702 // Check if the FV is write enabled
704 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
706 if ((Attributes
& EFI_FVB_WRITE_STATUS
) == 0) {
707 return EFI_ACCESS_DENIED
;
710 // Perform boundary checks and adjust NumBytes
712 if (BlockOffset
> LbaLength
) {
713 return EFI_INVALID_PARAMETER
;
716 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
717 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
718 Status
= EFI_BAD_BUFFER_SIZE
;
721 ReturnStatus
= FlashFdWrite (
722 LbaWriteAddress
+ BlockOffset
,
728 if (EFI_ERROR (ReturnStatus
)) {
739 IN ESAL_FWB_GLOBAL
*Global
,
745 Erases and initializes a firmware volume block
748 Instance - The FV instance to be erased
749 Lba - The logical block index to be erased
750 Global - Pointer to ESAL_FWB_GLOBAL that contains all
752 Virtual - Whether CPU is in virtual or physical mode
755 EFI_SUCCESS - The erase request was successfully completed
756 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
757 EFI_DEVICE_ERROR - The block device is not functioning correctly and
758 could not be written. Firmware device may have been
760 EFI_INVALID_PARAMETER - Instance not found
765 EFI_FVB_ATTRIBUTES Attributes
;
767 UINTN LbaWriteAddress
;
768 EFI_FW_VOL_INSTANCE
*FwhInstance
;
773 // Find the right instance of the FVB private data
775 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
776 ASSERT_EFI_ERROR (Status
);
779 // Writes are enabled in the init routine itself
781 if (!FwhInstance
->WriteEnabled
) {
782 return EFI_ACCESS_DENIED
;
785 // Check if the FV is write enabled
787 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
789 if ((Attributes
& EFI_FVB_WRITE_STATUS
) == 0) {
790 return EFI_ACCESS_DENIED
;
793 // Get the starting address of the block for erase. For debug reasons,
794 // LbaWriteAddress may not be the same as LbaAddress.
796 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaWriteAddress
, &LbaLength
, NULL
, Global
, Virtual
);
797 if (EFI_ERROR (Status
)) {
801 return FlashFdErase (
809 FvbEraseCustomBlockRange (
812 IN UINTN OffsetStartLba
,
814 IN UINTN OffsetLastLba
,
815 IN ESAL_FWB_GLOBAL
*Global
,
821 Erases and initializes a specified range of a firmware volume
824 Instance - The FV instance to be erased
825 StartLba - The starting logical block index to be erased
826 OffsetStartLba - Offset into the starting block at which to
828 LastLba - The last logical block index to be erased
829 OffsetStartLba - Offset into the last block at which to end erasing
830 Global - Pointer to ESAL_FWB_GLOBAL that contains all
832 Virtual - Whether CPU is in virtual or physical mode
835 EFI_SUCCESS - The firmware volume was erased successfully
836 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
837 EFI_DEVICE_ERROR - The block device is not functioning correctly and
838 could not be written. Firmware device may have been
840 EFI_INVALID_PARAMETER - Instance not found
846 UINTN ScratchLbaSizeData
;
851 FvbGetLbaAddress (Instance
, StartLba
, NULL
, NULL
, &LbaSize
, NULL
, Global
, Virtual
);
854 // Use the scratch space as the intermediate buffer to transfer data
855 // Back up the first LBA in scratch space.
857 FvbReadBlock (Instance
, StartLba
, 0, &LbaSize
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
862 FvbEraseBlock (Instance
, StartLba
, Global
, Virtual
);
863 ScratchLbaSizeData
= OffsetStartLba
;
866 // write the data back to the first block
868 if (ScratchLbaSizeData
> 0) {
869 FvbWriteBlock (Instance
, StartLba
, 0, &ScratchLbaSizeData
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
874 if (LastLba
> (StartLba
+ 1)) {
875 for (Index
= (StartLba
+ 1); Index
<= (LastLba
- 1); Index
++) {
876 FvbEraseBlock (Instance
, Index
, Global
, Virtual
);
880 // Last LBAs, the same as first LBAs
882 if (LastLba
> StartLba
) {
883 FvbGetLbaAddress (Instance
, LastLba
, NULL
, NULL
, &LbaSize
, NULL
, Global
, Virtual
);
884 FvbReadBlock (Instance
, LastLba
, 0, &LbaSize
, Global
->FvbScratchSpace
[Virtual
], Global
, Virtual
);
885 FvbEraseBlock (Instance
, LastLba
, Global
, Virtual
);
888 ScratchLbaSizeData
= LbaSize
- (OffsetStartLba
+ 1);
890 return FvbWriteBlock (
895 Global
->FvbScratchSpace
[Virtual
],
902 FvbSetVolumeAttributes (
904 IN OUT EFI_FVB_ATTRIBUTES
*Attributes
,
905 IN ESAL_FWB_GLOBAL
*Global
,
911 Modifies the current settings of the firmware volume according to the
912 input parameter, and returns the new setting of the volume
915 Instance - The FV instance whose attributes is going to be
917 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES
918 containing the desired firmware volume settings.
919 On successful return, it contains the new settings
920 of the firmware volume
921 Global - Pointer to ESAL_FWB_GLOBAL that contains all
923 Virtual - Whether CPU is in virtual or physical mode
926 EFI_SUCCESS - Successfully returns
927 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
928 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
929 in conflict with the capabilities as declared in the
930 firmware volume header
934 EFI_FW_VOL_INSTANCE
*FwhInstance
;
935 EFI_FVB_ATTRIBUTES OldAttributes
;
936 EFI_FVB_ATTRIBUTES
*AttribPtr
;
943 // Find the right instance of the FVB private data
945 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
946 ASSERT_EFI_ERROR (Status
);
948 AttribPtr
= (EFI_FVB_ATTRIBUTES
*) &(FwhInstance
->VolumeHeader
.Attributes
);
949 OldAttributes
= *AttribPtr
;
950 Capabilities
= OldAttributes
& EFI_FVB_CAPABILITIES
;
951 OldStatus
= OldAttributes
& EFI_FVB_STATUS
;
952 NewStatus
= *Attributes
& EFI_FVB_STATUS
;
955 // If firmware volume is locked, no status bit can be updated
957 if (OldAttributes
& EFI_FVB_LOCK_STATUS
) {
958 if (OldStatus
^ NewStatus
) {
959 return EFI_ACCESS_DENIED
;
965 if ((Capabilities
& EFI_FVB_READ_DISABLED_CAP
) == 0) {
966 if ((NewStatus
& EFI_FVB_READ_STATUS
) == 0) {
967 return EFI_INVALID_PARAMETER
;
973 if ((Capabilities
& EFI_FVB_READ_ENABLED_CAP
) == 0) {
974 if (NewStatus
& EFI_FVB_READ_STATUS
) {
975 return EFI_INVALID_PARAMETER
;
979 // Test write disable
981 if ((Capabilities
& EFI_FVB_WRITE_DISABLED_CAP
) == 0) {
982 if ((NewStatus
& EFI_FVB_WRITE_STATUS
) == 0) {
983 return EFI_INVALID_PARAMETER
;
989 if ((Capabilities
& EFI_FVB_WRITE_ENABLED_CAP
) == 0) {
990 if (NewStatus
& EFI_FVB_WRITE_STATUS
) {
991 return EFI_INVALID_PARAMETER
;
997 if ((Capabilities
& EFI_FVB_LOCK_CAP
) == 0) {
998 if (NewStatus
& EFI_FVB_LOCK_STATUS
) {
999 return EFI_INVALID_PARAMETER
;
1003 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB_STATUS
));
1004 *AttribPtr
= (*AttribPtr
) | NewStatus
;
1005 *Attributes
= *AttribPtr
;
1010 // FVB protocol APIs
1014 FvbProtocolGetPhysicalAddress (
1015 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1016 OUT EFI_PHYSICAL_ADDRESS
*Address
1020 Routine Description:
1022 Retrieves the physical address of the device.
1026 This - Calling context
1027 Address - Output buffer containing the address.
1032 EFI_SUCCESS - Successfully returns
1036 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1038 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1040 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
1045 FvbProtocolGetBlockSize (
1046 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1048 OUT UINTN
*BlockSize
,
1049 OUT UINTN
*NumOfBlocks
1053 Routine Description:
1054 Retrieve the size of a logical block
1057 This - Calling context
1058 Lba - Indicates which block to return the size for.
1059 BlockSize - A pointer to a caller allocated UINTN in which
1060 the size of the block is returned
1061 NumOfBlocks - a pointer to a caller allocated UINTN in which the
1062 number of consecutive blocks starting with Lba is
1063 returned. All blocks in this range have a size of
1067 EFI_SUCCESS - The firmware volume was read successfully and
1068 contents are in Buffer
1072 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1074 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1076 return FvbGetLbaAddress (
1077 FvbDevice
->Instance
,
1090 FvbProtocolGetAttributes (
1091 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1092 OUT EFI_FVB_ATTRIBUTES
*Attributes
1096 Routine Description:
1097 Retrieves Volume attributes. No polarity translations are done.
1100 This - Calling context
1101 Attributes - output buffer which contains attributes
1104 EFI_SUCCESS - Successfully returns
1108 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1110 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1112 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
1117 FvbProtocolSetAttributes (
1118 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1119 IN OUT EFI_FVB_ATTRIBUTES
*Attributes
1123 Routine Description:
1124 Sets Volume attributes. No polarity translations are done.
1127 This - Calling context
1128 Attributes - output buffer which contains attributes
1131 EFI_SUCCESS - Successfully returns
1135 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1137 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1139 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
1144 FvbProtocolEraseBlocks (
1145 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1150 Routine Description:
1152 The EraseBlock() function erases one or more blocks as denoted by the
1153 variable argument list. The entire parameter list of blocks must be verified
1154 prior to erasing any blocks. If a block is requested that does not exist
1155 within the associated firmware volume (it has a larger index than the last
1156 block of the firmware volume), the EraseBlock() function must return
1157 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
1160 This - Calling context
1161 ... - Starting LBA followed by Number of Lba to erase.
1162 a -1 to terminate the list.
1165 EFI_SUCCESS - The erase request was successfully completed
1166 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1167 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1168 could not be written. Firmware device may have been
1173 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1174 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1177 EFI_LBA StartingLba
;
1181 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1183 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
1184 ASSERT_EFI_ERROR (Status
);
1186 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
1188 VA_START (args
, This
);
1191 StartingLba
= VA_ARG (args
, EFI_LBA
);
1192 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
1196 NumOfLba
= VA_ARG (args
, UINT32
);
1199 // Check input parameters
1201 if ((NumOfLba
== 0) || ((StartingLba
+ NumOfLba
) > NumOfBlocks
)) {
1203 return EFI_INVALID_PARAMETER
;
1209 VA_START (args
, This
);
1211 StartingLba
= VA_ARG (args
, EFI_LBA
);
1212 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
1216 NumOfLba
= VA_ARG (args
, UINT32
);
1218 while (NumOfLba
> 0) {
1219 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
1220 if (EFI_ERROR (Status
)) {
1239 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1242 IN OUT UINTN
*NumBytes
,
1247 Routine Description:
1249 Writes data beginning at Lba:Offset from FV. The write terminates either
1250 when *NumBytes of data have been written, or when a block boundary is
1251 reached. *NumBytes is updated to reflect the actual number of bytes
1252 written. The write opertion does not include erase. This routine will
1253 attempt to write only the specified bytes. If the writes do not stick,
1254 it will return an error.
1257 This - Calling context
1258 Lba - Block in which to begin write
1259 Offset - Offset in the block at which to begin write
1260 NumBytes - On input, indicates the requested write size. On
1261 output, indicates the actual number of bytes written
1262 Buffer - Buffer containing source data for the write.
1265 EFI_SUCCESS - The firmware volume was written successfully
1266 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
1267 NumBytes contains the total number of bytes
1269 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1270 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1271 could not be written
1272 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1277 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1279 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1281 return FvbWriteBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1287 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1290 IN OUT UINTN
*NumBytes
,
1295 Routine Description:
1297 Reads data beginning at Lba:Offset from FV. The Read terminates either
1298 when *NumBytes of data have been read, or when a block boundary is
1299 reached. *NumBytes is updated to reflect the actual number of bytes
1300 written. The write opertion does not include erase. This routine will
1301 attempt to write only the specified bytes. If the writes do not stick,
1302 it will return an error.
1305 This - Calling context
1306 Lba - Block in which to begin Read
1307 Offset - Offset in the block at which to begin Read
1308 NumBytes - On input, indicates the requested write size. On
1309 output, indicates the actual number of bytes Read
1310 Buffer - Buffer containing source data for the Read.
1313 EFI_SUCCESS - The firmware volume was read successfully and
1314 contents are in Buffer
1315 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1316 NumBytes contains the total number of bytes returned
1318 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1319 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1321 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1326 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1328 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1330 return FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1333 // FVB Extension Protocols
1337 FvbExtendProtocolEraseCustomBlockRange (
1338 IN EFI_FVB_EXTENSION_PROTOCOL
*This
,
1339 IN EFI_LBA StartLba
,
1340 IN UINTN OffsetStartLba
,
1342 IN UINTN OffsetLastLba
1346 Routine Description:
1347 Erases and initializes a specified range of a firmware volume
1350 This - Calling context
1351 StartLba - The starting logical block index to be erased
1352 OffsetStartLba - Offset into the starting block at which to
1354 LastLba - The last logical block index to be erased
1355 OffsetStartLba - Offset into the last block at which to end erasing
1358 EFI_SUCCESS - The firmware volume was erased successfully
1359 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1360 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1361 could not be written. Firmware device may have been
1366 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1368 FvbDevice
= FVB_EXTEND_DEVICE_FROM_THIS (This
);
1370 return FvbEraseCustomBlockRange (
1371 FvbDevice
->Instance
,
1384 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1388 Routine Description:
1389 Check the integrity of firmware volume header
1392 FwVolHeader - A pointer to a firmware volume header
1395 EFI_SUCCESS - The firmware volume is consistent
1396 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1401 UINT16 HeaderLength
;
1405 // Verify the header revision, header signature, length
1406 // Length of FvBlock cannot be 2**64-1
1407 // HeaderLength cannot be an odd number
1409 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1410 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1411 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
1412 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1414 return EFI_NOT_FOUND
;
1417 // Verify the header checksum
1419 HeaderLength
= (UINT16
) (FwVolHeader
->HeaderLength
/ 2);
1420 Ptr
= (UINT16
*) FwVolHeader
;
1422 while (HeaderLength
> 0) {
1427 if (Checksum
!= 0) {
1428 return EFI_NOT_FOUND
;
1435 FvbGetCfiSupported (
1440 Routine Description:
1441 Check if the firmware volume is CFI typed flash
1444 LbaAddress - The physical address of the firmware volume
1447 TRUE - CFI supported
1448 FALSE - CFI un-supported
1459 // Issue CFI Query (98h) to address 55h
1461 HubCommand
= CFI_QUERY
;
1462 FvbMemWrite8 ((LbaAddress
+ 0x55), HubCommand
);
1464 // x8 device in 8-bit mode?
1466 EfiMemRead (EfiCpuIoWidthUint8
, (LbaAddress
+ 0x10), 0x3, &HubData
);
1467 if (!EfiCompareMem (HubData
, "QRY", 3)) {
1471 // paired x8 devices?
1473 EfiMemRead (EfiCpuIoWidthUint8
, (LbaAddress
+ 0x20), 0x6, &HubData
);
1474 if (!EfiCompareMem (HubData
, "QQRRYY", 6)) {
1478 // x16 device in 16-bit mode?
1480 EfiMemRead (EfiCpuIoWidthUint8
, (LbaAddress
+ 0x20), 0x4, &HubData
);
1481 if ((!EfiCompareMem (&HubData
[0], "R", 2)) && (!EfiCompareMem (&HubData
[2], "Q", 2))) {
1485 // x16 device in 8-bit mode?
1487 EfiMemRead (EfiCpuIoWidthUint8
, (LbaAddress
+ 0x20), 0x3, &HubData
);
1488 if (!EfiCompareMem (HubData
, "QQR", 3)) {
1492 // 2 x16 devices in 8-bit mode (paired chip configuration)?
1494 EfiMemRead (EfiCpuIoWidthUint8
, (LbaAddress
+ 0x40), 0x6, &HubData
);
1495 if (!EfiCompareMem (HubData
, "QQQQRR", 6)) {
1499 // x32 device in 8-bit mode
1501 EfiMemRead (EfiCpuIoWidthUint8
, (LbaAddress
+ 0x40), 0x5, &HubData
);
1502 if (!EfiCompareMem (HubData
, "QQQQR", 5)) {
1506 // x32 device in 32-bit mode
1508 if ((!EfiCompareMem (&HubData
[0], "R", 2)) && (((UINT16
) HubData
[2]) == 0) && (HubData
[4] == 'Q')) {
1512 // If it got to here, CFI is not supported
1519 // Issue command FWH_READ_ARRAY_COMMAND (0xff) at the end of this service to
1520 // guarantee that the FWH is back in read mode again
1522 HubCommand
= FWH_READ_ARRAY_COMMAND
;
1523 FvbMemWrite8 (LbaAddress
, HubCommand
);
1531 EFI_FIRMWARE_VOLUME_HEADER
**FwVolHeader
,
1532 EFI_PHYSICAL_ADDRESS
*BaseAddress
,
1538 EFI_FLASH_MAP_ENTRY_DATA
*FlashMapEntry
;
1539 EFI_FLASH_SUBAREA_ENTRY
*FlashMapSubEntry
;
1541 Status
= EFI_SUCCESS
;
1542 *FwVolHeader
= NULL
;
1545 Status
= GetNextGuidHob (HobList
, &gEfiFlashMapHobGuid
, &Buffer
, NULL
);
1546 if (EFI_ERROR (Status
)) {
1547 return EFI_NOT_FOUND
;
1550 FlashMapEntry
= (EFI_FLASH_MAP_ENTRY_DATA
*) Buffer
;
1551 FlashMapSubEntry
= &FlashMapEntry
->Entries
[0];
1553 // Check if it is a "FVB" area
1555 if (!EfiCompareGuid (&FlashMapSubEntry
->FileSystem
, &gEfiFirmwareVolumeBlockProtocolGuid
)) {
1559 // Check if it is a "real" flash
1561 if (FlashMapSubEntry
->Attributes
!= (EFI_FLASH_AREA_FV
| EFI_FLASH_AREA_MEMMAPPED_FV
)) {
1565 *BaseAddress
= FlashMapSubEntry
->Base
;
1566 DEBUG ((EFI_D_ERROR
, "FlashMap HOB: BaseAddress = 0x%lx\n", *BaseAddress
));
1568 *FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) (*BaseAddress
);
1569 Status
= ValidateFvHeader (*FwVolHeader
);
1570 if (EFI_ERROR (Status
)) {
1575 DEBUG ((EFI_D_ERROR
, "BaseAddress = 0x%lx\n", BaseAddress
));
1576 Status
= GetFvbInfo (*BaseAddress
, FwVolHeader
);
1577 DEBUG ((EFI_D_ERROR
, "Fvb: FV header invalid, GetFvbInfo - %r\n", Status
));
1578 ASSERT_EFI_ERROR (Status
);
1587 IN EFI_HANDLE ImageHandle
,
1588 IN EFI_SYSTEM_TABLE
*SystemTable
1592 Routine Description:
1593 This function does common initialization for FVB services
1602 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1603 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1605 VOID
*FirmwareVolumeHobList
;
1607 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1611 BOOLEAN WriteEnabled
;
1612 BOOLEAN WriteLocked
;
1613 EFI_HANDLE FwbHandle
;
1614 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1615 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1616 EFI_DEVICE_PATH_PROTOCOL
*TempFwbDevicePath
;
1617 FV_DEVICE_PATH TempFvbDevicePathData
;
1620 EFI_PHYSICAL_ADDRESS BaseAddress
;
1625 INITIALIZE_SCRIPT (ImageHandle
, SystemTable
);
1627 EfiInitializeRuntimeDriverLib (ImageHandle
, SystemTable
, FvbVirtualddressChangeEvent
);
1629 Status
= EfiGetSystemConfigurationTable (&gEfiHobListGuid
, &HobList
);
1634 ASSERT_EFI_ERROR (Status
);
1637 // Allocate runtime services data for global variable, which contains
1638 // the private data of all firmware volume block instances
1640 Status
= gBS
->AllocatePool (
1641 EfiRuntimeServicesData
,
1642 sizeof (ESAL_FWB_GLOBAL
),
1645 ASSERT_EFI_ERROR (Status
);
1647 EnablePlatformFvb ();
1648 EnableFvbWrites (TRUE
);
1651 // Calculate the total size for all firmware volume block instances
1654 FirmwareVolumeHobList
= HobList
;
1656 Status
= GetFvbHeader (&FirmwareVolumeHobList
, &FwVolHeader
, &BaseAddress
, &WriteBack
);
1657 if (EFI_ERROR (Status
)) {
1662 BufferSize
+= (FwVolHeader
->HeaderLength
+ sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1667 // Only need to allocate once. There is only one copy of physical memory for
1668 // the private data of each FV instance. But in virtual mode or in physical
1669 // mode, the address of the the physical memory may be different.
1671 Status
= gBS
->AllocatePool (
1672 EfiRuntimeServicesData
,
1674 &mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
]
1676 ASSERT_EFI_ERROR (Status
);
1679 // Make a virtual copy of the FvInstance pointer.
1681 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1682 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1684 mFvbModuleGlobal
->NumFv
= 0;
1685 FirmwareVolumeHobList
= HobList
;
1690 // Fill in the private data of each firmware volume block instance
1693 Status
= GetFvbHeader (&FirmwareVolumeHobList
, &FwVolHeader
, &BaseAddress
, &WriteBack
);
1694 if (EFI_ERROR (Status
)) {
1702 EfiCopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1703 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1705 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1706 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1709 // FwhInstance->FvWriteBase may not be the same as FwhInstance->FvBase
1711 PlatformGetFvbWriteBase (
1712 (UINTN
) BaseAddress
,
1713 (UINTN
*) &(FwhInstance
->FvWriteBase
[FVB_PHYSICAL
]),
1717 // Every pointer should have a virtual copy.
1719 FwhInstance
->FvWriteBase
[FVB_VIRTUAL
] = FwhInstance
->FvWriteBase
[FVB_PHYSICAL
];
1721 FwhInstance
->WriteEnabled
= WriteEnabled
;
1722 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), EFI_TPL_HIGH_LEVEL
);
1724 LbaAddress
= (UINTN
) FwhInstance
->FvWriteBase
[0];
1726 WriteLocked
= FALSE
;
1729 CfiEnabled
= FvbGetCfiSupported (LbaAddress
);
1730 for (PtrBlockMapEntry
= FwVolHeader
->FvBlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1732 for (BlockIndex2
= 0; BlockIndex2
< PtrBlockMapEntry
->NumBlocks
; BlockIndex2
++) {
1734 if (SetPlatformFvbLock (LbaAddress
)) {
1736 // Clear all write-lock and read-lock HW bits
1737 // For sync3, the software will enforce the protection
1740 Data
= CFI_BLOCK_LOCK_UNLOCK
;
1741 FvbMemWrite8 (LbaAddress
, Data
);
1742 Data
= CFI_BLOCK_UNLOCK_CONFIRM
;
1743 FvbMemWrite8 (LbaAddress
, Data
);
1745 EfiMemRead (EfiCpuIoWidthUint8
, (LbaAddress
+ 2), 1, &Data
);
1751 Data
= FWH_READ_ARRAY_COMMAND
;
1752 FvbMemWrite8 (LbaAddress
, Data
);
1754 EfiMemRead (EfiCpuIoWidthUint8
, (LbaAddress
- 0x400000 + 2), 0x1, &Data
);
1756 // bugbug: lock down is block based, not FV based. Here we assume that
1757 // the FV is locked if one of its block is locked
1759 if ((Data
& FWH_WRITE_LOCK
) && (Data
& FWH_LOCK_DOWN
)) {
1761 // the flash is locked and locked down
1765 Data
&= ~(FWH_WRITE_LOCK
| FWH_READ_LOCK
| FWH_LOCK_DOWN
);
1768 // Save boot script for S3 resume
1771 EFI_ACPI_S3_RESUME_SCRIPT_TABLE
,
1772 EfiBootScriptWidthUint8
,
1773 (UINT64
) (LbaAddress
- 0x400000 + 2),
1778 FvbMemWrite8 ((LbaAddress
- 0x400000 + 2), Data
);
1783 LbaAddress
+= PtrBlockMapEntry
->BlockLength
;
1786 // Get the maximum size of a block. The size will be used to allocate
1787 // buffer for Scratch space, the intermediate buffer for FVB extension
1790 if (MaxLbaSize
< PtrBlockMapEntry
->BlockLength
) {
1791 MaxLbaSize
= PtrBlockMapEntry
->BlockLength
;
1794 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1797 // Write back a healthy FV header
1799 if (WriteBack
&& (!WriteLocked
)) {
1800 Status
= FlashFdErase (
1801 (UINTN
) FwhInstance
->FvWriteBase
[0],
1802 (UINTN
) BaseAddress
,
1803 FwVolHeader
->FvBlockMap
->BlockLength
1806 HeaderLength
= (UINTN
) FwVolHeader
->HeaderLength
;
1807 Status
= FlashFdWrite (
1808 (UINTN
) FwhInstance
->FvWriteBase
[0],
1809 (UINTN
) BaseAddress
,
1810 (UINTN
*) &HeaderLength
,
1811 (UINT8
*) FwVolHeader
,
1812 FwVolHeader
->FvBlockMap
->BlockLength
1815 FwVolHeader
->HeaderLength
= (UINT16
) HeaderLength
;
1816 DEBUG ((EFI_D_ERROR
, "Fvb: FV header invalid, write back - %r\n", Status
));
1820 // The total number of blocks in the FV.
1822 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1825 // If the FV is write locked, set the appropriate attributes
1831 FwhInstance
->VolumeHeader
.Attributes
&= ~EFI_FVB_WRITE_STATUS
;
1835 FwhInstance
->VolumeHeader
.Attributes
|= EFI_FVB_LOCK_STATUS
;
1838 // Add a FVB Protocol Instance
1840 Status
= gBS
->AllocatePool (
1841 EfiRuntimeServicesData
,
1842 sizeof (EFI_FW_VOL_BLOCK_DEVICE
),
1845 ASSERT_EFI_ERROR (Status
);
1847 EfiCopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1849 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1850 mFvbModuleGlobal
->NumFv
++;
1853 // Set up the devicepath
1855 FvbDevice
->DevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
1856 FvbDevice
->DevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ (FwVolHeader
->FvLength
- 1);
1859 // Find a handle with a matching device path that has supports FW Block protocol
1861 TempFwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) &TempFvbDevicePathData
;
1862 EfiCopyMem (TempFwbDevicePath
, &FvbDevice
->DevicePath
, sizeof (FV_DEVICE_PATH
));
1863 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &TempFwbDevicePath
, &FwbHandle
);
1864 if (EFI_ERROR (Status
)) {
1866 // LocateDevicePath fails so install a new interface and device path
1869 Status
= gBS
->InstallMultipleProtocolInterfaces (
1871 &gEfiFirmwareVolumeBlockProtocolGuid
,
1872 &FvbDevice
->FwVolBlockInstance
,
1873 &gEfiDevicePathProtocolGuid
,
1874 &FvbDevice
->DevicePath
,
1877 ASSERT_EFI_ERROR (Status
);
1878 } else if (EfiIsDevicePathEnd (TempFwbDevicePath
)) {
1880 // Device allready exists, so reinstall the FVB protocol
1882 Status
= gBS
->HandleProtocol (
1884 &gEfiFirmwareVolumeBlockProtocolGuid
,
1887 ASSERT_EFI_ERROR (Status
);
1889 Status
= gBS
->ReinstallProtocolInterface (
1891 &gEfiFirmwareVolumeBlockProtocolGuid
,
1893 &FvbDevice
->FwVolBlockInstance
1895 ASSERT_EFI_ERROR (Status
);
1899 // There was a FVB protocol on an End Device Path node
1904 // Install FVB Extension Protocol on the same handle
1906 Status
= gBS
->InstallMultipleProtocolInterfaces (
1908 &gEfiFvbExtensionProtocolGuid
,
1909 &FvbDevice
->FvbExtension
,
1910 &gEfiAlternateFvBlockGuid
,
1915 ASSERT_EFI_ERROR (Status
);
1917 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1919 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1920 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1925 // Allocate for scratch space, an intermediate buffer for FVB extention
1927 Status
= gBS
->AllocatePool (
1928 EfiRuntimeServicesData
,
1930 &mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
]
1932 ASSERT_EFI_ERROR (Status
);
1934 mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
] = mFvbModuleGlobal
->FvbScratchSpace
[FVB_PHYSICAL
];
1936 FvbSpecificInitialize (mFvbModuleGlobal
);
1938 return EnableFvbWrites (FALSE
);