3 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
4 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.
23 // The package level header files this module uses
28 // The protocols, PPI and GUID defintions for this module
30 #include <Guid/EventGroup.h>
31 #include <Protocol/FirmwareVolumeBlock.h>
32 #include <Protocol/DevicePath.h>
35 // The Library classes this module consumes
37 #include <Library/UefiLib.h>
38 #include <Library/UefiDriverEntryPoint.h>
39 #include <Library/BaseLib.h>
40 #include <Library/DxeServicesTableLib.h>
41 #include <Library/UefiRuntimeLib.h>
42 #include <Library/DebugLib.h>
43 #include <Library/BaseMemoryLib.h>
44 #include <Library/MemoryAllocationLib.h>
45 #include <Library/UefiBootServicesTableLib.h>
46 #include <Library/DevicePathLib.h>
48 #include "FwBlockService.h"
49 #include "QemuFlash.h"
51 #define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
53 ESAL_FWB_GLOBAL
*mFvbModuleGlobal
;
55 FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate
= {
61 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
)),
62 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
) >> 8)
66 (EFI_PHYSICAL_ADDRESS
) 0,
67 (EFI_PHYSICAL_ADDRESS
) 0,
71 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
73 END_DEVICE_PATH_LENGTH
,
79 FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate
= {
85 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
)),
86 (UINT8
)(sizeof (MEDIA_FW_VOL_DEVICE_PATH
) >> 8)
93 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
95 END_DEVICE_PATH_LENGTH
,
101 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
102 FVB_DEVICE_SIGNATURE
,
106 FvbProtocolGetAttributes
,
107 FvbProtocolSetAttributes
,
108 FvbProtocolGetPhysicalAddress
,
109 FvbProtocolGetBlockSize
,
112 FvbProtocolEraseBlocks
,
121 FvbVirtualddressChangeEvent (
129 Fixup internal data so that EFI and SAL can be call in virtual mode.
130 Call the passed in Child Notify event and convert the mFvbModuleGlobal
131 date items to there virtual address.
133 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
134 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
139 (Standard EFI notify event - EFI_EVENT_NOTIFY)
147 EFI_FW_VOL_INSTANCE
*FwhInstance
;
150 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
153 // Convert the base address of all the instances
156 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
157 while (Index
< mFvbModuleGlobal
->NumFv
) {
158 EfiConvertPointer (0x0, (VOID
**) &FwhInstance
->FvBase
[FVB_VIRTUAL
]);
159 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
161 (UINTN
) ((UINT8
*) FwhInstance
) + FwhInstance
->VolumeHeader
.HeaderLength
+
162 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
167 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
]);
168 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
);
169 QemuFlashConvertPointers ();
175 IN ESAL_FWB_GLOBAL
*Global
,
176 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
182 Retrieves the physical address of a memory mapped FV
185 Instance - The FV instance whose base address is going to be
187 Global - Pointer to ESAL_FWB_GLOBAL that contains all
189 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
190 Virtual - Whether CPU is in virtual or physical mode
193 EFI_SUCCESS - Successfully returns
194 EFI_INVALID_PARAMETER - Instance not found
198 EFI_FW_VOL_INSTANCE
*FwhRecord
;
201 if (Instance
>= Global
->NumFv
) {
202 return EFI_INVALID_PARAMETER
;
205 // Find the right instance of the FVB private data
207 FwhRecord
= Global
->FvInstance
[Virtual
];
208 while (Instance
> 0) {
209 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
211 (UINTN
) ((UINT8
*) FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
212 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
217 *FwhInstance
= FwhRecord
;
223 FvbGetPhysicalAddress (
225 OUT EFI_PHYSICAL_ADDRESS
*Address
,
226 IN ESAL_FWB_GLOBAL
*Global
,
232 Retrieves the physical address of a memory mapped FV
235 Instance - The FV instance whose base address is going to be
237 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
238 that on successful return, contains the base address
239 of the firmware volume.
240 Global - Pointer to ESAL_FWB_GLOBAL that contains all
242 Virtual - Whether CPU is in virtual or physical mode
245 EFI_SUCCESS - Successfully returns
246 EFI_INVALID_PARAMETER - Instance not found
250 EFI_FW_VOL_INSTANCE
*FwhInstance
;
254 // Find the right instance of the FVB private data
256 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
257 ASSERT_EFI_ERROR (Status
);
258 *Address
= FwhInstance
->FvBase
[Virtual
];
264 FvbGetVolumeAttributes (
266 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
267 IN ESAL_FWB_GLOBAL
*Global
,
273 Retrieves attributes, insures positive polarity of attribute bits, returns
274 resulting attributes in output parameter
277 Instance - The FV instance whose attributes is going to be
279 Attributes - Output buffer which contains attributes
280 Global - Pointer to ESAL_FWB_GLOBAL that contains all
282 Virtual - Whether CPU is in virtual or physical mode
285 EFI_SUCCESS - Successfully returns
286 EFI_INVALID_PARAMETER - Instance not found
290 EFI_FW_VOL_INSTANCE
*FwhInstance
;
294 // Find the right instance of the FVB private data
296 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
297 ASSERT_EFI_ERROR (Status
);
298 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
307 OUT UINTN
*LbaAddress
,
308 OUT UINTN
*LbaLength
,
309 OUT UINTN
*NumOfBlocks
,
310 IN ESAL_FWB_GLOBAL
*Global
,
316 Retrieves the starting address of an LBA in an FV
319 Instance - The FV instance which the Lba belongs to
320 Lba - The logical block address
321 LbaAddress - On output, contains the physical starting address
323 LbaLength - On output, contains the length of the block
324 NumOfBlocks - A pointer to a caller allocated UINTN in which the
325 number of consecutive blocks starting with Lba is
326 returned. All blocks in this range have a size of
328 Global - Pointer to ESAL_FWB_GLOBAL that contains all
330 Virtual - Whether CPU is in virtual or physical mode
333 EFI_SUCCESS - Successfully returns
334 EFI_INVALID_PARAMETER - Instance not found
343 EFI_FW_VOL_INSTANCE
*FwhInstance
;
344 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
348 // Find the right instance of the FVB private data
350 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
351 ASSERT_EFI_ERROR (Status
);
355 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
358 // Parse the blockmap of the FV to find which map entry the Lba belongs to
361 NumBlocks
= BlockMap
->NumBlocks
;
362 BlockLength
= BlockMap
->Length
;
364 if (NumBlocks
== 0 || BlockLength
== 0) {
365 return EFI_INVALID_PARAMETER
;
368 NextLba
= StartLba
+ NumBlocks
;
371 // The map entry found
373 if (Lba
>= StartLba
&& Lba
< NextLba
) {
374 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
375 if (LbaAddress
!= NULL
) {
376 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
379 if (LbaLength
!= NULL
) {
380 *LbaLength
= BlockLength
;
383 if (NumOfBlocks
!= NULL
) {
384 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
391 Offset
= Offset
+ NumBlocks
* BlockLength
;
397 FvbSetVolumeAttributes (
399 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
400 IN ESAL_FWB_GLOBAL
*Global
,
406 Modifies the current settings of the firmware volume according to the
407 input parameter, and returns the new setting of the volume
410 Instance - The FV instance whose attributes is going to be
412 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
413 containing the desired firmware volume settings.
414 On successful return, it contains the new settings
415 of the firmware volume
416 Global - Pointer to ESAL_FWB_GLOBAL that contains all
418 Virtual - Whether CPU is in virtual or physical mode
421 EFI_SUCCESS - Successfully returns
422 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
423 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
424 in conflict with the capabilities as declared in the
425 firmware volume header
429 EFI_FW_VOL_INSTANCE
*FwhInstance
;
430 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
431 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
436 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes
;
439 // Find the right instance of the FVB private data
441 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
442 ASSERT_EFI_ERROR (Status
);
444 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
445 OldAttributes
= *AttribPtr
;
446 Capabilities
= OldAttributes
& (EFI_FVB2_READ_DISABLED_CAP
| \
447 EFI_FVB2_READ_ENABLED_CAP
| \
448 EFI_FVB2_WRITE_DISABLED_CAP
| \
449 EFI_FVB2_WRITE_ENABLED_CAP
| \
452 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
453 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
455 UnchangedAttributes
= EFI_FVB2_READ_DISABLED_CAP
| \
456 EFI_FVB2_READ_ENABLED_CAP
| \
457 EFI_FVB2_WRITE_DISABLED_CAP
| \
458 EFI_FVB2_WRITE_ENABLED_CAP
| \
459 EFI_FVB2_LOCK_CAP
| \
460 EFI_FVB2_STICKY_WRITE
| \
461 EFI_FVB2_MEMORY_MAPPED
| \
462 EFI_FVB2_ERASE_POLARITY
| \
463 EFI_FVB2_READ_LOCK_CAP
| \
464 EFI_FVB2_WRITE_LOCK_CAP
| \
468 // Some attributes of FV is read only can *not* be set
470 if ((OldAttributes
& UnchangedAttributes
) ^ (*Attributes
& UnchangedAttributes
)) {
471 return EFI_INVALID_PARAMETER
;
474 // If firmware volume is locked, no status bit can be updated
476 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
477 if (OldStatus
^ NewStatus
) {
478 return EFI_ACCESS_DENIED
;
484 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
485 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
486 return EFI_INVALID_PARAMETER
;
492 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
493 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
494 return EFI_INVALID_PARAMETER
;
498 // Test write disable
500 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
501 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
502 return EFI_INVALID_PARAMETER
;
508 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
509 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
510 return EFI_INVALID_PARAMETER
;
516 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
517 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
518 return EFI_INVALID_PARAMETER
;
522 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
523 *AttribPtr
= (*AttribPtr
) | NewStatus
;
524 *Attributes
= *AttribPtr
;
534 FvbProtocolGetPhysicalAddress (
535 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
536 OUT EFI_PHYSICAL_ADDRESS
*Address
542 Retrieves the physical address of the device.
546 This - Calling context
547 Address - Output buffer containing the address.
552 EFI_SUCCESS - Successfully returns
556 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
558 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
560 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
565 FvbProtocolGetBlockSize (
566 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
567 IN CONST EFI_LBA Lba
,
568 OUT UINTN
*BlockSize
,
569 OUT UINTN
*NumOfBlocks
574 Retrieve the size of a logical block
577 This - Calling context
578 Lba - Indicates which block to return the size for.
579 BlockSize - A pointer to a caller allocated UINTN in which
580 the size of the block is returned
581 NumOfBlocks - a pointer to a caller allocated UINTN in which the
582 number of consecutive blocks starting with Lba is
583 returned. All blocks in this range have a size of
587 EFI_SUCCESS - The firmware volume was read successfully and
588 contents are in Buffer
592 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
594 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
596 return FvbGetLbaAddress (
609 FvbProtocolGetAttributes (
610 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
611 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
616 Retrieves Volume attributes. No polarity translations are done.
619 This - Calling context
620 Attributes - output buffer which contains attributes
623 EFI_SUCCESS - Successfully returns
627 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
629 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
631 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
636 FvbProtocolSetAttributes (
637 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
638 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
643 Sets Volume attributes. No polarity translations are done.
646 This - Calling context
647 Attributes - output buffer which contains attributes
650 EFI_SUCCESS - Successfully returns
654 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
656 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
658 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
663 FvbProtocolEraseBlocks (
664 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
671 The EraseBlock() function erases one or more blocks as denoted by the
672 variable argument list. The entire parameter list of blocks must be verified
673 prior to erasing any blocks. If a block is requested that does not exist
674 within the associated firmware volume (it has a larger index than the last
675 block of the firmware volume), the EraseBlock() function must return
676 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
679 This - Calling context
680 ... - Starting LBA followed by Number of Lba to erase.
681 a -1 to terminate the list.
684 EFI_SUCCESS - The erase request was successfully completed
685 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
686 EFI_DEVICE_ERROR - The block device is not functioning correctly and
687 could not be written. Firmware device may have been
692 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
693 EFI_FW_VOL_INSTANCE
*FwhInstance
;
700 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
702 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
703 ASSERT_EFI_ERROR (Status
);
705 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
707 VA_START (args
, This
);
710 StartingLba
= VA_ARG (args
, EFI_LBA
);
711 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
715 NumOfLba
= VA_ARG (args
, UINT32
);
718 // Check input parameters
720 if ((NumOfLba
== 0) || ((StartingLba
+ NumOfLba
) > NumOfBlocks
)) {
722 return EFI_INVALID_PARAMETER
;
728 VA_START (args
, This
);
730 StartingLba
= VA_ARG (args
, EFI_LBA
);
731 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
735 NumOfLba
= VA_ARG (args
, UINT32
);
737 while (NumOfLba
> 0) {
738 Status
= QemuFlashEraseBlock (StartingLba
);
739 if (EFI_ERROR (Status
)) {
758 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
761 IN OUT UINTN
*NumBytes
,
768 Writes data beginning at Lba:Offset from FV. The write terminates either
769 when *NumBytes of data have been written, or when a block boundary is
770 reached. *NumBytes is updated to reflect the actual number of bytes
771 written. The write opertion does not include erase. This routine will
772 attempt to write only the specified bytes. If the writes do not stick,
773 it will return an error.
776 This - Calling context
777 Lba - Block in which to begin write
778 Offset - Offset in the block at which to begin write
779 NumBytes - On input, indicates the requested write size. On
780 output, indicates the actual number of bytes written
781 Buffer - Buffer containing source data for the write.
784 EFI_SUCCESS - The firmware volume was written successfully
785 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
786 NumBytes contains the total number of bytes
788 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
789 EFI_DEVICE_ERROR - The block device is not functioning correctly and
791 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
795 return QemuFlashWrite ((EFI_LBA
)Lba
, (UINTN
)Offset
, NumBytes
, (UINT8
*)Buffer
);
801 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
802 IN CONST EFI_LBA Lba
,
803 IN CONST UINTN Offset
,
804 IN OUT UINTN
*NumBytes
,
811 Reads data beginning at Lba:Offset from FV. The Read terminates either
812 when *NumBytes of data have been read, or when a block boundary is
813 reached. *NumBytes is updated to reflect the actual number of bytes
814 written. The write opertion does not include erase. This routine will
815 attempt to write only the specified bytes. If the writes do not stick,
816 it will return an error.
819 This - Calling context
820 Lba - Block in which to begin Read
821 Offset - Offset in the block at which to begin Read
822 NumBytes - On input, indicates the requested write size. On
823 output, indicates the actual number of bytes Read
824 Buffer - Buffer containing source data for the Read.
827 EFI_SUCCESS - The firmware volume was read successfully and
828 contents are in Buffer
829 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
830 NumBytes contains the total number of bytes returned
832 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
833 EFI_DEVICE_ERROR - The block device is not functioning correctly and
835 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
839 return QemuFlashRead ((EFI_LBA
)Lba
, (UINTN
)Offset
, NumBytes
, (UINT8
*)Buffer
);
844 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
849 Check the integrity of firmware volume header
852 FwVolHeader - A pointer to a firmware volume header
855 EFI_SUCCESS - The firmware volume is consistent
856 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
863 // Verify the header revision, header signature, length
864 // Length of FvBlock cannot be 2**64-1
865 // HeaderLength cannot be an odd number
867 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
868 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
869 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
870 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
872 return EFI_NOT_FOUND
;
876 // Verify the header checksum
879 Checksum
= CalculateSum16 ((UINT16
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
884 (UINT16
) (((UINTN
) FwVolHeader
->Checksum
+ 0x10000 - Checksum
) & 0xffff);
886 DEBUG ((EFI_D_INFO
, "FV@%p Checksum is 0x%x, expected 0x%x\n",
887 FwVolHeader
, FwVolHeader
->Checksum
, Expected
));
888 return EFI_NOT_FOUND
;
896 MarkMemoryRangeForRuntimeAccess (
897 EFI_PHYSICAL_ADDRESS BaseAddress
,
904 // Mark flash region as runtime memory
906 Status
= gDS
->RemoveMemorySpace (
911 Status
= gDS
->AddMemorySpace (
912 EfiGcdMemoryTypeSystemMemory
,
915 EFI_MEMORY_UC
| EFI_MEMORY_RUNTIME
917 ASSERT_EFI_ERROR (Status
);
919 Status
= gBS
->AllocatePages (
921 EfiRuntimeServicesData
,
922 EFI_SIZE_TO_PAGES (Length
),
925 ASSERT_EFI_ERROR (Status
);
932 InitializeVariableFvHeader (
937 EFI_FIRMWARE_VOLUME_HEADER
*GoodFwVolHeader
;
938 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
944 (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
)
945 PcdGet32 (PcdOvmfFlashNvStorageVariableBase
);
948 (FixedPcdGet32 (PcdFlashNvStorageVariableSize
) +
949 FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize
) +
950 FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize
) +
951 FixedPcdGet32 (PcdOvmfFlashNvStorageEventLogSize
));
953 BlockSize
= PcdGet32 (PcdOvmfFirmwareBlockSize
);
955 Status
= ValidateFvHeader (FwVolHeader
);
956 if (!EFI_ERROR (Status
)) {
957 if (FwVolHeader
->FvLength
!= Length
||
958 FwVolHeader
->BlockMap
[0].Length
!= BlockSize
) {
959 Status
= EFI_VOLUME_CORRUPTED
;
962 if (EFI_ERROR (Status
)) {
966 DEBUG ((EFI_D_INFO
, "Variable FV header is not valid. It will be reinitialized.\n"));
969 // Get FvbInfo to provide in FwhInstance.
971 Status
= GetFvbInfo (Length
, &GoodFwVolHeader
);
972 ASSERT (!EFI_ERROR (Status
));
974 Start
= (UINTN
)(UINT8
*) FwVolHeader
- PcdGet32 (PcdOvmfFdBaseAddress
);
975 ASSERT (Start
% BlockSize
== 0 && Length
% BlockSize
== 0);
976 ASSERT (GoodFwVolHeader
->HeaderLength
<= BlockSize
);
979 // Erase all the blocks
981 for (Offset
= Start
; Offset
< Start
+ Length
; Offset
+= BlockSize
) {
982 Status
= QemuFlashEraseBlock (Offset
/ BlockSize
);
983 ASSERT_EFI_ERROR (Status
);
987 // Write good FV header
989 WriteLength
= GoodFwVolHeader
->HeaderLength
;
990 Status
= QemuFlashWrite (
994 (UINT8
*) GoodFwVolHeader
);
995 ASSERT_EFI_ERROR (Status
);
996 ASSERT (WriteLength
== GoodFwVolHeader
->HeaderLength
);
1005 IN EFI_HANDLE ImageHandle
,
1006 IN EFI_SYSTEM_TABLE
*SystemTable
1010 Routine Description:
1011 This function does common initialization for FVB services
1020 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1021 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1023 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1024 EFI_HANDLE FwbHandle
;
1025 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1026 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1028 EFI_PHYSICAL_ADDRESS BaseAddress
;
1031 EFI_EVENT VirtualAddressChangeEvent
;
1033 if (EFI_ERROR (QemuFlashInitialize ())) {
1035 // Return an error so image will be unloaded
1037 DEBUG ((EFI_D_INFO
, "QEMU flash was not detected. Writable FVB is not being installed.\n"));
1038 return EFI_WRITE_PROTECTED
;
1042 // Allocate runtime services data for global variable, which contains
1043 // the private data of all firmware volume block instances
1045 mFvbModuleGlobal
= AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL
));
1046 ASSERT (mFvbModuleGlobal
!= NULL
);
1048 BaseAddress
= (UINTN
) PcdGet32 (PcdOvmfFdBaseAddress
);
1049 Length
= PcdGet32 (PcdOvmfFirmwareFdSize
);
1051 Status
= InitializeVariableFvHeader ();
1052 if (EFI_ERROR (Status
)) {
1053 DEBUG ((EFI_D_INFO
, "QEMU Flash: Unable to initialize variable FV header\n"));
1054 return EFI_WRITE_PROTECTED
;
1057 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1058 Status
= ValidateFvHeader (FwVolHeader
);
1059 if (EFI_ERROR (Status
)) {
1063 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1064 if (EFI_ERROR (Status
)) {
1065 DEBUG ((EFI_D_INFO
, "EFI_ERROR (GetFvbInfo (Length, &FwVolHeader))\n"));
1066 return EFI_WRITE_PROTECTED
;
1070 BufferSize
= (sizeof (EFI_FW_VOL_INSTANCE
) + FwVolHeader
->HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1073 // Only need to allocate once. There is only one copy of physical memory for
1074 // the private data of each FV instance. But in virtual mode or in physical
1075 // mode, the address of the the physical memory may be different.
1077 mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] = AllocateRuntimePool (BufferSize
);
1078 ASSERT (mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] != NULL
);
1081 // Make a virtual copy of the FvInstance pointer.
1083 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1084 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1086 mFvbModuleGlobal
->NumFv
= 0;
1090 (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
)
1091 PcdGet32 (PcdOvmfFlashNvStorageVariableBase
);
1093 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1094 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1096 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1097 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1098 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1102 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1104 // Get the maximum size of a block.
1106 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
1107 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1110 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1114 // The total number of blocks in the FV.
1116 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1119 // Add a FVB Protocol Instance
1121 FvbDevice
= AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1122 ASSERT (FvbDevice
!= NULL
);
1124 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1126 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1127 mFvbModuleGlobal
->NumFv
++;
1130 // Set up the devicepath
1132 if (FwVolHeader
->ExtHeaderOffset
== 0) {
1134 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
1136 FvbDevice
->DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH
), &mFvMemmapDevicePathTemplate
);
1137 ((FV_MEMMAP_DEVICE_PATH
*) FvbDevice
->DevicePath
)->MemMapDevPath
.StartingAddress
= BaseAddress
;
1138 ((FV_MEMMAP_DEVICE_PATH
*) FvbDevice
->DevicePath
)->MemMapDevPath
.EndingAddress
= BaseAddress
+ FwVolHeader
->FvLength
- 1;
1140 FvbDevice
->DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH
), &mFvPIWGDevicePathTemplate
);
1142 &((FV_PIWG_DEVICE_PATH
*)FvbDevice
->DevicePath
)->FvDevPath
.FvName
,
1143 (GUID
*)(UINTN
)(BaseAddress
+ FwVolHeader
->ExtHeaderOffset
)
1148 // Find a handle with a matching device path that has supports FW Block protocol
1150 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &FvbDevice
->DevicePath
, &FwbHandle
);
1151 if (EFI_ERROR (Status
)) {
1153 // LocateDevicePath fails so install a new interface and device path
1156 DEBUG ((EFI_D_INFO
, "Installing QEMU flash FVB\n"));
1157 Status
= gBS
->InstallMultipleProtocolInterfaces (
1159 &gEfiFirmwareVolumeBlockProtocolGuid
,
1160 &FvbDevice
->FwVolBlockInstance
,
1161 &gEfiDevicePathProtocolGuid
,
1162 FvbDevice
->DevicePath
,
1165 ASSERT_EFI_ERROR (Status
);
1166 } else if (IsDevicePathEnd (FvbDevice
->DevicePath
)) {
1168 // Device already exists, so reinstall the FVB protocol
1170 Status
= gBS
->HandleProtocol (
1172 &gEfiFirmwareVolumeBlockProtocolGuid
,
1173 (VOID
**)&OldFwbInterface
1175 ASSERT_EFI_ERROR (Status
);
1177 DEBUG ((EFI_D_INFO
, "Reinstalling FVB for QEMU flash region\n"));
1178 Status
= gBS
->ReinstallProtocolInterface (
1180 &gEfiFirmwareVolumeBlockProtocolGuid
,
1182 &FvbDevice
->FwVolBlockInstance
1184 ASSERT_EFI_ERROR (Status
);
1187 // There was a FVB protocol on an End Device Path node
1192 MarkMemoryRangeForRuntimeAccess (BaseAddress
, Length
);
1195 // Set several PCD values to point to flash
1198 PcdFlashNvStorageVariableBase64
,
1199 (UINTN
) PcdGet32 (PcdOvmfFlashNvStorageVariableBase
)
1202 PcdFlashNvStorageFtwWorkingBase
,
1203 PcdGet32 (PcdOvmfFlashNvStorageFtwWorkingBase
)
1206 PcdFlashNvStorageFtwSpareBase
,
1207 PcdGet32 (PcdOvmfFlashNvStorageFtwSpareBase
)
1210 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1212 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1213 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1216 VirtualAddressChangeEvent
= NULL
;
1217 Status
= gBS
->CreateEventEx (
1220 FvbVirtualddressChangeEvent
,
1222 &gEfiEventVirtualAddressChangeGuid
,
1223 &VirtualAddressChangeEvent
1225 ASSERT_EFI_ERROR (Status
);
1227 PcdSetBool (PcdOvmfFlashVariablesEnable
, TRUE
);