3 Copyright (c) 2006 - 2007, 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 // 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 <Guid/AlternateFvBlock.h>
33 #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/HobLib.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"
51 #define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
53 ESAL_FWB_GLOBAL
*mFvbModuleGlobal
;
55 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
63 sizeof (MEMMAP_DEVICE_PATH
),
73 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
75 sizeof (EFI_DEVICE_PATH_PROTOCOL
),
82 FvbProtocolGetAttributes
,
83 FvbProtocolSetAttributes
,
84 FvbProtocolGetPhysicalAddress
,
85 FvbProtocolGetBlockSize
,
88 FvbProtocolEraseBlocks
,
97 FvbVirtualddressChangeEvent (
105 Fixup internal data so that EFI and SAL can be call in virtual mode.
106 Call the passed in Child Notify event and convert the mFvbModuleGlobal
107 date items to there virtual address.
109 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
110 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
115 (Standard EFI notify event - EFI_EVENT_NOTIFY)
123 EFI_FW_VOL_INSTANCE
*FwhInstance
;
126 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
129 // Convert the base address of all the instances
132 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
133 while (Index
< mFvbModuleGlobal
->NumFv
) {
134 EfiConvertPointer (0x0, (VOID
**) &FwhInstance
->FvBase
[FVB_VIRTUAL
]);
135 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
137 (UINTN
) ((UINT8
*) FwhInstance
) + FwhInstance
->VolumeHeader
.HeaderLength
+
138 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
143 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvbScratchSpace
[FVB_VIRTUAL
]);
144 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
);
150 IN ESAL_FWB_GLOBAL
*Global
,
151 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
157 Retrieves the physical address of a memory mapped FV
160 Instance - The FV instance whose base address is going to be
162 Global - Pointer to ESAL_FWB_GLOBAL that contains all
164 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
165 Virtual - Whether CPU is in virtual or physical mode
168 EFI_SUCCESS - Successfully returns
169 EFI_INVALID_PARAMETER - Instance not found
173 EFI_FW_VOL_INSTANCE
*FwhRecord
;
175 if (Instance
>= Global
->NumFv
) {
176 return EFI_INVALID_PARAMETER
;
179 // Find the right instance of the FVB private data
181 FwhRecord
= Global
->FvInstance
[Virtual
];
182 while (Instance
> 0) {
183 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
185 (UINTN
) ((UINT8
*) FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
186 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
191 *FwhInstance
= FwhRecord
;
197 FvbGetPhysicalAddress (
199 OUT EFI_PHYSICAL_ADDRESS
*Address
,
200 IN ESAL_FWB_GLOBAL
*Global
,
206 Retrieves the physical address of a memory mapped FV
209 Instance - The FV instance whose base address is going to be
211 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
212 that on successful return, contains the base address
213 of the firmware volume.
214 Global - Pointer to ESAL_FWB_GLOBAL that contains all
216 Virtual - Whether CPU is in virtual or physical mode
219 EFI_SUCCESS - Successfully returns
220 EFI_INVALID_PARAMETER - Instance not found
224 EFI_FW_VOL_INSTANCE
*FwhInstance
;
228 // Find the right instance of the FVB private data
230 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
231 ASSERT_EFI_ERROR (Status
);
232 *Address
= FwhInstance
->FvBase
[Virtual
];
238 FvbGetVolumeAttributes (
240 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
241 IN ESAL_FWB_GLOBAL
*Global
,
247 Retrieves attributes, insures positive polarity of attribute bits, returns
248 resulting attributes in output parameter
251 Instance - The FV instance whose attributes is going to be
253 Attributes - Output buffer which contains attributes
254 Global - Pointer to ESAL_FWB_GLOBAL that contains all
256 Virtual - Whether CPU is in virtual or physical mode
259 EFI_SUCCESS - Successfully returns
260 EFI_INVALID_PARAMETER - Instance not found
264 EFI_FW_VOL_INSTANCE
*FwhInstance
;
268 // Find the right instance of the FVB private data
270 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
271 ASSERT_EFI_ERROR (Status
);
272 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
281 OUT UINTN
*LbaAddress
,
282 OUT UINTN
*LbaLength
,
283 OUT UINTN
*NumOfBlocks
,
284 IN ESAL_FWB_GLOBAL
*Global
,
290 Retrieves the starting address of an LBA in an FV
293 Instance - The FV instance which the Lba belongs to
294 Lba - The logical block address
295 LbaAddress - On output, contains the physical starting address
297 LbaLength - On output, contains the length of the block
298 NumOfBlocks - A pointer to a caller allocated UINTN in which the
299 number of consecutive blocks starting with Lba is
300 returned. All blocks in this range have a size of
302 Global - Pointer to ESAL_FWB_GLOBAL that contains all
304 Virtual - Whether CPU is in virtual or physical mode
307 EFI_SUCCESS - Successfully returns
308 EFI_INVALID_PARAMETER - Instance not found
317 EFI_FW_VOL_INSTANCE
*FwhInstance
;
318 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
322 // Find the right instance of the FVB private data
324 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
325 ASSERT_EFI_ERROR (Status
);
329 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
332 // Parse the blockmap of the FV to find which map entry the Lba belongs to
335 NumBlocks
= BlockMap
->NumBlocks
;
336 BlockLength
= BlockMap
->Length
;
338 if (NumBlocks
== 0 || BlockLength
== 0) {
339 return EFI_INVALID_PARAMETER
;
342 NextLba
= StartLba
+ NumBlocks
;
345 // The map entry found
347 if (Lba
>= StartLba
&& Lba
< NextLba
) {
348 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
349 if (LbaAddress
!= NULL
) {
350 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
353 if (LbaLength
!= NULL
) {
354 *LbaLength
= BlockLength
;
357 if (NumOfBlocks
!= NULL
) {
358 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
365 Offset
= Offset
+ NumBlocks
* BlockLength
;
374 IN UINTN BlockOffset
,
375 IN OUT UINTN
*NumBytes
,
377 IN ESAL_FWB_GLOBAL
*Global
,
383 Reads specified number of bytes into a buffer from the specified block
386 Instance - The FV instance to be read from
387 Lba - The logical block address to be read from
388 BlockOffset - Offset into the block at which to begin reading
389 NumBytes - Pointer that on input contains the total size of
390 the buffer. On output, it contains the total number
392 Buffer - Pointer to a caller allocated buffer that will be
393 used to hold the data read
394 Global - Pointer to ESAL_FWB_GLOBAL that contains all
396 Virtual - Whether CPU is in virtual or physical mode
399 EFI_SUCCESS - The firmware volume was read successfully and
400 contents are in Buffer
401 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
402 NumBytes contains the total number of bytes returned
404 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
405 EFI_DEVICE_ERROR - The block device is not functioning correctly and
407 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
411 EFI_FVB_ATTRIBUTES_2 Attributes
;
417 // Check for invalid conditions
419 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
420 return EFI_INVALID_PARAMETER
;
423 if (*NumBytes
== 0) {
424 return EFI_INVALID_PARAMETER
;
427 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
428 if (EFI_ERROR (Status
)) {
432 // Check if the FV is read enabled
434 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
436 if ((Attributes
& EFI_FVB2_READ_STATUS
) == 0) {
437 return EFI_ACCESS_DENIED
;
440 // Perform boundary checks and adjust NumBytes
442 if (BlockOffset
> LbaLength
) {
443 return EFI_INVALID_PARAMETER
;
446 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
447 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
448 Status
= EFI_BAD_BUFFER_SIZE
;
451 CopyMem (Buffer
, (UINT8
*) (LbaAddress
+ BlockOffset
), (UINTN
) (*NumBytes
));
460 IN UINTN BlockOffset
,
461 IN OUT UINTN
*NumBytes
,
463 IN ESAL_FWB_GLOBAL
*Global
,
469 Writes specified number of bytes from the input buffer to the block
472 Instance - The FV instance to be written to
473 Lba - The starting logical block index to write to
474 BlockOffset - Offset into the block at which to begin writing
475 NumBytes - Pointer that on input contains the total size of
476 the buffer. On output, it contains the total number
477 of bytes actually written
478 Buffer - Pointer to a caller allocated buffer that contains
479 the source for the write
480 Global - Pointer to ESAL_FWB_GLOBAL that contains all
482 Virtual - Whether CPU is in virtual or physical mode
485 EFI_SUCCESS - The firmware volume was written successfully
486 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
487 NumBytes contains the total number of bytes
489 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
490 EFI_DEVICE_ERROR - The block device is not functioning correctly and
492 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
496 EFI_FVB_ATTRIBUTES_2 Attributes
;
502 // Check for invalid conditions
504 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
505 return EFI_INVALID_PARAMETER
;
508 if (*NumBytes
== 0) {
509 return EFI_INVALID_PARAMETER
;
512 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
513 if (EFI_ERROR (Status
)) {
517 // Check if the FV is write enabled
519 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
521 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
522 return EFI_ACCESS_DENIED
;
525 // Perform boundary checks and adjust NumBytes
527 if (BlockOffset
> LbaLength
) {
528 return EFI_INVALID_PARAMETER
;
531 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
532 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
533 Status
= EFI_BAD_BUFFER_SIZE
;
538 CopyMem ((UINT8
*) (LbaAddress
+ BlockOffset
), Buffer
, (UINTN
) (*NumBytes
));
547 IN ESAL_FWB_GLOBAL
*Global
,
553 Erases and initializes a firmware volume block
556 Instance - The FV instance to be erased
557 Lba - The logical block index to be erased
558 Global - Pointer to ESAL_FWB_GLOBAL that contains all
560 Virtual - Whether CPU is in virtual or physical mode
563 EFI_SUCCESS - The erase request was successfully completed
564 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
565 EFI_DEVICE_ERROR - The block device is not functioning correctly and
566 could not be written. Firmware device may have been
568 EFI_INVALID_PARAMETER - Instance not found
573 EFI_FVB_ATTRIBUTES_2 Attributes
;
580 // Check if the FV is write enabled
582 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
584 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
585 return EFI_ACCESS_DENIED
;
588 // Get the starting address of the block for erase.
590 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
592 if (EFI_ERROR (Status
)) {
596 if ((Attributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
602 SetMem ((UINT8
*) LbaAddress
, LbaLength
, Data
);
608 FvbSetVolumeAttributes (
610 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
611 IN ESAL_FWB_GLOBAL
*Global
,
617 Modifies the current settings of the firmware volume according to the
618 input parameter, and returns the new setting of the volume
621 Instance - The FV instance whose attributes is going to be
623 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
624 containing the desired firmware volume settings.
625 On successful return, it contains the new settings
626 of the firmware volume
627 Global - Pointer to ESAL_FWB_GLOBAL that contains all
629 Virtual - Whether CPU is in virtual or physical mode
632 EFI_SUCCESS - Successfully returns
633 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
634 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
635 in conflict with the capabilities as declared in the
636 firmware volume header
640 EFI_FW_VOL_INSTANCE
*FwhInstance
;
641 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
642 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
647 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes
;
650 // Find the right instance of the FVB private data
652 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
653 ASSERT_EFI_ERROR (Status
);
655 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
656 OldAttributes
= *AttribPtr
;
657 Capabilities
= OldAttributes
& (EFI_FVB2_READ_DISABLED_CAP
| \
658 EFI_FVB2_READ_ENABLED_CAP
| \
659 EFI_FVB2_WRITE_DISABLED_CAP
| \
660 EFI_FVB2_WRITE_ENABLED_CAP
| \
663 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
664 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
666 UnchangedAttributes
= EFI_FVB2_READ_DISABLED_CAP
| \
667 EFI_FVB2_READ_ENABLED_CAP
| \
668 EFI_FVB2_WRITE_DISABLED_CAP
| \
669 EFI_FVB2_WRITE_ENABLED_CAP
| \
670 EFI_FVB2_LOCK_CAP
| \
671 EFI_FVB2_STICKY_WRITE
| \
672 EFI_FVB2_MEMORY_MAPPED
| \
673 EFI_FVB2_ERASE_POLARITY
| \
674 EFI_FVB2_READ_LOCK_CAP
| \
675 EFI_FVB2_WRITE_LOCK_CAP
| \
679 // Some attributes of FV is read only can *not* be set
681 if ((OldAttributes
& UnchangedAttributes
) ^ (*Attributes
& UnchangedAttributes
)) {
682 return EFI_INVALID_PARAMETER
;
685 // If firmware volume is locked, no status bit can be updated
687 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
688 if (OldStatus
^ NewStatus
) {
689 return EFI_ACCESS_DENIED
;
695 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
696 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
697 return EFI_INVALID_PARAMETER
;
703 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
704 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
705 return EFI_INVALID_PARAMETER
;
709 // Test write disable
711 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
712 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
713 return EFI_INVALID_PARAMETER
;
719 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
720 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
721 return EFI_INVALID_PARAMETER
;
727 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
728 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
729 return EFI_INVALID_PARAMETER
;
733 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
734 *AttribPtr
= (*AttribPtr
) | NewStatus
;
735 *Attributes
= *AttribPtr
;
744 FvbProtocolGetPhysicalAddress (
745 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
746 OUT EFI_PHYSICAL_ADDRESS
*Address
752 Retrieves the physical address of the device.
756 This - Calling context
757 Address - Output buffer containing the address.
762 EFI_SUCCESS - Successfully returns
766 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
768 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
770 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
775 FvbProtocolGetBlockSize (
776 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
777 IN CONST EFI_LBA Lba
,
778 OUT UINTN
*BlockSize
,
779 OUT UINTN
*NumOfBlocks
784 Retrieve the size of a logical block
787 This - Calling context
788 Lba - Indicates which block to return the size for.
789 BlockSize - A pointer to a caller allocated UINTN in which
790 the size of the block is returned
791 NumOfBlocks - a pointer to a caller allocated UINTN in which the
792 number of consecutive blocks starting with Lba is
793 returned. All blocks in this range have a size of
797 EFI_SUCCESS - The firmware volume was read successfully and
798 contents are in Buffer
802 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
804 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
806 return FvbGetLbaAddress (
819 FvbProtocolGetAttributes (
820 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
821 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
826 Retrieves Volume attributes. No polarity translations are done.
829 This - Calling context
830 Attributes - output buffer which contains attributes
833 EFI_SUCCESS - Successfully returns
837 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
839 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
841 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
846 FvbProtocolSetAttributes (
847 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
848 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
853 Sets Volume attributes. No polarity translations are done.
856 This - Calling context
857 Attributes - output buffer which contains attributes
860 EFI_SUCCESS - Successfully returns
864 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
866 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
868 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
873 FvbProtocolEraseBlocks (
874 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
881 The EraseBlock() function erases one or more blocks as denoted by the
882 variable argument list. The entire parameter list of blocks must be verified
883 prior to erasing any blocks. If a block is requested that does not exist
884 within the associated firmware volume (it has a larger index than the last
885 block of the firmware volume), the EraseBlock() function must return
886 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
889 This - Calling context
890 ... - Starting LBA followed by Number of Lba to erase.
891 a -1 to terminate the list.
894 EFI_SUCCESS - The erase request was successfully completed
895 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
896 EFI_DEVICE_ERROR - The block device is not functioning correctly and
897 could not be written. Firmware device may have been
902 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
903 EFI_FW_VOL_INSTANCE
*FwhInstance
;
910 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
912 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
913 ASSERT_EFI_ERROR (Status
);
915 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
917 VA_START (args
, This
);
920 StartingLba
= VA_ARG (args
, EFI_LBA
);
921 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
925 NumOfLba
= VA_ARG (args
, UINT32
);
928 // Check input parameters
932 return EFI_INVALID_PARAMETER
;
935 if ((StartingLba
+ NumOfLba
) > NumOfBlocks
) {
936 return EFI_INVALID_PARAMETER
;
942 VA_START (args
, This
);
944 StartingLba
= VA_ARG (args
, EFI_LBA
);
945 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
949 NumOfLba
= VA_ARG (args
, UINT32
);
951 while (NumOfLba
> 0) {
952 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
953 if (EFI_ERROR (Status
)) {
972 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
975 IN OUT UINTN
*NumBytes
,
982 Writes data beginning at Lba:Offset from FV. The write terminates either
983 when *NumBytes of data have been written, or when a block boundary is
984 reached. *NumBytes is updated to reflect the actual number of bytes
985 written. The write opertion does not include erase. This routine will
986 attempt to write only the specified bytes. If the writes do not stick,
987 it will return an error.
990 This - Calling context
991 Lba - Block in which to begin write
992 Offset - Offset in the block at which to begin write
993 NumBytes - On input, indicates the requested write size. On
994 output, indicates the actual number of bytes written
995 Buffer - Buffer containing source data for the write.
998 EFI_SUCCESS - The firmware volume was written successfully
999 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
1000 NumBytes contains the total number of bytes
1002 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1003 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1004 could not be written
1005 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1010 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1012 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1014 return FvbWriteBlock (FvbDevice
->Instance
, (EFI_LBA
)Lba
, (UINTN
)Offset
, NumBytes
, (UINT8
*)Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1020 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1021 IN CONST EFI_LBA Lba
,
1022 IN CONST UINTN Offset
,
1023 IN OUT UINTN
*NumBytes
,
1028 Routine Description:
1030 Reads data beginning at Lba:Offset from FV. The Read terminates either
1031 when *NumBytes of data have been read, or when a block boundary is
1032 reached. *NumBytes is updated to reflect the actual number of bytes
1033 written. The write opertion does not include erase. This routine will
1034 attempt to write only the specified bytes. If the writes do not stick,
1035 it will return an error.
1038 This - Calling context
1039 Lba - Block in which to begin Read
1040 Offset - Offset in the block at which to begin Read
1041 NumBytes - On input, indicates the requested write size. On
1042 output, indicates the actual number of bytes Read
1043 Buffer - Buffer containing source data for the Read.
1046 EFI_SUCCESS - The firmware volume was read successfully and
1047 contents are in Buffer
1048 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1049 NumBytes contains the total number of bytes returned
1051 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1052 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1054 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1059 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1061 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1063 return FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1068 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1072 Routine Description:
1073 Check the integrity of firmware volume header
1076 FwVolHeader - A pointer to a firmware volume header
1079 EFI_SUCCESS - The firmware volume is consistent
1080 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1085 UINT16 HeaderLength
;
1089 // Verify the header revision, header signature, length
1090 // Length of FvBlock cannot be 2**64-1
1091 // HeaderLength cannot be an odd number
1093 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1094 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1095 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
1096 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1098 return EFI_NOT_FOUND
;
1101 // Verify the header checksum
1103 HeaderLength
= (UINT16
) (FwVolHeader
->HeaderLength
/ 2);
1104 Ptr
= (UINT16
*) FwVolHeader
;
1106 while (HeaderLength
> 0) {
1107 Checksum
= (UINT16
)(Checksum
+ (*Ptr
));
1112 if (Checksum
!= 0) {
1113 return EFI_NOT_FOUND
;
1122 IN EFI_HANDLE ImageHandle
,
1123 IN EFI_SYSTEM_TABLE
*SystemTable
1127 Routine Description:
1128 This function does common initialization for FVB services
1137 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1138 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1139 EFI_DXE_SERVICES
*DxeServices
;
1140 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
1142 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1143 EFI_HANDLE FwbHandle
;
1144 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1145 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1146 EFI_DEVICE_PATH_PROTOCOL
*TempFwbDevicePath
;
1147 FV_DEVICE_PATH TempFvbDevicePathData
;
1149 EFI_PHYSICAL_ADDRESS BaseAddress
;
1152 EFI_PEI_HOB_POINTERS FvHob
;
1155 // Get the DXE services table
1160 // Allocate runtime services data for global variable, which contains
1161 // the private data of all firmware volume block instances
1163 mFvbModuleGlobal
= AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL
));
1164 ASSERT (mFvbModuleGlobal
!= NULL
);
1167 // Calculate the total size for all firmware volume block instances
1171 FvHob
.Raw
= GetHobList ();
1172 while ((FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
)) != NULL
) {
1173 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1174 Length
= FvHob
.FirmwareVolume
->Length
;
1176 // Check if it is a "real" flash
1178 Status
= DxeServices
->GetMemorySpaceDescriptor (
1182 if (EFI_ERROR (Status
)) {
1186 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1187 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1191 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1192 Status
= ValidateFvHeader (FwVolHeader
);
1193 if (EFI_ERROR (Status
)) {
1197 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1198 if (EFI_ERROR (Status
)) {
1199 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1204 BufferSize
+= (sizeof (EFI_FW_VOL_INSTANCE
) + FwVolHeader
->HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1205 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1209 // Only need to allocate once. There is only one copy of physical memory for
1210 // the private data of each FV instance. But in virtual mode or in physical
1211 // mode, the address of the the physical memory may be different.
1213 mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] = AllocateRuntimePool (BufferSize
);
1214 ASSERT (mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
] != NULL
);
1217 // Make a virtual copy of the FvInstance pointer.
1219 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1220 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1222 mFvbModuleGlobal
->NumFv
= 0;
1225 FvHob
.Raw
= GetHobList ();
1226 while (NULL
!= (FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
))) {
1227 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1228 Length
= FvHob
.FirmwareVolume
->Length
;
1230 // Check if it is a "real" flash
1232 Status
= DxeServices
->GetMemorySpaceDescriptor (
1236 if (EFI_ERROR (Status
)) {
1240 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1241 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1245 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1246 Status
= ValidateFvHeader (FwVolHeader
);
1247 if (EFI_ERROR (Status
)) {
1249 // Get FvbInfo to provide in FwhInstance.
1251 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1252 if (EFI_ERROR (Status
)) {
1253 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1257 // Write healthy FV header back.
1260 (VOID
*) (UINTN
) BaseAddress
,
1261 (VOID
*) FwVolHeader
,
1262 FwVolHeader
->HeaderLength
1266 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1267 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1269 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1270 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1271 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1275 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1277 // Get the maximum size of a block. The size will be used to allocate
1278 // buffer for Scratch space, the intermediate buffer for FVB extension
1281 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
1282 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1285 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1288 // The total number of blocks in the FV.
1290 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1293 // Add a FVB Protocol Instance
1295 FvbDevice
= AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1296 ASSERT (FvbDevice
!= NULL
);
1298 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1300 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1301 mFvbModuleGlobal
->NumFv
++;
1304 // Set up the devicepath
1306 FvbDevice
->DevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
1307 FvbDevice
->DevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ (FwVolHeader
->FvLength
- 1);
1310 // Find a handle with a matching device path that has supports FW Block protocol
1312 TempFwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) &TempFvbDevicePathData
;
1313 CopyMem (TempFwbDevicePath
, &FvbDevice
->DevicePath
, sizeof (FV_DEVICE_PATH
));
1314 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &TempFwbDevicePath
, &FwbHandle
);
1315 if (EFI_ERROR (Status
)) {
1317 // LocateDevicePath fails so install a new interface and device path
1320 Status
= gBS
->InstallMultipleProtocolInterfaces (
1322 &gEfiFirmwareVolumeBlockProtocolGuid
,
1323 &FvbDevice
->FwVolBlockInstance
,
1324 &gEfiDevicePathProtocolGuid
,
1325 &FvbDevice
->DevicePath
,
1328 ASSERT_EFI_ERROR (Status
);
1329 } else if (IsDevicePathEnd (TempFwbDevicePath
)) {
1331 // Device allready exists, so reinstall the FVB protocol
1333 Status
= gBS
->HandleProtocol (
1335 &gEfiFirmwareVolumeBlockProtocolGuid
,
1336 (VOID
**)&OldFwbInterface
1338 ASSERT_EFI_ERROR (Status
);
1340 Status
= gBS
->ReinstallProtocolInterface (
1342 &gEfiFirmwareVolumeBlockProtocolGuid
,
1344 &FvbDevice
->FwVolBlockInstance
1346 ASSERT_EFI_ERROR (Status
);
1350 // There was a FVB protocol on an End Device Path node
1355 Status
= gBS
->InstallMultipleProtocolInterfaces (
1357 &gEfiAlternateFvBlockGuid
,
1362 ASSERT_EFI_ERROR (Status
);
1364 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1366 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1367 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1370 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);