3 Copyright (c) 2006 - 2008, 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.
23 #include <Guid/EventGroup.h>
24 #include <Protocol/FirmwareVolumeBlock.h>
25 #include <Guid/AlternateFvBlock.h>
26 #include <Protocol/DevicePath.h>
28 #include <Library/UefiLib.h>
29 #include <Library/UefiDriverEntryPoint.h>
30 #include <Library/BaseLib.h>
31 #include <Library/DxeServicesTableLib.h>
32 #include <Library/UefiRuntimeLib.h>
33 #include <Library/DebugLib.h>
34 #include <Library/HobLib.h>
35 #include <Library/BaseMemoryLib.h>
36 #include <Library/MemoryAllocationLib.h>
37 #include <Library/UefiBootServicesTableLib.h>
38 #include <Library/DevicePathLib.h>
40 #include "FwBlockService.h"
42 ESAL_FWB_GLOBAL
*mFvbModuleGlobal
;
44 #define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
46 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
54 sizeof (MEMMAP_DEVICE_PATH
),
64 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
66 sizeof (EFI_DEVICE_PATH_PROTOCOL
),
73 FvbProtocolGetAttributes
,
74 FvbProtocolSetAttributes
,
75 FvbProtocolGetPhysicalAddress
,
76 FvbProtocolGetBlockSize
,
79 FvbProtocolEraseBlocks
,
88 FvbVirtualddressChangeEvent (
96 Fixup internal data so that EFI and SAL can be call in virtual mode.
97 Call the passed in Child Notify event and convert the mFvbModuleGlobal
98 date items to there virtual address.
100 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
101 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
106 (Standard EFI notify event - EFI_EVENT_NOTIFY)
114 EFI_FW_VOL_INSTANCE
*FwhInstance
;
117 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
120 // Convert the base address of all the instances
123 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
124 while (Index
< mFvbModuleGlobal
->NumFv
) {
125 EfiConvertPointer (0x0, (VOID
**) &FwhInstance
->FvBase
[FVB_VIRTUAL
]);
126 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
128 (UINTN
) ((UINT8
*) FwhInstance
) + FwhInstance
->VolumeHeader
.HeaderLength
+
129 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
134 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
);
140 IN ESAL_FWB_GLOBAL
*Global
,
141 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
147 Retrieves the physical address of a memory mapped FV
150 Instance - The FV instance whose base address is going to be
152 Global - Pointer to ESAL_FWB_GLOBAL that contains all
154 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
155 Virtual - Whether CPU is in virtual or physical mode
158 EFI_SUCCESS - Successfully returns
159 EFI_INVALID_PARAMETER - Instance not found
163 EFI_FW_VOL_INSTANCE
*FwhRecord
;
165 if (Instance
>= Global
->NumFv
) {
166 return EFI_INVALID_PARAMETER
;
169 // Find the right instance of the FVB private data
171 FwhRecord
= Global
->FvInstance
[Virtual
];
172 while (Instance
> 0) {
173 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
175 (UINTN
) ((UINT8
*) FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
176 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
181 *FwhInstance
= FwhRecord
;
187 FvbGetPhysicalAddress (
189 OUT EFI_PHYSICAL_ADDRESS
*Address
,
190 IN ESAL_FWB_GLOBAL
*Global
,
196 Retrieves the physical address of a memory mapped FV
199 Instance - The FV instance whose base address is going to be
201 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
202 that on successful return, contains the base address
203 of the firmware volume.
204 Global - Pointer to ESAL_FWB_GLOBAL that contains all
206 Virtual - Whether CPU is in virtual or physical mode
209 EFI_SUCCESS - Successfully returns
210 EFI_INVALID_PARAMETER - Instance not found
214 EFI_FW_VOL_INSTANCE
*FwhInstance
;
218 // Find the right instance of the FVB private data
220 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
221 ASSERT_EFI_ERROR (Status
);
222 *Address
= FwhInstance
->FvBase
[Virtual
];
228 FvbGetVolumeAttributes (
230 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
231 IN ESAL_FWB_GLOBAL
*Global
,
237 Retrieves attributes, insures positive polarity of attribute bits, returns
238 resulting attributes in output parameter
241 Instance - The FV instance whose attributes is going to be
243 Attributes - Output buffer which contains attributes
244 Global - Pointer to ESAL_FWB_GLOBAL that contains all
246 Virtual - Whether CPU is in virtual or physical mode
249 EFI_SUCCESS - Successfully returns
250 EFI_INVALID_PARAMETER - Instance not found
254 EFI_FW_VOL_INSTANCE
*FwhInstance
;
258 // Find the right instance of the FVB private data
260 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
261 ASSERT_EFI_ERROR (Status
);
262 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
271 OUT UINTN
*LbaAddress
,
272 OUT UINTN
*LbaLength
,
273 OUT UINTN
*NumOfBlocks
,
274 IN ESAL_FWB_GLOBAL
*Global
,
280 Retrieves the starting address of an LBA in an FV
283 Instance - The FV instance which the Lba belongs to
284 Lba - The logical block address
285 LbaAddress - On output, contains the physical starting address
287 LbaLength - On output, contains the length of the block
288 NumOfBlocks - A pointer to a caller allocated UINTN in which the
289 number of consecutive blocks starting with Lba is
290 returned. All blocks in this range have a size of
292 Global - Pointer to ESAL_FWB_GLOBAL that contains all
294 Virtual - Whether CPU is in virtual or physical mode
297 EFI_SUCCESS - Successfully returns
298 EFI_INVALID_PARAMETER - Instance not found
307 EFI_FW_VOL_INSTANCE
*FwhInstance
;
308 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
312 // Find the right instance of the FVB private data
314 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
315 ASSERT_EFI_ERROR (Status
);
319 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
322 // Parse the blockmap of the FV to find which map entry the Lba belongs to
325 NumBlocks
= BlockMap
->NumBlocks
;
326 BlockLength
= BlockMap
->Length
;
328 if (NumBlocks
== 0 || BlockLength
== 0) {
329 return EFI_INVALID_PARAMETER
;
332 NextLba
= StartLba
+ NumBlocks
;
335 // The map entry found
337 if (Lba
>= StartLba
&& Lba
< NextLba
) {
338 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
339 if (LbaAddress
!= NULL
) {
340 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
343 if (LbaLength
!= NULL
) {
344 *LbaLength
= BlockLength
;
347 if (NumOfBlocks
!= NULL
) {
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_2 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
, &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_FVB2_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 CopyMem (Buffer
, (UINT8
*) (LbaAddress
+ BlockOffset
), (UINTN
) (*NumBytes
));
450 IN UINTN BlockOffset
,
451 IN OUT UINTN
*NumBytes
,
453 IN ESAL_FWB_GLOBAL
*Global
,
459 Writes specified number of bytes from the input buffer to the block
462 Instance - The FV instance to be written to
463 Lba - The starting logical block index to write to
464 BlockOffset - Offset into the block at which to begin writing
465 NumBytes - Pointer that on input contains the total size of
466 the buffer. On output, it contains the total number
467 of bytes actually written
468 Buffer - Pointer to a caller allocated buffer that contains
469 the source for the write
470 Global - Pointer to ESAL_FWB_GLOBAL that contains all
472 Virtual - Whether CPU is in virtual or physical mode
475 EFI_SUCCESS - The firmware volume was written successfully
476 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
477 NumBytes contains the total number of bytes
479 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
480 EFI_DEVICE_ERROR - The block device is not functioning correctly and
482 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
486 EFI_FVB_ATTRIBUTES_2 Attributes
;
492 // Check for invalid conditions
494 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
495 return EFI_INVALID_PARAMETER
;
498 if (*NumBytes
== 0) {
499 return EFI_INVALID_PARAMETER
;
502 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
503 if (EFI_ERROR (Status
)) {
507 // Check if the FV is write enabled
509 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
511 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
512 return EFI_ACCESS_DENIED
;
515 // Perform boundary checks and adjust NumBytes
517 if (BlockOffset
> LbaLength
) {
518 return EFI_INVALID_PARAMETER
;
521 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
522 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
523 Status
= EFI_BAD_BUFFER_SIZE
;
528 CopyMem ((UINT8
*) (LbaAddress
+ BlockOffset
), Buffer
, (UINTN
) (*NumBytes
));
537 IN ESAL_FWB_GLOBAL
*Global
,
543 Erases and initializes a firmware volume block
546 Instance - The FV instance to be erased
547 Lba - The logical block index to be erased
548 Global - Pointer to ESAL_FWB_GLOBAL that contains all
550 Virtual - Whether CPU is in virtual or physical mode
553 EFI_SUCCESS - The erase request was successfully completed
554 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
555 EFI_DEVICE_ERROR - The block device is not functioning correctly and
556 could not be written. Firmware device may have been
558 EFI_INVALID_PARAMETER - Instance not found
563 EFI_FVB_ATTRIBUTES_2 Attributes
;
570 // Check if the FV is write enabled
572 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
574 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
575 return EFI_ACCESS_DENIED
;
578 // Get the starting address of the block for erase.
580 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
582 if (EFI_ERROR (Status
)) {
586 if ((Attributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
592 SetMem ((UINT8
*) LbaAddress
, LbaLength
, Data
);
598 FvbSetVolumeAttributes (
600 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
601 IN ESAL_FWB_GLOBAL
*Global
,
607 Modifies the current settings of the firmware volume according to the
608 input parameter, and returns the new setting of the volume
611 Instance - The FV instance whose attributes is going to be
613 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
614 containing the desired firmware volume settings.
615 On successful return, it contains the new settings
616 of the firmware volume
617 Global - Pointer to ESAL_FWB_GLOBAL that contains all
619 Virtual - Whether CPU is in virtual or physical mode
622 EFI_SUCCESS - Successfully returns
623 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
624 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
625 in conflict with the capabilities as declared in the
626 firmware volume header
630 EFI_FW_VOL_INSTANCE
*FwhInstance
;
631 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
632 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
637 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes
;
641 // Find the right instance of the FVB private data
643 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
644 ASSERT_EFI_ERROR (Status
);
646 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
647 OldAttributes
= *AttribPtr
;
648 Capabilities
= OldAttributes
& (EFI_FVB2_READ_DISABLED_CAP
| \
649 EFI_FVB2_READ_ENABLED_CAP
| \
650 EFI_FVB2_WRITE_DISABLED_CAP
| \
651 EFI_FVB2_WRITE_ENABLED_CAP
| \
655 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
656 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
657 UnchangedAttributes
= EFI_FVB2_READ_DISABLED_CAP
| \
658 EFI_FVB2_READ_ENABLED_CAP
| \
659 EFI_FVB2_WRITE_DISABLED_CAP
| \
660 EFI_FVB2_WRITE_ENABLED_CAP
| \
661 EFI_FVB2_LOCK_CAP
| \
662 EFI_FVB2_STICKY_WRITE
| \
663 EFI_FVB2_MEMORY_MAPPED
| \
664 EFI_FVB2_ERASE_POLARITY
| \
665 EFI_FVB2_READ_LOCK_CAP
| \
666 EFI_FVB2_WRITE_LOCK_CAP
| \
670 // Some attributes of FV is read only can *not* be set
672 if ((OldAttributes
& UnchangedAttributes
) ^ (*Attributes
& UnchangedAttributes
)) {
673 return EFI_INVALID_PARAMETER
;
677 // If firmware volume is locked, no status bit can be updated
679 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
680 if (OldStatus
^ NewStatus
) {
681 return EFI_ACCESS_DENIED
;
687 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
688 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
689 return EFI_INVALID_PARAMETER
;
695 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
696 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
697 return EFI_INVALID_PARAMETER
;
701 // Test write disable
703 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
704 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
705 return EFI_INVALID_PARAMETER
;
711 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
712 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
713 return EFI_INVALID_PARAMETER
;
719 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
720 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
721 return EFI_INVALID_PARAMETER
;
725 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
726 *AttribPtr
= (*AttribPtr
) | NewStatus
;
727 *Attributes
= *AttribPtr
;
736 FvbProtocolGetPhysicalAddress (
737 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
738 OUT EFI_PHYSICAL_ADDRESS
*Address
744 Retrieves the physical address of the device.
748 This - Calling context
749 Address - Output buffer containing the address.
754 EFI_SUCCESS - Successfully returns
758 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
760 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
762 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
767 FvbProtocolGetBlockSize (
768 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
770 OUT UINTN
*BlockSize
,
771 OUT UINTN
*NumOfBlocks
776 Retrieve the size of a logical block
779 This - Calling context
780 Lba - Indicates which block to return the size for.
781 BlockSize - A pointer to a caller allocated UINTN in which
782 the size of the block is returned
783 NumOfBlocks - a pointer to a caller allocated UINTN in which the
784 number of consecutive blocks starting with Lba is
785 returned. All blocks in this range have a size of
789 EFI_SUCCESS - The firmware volume was read successfully and
790 contents are in Buffer
794 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
796 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
798 return FvbGetLbaAddress (
811 FvbProtocolGetAttributes (
812 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
813 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
818 Retrieves Volume attributes. No polarity translations are done.
821 This - Calling context
822 Attributes - output buffer which contains attributes
825 EFI_SUCCESS - Successfully returns
829 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
831 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
833 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
838 FvbProtocolSetAttributes (
839 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
840 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
845 Sets Volume attributes. No polarity translations are done.
848 This - Calling context
849 Attributes - output buffer which contains attributes
852 EFI_SUCCESS - Successfully returns
856 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
858 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
860 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
865 FvbProtocolEraseBlocks (
866 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
873 The EraseBlock() function erases one or more blocks as denoted by the
874 variable argument list. The entire parameter list of blocks must be verified
875 prior to erasing any blocks. If a block is requested that does not exist
876 within the associated firmware volume (it has a larger index than the last
877 block of the firmware volume), the EraseBlock() function must return
878 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
881 This - Calling context
882 ... - Starting LBA followed by Number of Lba to erase.
883 a -1 to terminate the list.
886 EFI_SUCCESS - The erase request was successfully completed
887 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
888 EFI_DEVICE_ERROR - The block device is not functioning correctly and
889 could not be written. Firmware device may have been
894 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
895 EFI_FW_VOL_INSTANCE
*FwhInstance
;
902 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
904 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
905 ASSERT_EFI_ERROR (Status
);
907 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
909 VA_START (args
, This
);
912 StartingLba
= VA_ARG (args
, EFI_LBA
);
913 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
917 NumOfLba
= VA_ARG (args
, UINT32
);
920 // Check input parameters
924 return EFI_INVALID_PARAMETER
;
927 if ((StartingLba
+ NumOfLba
) > NumOfBlocks
) {
928 return EFI_INVALID_PARAMETER
;
934 VA_START (args
, This
);
936 StartingLba
= VA_ARG (args
, EFI_LBA
);
937 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
941 NumOfLba
= VA_ARG (args
, UINT32
);
943 while (NumOfLba
> 0) {
944 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
945 if (EFI_ERROR (Status
)) {
964 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
967 IN OUT UINTN
*NumBytes
,
974 Writes data beginning at Lba:Offset from FV. The write terminates either
975 when *NumBytes of data have been written, or when a block boundary is
976 reached. *NumBytes is updated to reflect the actual number of bytes
977 written. The write opertion does not include erase. This routine will
978 attempt to write only the specified bytes. If the writes do not stick,
979 it will return an error.
982 This - Calling context
983 Lba - Block in which to begin write
984 Offset - Offset in the block at which to begin write
985 NumBytes - On input, indicates the requested write size. On
986 output, indicates the actual number of bytes written
987 Buffer - Buffer containing source data for the write.
990 EFI_SUCCESS - The firmware volume was written successfully
991 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
992 NumBytes contains the total number of bytes
994 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
995 EFI_DEVICE_ERROR - The block device is not functioning correctly and
997 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1002 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1004 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1006 return FvbWriteBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1012 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1015 IN OUT UINTN
*NumBytes
,
1020 Routine Description:
1022 Reads data beginning at Lba:Offset from FV. The Read terminates either
1023 when *NumBytes of data have been read, or when a block boundary is
1024 reached. *NumBytes is updated to reflect the actual number of bytes
1025 written. The write opertion does not include erase. This routine will
1026 attempt to write only the specified bytes. If the writes do not stick,
1027 it will return an error.
1030 This - Calling context
1031 Lba - Block in which to begin Read
1032 Offset - Offset in the block at which to begin Read
1033 NumBytes - On input, indicates the requested write size. On
1034 output, indicates the actual number of bytes Read
1035 Buffer - Buffer containing source data for the Read.
1038 EFI_SUCCESS - The firmware volume was read successfully and
1039 contents are in Buffer
1040 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1041 NumBytes contains the total number of bytes returned
1043 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1044 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1046 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1051 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1053 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1055 return FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1059 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1063 Routine Description:
1064 Check the integrity of firmware volume header
1067 FwVolHeader - A pointer to a firmware volume header
1070 EFI_SUCCESS - The firmware volume is consistent
1071 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1076 UINT16 HeaderLength
;
1080 // Verify the header revision, header signature, length
1081 // Length of FvBlock cannot be 2**64-1
1082 // HeaderLength cannot be an odd number
1084 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1085 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1086 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
1087 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1089 return EFI_NOT_FOUND
;
1092 // Verify the header checksum
1094 HeaderLength
= (UINT16
) (FwVolHeader
->HeaderLength
/ 2);
1095 Ptr
= (UINT16
*) FwVolHeader
;
1097 while (HeaderLength
> 0) {
1098 Checksum
= Checksum
+ (*Ptr
);
1103 if (Checksum
!= 0) {
1104 return EFI_NOT_FOUND
;
1113 IN EFI_HANDLE ImageHandle
,
1114 IN EFI_SYSTEM_TABLE
*SystemTable
1118 Routine Description:
1119 This function does common initialization for FVB services
1128 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1129 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1130 EFI_DXE_SERVICES
*DxeServices
;
1131 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
1133 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1134 EFI_HANDLE FwbHandle
;
1135 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1136 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1137 EFI_DEVICE_PATH_PROTOCOL
*TempFwbDevicePath
;
1138 FV_DEVICE_PATH TempFvbDevicePathData
;
1140 EFI_PHYSICAL_ADDRESS BaseAddress
;
1143 EFI_PEI_HOB_POINTERS FvHob
;
1146 // Get the DXE services table
1151 // Allocate runtime services data for global variable, which contains
1152 // the private data of all firmware volume block instances
1154 Status
= gBS
->AllocatePool (
1155 EfiRuntimeServicesData
,
1156 sizeof (ESAL_FWB_GLOBAL
),
1157 (VOID
**) &mFvbModuleGlobal
1159 ASSERT_EFI_ERROR (Status
);
1162 // Calculate the total size for all firmware volume block instances
1166 FvHob
.Raw
= GetHobList ();
1167 while ((FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
)) != NULL
) {
1168 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1169 Length
= FvHob
.FirmwareVolume
->Length
;
1171 // Check if it is a "real" flash
1173 Status
= DxeServices
->GetMemorySpaceDescriptor (
1177 if (EFI_ERROR (Status
)) {
1181 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1182 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1186 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1187 Status
= ValidateFvHeader (FwVolHeader
);
1188 if (EFI_ERROR (Status
)) {
1192 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1193 if (EFI_ERROR (Status
)) {
1194 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1199 BufferSize
+= (sizeof (EFI_FW_VOL_INSTANCE
) + FwVolHeader
->HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1200 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1204 // Only need to allocate once. There is only one copy of physical memory for
1205 // the private data of each FV instance. But in virtual mode or in physical
1206 // mode, the address of the the physical memory may be different.
1208 Status
= gBS
->AllocatePool (
1209 EfiRuntimeServicesData
,
1211 (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
]
1213 ASSERT_EFI_ERROR (Status
);
1216 // Make a virtual copy of the FvInstance pointer.
1218 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1219 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1221 mFvbModuleGlobal
->NumFv
= 0;
1224 FvHob
.Raw
= GetHobList ();
1225 while (NULL
!= (FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
))) {
1226 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1227 Length
= FvHob
.FirmwareVolume
->Length
;
1229 // Check if it is a "real" flash
1231 Status
= DxeServices
->GetMemorySpaceDescriptor (
1235 if (EFI_ERROR (Status
)) {
1239 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1240 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1244 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1245 Status
= ValidateFvHeader (FwVolHeader
);
1246 if (EFI_ERROR (Status
)) {
1248 // Get FvbInfo to provide in FwhInstance.
1250 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1251 if (EFI_ERROR (Status
)) {
1252 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1256 // Write healthy FV header back.
1259 (VOID
*) (UINTN
) BaseAddress
,
1260 (VOID
*) FwVolHeader
,
1261 FwVolHeader
->HeaderLength
1265 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1266 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1268 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1269 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1270 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1274 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1276 // Get the maximum size of a block. The size will be used to allocate
1277 // buffer for Scratch space, the intermediate buffer for FVB extension
1280 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
1281 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1284 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1287 // The total number of blocks in the FV.
1289 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1292 // Add a FVB Protocol Instance
1294 Status
= gBS
->AllocatePool (
1295 EfiRuntimeServicesData
,
1296 sizeof (EFI_FW_VOL_BLOCK_DEVICE
),
1299 ASSERT_EFI_ERROR (Status
);
1301 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1303 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1304 mFvbModuleGlobal
->NumFv
++;
1307 // Set up the devicepath
1309 FvbDevice
->DevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
1310 FvbDevice
->DevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ (FwVolHeader
->FvLength
- 1);
1313 // Find a handle with a matching device path that has supports FW Block protocol
1315 TempFwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) &TempFvbDevicePathData
;
1316 CopyMem (TempFwbDevicePath
, &FvbDevice
->DevicePath
, sizeof (FV_DEVICE_PATH
));
1317 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &TempFwbDevicePath
, &FwbHandle
);
1318 if (EFI_ERROR (Status
)) {
1320 // LocateDevicePath fails so install a new interface and device path
1323 Status
= gBS
->InstallMultipleProtocolInterfaces (
1325 &gEfiFirmwareVolumeBlockProtocolGuid
,
1326 &FvbDevice
->FwVolBlockInstance
,
1327 &gEfiDevicePathProtocolGuid
,
1328 &FvbDevice
->DevicePath
,
1331 ASSERT_EFI_ERROR (Status
);
1332 } else if (IsDevicePathEnd (TempFwbDevicePath
)) {
1334 // Device allready exists, so reinstall the FVB protocol
1336 Status
= gBS
->HandleProtocol (
1338 &gEfiFirmwareVolumeBlockProtocolGuid
,
1339 (VOID
**)&OldFwbInterface
1341 ASSERT_EFI_ERROR (Status
);
1343 Status
= gBS
->ReinstallProtocolInterface (
1345 &gEfiFirmwareVolumeBlockProtocolGuid
,
1347 &FvbDevice
->FwVolBlockInstance
1349 ASSERT_EFI_ERROR (Status
);
1353 // There was a FVB protocol on an End Device Path node
1358 Status
= gBS
->InstallMultipleProtocolInterfaces (
1360 &gEfiAlternateFvBlockGuid
,
1365 ASSERT_EFI_ERROR (Status
);
1367 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1369 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1370 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1373 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);