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 <Protocol/DevicePath.h>
27 #include <Library/UefiLib.h>
28 #include <Library/UefiDriverEntryPoint.h>
29 #include <Library/BaseLib.h>
30 #include <Library/DxeServicesTableLib.h>
31 #include <Library/UefiRuntimeLib.h>
32 #include <Library/DebugLib.h>
33 #include <Library/HobLib.h>
34 #include <Library/BaseMemoryLib.h>
35 #include <Library/MemoryAllocationLib.h>
36 #include <Library/UefiBootServicesTableLib.h>
37 #include <Library/DevicePathLib.h>
39 #include "FwBlockService.h"
41 ESAL_FWB_GLOBAL
*mFvbModuleGlobal
;
43 #define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
45 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate
= {
53 sizeof (MEMMAP_DEVICE_PATH
),
63 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
65 sizeof (EFI_DEVICE_PATH_PROTOCOL
),
72 FvbProtocolGetAttributes
,
73 FvbProtocolSetAttributes
,
74 FvbProtocolGetPhysicalAddress
,
75 FvbProtocolGetBlockSize
,
78 FvbProtocolEraseBlocks
,
87 FvbVirtualddressChangeEvent (
95 Fixup internal data so that EFI and SAL can be call in virtual mode.
96 Call the passed in Child Notify event and convert the mFvbModuleGlobal
97 date items to there virtual address.
99 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
100 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
105 (Standard EFI notify event - EFI_EVENT_NOTIFY)
113 EFI_FW_VOL_INSTANCE
*FwhInstance
;
116 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
]);
119 // Convert the base address of all the instances
122 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
123 while (Index
< mFvbModuleGlobal
->NumFv
) {
124 EfiConvertPointer (0x0, (VOID
**) &FwhInstance
->FvBase
[FVB_VIRTUAL
]);
125 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
127 (UINTN
) ((UINT8
*) FwhInstance
) + FwhInstance
->VolumeHeader
.HeaderLength
+
128 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
133 EfiConvertPointer (0x0, (VOID
**) &mFvbModuleGlobal
);
139 IN ESAL_FWB_GLOBAL
*Global
,
140 OUT EFI_FW_VOL_INSTANCE
**FwhInstance
,
146 Retrieves the physical address of a memory mapped FV
149 Instance - The FV instance whose base address is going to be
151 Global - Pointer to ESAL_FWB_GLOBAL that contains all
153 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
154 Virtual - Whether CPU is in virtual or physical mode
157 EFI_SUCCESS - Successfully returns
158 EFI_INVALID_PARAMETER - Instance not found
162 EFI_FW_VOL_INSTANCE
*FwhRecord
;
164 if (Instance
>= Global
->NumFv
) {
165 return EFI_INVALID_PARAMETER
;
168 // Find the right instance of the FVB private data
170 FwhRecord
= Global
->FvInstance
[Virtual
];
171 while (Instance
> 0) {
172 FwhRecord
= (EFI_FW_VOL_INSTANCE
*)
174 (UINTN
) ((UINT8
*) FwhRecord
) + FwhRecord
->VolumeHeader
.HeaderLength
+
175 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
180 *FwhInstance
= FwhRecord
;
186 FvbGetPhysicalAddress (
188 OUT EFI_PHYSICAL_ADDRESS
*Address
,
189 IN ESAL_FWB_GLOBAL
*Global
,
195 Retrieves the physical address of a memory mapped FV
198 Instance - The FV instance whose base address is going to be
200 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
201 that on successful return, contains the base address
202 of the firmware volume.
203 Global - Pointer to ESAL_FWB_GLOBAL that contains all
205 Virtual - Whether CPU is in virtual or physical mode
208 EFI_SUCCESS - Successfully returns
209 EFI_INVALID_PARAMETER - Instance not found
213 EFI_FW_VOL_INSTANCE
*FwhInstance
;
217 // Find the right instance of the FVB private data
219 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
220 ASSERT_EFI_ERROR (Status
);
221 *Address
= FwhInstance
->FvBase
[Virtual
];
227 FvbGetVolumeAttributes (
229 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
230 IN ESAL_FWB_GLOBAL
*Global
,
236 Retrieves attributes, insures positive polarity of attribute bits, returns
237 resulting attributes in output parameter
240 Instance - The FV instance whose attributes is going to be
242 Attributes - Output buffer which contains attributes
243 Global - Pointer to ESAL_FWB_GLOBAL that contains all
245 Virtual - Whether CPU is in virtual or physical mode
248 EFI_SUCCESS - Successfully returns
249 EFI_INVALID_PARAMETER - Instance not found
253 EFI_FW_VOL_INSTANCE
*FwhInstance
;
257 // Find the right instance of the FVB private data
259 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
260 ASSERT_EFI_ERROR (Status
);
261 *Attributes
= FwhInstance
->VolumeHeader
.Attributes
;
270 OUT UINTN
*LbaAddress
,
271 OUT UINTN
*LbaLength
,
272 OUT UINTN
*NumOfBlocks
,
273 IN ESAL_FWB_GLOBAL
*Global
,
279 Retrieves the starting address of an LBA in an FV
282 Instance - The FV instance which the Lba belongs to
283 Lba - The logical block address
284 LbaAddress - On output, contains the physical starting address
286 LbaLength - On output, contains the length of the block
287 NumOfBlocks - A pointer to a caller allocated UINTN in which the
288 number of consecutive blocks starting with Lba is
289 returned. All blocks in this range have a size of
291 Global - Pointer to ESAL_FWB_GLOBAL that contains all
293 Virtual - Whether CPU is in virtual or physical mode
296 EFI_SUCCESS - Successfully returns
297 EFI_INVALID_PARAMETER - Instance not found
306 EFI_FW_VOL_INSTANCE
*FwhInstance
;
307 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
311 // Find the right instance of the FVB private data
313 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
314 ASSERT_EFI_ERROR (Status
);
318 BlockMap
= &(FwhInstance
->VolumeHeader
.BlockMap
[0]);
321 // Parse the blockmap of the FV to find which map entry the Lba belongs to
324 NumBlocks
= BlockMap
->NumBlocks
;
325 BlockLength
= BlockMap
->Length
;
327 if (NumBlocks
== 0 || BlockLength
== 0) {
328 return EFI_INVALID_PARAMETER
;
331 NextLba
= StartLba
+ NumBlocks
;
334 // The map entry found
336 if (Lba
>= StartLba
&& Lba
< NextLba
) {
337 Offset
= Offset
+ (UINTN
) MultU64x32 ((Lba
- StartLba
), BlockLength
);
338 if (LbaAddress
!= NULL
) {
339 *LbaAddress
= FwhInstance
->FvBase
[Virtual
] + Offset
;
342 if (LbaLength
!= NULL
) {
343 *LbaLength
= BlockLength
;
346 if (NumOfBlocks
!= NULL
) {
347 *NumOfBlocks
= (UINTN
) (NextLba
- Lba
);
354 Offset
= Offset
+ NumBlocks
* BlockLength
;
363 IN UINTN BlockOffset
,
364 IN OUT UINTN
*NumBytes
,
366 IN ESAL_FWB_GLOBAL
*Global
,
372 Reads specified number of bytes into a buffer from the specified block
375 Instance - The FV instance to be read from
376 Lba - The logical block address to be read from
377 BlockOffset - Offset into the block at which to begin reading
378 NumBytes - Pointer that on input contains the total size of
379 the buffer. On output, it contains the total number
381 Buffer - Pointer to a caller allocated buffer that will be
382 used to hold the data read
383 Global - Pointer to ESAL_FWB_GLOBAL that contains all
385 Virtual - Whether CPU is in virtual or physical mode
388 EFI_SUCCESS - The firmware volume was read successfully and
389 contents are in Buffer
390 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
391 NumBytes contains the total number of bytes returned
393 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
394 EFI_DEVICE_ERROR - The block device is not functioning correctly and
396 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
400 EFI_FVB_ATTRIBUTES_2 Attributes
;
406 // Check for invalid conditions
408 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
409 return EFI_INVALID_PARAMETER
;
412 if (*NumBytes
== 0) {
413 return EFI_INVALID_PARAMETER
;
416 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
417 if (EFI_ERROR (Status
)) {
421 // Check if the FV is read enabled
423 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
425 if ((Attributes
& EFI_FVB2_READ_STATUS
) == 0) {
426 return EFI_ACCESS_DENIED
;
429 // Perform boundary checks and adjust NumBytes
431 if (BlockOffset
> LbaLength
) {
432 return EFI_INVALID_PARAMETER
;
435 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
436 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
437 Status
= EFI_BAD_BUFFER_SIZE
;
440 CopyMem (Buffer
, (UINT8
*) (LbaAddress
+ BlockOffset
), (UINTN
) (*NumBytes
));
449 IN UINTN BlockOffset
,
450 IN OUT UINTN
*NumBytes
,
452 IN ESAL_FWB_GLOBAL
*Global
,
458 Writes specified number of bytes from the input buffer to the block
461 Instance - The FV instance to be written to
462 Lba - The starting logical block index to write to
463 BlockOffset - Offset into the block at which to begin writing
464 NumBytes - Pointer that on input contains the total size of
465 the buffer. On output, it contains the total number
466 of bytes actually written
467 Buffer - Pointer to a caller allocated buffer that contains
468 the source for the write
469 Global - Pointer to ESAL_FWB_GLOBAL that contains all
471 Virtual - Whether CPU is in virtual or physical mode
474 EFI_SUCCESS - The firmware volume was written successfully
475 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
476 NumBytes contains the total number of bytes
478 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
479 EFI_DEVICE_ERROR - The block device is not functioning correctly and
481 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
485 EFI_FVB_ATTRIBUTES_2 Attributes
;
491 // Check for invalid conditions
493 if ((NumBytes
== NULL
) || (Buffer
== NULL
)) {
494 return EFI_INVALID_PARAMETER
;
497 if (*NumBytes
== 0) {
498 return EFI_INVALID_PARAMETER
;
501 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
502 if (EFI_ERROR (Status
)) {
506 // Check if the FV is write enabled
508 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
510 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
511 return EFI_ACCESS_DENIED
;
514 // Perform boundary checks and adjust NumBytes
516 if (BlockOffset
> LbaLength
) {
517 return EFI_INVALID_PARAMETER
;
520 if (LbaLength
< (*NumBytes
+ BlockOffset
)) {
521 *NumBytes
= (UINT32
) (LbaLength
- BlockOffset
);
522 Status
= EFI_BAD_BUFFER_SIZE
;
527 CopyMem ((UINT8
*) (LbaAddress
+ BlockOffset
), Buffer
, (UINTN
) (*NumBytes
));
536 IN ESAL_FWB_GLOBAL
*Global
,
542 Erases and initializes a firmware volume block
545 Instance - The FV instance to be erased
546 Lba - The logical block index to be erased
547 Global - Pointer to ESAL_FWB_GLOBAL that contains all
549 Virtual - Whether CPU is in virtual or physical mode
552 EFI_SUCCESS - The erase request was successfully completed
553 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
554 EFI_DEVICE_ERROR - The block device is not functioning correctly and
555 could not be written. Firmware device may have been
557 EFI_INVALID_PARAMETER - Instance not found
562 EFI_FVB_ATTRIBUTES_2 Attributes
;
569 // Check if the FV is write enabled
571 FvbGetVolumeAttributes (Instance
, &Attributes
, Global
, Virtual
);
573 if ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0) {
574 return EFI_ACCESS_DENIED
;
577 // Get the starting address of the block for erase.
579 Status
= FvbGetLbaAddress (Instance
, Lba
, &LbaAddress
, &LbaLength
, NULL
, Global
, Virtual
);
581 if (EFI_ERROR (Status
)) {
585 if ((Attributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
591 SetMem ((UINT8
*) LbaAddress
, LbaLength
, Data
);
597 FvbSetVolumeAttributes (
599 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
,
600 IN ESAL_FWB_GLOBAL
*Global
,
606 Modifies the current settings of the firmware volume according to the
607 input parameter, and returns the new setting of the volume
610 Instance - The FV instance whose attributes is going to be
612 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
613 containing the desired firmware volume settings.
614 On successful return, it contains the new settings
615 of the firmware volume
616 Global - Pointer to ESAL_FWB_GLOBAL that contains all
618 Virtual - Whether CPU is in virtual or physical mode
621 EFI_SUCCESS - Successfully returns
622 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
623 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
624 in conflict with the capabilities as declared in the
625 firmware volume header
629 EFI_FW_VOL_INSTANCE
*FwhInstance
;
630 EFI_FVB_ATTRIBUTES_2 OldAttributes
;
631 EFI_FVB_ATTRIBUTES_2
*AttribPtr
;
636 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes
;
640 // Find the right instance of the FVB private data
642 Status
= GetFvbInstance (Instance
, Global
, &FwhInstance
, Virtual
);
643 ASSERT_EFI_ERROR (Status
);
645 AttribPtr
= (EFI_FVB_ATTRIBUTES_2
*) &(FwhInstance
->VolumeHeader
.Attributes
);
646 OldAttributes
= *AttribPtr
;
647 Capabilities
= OldAttributes
& (EFI_FVB2_READ_DISABLED_CAP
| \
648 EFI_FVB2_READ_ENABLED_CAP
| \
649 EFI_FVB2_WRITE_DISABLED_CAP
| \
650 EFI_FVB2_WRITE_ENABLED_CAP
| \
654 OldStatus
= OldAttributes
& EFI_FVB2_STATUS
;
655 NewStatus
= *Attributes
& EFI_FVB2_STATUS
;
656 UnchangedAttributes
= EFI_FVB2_READ_DISABLED_CAP
| \
657 EFI_FVB2_READ_ENABLED_CAP
| \
658 EFI_FVB2_WRITE_DISABLED_CAP
| \
659 EFI_FVB2_WRITE_ENABLED_CAP
| \
660 EFI_FVB2_LOCK_CAP
| \
661 EFI_FVB2_STICKY_WRITE
| \
662 EFI_FVB2_MEMORY_MAPPED
| \
663 EFI_FVB2_ERASE_POLARITY
| \
664 EFI_FVB2_READ_LOCK_CAP
| \
665 EFI_FVB2_WRITE_LOCK_CAP
| \
669 // Some attributes of FV is read only can *not* be set
671 if ((OldAttributes
& UnchangedAttributes
) ^ (*Attributes
& UnchangedAttributes
)) {
672 return EFI_INVALID_PARAMETER
;
676 // If firmware volume is locked, no status bit can be updated
678 if (OldAttributes
& EFI_FVB2_LOCK_STATUS
) {
679 if (OldStatus
^ NewStatus
) {
680 return EFI_ACCESS_DENIED
;
686 if ((Capabilities
& EFI_FVB2_READ_DISABLED_CAP
) == 0) {
687 if ((NewStatus
& EFI_FVB2_READ_STATUS
) == 0) {
688 return EFI_INVALID_PARAMETER
;
694 if ((Capabilities
& EFI_FVB2_READ_ENABLED_CAP
) == 0) {
695 if (NewStatus
& EFI_FVB2_READ_STATUS
) {
696 return EFI_INVALID_PARAMETER
;
700 // Test write disable
702 if ((Capabilities
& EFI_FVB2_WRITE_DISABLED_CAP
) == 0) {
703 if ((NewStatus
& EFI_FVB2_WRITE_STATUS
) == 0) {
704 return EFI_INVALID_PARAMETER
;
710 if ((Capabilities
& EFI_FVB2_WRITE_ENABLED_CAP
) == 0) {
711 if (NewStatus
& EFI_FVB2_WRITE_STATUS
) {
712 return EFI_INVALID_PARAMETER
;
718 if ((Capabilities
& EFI_FVB2_LOCK_CAP
) == 0) {
719 if (NewStatus
& EFI_FVB2_LOCK_STATUS
) {
720 return EFI_INVALID_PARAMETER
;
724 *AttribPtr
= (*AttribPtr
) & (0xFFFFFFFF & (~EFI_FVB2_STATUS
));
725 *AttribPtr
= (*AttribPtr
) | NewStatus
;
726 *Attributes
= *AttribPtr
;
735 FvbProtocolGetPhysicalAddress (
736 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
737 OUT EFI_PHYSICAL_ADDRESS
*Address
743 Retrieves the physical address of the device.
747 This - Calling context
748 Address - Output buffer containing the address.
753 EFI_SUCCESS - Successfully returns
757 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
759 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
761 return FvbGetPhysicalAddress (FvbDevice
->Instance
, Address
, mFvbModuleGlobal
, EfiGoneVirtual ());
766 FvbProtocolGetBlockSize (
767 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
769 OUT UINTN
*BlockSize
,
770 OUT UINTN
*NumOfBlocks
775 Retrieve the size of a logical block
778 This - Calling context
779 Lba - Indicates which block to return the size for.
780 BlockSize - A pointer to a caller allocated UINTN in which
781 the size of the block is returned
782 NumOfBlocks - a pointer to a caller allocated UINTN in which the
783 number of consecutive blocks starting with Lba is
784 returned. All blocks in this range have a size of
788 EFI_SUCCESS - The firmware volume was read successfully and
789 contents are in Buffer
793 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
795 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
797 return FvbGetLbaAddress (
810 FvbProtocolGetAttributes (
811 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
812 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
817 Retrieves Volume attributes. No polarity translations are done.
820 This - Calling context
821 Attributes - output buffer which contains attributes
824 EFI_SUCCESS - Successfully returns
828 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
830 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
832 return FvbGetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
837 FvbProtocolSetAttributes (
838 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
839 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
844 Sets Volume attributes. No polarity translations are done.
847 This - Calling context
848 Attributes - output buffer which contains attributes
851 EFI_SUCCESS - Successfully returns
855 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
857 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
859 return FvbSetVolumeAttributes (FvbDevice
->Instance
, Attributes
, mFvbModuleGlobal
, EfiGoneVirtual ());
864 FvbProtocolEraseBlocks (
865 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
872 The EraseBlock() function erases one or more blocks as denoted by the
873 variable argument list. The entire parameter list of blocks must be verified
874 prior to erasing any blocks. If a block is requested that does not exist
875 within the associated firmware volume (it has a larger index than the last
876 block of the firmware volume), the EraseBlock() function must return
877 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
880 This - Calling context
881 ... - Starting LBA followed by Number of Lba to erase.
882 a -1 to terminate the list.
885 EFI_SUCCESS - The erase request was successfully completed
886 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
887 EFI_DEVICE_ERROR - The block device is not functioning correctly and
888 could not be written. Firmware device may have been
893 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
894 EFI_FW_VOL_INSTANCE
*FwhInstance
;
901 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
903 Status
= GetFvbInstance (FvbDevice
->Instance
, mFvbModuleGlobal
, &FwhInstance
, EfiGoneVirtual ());
904 ASSERT_EFI_ERROR (Status
);
906 NumOfBlocks
= FwhInstance
->NumOfBlocks
;
908 VA_START (args
, This
);
911 StartingLba
= VA_ARG (args
, EFI_LBA
);
912 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
916 NumOfLba
= VA_ARG (args
, UINT32
);
919 // Check input parameters
923 return EFI_INVALID_PARAMETER
;
926 if ((StartingLba
+ NumOfLba
) > NumOfBlocks
) {
927 return EFI_INVALID_PARAMETER
;
933 VA_START (args
, This
);
935 StartingLba
= VA_ARG (args
, EFI_LBA
);
936 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
940 NumOfLba
= VA_ARG (args
, UINT32
);
942 while (NumOfLba
> 0) {
943 Status
= FvbEraseBlock (FvbDevice
->Instance
, StartingLba
, mFvbModuleGlobal
, EfiGoneVirtual ());
944 if (EFI_ERROR (Status
)) {
963 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
966 IN OUT UINTN
*NumBytes
,
973 Writes data beginning at Lba:Offset from FV. The write terminates either
974 when *NumBytes of data have been written, or when a block boundary is
975 reached. *NumBytes is updated to reflect the actual number of bytes
976 written. The write opertion does not include erase. This routine will
977 attempt to write only the specified bytes. If the writes do not stick,
978 it will return an error.
981 This - Calling context
982 Lba - Block in which to begin write
983 Offset - Offset in the block at which to begin write
984 NumBytes - On input, indicates the requested write size. On
985 output, indicates the actual number of bytes written
986 Buffer - Buffer containing source data for the write.
989 EFI_SUCCESS - The firmware volume was written successfully
990 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
991 NumBytes contains the total number of bytes
993 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
994 EFI_DEVICE_ERROR - The block device is not functioning correctly and
996 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1001 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1003 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1005 return FvbWriteBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1011 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
1014 IN OUT UINTN
*NumBytes
,
1019 Routine Description:
1021 Reads data beginning at Lba:Offset from FV. The Read terminates either
1022 when *NumBytes of data have been read, or when a block boundary is
1023 reached. *NumBytes is updated to reflect the actual number of bytes
1024 written. The write opertion does not include erase. This routine will
1025 attempt to write only the specified bytes. If the writes do not stick,
1026 it will return an error.
1029 This - Calling context
1030 Lba - Block in which to begin Read
1031 Offset - Offset in the block at which to begin Read
1032 NumBytes - On input, indicates the requested write size. On
1033 output, indicates the actual number of bytes Read
1034 Buffer - Buffer containing source data for the Read.
1037 EFI_SUCCESS - The firmware volume was read successfully and
1038 contents are in Buffer
1039 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1040 NumBytes contains the total number of bytes returned
1042 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1043 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1045 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1050 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1052 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
1054 return FvbReadBlock (FvbDevice
->Instance
, Lba
, Offset
, NumBytes
, Buffer
, mFvbModuleGlobal
, EfiGoneVirtual ());
1058 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
1062 Routine Description:
1063 Check the integrity of firmware volume header
1066 FwVolHeader - A pointer to a firmware volume header
1069 EFI_SUCCESS - The firmware volume is consistent
1070 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1075 UINT16 HeaderLength
;
1079 // Verify the header revision, header signature, length
1080 // Length of FvBlock cannot be 2**64-1
1081 // HeaderLength cannot be an odd number
1083 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
1084 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
1085 (FwVolHeader
->FvLength
== ((UINTN
) -1)) ||
1086 ((FwVolHeader
->HeaderLength
& 0x01) != 0)
1088 return EFI_NOT_FOUND
;
1091 // Verify the header checksum
1093 HeaderLength
= (UINT16
) (FwVolHeader
->HeaderLength
/ 2);
1094 Ptr
= (UINT16
*) FwVolHeader
;
1096 while (HeaderLength
> 0) {
1097 Checksum
= Checksum
+ (*Ptr
);
1102 if (Checksum
!= 0) {
1103 return EFI_NOT_FOUND
;
1112 IN EFI_HANDLE ImageHandle
,
1113 IN EFI_SYSTEM_TABLE
*SystemTable
1117 Routine Description:
1118 This function does common initialization for FVB services
1127 EFI_FW_VOL_INSTANCE
*FwhInstance
;
1128 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1129 EFI_DXE_SERVICES
*DxeServices
;
1130 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
1132 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
1133 EFI_HANDLE FwbHandle
;
1134 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
1135 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
1136 EFI_DEVICE_PATH_PROTOCOL
*TempFwbDevicePath
;
1137 FV_DEVICE_PATH TempFvbDevicePathData
;
1139 EFI_PHYSICAL_ADDRESS BaseAddress
;
1142 EFI_PEI_HOB_POINTERS FvHob
;
1145 // Get the DXE services table
1150 // Allocate runtime services data for global variable, which contains
1151 // the private data of all firmware volume block instances
1153 Status
= gBS
->AllocatePool (
1154 EfiRuntimeServicesData
,
1155 sizeof (ESAL_FWB_GLOBAL
),
1156 (VOID
**) &mFvbModuleGlobal
1158 ASSERT_EFI_ERROR (Status
);
1161 // Calculate the total size for all firmware volume block instances
1165 FvHob
.Raw
= GetHobList ();
1166 while ((FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
)) != NULL
) {
1167 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1168 Length
= FvHob
.FirmwareVolume
->Length
;
1170 // Check if it is a "real" flash
1172 Status
= DxeServices
->GetMemorySpaceDescriptor (
1176 if (EFI_ERROR (Status
)) {
1180 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1181 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1185 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1186 Status
= ValidateFvHeader (FwVolHeader
);
1187 if (EFI_ERROR (Status
)) {
1191 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1192 if (EFI_ERROR (Status
)) {
1193 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1198 BufferSize
+= (sizeof (EFI_FW_VOL_INSTANCE
) + FwVolHeader
->HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
1199 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1203 // Only need to allocate once. There is only one copy of physical memory for
1204 // the private data of each FV instance. But in virtual mode or in physical
1205 // mode, the address of the the physical memory may be different.
1207 Status
= gBS
->AllocatePool (
1208 EfiRuntimeServicesData
,
1210 (VOID
**) &mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
]
1212 ASSERT_EFI_ERROR (Status
);
1215 // Make a virtual copy of the FvInstance pointer.
1217 FwhInstance
= mFvbModuleGlobal
->FvInstance
[FVB_PHYSICAL
];
1218 mFvbModuleGlobal
->FvInstance
[FVB_VIRTUAL
] = FwhInstance
;
1220 mFvbModuleGlobal
->NumFv
= 0;
1223 FvHob
.Raw
= GetHobList ();
1224 while (NULL
!= (FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
))) {
1225 BaseAddress
= FvHob
.FirmwareVolume
->BaseAddress
;
1226 Length
= FvHob
.FirmwareVolume
->Length
;
1228 // Check if it is a "real" flash
1230 Status
= DxeServices
->GetMemorySpaceDescriptor (
1234 if (EFI_ERROR (Status
)) {
1238 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeMemoryMappedIo
) {
1239 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1243 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) BaseAddress
;
1244 Status
= ValidateFvHeader (FwVolHeader
);
1245 if (EFI_ERROR (Status
)) {
1247 // Get FvbInfo to provide in FwhInstance.
1249 Status
= GetFvbInfo (Length
, &FwVolHeader
);
1250 if (EFI_ERROR (Status
)) {
1251 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
1255 // Write healthy FV header back.
1258 (VOID
*) (UINTN
) BaseAddress
,
1259 (VOID
*) FwVolHeader
,
1260 FwVolHeader
->HeaderLength
1264 FwhInstance
->FvBase
[FVB_PHYSICAL
] = (UINTN
) BaseAddress
;
1265 FwhInstance
->FvBase
[FVB_VIRTUAL
] = (UINTN
) BaseAddress
;
1267 CopyMem ((UINTN
*) &(FwhInstance
->VolumeHeader
), (UINTN
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
1268 FwVolHeader
= &(FwhInstance
->VolumeHeader
);
1269 EfiInitializeLock (&(FwhInstance
->FvbDevLock
), TPL_HIGH_LEVEL
);
1273 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
1275 // Get the maximum size of a block. The size will be used to allocate
1276 // buffer for Scratch space, the intermediate buffer for FVB extension
1279 if (MaxLbaSize
< PtrBlockMapEntry
->Length
) {
1280 MaxLbaSize
= PtrBlockMapEntry
->Length
;
1283 NumOfBlocks
= NumOfBlocks
+ PtrBlockMapEntry
->NumBlocks
;
1286 // The total number of blocks in the FV.
1288 FwhInstance
->NumOfBlocks
= NumOfBlocks
;
1291 // Add a FVB Protocol Instance
1293 Status
= gBS
->AllocatePool (
1294 EfiRuntimeServicesData
,
1295 sizeof (EFI_FW_VOL_BLOCK_DEVICE
),
1298 ASSERT_EFI_ERROR (Status
);
1300 CopyMem (FvbDevice
, &mFvbDeviceTemplate
, sizeof (EFI_FW_VOL_BLOCK_DEVICE
));
1302 FvbDevice
->Instance
= mFvbModuleGlobal
->NumFv
;
1303 mFvbModuleGlobal
->NumFv
++;
1306 // Set up the devicepath
1308 FvbDevice
->DevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
1309 FvbDevice
->DevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ (FwVolHeader
->FvLength
- 1);
1312 // Find a handle with a matching device path that has supports FW Block protocol
1314 TempFwbDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) &TempFvbDevicePathData
;
1315 CopyMem (TempFwbDevicePath
, &FvbDevice
->DevicePath
, sizeof (FV_DEVICE_PATH
));
1316 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &TempFwbDevicePath
, &FwbHandle
);
1317 if (EFI_ERROR (Status
)) {
1319 // LocateDevicePath fails so install a new interface and device path
1322 Status
= gBS
->InstallMultipleProtocolInterfaces (
1324 &gEfiFirmwareVolumeBlockProtocolGuid
,
1325 &FvbDevice
->FwVolBlockInstance
,
1326 &gEfiDevicePathProtocolGuid
,
1327 &FvbDevice
->DevicePath
,
1330 ASSERT_EFI_ERROR (Status
);
1331 } else if (IsDevicePathEnd (TempFwbDevicePath
)) {
1333 // Device allready exists, so reinstall the FVB protocol
1335 Status
= gBS
->HandleProtocol (
1337 &gEfiFirmwareVolumeBlockProtocolGuid
,
1338 (VOID
**)&OldFwbInterface
1340 ASSERT_EFI_ERROR (Status
);
1342 Status
= gBS
->ReinstallProtocolInterface (
1344 &gEfiFirmwareVolumeBlockProtocolGuid
,
1346 &FvbDevice
->FwVolBlockInstance
1348 ASSERT_EFI_ERROR (Status
);
1352 // There was a FVB protocol on an End Device Path node
1357 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
1359 (UINTN
) ((UINT8
*) FwhInstance
) + FwVolHeader
->HeaderLength
+
1360 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
1363 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);