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
->FvbScratchSpace
[FVB_VIRTUAL
]);
135 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
);
141 IN ESAL_FWB_GLOBAL
*Global
,
142 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
148 Retrieves the physical address of a memory mapped FV
151 Instance - The FV instance whose base address is going to be
153 Global - Pointer to ESAL_FWB_GLOBAL that contains all
155 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
156 Virtual - Whether CPU is in virtual or physical mode
159 EFI_SUCCESS - Successfully returns
160 EFI_INVALID_PARAMETER - Instance not found
164 EFI_FW_VOL_INSTANCE
*FwhRecord
;
166 if (Instance
>= Global
->NumFv
) {
167 return EFI_INVALID_PARAMETER
;
170 // Find the right instance of the FVB private data
172 FwhRecord
= Global
->FvInstance
[Virtual
];
173 while (Instance
> 0) {
174 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
176 (UINTN
) ((UINT8
*) FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
177 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
182 *FwhInstance
= FwhRecord
;
188 FvbGetPhysicalAddress (
190 OUT EFI_PHYSICAL_ADDRESS
*Address
,
191 IN ESAL_FWB_GLOBAL
*Global
,
197 Retrieves the physical address of a memory mapped FV
200 Instance - The FV instance whose base address is going to be
202 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
203 that on successful return, contains the base address
204 of the firmware volume.
205 Global - Pointer to ESAL_FWB_GLOBAL that contains all
207 Virtual - Whether CPU is in virtual or physical mode
210 EFI_SUCCESS - Successfully returns
211 EFI_INVALID_PARAMETER - Instance not found
215 EFI_FW_VOL_INSTANCE
*FwhInstance
;
219 // Find the right instance of the FVB private data
221 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
222 ASSERT_EFI_ERROR (Status
);
223 *Address
= FwhInstance
->FvBase
[Virtual
];
229 FvbGetVolumeAttributes (
231 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
232 IN ESAL_FWB_GLOBAL
*Global
,
238 Retrieves attributes, insures positive polarity of attribute bits, returns
239 resulting attributes in output parameter
242 Instance - The FV instance whose attributes is going to be
244 Attributes - Output buffer which contains attributes
245 Global - Pointer to ESAL_FWB_GLOBAL that contains all
247 Virtual - Whether CPU is in virtual or physical mode
250 EFI_SUCCESS - Successfully returns
251 EFI_INVALID_PARAMETER - Instance not found
255 EFI_FW_VOL_INSTANCE
*FwhInstance
;
259 // Find the right instance of the FVB private data
261 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
262 ASSERT_EFI_ERROR (Status
);
263 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
272 OUT UINTN
*LbaAddress
,
273 OUT UINTN
*LbaLength
,
274 OUT UINTN
*NumOfBlocks
,
275 IN ESAL_FWB_GLOBAL
*Global
,
281 Retrieves the starting address of an LBA in an FV
284 Instance - The FV instance which the Lba belongs to
285 Lba - The logical block address
286 LbaAddress - On output, contains the physical starting address
288 LbaLength - On output, contains the length of the block
289 NumOfBlocks - A pointer to a caller allocated UINTN in which the
290 number of consecutive blocks starting with Lba is
291 returned. All blocks in this range have a size of
293 Global - Pointer to ESAL_FWB_GLOBAL that contains all
295 Virtual - Whether CPU is in virtual or physical mode
298 EFI_SUCCESS - Successfully returns
299 EFI_INVALID_PARAMETER - Instance not found
308 EFI_FW_VOL_INSTANCE
*FwhInstance
;
309 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
313 // Find the right instance of the FVB private data
315 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
316 ASSERT_EFI_ERROR (Status
);
320 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
323 // Parse the blockmap of the FV to find which map entry the Lba belongs to
326 NumBlocks
= BlockMap
->NumBlocks
;
327 BlockLength
= BlockMap
->Length
;
329 if (NumBlocks
== 0 || BlockLength
== 0) {
330 return EFI_INVALID_PARAMETER
;
333 NextLba
= StartLba
+ NumBlocks
;
336 // The map entry found
338 if (Lba
>= StartLba
&& Lba
< NextLba
) {
339 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
340 if (LbaAddress
!= NULL
) {
341 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
344 if (LbaLength
!= NULL
) {
345 *LbaLength
= BlockLength
;
348 if (NumOfBlocks
!= NULL
) {
349 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
356 Offset
= Offset
+ NumBlocks
* BlockLength
;
365 IN UINTN BlockOffset
,
366 IN OUT UINTN
*NumBytes
,
368 IN ESAL_FWB_GLOBAL
*Global
,
374 Reads specified number of bytes into a buffer from the specified block
377 Instance - The FV instance to be read from
378 Lba - The logical block address to be read from
379 BlockOffset - Offset into the block at which to begin reading
380 NumBytes - Pointer that on input contains the total size of
381 the buffer. On output, it contains the total number
383 Buffer - Pointer to a caller allocated buffer that will be
384 used to hold the data read
385 Global - Pointer to ESAL_FWB_GLOBAL that contains all
387 Virtual - Whether CPU is in virtual or physical mode
390 EFI_SUCCESS - The firmware volume was read successfully and
391 contents are in Buffer
392 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
393 NumBytes contains the total number of bytes returned
395 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
396 EFI_DEVICE_ERROR - The block device is not functioning correctly and
398 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
402 EFI_FVB_ATTRIBUTES_2 Attributes
;
408 // Check for invalid conditions
410 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
411 return EFI_INVALID_PARAMETER
;
414 if (*NumBytes
== 0) {
415 return EFI_INVALID_PARAMETER
;
418 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
419 if (EFI_ERROR (Status
)) {
423 // Check if the FV is read enabled
425 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
427 if ((Attributes
& EFI_FVB2_READ_STATUS
) == 0) {
428 return EFI_ACCESS_DENIED
;
431 // Perform boundary checks and adjust NumBytes
433 if (BlockOffset
> LbaLength
) {
434 return EFI_INVALID_PARAMETER
;
437 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
438 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
439 Status
= EFI_BAD_BUFFER_SIZE
;
442 CopyMem (Buffer
, (UINT8
*) (LbaAddress
+ BlockOffset
), (UINTN
) (*NumBytes
));
451 IN UINTN BlockOffset
,
452 IN OUT UINTN
*NumBytes
,
454 IN ESAL_FWB_GLOBAL
*Global
,
460 Writes specified number of bytes from the input buffer to the block
463 Instance - The FV instance to be written to
464 Lba - The starting logical block index to write to
465 BlockOffset - Offset into the block at which to begin writing
466 NumBytes - Pointer that on input contains the total size of
467 the buffer. On output, it contains the total number
468 of bytes actually written
469 Buffer - Pointer to a caller allocated buffer that contains
470 the source for the write
471 Global - Pointer to ESAL_FWB_GLOBAL that contains all
473 Virtual - Whether CPU is in virtual or physical mode
476 EFI_SUCCESS - The firmware volume was written successfully
477 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
478 NumBytes contains the total number of bytes
480 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
481 EFI_DEVICE_ERROR - The block device is not functioning correctly and
483 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
487 EFI_FVB_ATTRIBUTES_2 Attributes
;
493 // Check for invalid conditions
495 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
496 return EFI_INVALID_PARAMETER
;
499 if (*NumBytes
== 0) {
500 return EFI_INVALID_PARAMETER
;
503 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
504 if (EFI_ERROR (Status
)) {
508 // Check if the FV is write enabled
510 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
512 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
513 return EFI_ACCESS_DENIED
;
516 // Perform boundary checks and adjust NumBytes
518 if (BlockOffset
> LbaLength
) {
519 return EFI_INVALID_PARAMETER
;
522 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
523 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
524 Status
= EFI_BAD_BUFFER_SIZE
;
529 CopyMem ((UINT8
*) (LbaAddress
+ BlockOffset
), Buffer
, (UINTN
) (*NumBytes
));
538 IN ESAL_FWB_GLOBAL
*Global
,
544 Erases and initializes a firmware volume block
547 Instance - The FV instance to be erased
548 Lba - The logical block index to be erased
549 Global - Pointer to ESAL_FWB_GLOBAL that contains all
551 Virtual - Whether CPU is in virtual or physical mode
554 EFI_SUCCESS - The erase request was successfully completed
555 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
556 EFI_DEVICE_ERROR - The block device is not functioning correctly and
557 could not be written. Firmware device may have been
559 EFI_INVALID_PARAMETER - Instance not found
564 EFI_FVB_ATTRIBUTES_2 Attributes
;
571 // Check if the FV is write enabled
573 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
575 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
576 return EFI_ACCESS_DENIED
;
579 // Get the starting address of the block for erase.
581 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
583 if (EFI_ERROR (Status
)) {
587 if ((Attributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
593 SetMem ((UINT8
*) LbaAddress
, LbaLength
, Data
);
599 FvbSetVolumeAttributes (
601 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
602 IN ESAL_FWB_GLOBAL
*Global
,
608 Modifies the current settings of the firmware volume according to the
609 input parameter, and returns the new setting of the volume
612 Instance - The FV instance whose attributes is going to be
614 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
615 containing the desired firmware volume settings.
616 On successful return, it contains the new settings
617 of the firmware volume
618 Global - Pointer to ESAL_FWB_GLOBAL that contains all
620 Virtual - Whether CPU is in virtual or physical mode
623 EFI_SUCCESS - Successfully returns
624 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
625 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
626 in conflict with the capabilities as declared in the
627 firmware volume header
631 EFI_FW_VOL_INSTANCE
*FwhInstance
;
632 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
633 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
638 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes
;
642 // Find the right instance of the FVB private data
644 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
645 ASSERT_EFI_ERROR (Status
);
647 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
648 OldAttributes
= *AttribPtr
;
649 Capabilities
= OldAttributes
& (EFI_FVB2_READ_DISABLED_CAP
| \
650 EFI_FVB2_READ_ENABLED_CAP
| \
651 EFI_FVB2_WRITE_DISABLED_CAP
| \
652 EFI_FVB2_WRITE_ENABLED_CAP
| \
656 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
657 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
658 UnchangedAttributes
= EFI_FVB2_READ_DISABLED_CAP
| \
659 EFI_FVB2_READ_ENABLED_CAP
| \
660 EFI_FVB2_WRITE_DISABLED_CAP
| \
661 EFI_FVB2_WRITE_ENABLED_CAP
| \
662 EFI_FVB2_LOCK_CAP
| \
663 EFI_FVB2_STICKY_WRITE
| \
664 EFI_FVB2_MEMORY_MAPPED
| \
665 EFI_FVB2_ERASE_POLARITY
| \
666 EFI_FVB2_READ_LOCK_CAP
| \
667 EFI_FVB2_WRITE_LOCK_CAP
| \
671 // Some attributes of FV is read only can *not* be set
673 if ((OldAttributes
& UnchangedAttributes
) ^ (*Attributes
& UnchangedAttributes
)) {
674 return EFI_INVALID_PARAMETER
;
678 // If firmware volume is locked, no status bit can be updated
680 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
681 if (OldStatus
^ NewStatus
) {
682 return EFI_ACCESS_DENIED
;
688 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
689 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
690 return EFI_INVALID_PARAMETER
;
696 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
697 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
698 return EFI_INVALID_PARAMETER
;
702 // Test write disable
704 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
705 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
706 return EFI_INVALID_PARAMETER
;
712 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
713 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
714 return EFI_INVALID_PARAMETER
;
720 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
721 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
722 return EFI_INVALID_PARAMETER
;
726 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
727 *AttribPtr
= (*AttribPtr
) | NewStatus
;
728 *Attributes
= *AttribPtr
;
737 FvbProtocolGetPhysicalAddress (
738 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
739 OUT EFI_PHYSICAL_ADDRESS
*Address
745 Retrieves the physical address of the device.
749 This - Calling context
750 Address - Output buffer containing the address.
755 EFI_SUCCESS - Successfully returns
759 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
761 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
763 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
768 FvbProtocolGetBlockSize (
769 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
771 OUT UINTN
*BlockSize
,
772 OUT UINTN
*NumOfBlocks
777 Retrieve the size of a logical block
780 This - Calling context
781 Lba - Indicates which block to return the size for.
782 BlockSize - A pointer to a caller allocated UINTN in which
783 the size of the block is returned
784 NumOfBlocks - a pointer to a caller allocated UINTN in which the
785 number of consecutive blocks starting with Lba is
786 returned. All blocks in this range have a size of
790 EFI_SUCCESS - The firmware volume was read successfully and
791 contents are in Buffer
795 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
797 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
799 return FvbGetLbaAddress (
812 FvbProtocolGetAttributes (
813 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
814 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
819 Retrieves Volume attributes. No polarity translations are done.
822 This - Calling context
823 Attributes - output buffer which contains attributes
826 EFI_SUCCESS - Successfully returns
830 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
832 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
834 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
839 FvbProtocolSetAttributes (
840 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
841 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
846 Sets Volume attributes. No polarity translations are done.
849 This - Calling context
850 Attributes - output buffer which contains attributes
853 EFI_SUCCESS - Successfully returns
857 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
859 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
861 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
866 FvbProtocolEraseBlocks (
867 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
874 The EraseBlock() function erases one or more blocks as denoted by the
875 variable argument list. The entire parameter list of blocks must be verified
876 prior to erasing any blocks. If a block is requested that does not exist
877 within the associated firmware volume (it has a larger index than the last
878 block of the firmware volume), the EraseBlock() function must return
879 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
882 This - Calling context
883 ... - Starting LBA followed by Number of Lba to erase.
884 a -1 to terminate the list.
887 EFI_SUCCESS - The erase request was successfully completed
888 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
889 EFI_DEVICE_ERROR - The block device is not functioning correctly and
890 could not be written. Firmware device may have been
895 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
896 EFI_FW_VOL_INSTANCE
*FwhInstance
;
903 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
905 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
906 ASSERT_EFI_ERROR (Status
);
908 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
910 VA_START (args
, This
);
913 StartingLba
= VA_ARG (args
, EFI_LBA
);
914 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
918 NumOfLba
= VA_ARG (args
, UINT32
);
921 // Check input parameters
925 return EFI_INVALID_PARAMETER
;
928 if ((StartingLba
+ NumOfLba
) > NumOfBlocks
) {
929 return EFI_INVALID_PARAMETER
;
935 VA_START (args
, This
);
937 StartingLba
= VA_ARG (args
, EFI_LBA
);
938 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
942 NumOfLba
= VA_ARG (args
, UINT32
);
944 while (NumOfLba
> 0) {
945 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
946 if (EFI_ERROR (Status
)) {
965 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
968 IN OUT UINTN
*NumBytes
,
975 Writes data beginning at Lba:Offset from FV. The write terminates either
976 when *NumBytes of data have been written, or when a block boundary is
977 reached. *NumBytes is updated to reflect the actual number of bytes
978 written. The write opertion does not include erase. This routine will
979 attempt to write only the specified bytes. If the writes do not stick,
980 it will return an error.
983 This - Calling context
984 Lba - Block in which to begin write
985 Offset - Offset in the block at which to begin write
986 NumBytes - On input, indicates the requested write size. On
987 output, indicates the actual number of bytes written
988 Buffer - Buffer containing source data for the write.
991 EFI_SUCCESS - The firmware volume was written successfully
992 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
993 NumBytes contains the total number of bytes
995 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
996 EFI_DEVICE_ERROR - The block device is not functioning correctly and
998 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1003 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1005 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1007 return FvbWriteBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1013 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1016 IN OUT UINTN
*NumBytes
,
1021 Routine Description:
1023 Reads data beginning at Lba:Offset from FV. The Read terminates either
1024 when *NumBytes of data have been read, or when a block boundary is
1025 reached. *NumBytes is updated to reflect the actual number of bytes
1026 written. The write opertion does not include erase. This routine will
1027 attempt to write only the specified bytes. If the writes do not stick,
1028 it will return an error.
1031 This - Calling context
1032 Lba - Block in which to begin Read
1033 Offset - Offset in the block at which to begin Read
1034 NumBytes - On input, indicates the requested write size. On
1035 output, indicates the actual number of bytes Read
1036 Buffer - Buffer containing source data for the Read.
1039 EFI_SUCCESS - The firmware volume was read successfully and
1040 contents are in Buffer
1041 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1042 NumBytes contains the total number of bytes returned
1044 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1045 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1047 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1052 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1054 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1056 return FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1060 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1064 Routine Description:
1065 Check the integrity of firmware volume header
1068 FwVolHeader - A pointer to a firmware volume header
1071 EFI_SUCCESS - The firmware volume is consistent
1072 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1077 UINT16 HeaderLength
;
1081 // Verify the header revision, header signature, length
1082 // Length of FvBlock cannot be 2**64-1
1083 // HeaderLength cannot be an odd number
1085 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1086 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1087 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
1088 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1090 return EFI_NOT_FOUND
;
1093 // Verify the header checksum
1095 HeaderLength
= (UINT16
) (FwVolHeader
->HeaderLength
/ 2);
1096 Ptr
= (UINT16
*) FwVolHeader
;
1098 while (HeaderLength
> 0) {
1099 Checksum
= Checksum
+ (*Ptr
);
1104 if (Checksum
!= 0) {
1105 return EFI_NOT_FOUND
;
1114 IN EFI_HANDLE ImageHandle
,
1115 IN EFI_SYSTEM_TABLE
*SystemTable
1119 Routine Description:
1120 This function does common initialization for FVB services
1129 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1130 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1131 EFI_DXE_SERVICES
*DxeServices
;
1132 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
1134 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1135 EFI_HANDLE FwbHandle
;
1136 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1137 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1138 EFI_DEVICE_PATH_PROTOCOL
*TempFwbDevicePath
;
1139 FV_DEVICE_PATH TempFvbDevicePathData
;
1141 EFI_PHYSICAL_ADDRESS BaseAddress
;
1144 EFI_PEI_HOB_POINTERS FvHob
;
1147 // Get the DXE services table
1152 // Allocate runtime services data for global variable, which contains
1153 // the private data of all firmware volume block instances
1155 Status
= gBS
->AllocatePool (
1156 EfiRuntimeServicesData
,
1157 sizeof (ESAL_FWB_GLOBAL
),
1158 (VOID
**) &mFvbModuleGlobal
1160 ASSERT_EFI_ERROR (Status
);
1163 // Calculate the total size for all firmware volume block instances
1167 FvHob
.Raw
= GetHobList ();
1168 while ((FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
)) != NULL
) {
1169 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1170 Length
= FvHob
.FirmwareVolume
->Length
;
1172 // Check if it is a "real" flash
1174 Status
= DxeServices
->GetMemorySpaceDescriptor (
1178 if (EFI_ERROR (Status
)) {
1182 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1183 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1187 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1188 Status
= ValidateFvHeader (FwVolHeader
);
1189 if (EFI_ERROR (Status
)) {
1193 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1194 if (EFI_ERROR (Status
)) {
1195 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1200 BufferSize
+= (sizeof (EFI_FW_VOL_INSTANCE
) + FwVolHeader
->HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1201 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1205 // Only need to allocate once. There is only one copy of physical memory for
1206 // the private data of each FV instance. But in virtual mode or in physical
1207 // mode, the address of the the physical memory may be different.
1209 Status
= gBS
->AllocatePool (
1210 EfiRuntimeServicesData
,
1212 (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
]
1214 ASSERT_EFI_ERROR (Status
);
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 Status
= gBS
->AllocatePool (
1296 EfiRuntimeServicesData
,
1297 sizeof (EFI_FW_VOL_BLOCK_DEVICE
),
1300 ASSERT_EFI_ERROR (Status
);
1302 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1304 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1305 mFvbModuleGlobal
->NumFv
++;
1308 // Set up the devicepath
1310 FvbDevice
->DevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
1311 FvbDevice
->DevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ (FwVolHeader
->FvLength
- 1);
1314 // Find a handle with a matching device path that has supports FW Block protocol
1316 TempFwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) &TempFvbDevicePathData
;
1317 CopyMem (TempFwbDevicePath
, &FvbDevice
->DevicePath
, sizeof (FV_DEVICE_PATH
));
1318 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &TempFwbDevicePath
, &FwbHandle
);
1319 if (EFI_ERROR (Status
)) {
1321 // LocateDevicePath fails so install a new interface and device path
1324 Status
= gBS
->InstallMultipleProtocolInterfaces (
1326 &gEfiFirmwareVolumeBlockProtocolGuid
,
1327 &FvbDevice
->FwVolBlockInstance
,
1328 &gEfiDevicePathProtocolGuid
,
1329 &FvbDevice
->DevicePath
,
1332 ASSERT_EFI_ERROR (Status
);
1333 } else if (IsDevicePathEnd (TempFwbDevicePath
)) {
1335 // Device allready exists, so reinstall the FVB protocol
1337 Status
= gBS
->HandleProtocol (
1339 &gEfiFirmwareVolumeBlockProtocolGuid
,
1340 (VOID
**)&OldFwbInterface
1342 ASSERT_EFI_ERROR (Status
);
1344 Status
= gBS
->ReinstallProtocolInterface (
1346 &gEfiFirmwareVolumeBlockProtocolGuid
,
1348 &FvbDevice
->FwVolBlockInstance
1350 ASSERT_EFI_ERROR (Status
);
1354 // There was a FVB protocol on an End Device Path node
1359 Status
= gBS
->InstallMultipleProtocolInterfaces (
1361 &gEfiAlternateFvBlockGuid
,
1366 ASSERT_EFI_ERROR (Status
);
1368 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1370 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1371 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1374 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);