3 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
4 Portions copyright (c) 2011, Apple Inc. All rights reserved.
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include <Guid/EventGroup.h>
17 #include <Protocol/FirmwareVolumeBlock.h>
18 #include <Protocol/DevicePath.h>
20 #include <Library/UefiLib.h>
21 #include <Library/UefiDriverEntryPoint.h>
22 #include <Library/BaseLib.h>
23 #include <Library/DxeServicesTableLib.h>
24 #include <Library/UefiRuntimeLib.h>
25 #include <Library/DebugLib.h>
26 #include <Library/HobLib.h>
27 #include <Library/BaseMemoryLib.h>
28 #include <Library/MemoryAllocationLib.h>
29 #include <Library/UefiBootServicesTableLib.h>
30 #include <Library/DevicePathLib.h>
32 #include "FwBlockService.h"
34 ESAL_FWB_GLOBAL
*mFvbModuleGlobal
;
36 #define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
38 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
46 sizeof (MEMMAP_DEVICE_PATH
),
56 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
58 sizeof (EFI_DEVICE_PATH_PROTOCOL
),
65 FvbProtocolGetAttributes
,
66 FvbProtocolSetAttributes
,
67 FvbProtocolGetPhysicalAddress
,
68 FvbProtocolGetBlockSize
,
71 FvbProtocolEraseBlocks
,
80 FvbVirtualddressChangeEvent (
88 Fixup internal data so that EFI and SAL can be call in virtual mode.
89 Call the passed in Child Notify event and convert the mFvbModuleGlobal
90 date items to there virtual address.
92 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
93 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
98 (Standard EFI notify event - EFI_EVENT_NOTIFY)
106 EFI_FW_VOL_INSTANCE
*FwhInstance
;
109 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
112 // Convert the base address of all the instances
115 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
116 while (Index
< mFvbModuleGlobal
->NumFv
) {
117 EfiConvertPointer (0x0, (VOID
**) &FwhInstance
->FvBase
[FVB_VIRTUAL
]);
118 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
120 (UINTN
) ((UINT8
*) FwhInstance
) + FwhInstance
->VolumeHeader
.HeaderLength
+
121 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
126 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
);
132 IN ESAL_FWB_GLOBAL
*Global
,
133 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
139 Retrieves the physical address of a memory mapped FV
142 Instance - The FV instance whose base address is going to be
144 Global - Pointer to ESAL_FWB_GLOBAL that contains all
146 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
147 Virtual - Whether CPU is in virtual or physical mode
150 EFI_SUCCESS - Successfully returns
151 EFI_INVALID_PARAMETER - Instance not found
155 EFI_FW_VOL_INSTANCE
*FwhRecord
;
157 if (Instance
>= Global
->NumFv
) {
158 return EFI_INVALID_PARAMETER
;
161 // Find the right instance of the FVB private data
163 FwhRecord
= Global
->FvInstance
[Virtual
];
164 while (Instance
> 0) {
165 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
167 (UINTN
) ((UINT8
*) FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
168 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
173 *FwhInstance
= FwhRecord
;
179 FvbGetPhysicalAddress (
181 OUT EFI_PHYSICAL_ADDRESS
*Address
,
182 IN ESAL_FWB_GLOBAL
*Global
,
188 Retrieves the physical address of a memory mapped FV
191 Instance - The FV instance whose base address is going to be
193 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
194 that on successful return, contains the base address
195 of the firmware volume.
196 Global - Pointer to ESAL_FWB_GLOBAL that contains all
198 Virtual - Whether CPU is in virtual or physical mode
201 EFI_SUCCESS - Successfully returns
202 EFI_INVALID_PARAMETER - Instance not found
206 EFI_FW_VOL_INSTANCE
*FwhInstance
= NULL
;
210 // Find the right instance of the FVB private data
212 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
213 ASSERT_EFI_ERROR (Status
);
214 *Address
= FwhInstance
->FvBase
[Virtual
];
220 FvbGetVolumeAttributes (
222 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
223 IN ESAL_FWB_GLOBAL
*Global
,
229 Retrieves attributes, insures positive polarity of attribute bits, returns
230 resulting attributes in output parameter
233 Instance - The FV instance whose attributes is going to be
235 Attributes - Output buffer which contains attributes
236 Global - Pointer to ESAL_FWB_GLOBAL that contains all
238 Virtual - Whether CPU is in virtual or physical mode
241 EFI_SUCCESS - Successfully returns
242 EFI_INVALID_PARAMETER - Instance not found
246 EFI_FW_VOL_INSTANCE
*FwhInstance
= NULL
;
250 // Find the right instance of the FVB private data
252 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
253 ASSERT_EFI_ERROR (Status
);
254 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
263 OUT UINTN
*LbaAddress
,
264 OUT UINTN
*LbaLength
,
265 OUT UINTN
*NumOfBlocks
,
266 IN ESAL_FWB_GLOBAL
*Global
,
272 Retrieves the starting address of an LBA in an FV
275 Instance - The FV instance which the Lba belongs to
276 Lba - The logical block address
277 LbaAddress - On output, contains the physical starting address
279 LbaLength - On output, contains the length of the block
280 NumOfBlocks - A pointer to a caller allocated UINTN in which the
281 number of consecutive blocks starting with Lba is
282 returned. All blocks in this range have a size of
284 Global - Pointer to ESAL_FWB_GLOBAL that contains all
286 Virtual - Whether CPU is in virtual or physical mode
289 EFI_SUCCESS - Successfully returns
290 EFI_INVALID_PARAMETER - Instance not found
299 EFI_FW_VOL_INSTANCE
*FwhInstance
= NULL
;
300 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
304 // Find the right instance of the FVB private data
306 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
307 ASSERT_EFI_ERROR (Status
);
311 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
314 // Parse the blockmap of the FV to find which map entry the Lba belongs to
317 NumBlocks
= BlockMap
->NumBlocks
;
318 BlockLength
= BlockMap
->Length
;
320 if (NumBlocks
== 0 || BlockLength
== 0) {
321 return EFI_INVALID_PARAMETER
;
324 NextLba
= StartLba
+ NumBlocks
;
327 // The map entry found
329 if (Lba
>= StartLba
&& Lba
< NextLba
) {
330 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
331 if (LbaAddress
!= NULL
) {
332 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
335 if (LbaLength
!= NULL
) {
336 *LbaLength
= BlockLength
;
339 if (NumOfBlocks
!= NULL
) {
340 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
347 Offset
= Offset
+ NumBlocks
* BlockLength
;
356 IN UINTN BlockOffset
,
357 IN OUT UINTN
*NumBytes
,
359 IN ESAL_FWB_GLOBAL
*Global
,
365 Reads specified number of bytes into a buffer from the specified block
368 Instance - The FV instance to be read from
369 Lba - The logical block address to be read from
370 BlockOffset - Offset into the block at which to begin reading
371 NumBytes - Pointer that on input contains the total size of
372 the buffer. On output, it contains the total number
374 Buffer - Pointer to a caller allocated buffer that will be
375 used to hold the data read
376 Global - Pointer to ESAL_FWB_GLOBAL that contains all
378 Virtual - Whether CPU is in virtual or physical mode
381 EFI_SUCCESS - The firmware volume was read successfully and
382 contents are in Buffer
383 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
384 NumBytes contains the total number of bytes returned
386 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
387 EFI_DEVICE_ERROR - The block device is not functioning correctly and
389 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
393 EFI_FVB_ATTRIBUTES_2 Attributes
;
399 // Check for invalid conditions
401 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
402 return EFI_INVALID_PARAMETER
;
405 if (*NumBytes
== 0) {
406 return EFI_INVALID_PARAMETER
;
409 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
410 if (EFI_ERROR (Status
)) {
414 // Check if the FV is read enabled
416 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
418 if ((Attributes
& EFI_FVB2_READ_STATUS
) == 0) {
419 return EFI_ACCESS_DENIED
;
422 // Perform boundary checks and adjust NumBytes
424 if (BlockOffset
> LbaLength
) {
425 return EFI_INVALID_PARAMETER
;
428 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
429 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
430 Status
= EFI_BAD_BUFFER_SIZE
;
433 CopyMem (Buffer
, (UINT8
*) (LbaAddress
+ BlockOffset
), (UINTN
) (*NumBytes
));
442 IN UINTN BlockOffset
,
443 IN OUT UINTN
*NumBytes
,
445 IN ESAL_FWB_GLOBAL
*Global
,
451 Writes specified number of bytes from the input buffer to the block
454 Instance - The FV instance to be written to
455 Lba - The starting logical block index to write to
456 BlockOffset - Offset into the block at which to begin writing
457 NumBytes - Pointer that on input contains the total size of
458 the buffer. On output, it contains the total number
459 of bytes actually written
460 Buffer - Pointer to a caller allocated buffer that contains
461 the source for the write
462 Global - Pointer to ESAL_FWB_GLOBAL that contains all
464 Virtual - Whether CPU is in virtual or physical mode
467 EFI_SUCCESS - The firmware volume was written successfully
468 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
469 NumBytes contains the total number of bytes
471 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
472 EFI_DEVICE_ERROR - The block device is not functioning correctly and
474 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
478 EFI_FVB_ATTRIBUTES_2 Attributes
;
484 // Check for invalid conditions
486 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
487 return EFI_INVALID_PARAMETER
;
490 if (*NumBytes
== 0) {
491 return EFI_INVALID_PARAMETER
;
494 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
495 if (EFI_ERROR (Status
)) {
499 // Check if the FV is write enabled
501 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
503 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
504 return EFI_ACCESS_DENIED
;
507 // Perform boundary checks and adjust NumBytes
509 if (BlockOffset
> LbaLength
) {
510 return EFI_INVALID_PARAMETER
;
513 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
514 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
515 Status
= EFI_BAD_BUFFER_SIZE
;
520 CopyMem ((UINT8
*) (LbaAddress
+ BlockOffset
), Buffer
, (UINTN
) (*NumBytes
));
529 IN ESAL_FWB_GLOBAL
*Global
,
535 Erases and initializes a firmware volume block
538 Instance - The FV instance to be erased
539 Lba - The logical block index to be erased
540 Global - Pointer to ESAL_FWB_GLOBAL that contains all
542 Virtual - Whether CPU is in virtual or physical mode
545 EFI_SUCCESS - The erase request was successfully completed
546 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
547 EFI_DEVICE_ERROR - The block device is not functioning correctly and
548 could not be written. Firmware device may have been
550 EFI_INVALID_PARAMETER - Instance not found
555 EFI_FVB_ATTRIBUTES_2 Attributes
;
562 // Check if the FV is write enabled
564 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
566 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
567 return EFI_ACCESS_DENIED
;
570 // Get the starting address of the block for erase.
572 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
574 if (EFI_ERROR (Status
)) {
578 if ((Attributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
584 SetMem ((UINT8
*) LbaAddress
, LbaLength
, Data
);
590 FvbSetVolumeAttributes (
592 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
593 IN ESAL_FWB_GLOBAL
*Global
,
599 Modifies the current settings of the firmware volume according to the
600 input parameter, and returns the new setting of the volume
603 Instance - The FV instance whose attributes is going to be
605 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
606 containing the desired firmware volume settings.
607 On successful return, it contains the new settings
608 of the firmware volume
609 Global - Pointer to ESAL_FWB_GLOBAL that contains all
611 Virtual - Whether CPU is in virtual or physical mode
614 EFI_SUCCESS - Successfully returns
615 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
616 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
617 in conflict with the capabilities as declared in the
618 firmware volume header
622 EFI_FW_VOL_INSTANCE
*FwhInstance
= NULL
;
623 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
624 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
629 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes
;
633 // Find the right instance of the FVB private data
635 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
636 ASSERT_EFI_ERROR (Status
);
638 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
639 OldAttributes
= *AttribPtr
;
640 Capabilities
= OldAttributes
& (EFI_FVB2_READ_DISABLED_CAP
| \
641 EFI_FVB2_READ_ENABLED_CAP
| \
642 EFI_FVB2_WRITE_DISABLED_CAP
| \
643 EFI_FVB2_WRITE_ENABLED_CAP
| \
647 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
648 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
649 UnchangedAttributes
= EFI_FVB2_READ_DISABLED_CAP
| \
650 EFI_FVB2_READ_ENABLED_CAP
| \
651 EFI_FVB2_WRITE_DISABLED_CAP
| \
652 EFI_FVB2_WRITE_ENABLED_CAP
| \
653 EFI_FVB2_LOCK_CAP
| \
654 EFI_FVB2_STICKY_WRITE
| \
655 EFI_FVB2_MEMORY_MAPPED
| \
656 EFI_FVB2_ERASE_POLARITY
| \
657 EFI_FVB2_READ_LOCK_CAP
| \
658 EFI_FVB2_WRITE_LOCK_CAP
| \
662 // Some attributes of FV is read only can *not* be set
664 if ((OldAttributes
& UnchangedAttributes
) ^ (*Attributes
& UnchangedAttributes
)) {
665 return EFI_INVALID_PARAMETER
;
669 // If firmware volume is locked, no status bit can be updated
671 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
672 if (OldStatus
^ NewStatus
) {
673 return EFI_ACCESS_DENIED
;
679 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
680 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
681 return EFI_INVALID_PARAMETER
;
687 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
688 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
689 return EFI_INVALID_PARAMETER
;
693 // Test write disable
695 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
696 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
697 return EFI_INVALID_PARAMETER
;
703 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
704 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
705 return EFI_INVALID_PARAMETER
;
711 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
712 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
713 return EFI_INVALID_PARAMETER
;
717 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
718 *AttribPtr
= (*AttribPtr
) | NewStatus
;
719 *Attributes
= *AttribPtr
;
728 FvbProtocolGetPhysicalAddress (
729 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
730 OUT EFI_PHYSICAL_ADDRESS
*Address
736 Retrieves the physical address of the device.
740 This - Calling context
741 Address - Output buffer containing the address.
746 EFI_SUCCESS - Successfully returns
750 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
752 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
754 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
759 FvbProtocolGetBlockSize (
760 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
762 OUT UINTN
*BlockSize
,
763 OUT UINTN
*NumOfBlocks
768 Retrieve the size of a logical block
771 This - Calling context
772 Lba - Indicates which block to return the size for.
773 BlockSize - A pointer to a caller allocated UINTN in which
774 the size of the block is returned
775 NumOfBlocks - a pointer to a caller allocated UINTN in which the
776 number of consecutive blocks starting with Lba is
777 returned. All blocks in this range have a size of
781 EFI_SUCCESS - The firmware volume was read successfully and
782 contents are in Buffer
786 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
788 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
790 return FvbGetLbaAddress (
803 FvbProtocolGetAttributes (
804 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
805 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
810 Retrieves Volume attributes. No polarity translations are done.
813 This - Calling context
814 Attributes - output buffer which contains attributes
817 EFI_SUCCESS - Successfully returns
821 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
823 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
825 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
830 FvbProtocolSetAttributes (
831 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
832 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
837 Sets Volume attributes. No polarity translations are done.
840 This - Calling context
841 Attributes - output buffer which contains attributes
844 EFI_SUCCESS - Successfully returns
848 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
850 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
852 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
857 FvbProtocolEraseBlocks (
858 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
865 The EraseBlock() function erases one or more blocks as denoted by the
866 variable argument list. The entire parameter list of blocks must be verified
867 prior to erasing any blocks. If a block is requested that does not exist
868 within the associated firmware volume (it has a larger index than the last
869 block of the firmware volume), the EraseBlock() function must return
870 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
873 This - Calling context
874 ... - Starting LBA followed by Number of Lba to erase.
875 a -1 to terminate the list.
878 EFI_SUCCESS - The erase request was successfully completed
879 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
880 EFI_DEVICE_ERROR - The block device is not functioning correctly and
881 could not be written. Firmware device may have been
886 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
887 EFI_FW_VOL_INSTANCE
*FwhInstance
= NULL
;
894 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
896 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
897 ASSERT_EFI_ERROR (Status
);
899 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
901 VA_START (args
, This
);
904 StartingLba
= VA_ARG (args
, EFI_LBA
);
905 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
909 NumOfLba
= VA_ARG (args
, UINTN
);
912 // Check input parameters
914 if (NumOfLba
== 0 || (StartingLba
+ NumOfLba
) > NumOfBlocks
) {
916 return EFI_INVALID_PARAMETER
;
922 VA_START (args
, This
);
924 StartingLba
= VA_ARG (args
, EFI_LBA
);
925 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
929 NumOfLba
= VA_ARG (args
, UINTN
);
931 while (NumOfLba
> 0) {
932 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
933 if (EFI_ERROR (Status
)) {
952 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
955 IN OUT UINTN
*NumBytes
,
962 Writes data beginning at Lba:Offset from FV. The write terminates either
963 when *NumBytes of data have been written, or when a block boundary is
964 reached. *NumBytes is updated to reflect the actual number of bytes
965 written. The write opertion does not include erase. This routine will
966 attempt to write only the specified bytes. If the writes do not stick,
967 it will return an error.
970 This - Calling context
971 Lba - Block in which to begin write
972 Offset - Offset in the block at which to begin write
973 NumBytes - On input, indicates the requested write size. On
974 output, indicates the actual number of bytes written
975 Buffer - Buffer containing source data for the write.
978 EFI_SUCCESS - The firmware volume was written successfully
979 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
980 NumBytes contains the total number of bytes
982 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
983 EFI_DEVICE_ERROR - The block device is not functioning correctly and
985 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
990 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
992 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
994 return FvbWriteBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1000 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1003 IN OUT UINTN
*NumBytes
,
1008 Routine Description:
1010 Reads data beginning at Lba:Offset from FV. The Read terminates either
1011 when *NumBytes of data have been read, or when a block boundary is
1012 reached. *NumBytes is updated to reflect the actual number of bytes
1013 written. The write opertion does not include erase. This routine will
1014 attempt to write only the specified bytes. If the writes do not stick,
1015 it will return an error.
1018 This - Calling context
1019 Lba - Block in which to begin Read
1020 Offset - Offset in the block at which to begin Read
1021 NumBytes - On input, indicates the requested write size. On
1022 output, indicates the actual number of bytes Read
1023 Buffer - Buffer containing source data for the Read.
1026 EFI_SUCCESS - The firmware volume was read successfully and
1027 contents are in Buffer
1028 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1029 NumBytes contains the total number of bytes returned
1031 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1032 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1034 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1039 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1041 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1043 return FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1047 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1051 Routine Description:
1052 Check the integrity of firmware volume header
1055 FwVolHeader - A pointer to a firmware volume header
1058 EFI_SUCCESS - The firmware volume is consistent
1059 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1064 UINT16 HeaderLength
;
1068 // Verify the header revision, header signature, length
1069 // Length of FvBlock cannot be 2**64-1
1070 // HeaderLength cannot be an odd number
1072 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1073 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1074 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
1075 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1077 return EFI_NOT_FOUND
;
1080 // Verify the header checksum
1082 HeaderLength
= (UINT16
) (FwVolHeader
->HeaderLength
/ 2);
1083 Ptr
= (UINT16
*) FwVolHeader
;
1085 while (HeaderLength
> 0) {
1086 Checksum
= Checksum
+ (*Ptr
);
1091 if (Checksum
!= 0) {
1092 return EFI_NOT_FOUND
;
1101 IN EFI_HANDLE ImageHandle
,
1102 IN EFI_SYSTEM_TABLE
*SystemTable
1106 Routine Description:
1107 This function does common initialization for FVB services
1116 EFI_FW_VOL_INSTANCE
*FwhInstance
= NULL
;
1117 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1118 EFI_DXE_SERVICES
*DxeServices
;
1119 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
1121 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1122 EFI_HANDLE FwbHandle
;
1123 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1124 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1125 EFI_DEVICE_PATH_PROTOCOL
*TempFwbDevicePath
;
1126 FV_DEVICE_PATH TempFvbDevicePathData
;
1128 EFI_PHYSICAL_ADDRESS BaseAddress
;
1131 EFI_PEI_HOB_POINTERS FvHob
;
1134 // Get the DXE services table
1139 // Allocate runtime services data for global variable, which contains
1140 // the private data of all firmware volume block instances
1142 Status
= gBS
->AllocatePool (
1143 EfiRuntimeServicesData
,
1144 sizeof (ESAL_FWB_GLOBAL
),
1145 (VOID
**) &mFvbModuleGlobal
1147 ASSERT_EFI_ERROR (Status
);
1150 // Calculate the total size for all firmware volume block instances
1154 FvHob
.Raw
= GetHobList ();
1155 while ((FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
)) != NULL
) {
1156 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1157 Length
= FvHob
.FirmwareVolume
->Length
;
1159 // Check if it is a "real" flash
1161 Status
= DxeServices
->GetMemorySpaceDescriptor (
1165 if (EFI_ERROR (Status
)) {
1169 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1170 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1174 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1175 Status
= ValidateFvHeader (FwVolHeader
);
1176 if (EFI_ERROR (Status
)) {
1180 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1181 if (EFI_ERROR (Status
)) {
1182 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1187 BufferSize
+= (sizeof (EFI_FW_VOL_INSTANCE
) + FwVolHeader
->HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1188 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1192 // Only need to allocate once. There is only one copy of physical memory for
1193 // the private data of each FV instance. But in virtual mode or in physical
1194 // mode, the address of the the physical memory may be different.
1196 Status
= gBS
->AllocatePool (
1197 EfiRuntimeServicesData
,
1199 (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
]
1201 ASSERT_EFI_ERROR (Status
);
1204 // Make a virtual copy of the FvInstance pointer.
1206 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1207 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1209 mFvbModuleGlobal
->NumFv
= 0;
1212 FvHob
.Raw
= GetHobList ();
1213 while (NULL
!= (FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
))) {
1214 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1215 Length
= FvHob
.FirmwareVolume
->Length
;
1217 // Check if it is a "real" flash
1219 Status
= DxeServices
->GetMemorySpaceDescriptor (
1223 if (EFI_ERROR (Status
)) {
1227 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1228 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1232 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1233 Status
= ValidateFvHeader (FwVolHeader
);
1234 if (EFI_ERROR (Status
)) {
1236 // Get FvbInfo to provide in FwhInstance.
1238 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1239 if (EFI_ERROR (Status
)) {
1240 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1244 // Write healthy FV header back.
1247 (VOID
*) (UINTN
) BaseAddress
,
1248 (VOID
*) FwVolHeader
,
1249 FwVolHeader
->HeaderLength
1253 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1254 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1256 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1257 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1258 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1262 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1264 // Get the maximum size of a block. The size will be used to allocate
1265 // buffer for Scratch space, the intermediate buffer for FVB extension
1268 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
1269 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1272 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1275 // The total number of blocks in the FV.
1277 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1280 // Add a FVB Protocol Instance
1282 Status
= gBS
->AllocatePool (
1283 EfiRuntimeServicesData
,
1284 sizeof (EFI_FW_VOL_BLOCK_DEVICE
),
1287 ASSERT_EFI_ERROR (Status
);
1289 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1291 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1292 mFvbModuleGlobal
->NumFv
++;
1295 // Set up the devicepath
1297 FvbDevice
->DevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
1298 FvbDevice
->DevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ (FwVolHeader
->FvLength
- 1);
1301 // Find a handle with a matching device path that has supports FW Block protocol
1303 TempFwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) &TempFvbDevicePathData
;
1304 CopyMem (TempFwbDevicePath
, &FvbDevice
->DevicePath
, sizeof (FV_DEVICE_PATH
));
1305 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &TempFwbDevicePath
, &FwbHandle
);
1306 if (EFI_ERROR (Status
)) {
1308 // LocateDevicePath fails so install a new interface and device path
1311 Status
= gBS
->InstallMultipleProtocolInterfaces (
1313 &gEfiFirmwareVolumeBlockProtocolGuid
,
1314 &FvbDevice
->FwVolBlockInstance
,
1315 &gEfiDevicePathProtocolGuid
,
1316 &FvbDevice
->DevicePath
,
1319 ASSERT_EFI_ERROR (Status
);
1320 } else if (IsDevicePathEnd (TempFwbDevicePath
)) {
1322 // Device allready exists, so reinstall the FVB protocol
1324 Status
= gBS
->HandleProtocol (
1326 &gEfiFirmwareVolumeBlockProtocolGuid
,
1327 (VOID
**)&OldFwbInterface
1329 ASSERT_EFI_ERROR (Status
);
1331 Status
= gBS
->ReinstallProtocolInterface (
1333 &gEfiFirmwareVolumeBlockProtocolGuid
,
1335 &FvbDevice
->FwVolBlockInstance
1337 ASSERT_EFI_ERROR (Status
);
1341 // There was a FVB protocol on an End Device Path node
1346 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1348 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1349 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1352 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);