3 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
18 // The protocols, PPI and GUID defintions for this module
20 #include <Protocol/DevicePath.h>
21 #include <Protocol/FirmwareVolumeBlock.h>
24 // The Library classes this module consumes
26 #include <Library/BaseLib.h>
27 #include <Library/BaseMemoryLib.h>
28 #include <Library/DebugLib.h>
29 #include <Library/DevicePathLib.h>
30 #include <Library/DxeServicesTableLib.h>
31 #include <Library/MemoryAllocationLib.h>
32 #include <Library/UefiBootServicesTableLib.h>
34 #include "FwBlockService.h"
35 #include "QemuFlash.h"
37 #define EFI_FVB2_STATUS \
38 (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
40 ESAL_FWB_GLOBAL
*mFvbModuleGlobal
;
42 FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate
= {
48 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
)),
49 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
) >> 8)
53 (EFI_PHYSICAL_ADDRESS
) 0,
54 (EFI_PHYSICAL_ADDRESS
) 0,
58 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
60 END_DEVICE_PATH_LENGTH
,
66 FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate
= {
72 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
)),
73 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
) >> 8)
80 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
82 END_DEVICE_PATH_LENGTH
,
88 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
93 FvbProtocolGetAttributes
,
94 FvbProtocolSetAttributes
,
95 FvbProtocolGetPhysicalAddress
,
96 FvbProtocolGetBlockSize
,
99 FvbProtocolEraseBlocks
,
108 IN ESAL_FWB_GLOBAL
*Global
,
109 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
114 Retrieves the physical address of a memory mapped FV
117 Instance - The FV instance whose base address is going to be
119 Global - Pointer to ESAL_FWB_GLOBAL that contains all
121 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
124 EFI_SUCCESS - Successfully returns
125 EFI_INVALID_PARAMETER - Instance not found
129 EFI_FW_VOL_INSTANCE
*FwhRecord
;
132 if (Instance
>= Global
->NumFv
) {
133 return EFI_INVALID_PARAMETER
;
136 // Find the right instance of the FVB private data
138 FwhRecord
= Global
->FvInstance
;
139 while (Instance
> 0) {
140 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
142 (UINTN
) ((UINT8
*) FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
143 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
148 *FwhInstance
= FwhRecord
;
154 FvbGetPhysicalAddress (
156 OUT EFI_PHYSICAL_ADDRESS
*Address
,
157 IN ESAL_FWB_GLOBAL
*Global
162 Retrieves the physical address of a memory mapped FV
165 Instance - The FV instance whose base address is going to be
167 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
168 that on successful return, contains the base
169 address of the firmware volume.
170 Global - Pointer to ESAL_FWB_GLOBAL that contains all
174 EFI_SUCCESS - Successfully returns
175 EFI_INVALID_PARAMETER - Instance not found
179 EFI_FW_VOL_INSTANCE
*FwhInstance
;
183 // Find the right instance of the FVB private data
185 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
);
186 ASSERT_EFI_ERROR (Status
);
187 *Address
= FwhInstance
->FvBase
;
193 FvbGetVolumeAttributes (
195 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
196 IN ESAL_FWB_GLOBAL
*Global
201 Retrieves attributes, insures positive polarity of attribute bits, returns
202 resulting attributes in output parameter
205 Instance - The FV instance whose attributes is going to be
207 Attributes - Output buffer which contains attributes
208 Global - Pointer to ESAL_FWB_GLOBAL that contains all
212 EFI_SUCCESS - Successfully returns
213 EFI_INVALID_PARAMETER - Instance not found
217 EFI_FW_VOL_INSTANCE
*FwhInstance
;
221 // Find the right instance of the FVB private data
223 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
);
224 ASSERT_EFI_ERROR (Status
);
225 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
234 OUT UINTN
*LbaAddress
,
235 OUT UINTN
*LbaLength
,
236 OUT UINTN
*NumOfBlocks
,
237 IN ESAL_FWB_GLOBAL
*Global
242 Retrieves the starting address of an LBA in an FV
245 Instance - The FV instance which the Lba belongs to
246 Lba - The logical block address
247 LbaAddress - On output, contains the physical starting address
249 LbaLength - On output, contains the length of the block
250 NumOfBlocks - A pointer to a caller allocated UINTN in which the
251 number of consecutive blocks starting with Lba is
252 returned. All blocks in this range have a size of
254 Global - Pointer to ESAL_FWB_GLOBAL that contains all
258 EFI_SUCCESS - Successfully returns
259 EFI_INVALID_PARAMETER - Instance not found
268 EFI_FW_VOL_INSTANCE
*FwhInstance
;
269 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
273 // Find the right instance of the FVB private data
275 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
);
276 ASSERT_EFI_ERROR (Status
);
280 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
283 // Parse the blockmap of the FV to find which map entry the Lba belongs to
286 NumBlocks
= BlockMap
->NumBlocks
;
287 BlockLength
= BlockMap
->Length
;
289 if (NumBlocks
== 0 || BlockLength
== 0) {
290 return EFI_INVALID_PARAMETER
;
293 NextLba
= StartLba
+ NumBlocks
;
296 // The map entry found
298 if (Lba
>= StartLba
&& Lba
< NextLba
) {
299 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
300 if (LbaAddress
!= NULL
) {
301 *LbaAddress
= FwhInstance
->FvBase
+ Offset
;
304 if (LbaLength
!= NULL
) {
305 *LbaLength
= BlockLength
;
308 if (NumOfBlocks
!= NULL
) {
309 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
316 Offset
= Offset
+ NumBlocks
* BlockLength
;
322 FvbSetVolumeAttributes (
324 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
325 IN ESAL_FWB_GLOBAL
*Global
330 Modifies the current settings of the firmware volume according to the
331 input parameter, and returns the new setting of the volume
334 Instance - The FV instance whose attributes is going to be
336 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
337 containing the desired firmware volume settings.
338 On successful return, it contains the new settings
339 of the firmware volume
340 Global - Pointer to ESAL_FWB_GLOBAL that contains all
344 EFI_SUCCESS - Successfully returns
345 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
346 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
347 in conflict with the capabilities as declared in
348 the firmware volume header
352 EFI_FW_VOL_INSTANCE
*FwhInstance
;
353 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
354 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
359 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes
;
362 // Find the right instance of the FVB private data
364 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
);
365 ASSERT_EFI_ERROR (Status
);
368 (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
369 OldAttributes
= *AttribPtr
;
370 Capabilities
= OldAttributes
& (EFI_FVB2_READ_DISABLED_CAP
| \
371 EFI_FVB2_READ_ENABLED_CAP
| \
372 EFI_FVB2_WRITE_DISABLED_CAP
| \
373 EFI_FVB2_WRITE_ENABLED_CAP
| \
376 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
377 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
379 UnchangedAttributes
= EFI_FVB2_READ_DISABLED_CAP
| \
380 EFI_FVB2_READ_ENABLED_CAP
| \
381 EFI_FVB2_WRITE_DISABLED_CAP
| \
382 EFI_FVB2_WRITE_ENABLED_CAP
| \
383 EFI_FVB2_LOCK_CAP
| \
384 EFI_FVB2_STICKY_WRITE
| \
385 EFI_FVB2_MEMORY_MAPPED
| \
386 EFI_FVB2_ERASE_POLARITY
| \
387 EFI_FVB2_READ_LOCK_CAP
| \
388 EFI_FVB2_WRITE_LOCK_CAP
| \
392 // Some attributes of FV is read only can *not* be set
394 if ((OldAttributes
& UnchangedAttributes
) ^
395 (*Attributes
& UnchangedAttributes
)) {
396 return EFI_INVALID_PARAMETER
;
399 // If firmware volume is locked, no status bit can be updated
401 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
402 if (OldStatus
^ NewStatus
) {
403 return EFI_ACCESS_DENIED
;
409 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
410 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
411 return EFI_INVALID_PARAMETER
;
417 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
418 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
419 return EFI_INVALID_PARAMETER
;
423 // Test write disable
425 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
426 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
427 return EFI_INVALID_PARAMETER
;
433 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
434 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
435 return EFI_INVALID_PARAMETER
;
441 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
442 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
443 return EFI_INVALID_PARAMETER
;
447 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
448 *AttribPtr
= (*AttribPtr
) | NewStatus
;
449 *Attributes
= *AttribPtr
;
459 FvbProtocolGetPhysicalAddress (
460 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
461 OUT EFI_PHYSICAL_ADDRESS
*Address
467 Retrieves the physical address of the device.
471 This - Calling context
472 Address - Output buffer containing the address.
475 EFI_SUCCESS - Successfully returns
479 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
481 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
483 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
,
489 FvbProtocolGetBlockSize (
490 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
491 IN CONST EFI_LBA Lba
,
492 OUT UINTN
*BlockSize
,
493 OUT UINTN
*NumOfBlocks
498 Retrieve the size of a logical block
501 This - Calling context
502 Lba - Indicates which block to return the size for.
503 BlockSize - A pointer to a caller allocated UINTN in which
504 the size of the block is returned
505 NumOfBlocks - a pointer to a caller allocated UINTN in which the
506 number of consecutive blocks starting with Lba is
507 returned. All blocks in this range have a size of
511 EFI_SUCCESS - The firmware volume was read successfully and
512 contents are in Buffer
516 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
518 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
520 return FvbGetLbaAddress (
532 FvbProtocolGetAttributes (
533 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
534 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
539 Retrieves Volume attributes. No polarity translations are done.
542 This - Calling context
543 Attributes - output buffer which contains attributes
546 EFI_SUCCESS - Successfully returns
550 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
552 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
554 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
,
560 FvbProtocolSetAttributes (
561 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
562 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
567 Sets Volume attributes. No polarity translations are done.
570 This - Calling context
571 Attributes - output buffer which contains attributes
574 EFI_SUCCESS - Successfully returns
578 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
580 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
582 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
,
588 FvbProtocolEraseBlocks (
589 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
596 The EraseBlock() function erases one or more blocks as denoted by the
597 variable argument list. The entire parameter list of blocks must be
598 verified prior to erasing any blocks. If a block is requested that does
599 not exist within the associated firmware volume (it has a larger index than
600 the last block of the firmware volume), the EraseBlock() function must
601 return EFI_INVALID_PARAMETER without modifying the contents of the firmware
605 This - Calling context
606 ... - Starting LBA followed by Number of Lba to erase.
607 a -1 to terminate the list.
610 EFI_SUCCESS - The erase request was successfully completed
611 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
612 EFI_DEVICE_ERROR - The block device is not functioning correctly and
613 could not be written. Firmware device may have been
618 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
619 EFI_FW_VOL_INSTANCE
*FwhInstance
;
626 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
628 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
,
630 ASSERT_EFI_ERROR (Status
);
632 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
634 VA_START (args
, This
);
637 StartingLba
= VA_ARG (args
, EFI_LBA
);
638 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
642 NumOfLba
= VA_ARG (args
, UINTN
);
645 // Check input parameters
647 if ((NumOfLba
== 0) || ((StartingLba
+ NumOfLba
) > NumOfBlocks
)) {
649 return EFI_INVALID_PARAMETER
;
655 VA_START (args
, This
);
657 StartingLba
= VA_ARG (args
, EFI_LBA
);
658 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
662 NumOfLba
= VA_ARG (args
, UINTN
);
664 while (NumOfLba
> 0) {
665 Status
= QemuFlashEraseBlock (StartingLba
);
666 if (EFI_ERROR (Status
)) {
685 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
688 IN OUT UINTN
*NumBytes
,
695 Writes data beginning at Lba:Offset from FV. The write terminates either
696 when *NumBytes of data have been written, or when a block boundary is
697 reached. *NumBytes is updated to reflect the actual number of bytes
698 written. The write opertion does not include erase. This routine will
699 attempt to write only the specified bytes. If the writes do not stick,
700 it will return an error.
703 This - Calling context
704 Lba - Block in which to begin write
705 Offset - Offset in the block at which to begin write
706 NumBytes - On input, indicates the requested write size. On
707 output, indicates the actual number of bytes
709 Buffer - Buffer containing source data for the write.
712 EFI_SUCCESS - The firmware volume was written successfully
713 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
714 NumBytes contains the total number of bytes
716 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
717 EFI_DEVICE_ERROR - The block device is not functioning correctly and
719 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
723 return QemuFlashWrite ((EFI_LBA
)Lba
, (UINTN
)Offset
, NumBytes
,
730 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
731 IN CONST EFI_LBA Lba
,
732 IN CONST UINTN Offset
,
733 IN OUT UINTN
*NumBytes
,
740 Reads data beginning at Lba:Offset from FV. The Read terminates either
741 when *NumBytes of data have been read, or when a block boundary is
742 reached. *NumBytes is updated to reflect the actual number of bytes
743 written. The write opertion does not include erase. This routine will
744 attempt to write only the specified bytes. If the writes do not stick,
745 it will return an error.
748 This - Calling context
749 Lba - Block in which to begin Read
750 Offset - Offset in the block at which to begin Read
751 NumBytes - On input, indicates the requested write size. On
752 output, indicates the actual number of bytes Read
753 Buffer - Buffer containing source data for the Read.
756 EFI_SUCCESS - The firmware volume was read successfully and
757 contents are in Buffer
758 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
759 NumBytes contains the total number of bytes
761 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
762 EFI_DEVICE_ERROR - The block device is not functioning correctly and
764 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
768 return QemuFlashRead ((EFI_LBA
)Lba
, (UINTN
)Offset
, NumBytes
,
774 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
779 Check the integrity of firmware volume header
782 FwVolHeader - A pointer to a firmware volume header
785 EFI_SUCCESS - The firmware volume is consistent
786 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an
794 // Verify the header revision, header signature, length
795 // Length of FvBlock cannot be 2**64-1
796 // HeaderLength cannot be an odd number
798 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
799 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
800 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
801 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
803 return EFI_NOT_FOUND
;
807 // Verify the header checksum
810 Checksum
= CalculateSum16 ((UINT16
*) FwVolHeader
,
811 FwVolHeader
->HeaderLength
);
816 (UINT16
) (((UINTN
) FwVolHeader
->Checksum
+ 0x10000 - Checksum
) & 0xffff);
818 DEBUG ((EFI_D_INFO
, "FV@%p Checksum is 0x%x, expected 0x%x\n",
819 FwVolHeader
, FwVolHeader
->Checksum
, Expected
));
820 return EFI_NOT_FOUND
;
828 InitializeVariableFvHeader (
833 EFI_FIRMWARE_VOLUME_HEADER
*GoodFwVolHeader
;
834 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
840 (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
)
841 PcdGet32 (PcdOvmfFlashNvStorageVariableBase
);
844 (FixedPcdGet32 (PcdFlashNvStorageVariableSize
) +
845 FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize
) +
846 FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize
) +
847 FixedPcdGet32 (PcdOvmfFlashNvStorageEventLogSize
));
849 BlockSize
= PcdGet32 (PcdOvmfFirmwareBlockSize
);
851 Status
= ValidateFvHeader (FwVolHeader
);
852 if (!EFI_ERROR (Status
)) {
853 if (FwVolHeader
->FvLength
!= Length
||
854 FwVolHeader
->BlockMap
[0].Length
!= BlockSize
) {
855 Status
= EFI_VOLUME_CORRUPTED
;
858 if (EFI_ERROR (Status
)) {
863 "Variable FV header is not valid. It will be reinitialized.\n"));
866 // Get FvbInfo to provide in FwhInstance.
868 Status
= GetFvbInfo (Length
, &GoodFwVolHeader
);
869 ASSERT (!EFI_ERROR (Status
));
871 Start
= (UINTN
)(UINT8
*) FwVolHeader
- PcdGet32 (PcdOvmfFdBaseAddress
);
872 ASSERT (Start
% BlockSize
== 0 && Length
% BlockSize
== 0);
873 ASSERT (GoodFwVolHeader
->HeaderLength
<= BlockSize
);
876 // Erase all the blocks
878 for (Offset
= Start
; Offset
< Start
+ Length
; Offset
+= BlockSize
) {
879 Status
= QemuFlashEraseBlock (Offset
/ BlockSize
);
880 ASSERT_EFI_ERROR (Status
);
884 // Write good FV header
886 WriteLength
= GoodFwVolHeader
->HeaderLength
;
887 Status
= QemuFlashWrite (
891 (UINT8
*) GoodFwVolHeader
);
892 ASSERT_EFI_ERROR (Status
);
893 ASSERT (WriteLength
== GoodFwVolHeader
->HeaderLength
);
902 IN EFI_HANDLE ImageHandle
,
903 IN EFI_SYSTEM_TABLE
*SystemTable
908 This function does common initialization for FVB services
917 EFI_FW_VOL_INSTANCE
*FwhInstance
;
918 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
920 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
921 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
923 EFI_PHYSICAL_ADDRESS BaseAddress
;
926 RETURN_STATUS PcdStatus
;
928 if (EFI_ERROR (QemuFlashInitialize ())) {
930 // Return an error so image will be unloaded
933 "QEMU flash was not detected. Writable FVB is not being installed.\n"));
934 return EFI_WRITE_PROTECTED
;
938 // Allocate runtime services data for global variable, which contains
939 // the private data of all firmware volume block instances
941 mFvbModuleGlobal
= AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL
));
942 ASSERT (mFvbModuleGlobal
!= NULL
);
944 BaseAddress
= (UINTN
) PcdGet32 (PcdOvmfFdBaseAddress
);
945 Length
= PcdGet32 (PcdOvmfFirmwareFdSize
);
947 Status
= InitializeVariableFvHeader ();
948 if (EFI_ERROR (Status
)) {
950 "QEMU Flash: Unable to initialize variable FV header\n"));
951 return EFI_WRITE_PROTECTED
;
954 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
955 Status
= ValidateFvHeader (FwVolHeader
);
956 if (EFI_ERROR (Status
)) {
960 Status
= GetFvbInfo (Length
, &FwVolHeader
);
961 if (EFI_ERROR (Status
)) {
962 DEBUG ((EFI_D_INFO
, "EFI_ERROR (GetFvbInfo (Length, &FwVolHeader))\n"));
963 return EFI_WRITE_PROTECTED
;
967 BufferSize
= (sizeof (EFI_FW_VOL_INSTANCE
) +
968 FwVolHeader
->HeaderLength
-
969 sizeof (EFI_FIRMWARE_VOLUME_HEADER
)
971 mFvbModuleGlobal
->FvInstance
= AllocateRuntimePool (BufferSize
);
972 ASSERT (mFvbModuleGlobal
->FvInstance
!= NULL
);
974 FwhInstance
= mFvbModuleGlobal
->FvInstance
;
976 mFvbModuleGlobal
->NumFv
= 0;
980 (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
)
981 PcdGet32 (PcdOvmfFlashNvStorageVariableBase
);
983 FwhInstance
->FvBase
= (UINTN
) BaseAddress
;
985 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
,
986 FwVolHeader
->HeaderLength
);
987 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
991 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
;
992 PtrBlockMapEntry
->NumBlocks
!= 0;
993 PtrBlockMapEntry
++) {
995 // Get the maximum size of a block.
997 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
998 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1001 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1005 // The total number of blocks in the FV.
1007 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1010 // Add a FVB Protocol Instance
1012 FvbDevice
= AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1013 ASSERT (FvbDevice
!= NULL
);
1015 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1017 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1018 mFvbModuleGlobal
->NumFv
++;
1021 // Set up the devicepath
1023 if (FwVolHeader
->ExtHeaderOffset
== 0) {
1024 FV_MEMMAP_DEVICE_PATH
*FvMemmapDevicePath
;
1027 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
1029 FvMemmapDevicePath
= AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH
),
1030 &mFvMemmapDevicePathTemplate
);
1031 FvMemmapDevicePath
->MemMapDevPath
.StartingAddress
= BaseAddress
;
1032 FvMemmapDevicePath
->MemMapDevPath
.EndingAddress
=
1033 BaseAddress
+ FwVolHeader
->FvLength
- 1;
1034 FvbDevice
->DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)FvMemmapDevicePath
;
1036 FV_PIWG_DEVICE_PATH
*FvPiwgDevicePath
;
1038 FvPiwgDevicePath
= AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH
),
1039 &mFvPIWGDevicePathTemplate
);
1041 &FvPiwgDevicePath
->FvDevPath
.FvName
,
1042 (GUID
*)(UINTN
)(BaseAddress
+ FwVolHeader
->ExtHeaderOffset
)
1044 FvbDevice
->DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)FvPiwgDevicePath
;
1048 // Module type specific hook.
1050 InstallProtocolInterfaces (FvbDevice
);
1052 MarkIoMemoryRangeForRuntimeAccess (BaseAddress
, Length
);
1055 // Set several PCD values to point to flash
1057 PcdStatus
= PcdSet64S (
1058 PcdFlashNvStorageVariableBase64
,
1059 (UINTN
) PcdGet32 (PcdOvmfFlashNvStorageVariableBase
)
1061 ASSERT_RETURN_ERROR (PcdStatus
);
1062 PcdStatus
= PcdSet32S (
1063 PcdFlashNvStorageFtwWorkingBase
,
1064 PcdGet32 (PcdOvmfFlashNvStorageFtwWorkingBase
)
1066 ASSERT_RETURN_ERROR (PcdStatus
);
1067 PcdStatus
= PcdSet32S (
1068 PcdFlashNvStorageFtwSpareBase
,
1069 PcdGet32 (PcdOvmfFlashNvStorageFtwSpareBase
)
1071 ASSERT_RETURN_ERROR (PcdStatus
);
1073 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1075 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1076 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1080 // Module type specific hook.
1082 InstallVirtualAddressChangeHandler ();
1084 PcdStatus
= PcdSetBoolS (PcdOvmfFlashVariablesEnable
, TRUE
);
1085 ASSERT_RETURN_ERROR (PcdStatus
);