3 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available
6 under the terms and conditions of the BSD License which accompanies this
7 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.
24 // The package level header files this module uses
29 // The protocols, PPI and GUID defintions for this module
31 #include <Guid/EventGroup.h>
32 #include <Protocol/FirmwareVolumeBlock.h>
33 #include <Protocol/DevicePath.h>
36 // The Library classes this module consumes
38 #include <Library/UefiLib.h>
39 #include <Library/UefiDriverEntryPoint.h>
40 #include <Library/BaseLib.h>
41 #include <Library/DxeServicesTableLib.h>
42 #include <Library/UefiRuntimeLib.h>
43 #include <Library/DebugLib.h>
44 #include <Library/BaseMemoryLib.h>
45 #include <Library/MemoryAllocationLib.h>
46 #include <Library/UefiBootServicesTableLib.h>
47 #include <Library/DevicePathLib.h>
49 #include "FwBlockService.h"
50 #include "QemuFlash.h"
52 #define EFI_FVB2_STATUS \
53 (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
55 ESAL_FWB_GLOBAL
*mFvbModuleGlobal
;
57 FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate
= {
63 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
)),
64 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
) >> 8)
68 (EFI_PHYSICAL_ADDRESS
) 0,
69 (EFI_PHYSICAL_ADDRESS
) 0,
73 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
75 END_DEVICE_PATH_LENGTH
,
81 FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate
= {
87 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
)),
88 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
) >> 8)
95 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
97 END_DEVICE_PATH_LENGTH
,
103 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
104 FVB_DEVICE_SIGNATURE
,
108 FvbProtocolGetAttributes
,
109 FvbProtocolSetAttributes
,
110 FvbProtocolGetPhysicalAddress
,
111 FvbProtocolGetBlockSize
,
114 FvbProtocolEraseBlocks
,
123 FvbVirtualddressChangeEvent (
131 Fixup internal data so that EFI and SAL can be call in virtual mode.
132 Call the passed in Child Notify event and convert the mFvbModuleGlobal
133 date items to there virtual address.
135 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance
137 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
142 (Standard EFI notify event - EFI_EVENT_NOTIFY)
150 EFI_FW_VOL_INSTANCE
*FwhInstance
;
153 EfiConvertPointer (0x0,
154 (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
157 // Convert the base address of all the instances
160 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
161 while (Index
< mFvbModuleGlobal
->NumFv
) {
162 EfiConvertPointer (0x0, (VOID
**) &FwhInstance
->FvBase
[FVB_VIRTUAL
]);
163 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
165 (UINTN
) ((UINT8
*) FwhInstance
) +
166 FwhInstance
->VolumeHeader
.HeaderLength
+
167 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
172 EfiConvertPointer (0x0,
173 (VOID
**) &mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
]);
174 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
);
175 QemuFlashConvertPointers ();
181 IN ESAL_FWB_GLOBAL
*Global
,
182 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
188 Retrieves the physical address of a memory mapped FV
191 Instance - The FV instance whose base address is going to be
193 Global - Pointer to ESAL_FWB_GLOBAL that contains all
195 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
196 Virtual - Whether CPU is in virtual or physical mode
199 EFI_SUCCESS - Successfully returns
200 EFI_INVALID_PARAMETER - Instance not found
204 EFI_FW_VOL_INSTANCE
*FwhRecord
;
207 if (Instance
>= Global
->NumFv
) {
208 return EFI_INVALID_PARAMETER
;
211 // Find the right instance of the FVB private data
213 FwhRecord
= Global
->FvInstance
[Virtual
];
214 while (Instance
> 0) {
215 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
217 (UINTN
) ((UINT8
*) FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
218 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
223 *FwhInstance
= FwhRecord
;
229 FvbGetPhysicalAddress (
231 OUT EFI_PHYSICAL_ADDRESS
*Address
,
232 IN ESAL_FWB_GLOBAL
*Global
,
238 Retrieves the physical address of a memory mapped FV
241 Instance - The FV instance whose base address is going to be
243 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
244 that on successful return, contains the base
245 address of the firmware volume.
246 Global - Pointer to ESAL_FWB_GLOBAL that contains all
248 Virtual - Whether CPU is in virtual or physical mode
251 EFI_SUCCESS - Successfully returns
252 EFI_INVALID_PARAMETER - Instance not found
256 EFI_FW_VOL_INSTANCE
*FwhInstance
;
260 // Find the right instance of the FVB private data
262 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
263 ASSERT_EFI_ERROR (Status
);
264 *Address
= FwhInstance
->FvBase
[Virtual
];
270 FvbGetVolumeAttributes (
272 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
273 IN ESAL_FWB_GLOBAL
*Global
,
279 Retrieves attributes, insures positive polarity of attribute bits, returns
280 resulting attributes in output parameter
283 Instance - The FV instance whose attributes is going to be
285 Attributes - Output buffer which contains attributes
286 Global - Pointer to ESAL_FWB_GLOBAL that contains all
288 Virtual - Whether CPU is in virtual or physical mode
291 EFI_SUCCESS - Successfully returns
292 EFI_INVALID_PARAMETER - Instance not found
296 EFI_FW_VOL_INSTANCE
*FwhInstance
;
300 // Find the right instance of the FVB private data
302 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
303 ASSERT_EFI_ERROR (Status
);
304 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
313 OUT UINTN
*LbaAddress
,
314 OUT UINTN
*LbaLength
,
315 OUT UINTN
*NumOfBlocks
,
316 IN ESAL_FWB_GLOBAL
*Global
,
322 Retrieves the starting address of an LBA in an FV
325 Instance - The FV instance which the Lba belongs to
326 Lba - The logical block address
327 LbaAddress - On output, contains the physical starting address
329 LbaLength - On output, contains the length of the block
330 NumOfBlocks - A pointer to a caller allocated UINTN in which the
331 number of consecutive blocks starting with Lba is
332 returned. All blocks in this range have a size of
334 Global - Pointer to ESAL_FWB_GLOBAL that contains all
336 Virtual - Whether CPU is in virtual or physical mode
339 EFI_SUCCESS - Successfully returns
340 EFI_INVALID_PARAMETER - Instance not found
349 EFI_FW_VOL_INSTANCE
*FwhInstance
;
350 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
354 // Find the right instance of the FVB private data
356 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
357 ASSERT_EFI_ERROR (Status
);
361 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
364 // Parse the blockmap of the FV to find which map entry the Lba belongs to
367 NumBlocks
= BlockMap
->NumBlocks
;
368 BlockLength
= BlockMap
->Length
;
370 if (NumBlocks
== 0 || BlockLength
== 0) {
371 return EFI_INVALID_PARAMETER
;
374 NextLba
= StartLba
+ NumBlocks
;
377 // The map entry found
379 if (Lba
>= StartLba
&& Lba
< NextLba
) {
380 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
381 if (LbaAddress
!= NULL
) {
382 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
385 if (LbaLength
!= NULL
) {
386 *LbaLength
= BlockLength
;
389 if (NumOfBlocks
!= NULL
) {
390 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
397 Offset
= Offset
+ NumBlocks
* BlockLength
;
403 FvbSetVolumeAttributes (
405 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
406 IN ESAL_FWB_GLOBAL
*Global
,
412 Modifies the current settings of the firmware volume according to the
413 input parameter, and returns the new setting of the volume
416 Instance - The FV instance whose attributes is going to be
418 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
419 containing the desired firmware volume settings.
420 On successful return, it contains the new settings
421 of the firmware volume
422 Global - Pointer to ESAL_FWB_GLOBAL that contains all
424 Virtual - Whether CPU is in virtual or physical mode
427 EFI_SUCCESS - Successfully returns
428 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
429 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
430 in conflict with the capabilities as declared in
431 the firmware volume header
435 EFI_FW_VOL_INSTANCE
*FwhInstance
;
436 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
437 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
442 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes
;
445 // Find the right instance of the FVB private data
447 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
448 ASSERT_EFI_ERROR (Status
);
451 (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
452 OldAttributes
= *AttribPtr
;
453 Capabilities
= OldAttributes
& (EFI_FVB2_READ_DISABLED_CAP
| \
454 EFI_FVB2_READ_ENABLED_CAP
| \
455 EFI_FVB2_WRITE_DISABLED_CAP
| \
456 EFI_FVB2_WRITE_ENABLED_CAP
| \
459 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
460 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
462 UnchangedAttributes
= EFI_FVB2_READ_DISABLED_CAP
| \
463 EFI_FVB2_READ_ENABLED_CAP
| \
464 EFI_FVB2_WRITE_DISABLED_CAP
| \
465 EFI_FVB2_WRITE_ENABLED_CAP
| \
466 EFI_FVB2_LOCK_CAP
| \
467 EFI_FVB2_STICKY_WRITE
| \
468 EFI_FVB2_MEMORY_MAPPED
| \
469 EFI_FVB2_ERASE_POLARITY
| \
470 EFI_FVB2_READ_LOCK_CAP
| \
471 EFI_FVB2_WRITE_LOCK_CAP
| \
475 // Some attributes of FV is read only can *not* be set
477 if ((OldAttributes
& UnchangedAttributes
) ^
478 (*Attributes
& UnchangedAttributes
)) {
479 return EFI_INVALID_PARAMETER
;
482 // If firmware volume is locked, no status bit can be updated
484 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
485 if (OldStatus
^ NewStatus
) {
486 return EFI_ACCESS_DENIED
;
492 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
493 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
494 return EFI_INVALID_PARAMETER
;
500 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
501 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
502 return EFI_INVALID_PARAMETER
;
506 // Test write disable
508 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
509 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
510 return EFI_INVALID_PARAMETER
;
516 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
517 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
518 return EFI_INVALID_PARAMETER
;
524 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
525 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
526 return EFI_INVALID_PARAMETER
;
530 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
531 *AttribPtr
= (*AttribPtr
) | NewStatus
;
532 *Attributes
= *AttribPtr
;
542 FvbProtocolGetPhysicalAddress (
543 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
544 OUT EFI_PHYSICAL_ADDRESS
*Address
550 Retrieves the physical address of the device.
554 This - Calling context
555 Address - Output buffer containing the address.
558 EFI_SUCCESS - Successfully returns
562 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
564 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
566 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
,
567 mFvbModuleGlobal
, EfiGoneVirtual ());
572 FvbProtocolGetBlockSize (
573 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
574 IN CONST EFI_LBA Lba
,
575 OUT UINTN
*BlockSize
,
576 OUT UINTN
*NumOfBlocks
581 Retrieve the size of a logical block
584 This - Calling context
585 Lba - Indicates which block to return the size for.
586 BlockSize - A pointer to a caller allocated UINTN in which
587 the size of the block is returned
588 NumOfBlocks - a pointer to a caller allocated UINTN in which the
589 number of consecutive blocks starting with Lba is
590 returned. All blocks in this range have a size of
594 EFI_SUCCESS - The firmware volume was read successfully and
595 contents are in Buffer
599 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
601 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
603 return FvbGetLbaAddress (
616 FvbProtocolGetAttributes (
617 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
618 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
623 Retrieves Volume attributes. No polarity translations are done.
626 This - Calling context
627 Attributes - output buffer which contains attributes
630 EFI_SUCCESS - Successfully returns
634 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
636 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
638 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
,
639 mFvbModuleGlobal
, EfiGoneVirtual ());
644 FvbProtocolSetAttributes (
645 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
646 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
651 Sets Volume attributes. No polarity translations are done.
654 This - Calling context
655 Attributes - output buffer which contains attributes
658 EFI_SUCCESS - Successfully returns
662 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
664 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
666 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
,
667 mFvbModuleGlobal
, EfiGoneVirtual ());
672 FvbProtocolEraseBlocks (
673 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
680 The EraseBlock() function erases one or more blocks as denoted by the
681 variable argument list. The entire parameter list of blocks must be
682 verified prior to erasing any blocks. If a block is requested that does
683 not exist within the associated firmware volume (it has a larger index than
684 the last block of the firmware volume), the EraseBlock() function must
685 return EFI_INVALID_PARAMETER without modifying the contents of the firmware
689 This - Calling context
690 ... - Starting LBA followed by Number of Lba to erase.
691 a -1 to terminate the list.
694 EFI_SUCCESS - The erase request was successfully completed
695 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
696 EFI_DEVICE_ERROR - The block device is not functioning correctly and
697 could not be written. Firmware device may have been
702 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
703 EFI_FW_VOL_INSTANCE
*FwhInstance
;
710 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
712 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
,
713 &FwhInstance
, EfiGoneVirtual ());
714 ASSERT_EFI_ERROR (Status
);
716 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
718 VA_START (args
, This
);
721 StartingLba
= VA_ARG (args
, EFI_LBA
);
722 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
726 NumOfLba
= VA_ARG (args
, UINT32
);
729 // Check input parameters
731 if ((NumOfLba
== 0) || ((StartingLba
+ NumOfLba
) > NumOfBlocks
)) {
733 return EFI_INVALID_PARAMETER
;
739 VA_START (args
, This
);
741 StartingLba
= VA_ARG (args
, EFI_LBA
);
742 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
746 NumOfLba
= VA_ARG (args
, UINT32
);
748 while (NumOfLba
> 0) {
749 Status
= QemuFlashEraseBlock (StartingLba
);
750 if (EFI_ERROR (Status
)) {
769 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
772 IN OUT UINTN
*NumBytes
,
779 Writes data beginning at Lba:Offset from FV. The write terminates either
780 when *NumBytes of data have been written, or when a block boundary is
781 reached. *NumBytes is updated to reflect the actual number of bytes
782 written. The write opertion does not include erase. This routine will
783 attempt to write only the specified bytes. If the writes do not stick,
784 it will return an error.
787 This - Calling context
788 Lba - Block in which to begin write
789 Offset - Offset in the block at which to begin write
790 NumBytes - On input, indicates the requested write size. On
791 output, indicates the actual number of bytes
793 Buffer - Buffer containing source data for the write.
796 EFI_SUCCESS - The firmware volume was written successfully
797 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
798 NumBytes contains the total number of bytes
800 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
801 EFI_DEVICE_ERROR - The block device is not functioning correctly and
803 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
807 return QemuFlashWrite ((EFI_LBA
)Lba
, (UINTN
)Offset
, NumBytes
,
814 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
815 IN CONST EFI_LBA Lba
,
816 IN CONST UINTN Offset
,
817 IN OUT UINTN
*NumBytes
,
824 Reads data beginning at Lba:Offset from FV. The Read terminates either
825 when *NumBytes of data have been read, or when a block boundary is
826 reached. *NumBytes is updated to reflect the actual number of bytes
827 written. The write opertion does not include erase. This routine will
828 attempt to write only the specified bytes. If the writes do not stick,
829 it will return an error.
832 This - Calling context
833 Lba - Block in which to begin Read
834 Offset - Offset in the block at which to begin Read
835 NumBytes - On input, indicates the requested write size. On
836 output, indicates the actual number of bytes Read
837 Buffer - Buffer containing source data for the Read.
840 EFI_SUCCESS - The firmware volume was read successfully and
841 contents are in Buffer
842 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
843 NumBytes contains the total number of bytes
845 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
846 EFI_DEVICE_ERROR - The block device is not functioning correctly and
848 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
852 return QemuFlashRead ((EFI_LBA
)Lba
, (UINTN
)Offset
, NumBytes
,
858 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
863 Check the integrity of firmware volume header
866 FwVolHeader - A pointer to a firmware volume header
869 EFI_SUCCESS - The firmware volume is consistent
870 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an
878 // Verify the header revision, header signature, length
879 // Length of FvBlock cannot be 2**64-1
880 // HeaderLength cannot be an odd number
882 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
883 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
884 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
885 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
887 return EFI_NOT_FOUND
;
891 // Verify the header checksum
894 Checksum
= CalculateSum16 ((UINT16
*) FwVolHeader
,
895 FwVolHeader
->HeaderLength
);
900 (UINT16
) (((UINTN
) FwVolHeader
->Checksum
+ 0x10000 - Checksum
) & 0xffff);
902 DEBUG ((EFI_D_INFO
, "FV@%p Checksum is 0x%x, expected 0x%x\n",
903 FwVolHeader
, FwVolHeader
->Checksum
, Expected
));
904 return EFI_NOT_FOUND
;
912 MarkMemoryRangeForRuntimeAccess (
913 EFI_PHYSICAL_ADDRESS BaseAddress
,
920 // Mark flash region as runtime memory
922 Status
= gDS
->RemoveMemorySpace (
927 Status
= gDS
->AddMemorySpace (
928 EfiGcdMemoryTypeSystemMemory
,
931 EFI_MEMORY_UC
| EFI_MEMORY_RUNTIME
933 ASSERT_EFI_ERROR (Status
);
935 Status
= gBS
->AllocatePages (
937 EfiRuntimeServicesData
,
938 EFI_SIZE_TO_PAGES (Length
),
941 ASSERT_EFI_ERROR (Status
);
948 InitializeVariableFvHeader (
953 EFI_FIRMWARE_VOLUME_HEADER
*GoodFwVolHeader
;
954 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
960 (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
)
961 PcdGet32 (PcdOvmfFlashNvStorageVariableBase
);
964 (FixedPcdGet32 (PcdFlashNvStorageVariableSize
) +
965 FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize
) +
966 FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize
) +
967 FixedPcdGet32 (PcdOvmfFlashNvStorageEventLogSize
));
969 BlockSize
= PcdGet32 (PcdOvmfFirmwareBlockSize
);
971 Status
= ValidateFvHeader (FwVolHeader
);
972 if (!EFI_ERROR (Status
)) {
973 if (FwVolHeader
->FvLength
!= Length
||
974 FwVolHeader
->BlockMap
[0].Length
!= BlockSize
) {
975 Status
= EFI_VOLUME_CORRUPTED
;
978 if (EFI_ERROR (Status
)) {
983 "Variable FV header is not valid. It will be reinitialized.\n"));
986 // Get FvbInfo to provide in FwhInstance.
988 Status
= GetFvbInfo (Length
, &GoodFwVolHeader
);
989 ASSERT (!EFI_ERROR (Status
));
991 Start
= (UINTN
)(UINT8
*) FwVolHeader
- PcdGet32 (PcdOvmfFdBaseAddress
);
992 ASSERT (Start
% BlockSize
== 0 && Length
% BlockSize
== 0);
993 ASSERT (GoodFwVolHeader
->HeaderLength
<= BlockSize
);
996 // Erase all the blocks
998 for (Offset
= Start
; Offset
< Start
+ Length
; Offset
+= BlockSize
) {
999 Status
= QemuFlashEraseBlock (Offset
/ BlockSize
);
1000 ASSERT_EFI_ERROR (Status
);
1004 // Write good FV header
1006 WriteLength
= GoodFwVolHeader
->HeaderLength
;
1007 Status
= QemuFlashWrite (
1011 (UINT8
*) GoodFwVolHeader
);
1012 ASSERT_EFI_ERROR (Status
);
1013 ASSERT (WriteLength
== GoodFwVolHeader
->HeaderLength
);
1022 IN EFI_HANDLE ImageHandle
,
1023 IN EFI_SYSTEM_TABLE
*SystemTable
1027 Routine Description:
1028 This function does common initialization for FVB services
1037 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1038 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1040 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1041 EFI_HANDLE FwbHandle
;
1042 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1043 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1045 EFI_PHYSICAL_ADDRESS BaseAddress
;
1048 EFI_EVENT VirtualAddressChangeEvent
;
1050 if (EFI_ERROR (QemuFlashInitialize ())) {
1052 // Return an error so image will be unloaded
1055 "QEMU flash was not detected. Writable FVB is not being installed.\n"));
1056 return EFI_WRITE_PROTECTED
;
1060 // Allocate runtime services data for global variable, which contains
1061 // the private data of all firmware volume block instances
1063 mFvbModuleGlobal
= AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL
));
1064 ASSERT (mFvbModuleGlobal
!= NULL
);
1066 BaseAddress
= (UINTN
) PcdGet32 (PcdOvmfFdBaseAddress
);
1067 Length
= PcdGet32 (PcdOvmfFirmwareFdSize
);
1069 Status
= InitializeVariableFvHeader ();
1070 if (EFI_ERROR (Status
)) {
1072 "QEMU Flash: Unable to initialize variable FV header\n"));
1073 return EFI_WRITE_PROTECTED
;
1076 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1077 Status
= ValidateFvHeader (FwVolHeader
);
1078 if (EFI_ERROR (Status
)) {
1082 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1083 if (EFI_ERROR (Status
)) {
1084 DEBUG ((EFI_D_INFO
, "EFI_ERROR (GetFvbInfo (Length, &FwVolHeader))\n"));
1085 return EFI_WRITE_PROTECTED
;
1089 BufferSize
= (sizeof (EFI_FW_VOL_INSTANCE
) +
1090 FwVolHeader
->HeaderLength
-
1091 sizeof (EFI_FIRMWARE_VOLUME_HEADER
)
1095 // Only need to allocate once. There is only one copy of physical memory for
1096 // the private data of each FV instance. But in virtual mode or in physical
1097 // mode, the address of the the physical memory may be different.
1099 mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] = AllocateRuntimePool (
1101 ASSERT (mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] != NULL
);
1104 // Make a virtual copy of the FvInstance pointer.
1106 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1107 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1109 mFvbModuleGlobal
->NumFv
= 0;
1113 (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
)
1114 PcdGet32 (PcdOvmfFlashNvStorageVariableBase
);
1116 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1117 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1119 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
,
1120 FwVolHeader
->HeaderLength
);
1121 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1122 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1126 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
;
1127 PtrBlockMapEntry
->NumBlocks
!= 0;
1128 PtrBlockMapEntry
++) {
1130 // Get the maximum size of a block.
1132 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
1133 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1136 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1140 // The total number of blocks in the FV.
1142 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1145 // Add a FVB Protocol Instance
1147 FvbDevice
= AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1148 ASSERT (FvbDevice
!= NULL
);
1150 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1152 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1153 mFvbModuleGlobal
->NumFv
++;
1156 // Set up the devicepath
1158 if (FwVolHeader
->ExtHeaderOffset
== 0) {
1159 FV_MEMMAP_DEVICE_PATH
*FvMemmapDevicePath
;
1162 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
1164 FvMemmapDevicePath
= AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH
),
1165 &mFvMemmapDevicePathTemplate
);
1166 FvMemmapDevicePath
->MemMapDevPath
.StartingAddress
= BaseAddress
;
1167 FvMemmapDevicePath
->MemMapDevPath
.EndingAddress
=
1168 BaseAddress
+ FwVolHeader
->FvLength
- 1;
1169 FvbDevice
->DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)FvMemmapDevicePath
;
1171 FV_PIWG_DEVICE_PATH
*FvPiwgDevicePath
;
1173 FvPiwgDevicePath
= AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH
),
1174 &mFvPIWGDevicePathTemplate
);
1176 &FvPiwgDevicePath
->FvDevPath
.FvName
,
1177 (GUID
*)(UINTN
)(BaseAddress
+ FwVolHeader
->ExtHeaderOffset
)
1179 FvbDevice
->DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)FvPiwgDevicePath
;
1183 // Find a handle with a matching device path that has supports FW Block
1186 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
,
1187 &FvbDevice
->DevicePath
, &FwbHandle
);
1188 if (EFI_ERROR (Status
)) {
1190 // LocateDevicePath fails so install a new interface and device path
1193 DEBUG ((EFI_D_INFO
, "Installing QEMU flash FVB\n"));
1194 Status
= gBS
->InstallMultipleProtocolInterfaces (
1196 &gEfiFirmwareVolumeBlockProtocolGuid
,
1197 &FvbDevice
->FwVolBlockInstance
,
1198 &gEfiDevicePathProtocolGuid
,
1199 FvbDevice
->DevicePath
,
1202 ASSERT_EFI_ERROR (Status
);
1203 } else if (IsDevicePathEnd (FvbDevice
->DevicePath
)) {
1205 // Device already exists, so reinstall the FVB protocol
1207 Status
= gBS
->HandleProtocol (
1209 &gEfiFirmwareVolumeBlockProtocolGuid
,
1210 (VOID
**)&OldFwbInterface
1212 ASSERT_EFI_ERROR (Status
);
1214 DEBUG ((EFI_D_INFO
, "Reinstalling FVB for QEMU flash region\n"));
1215 Status
= gBS
->ReinstallProtocolInterface (
1217 &gEfiFirmwareVolumeBlockProtocolGuid
,
1219 &FvbDevice
->FwVolBlockInstance
1221 ASSERT_EFI_ERROR (Status
);
1224 // There was a FVB protocol on an End Device Path node
1229 MarkMemoryRangeForRuntimeAccess (BaseAddress
, Length
);
1232 // Set several PCD values to point to flash
1235 PcdFlashNvStorageVariableBase64
,
1236 (UINTN
) PcdGet32 (PcdOvmfFlashNvStorageVariableBase
)
1239 PcdFlashNvStorageFtwWorkingBase
,
1240 PcdGet32 (PcdOvmfFlashNvStorageFtwWorkingBase
)
1243 PcdFlashNvStorageFtwSpareBase
,
1244 PcdGet32 (PcdOvmfFlashNvStorageFtwSpareBase
)
1247 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1249 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1250 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1253 VirtualAddressChangeEvent
= NULL
;
1254 Status
= gBS
->CreateEventEx (
1257 FvbVirtualddressChangeEvent
,
1259 &gEfiEventVirtualAddressChangeGuid
,
1260 &VirtualAddressChangeEvent
1262 ASSERT_EFI_ERROR (Status
);
1264 PcdSetBool (PcdOvmfFlashVariablesEnable
, TRUE
);