2 Implementations for Firmware Volume Block protocol.
4 It consumes FV HOBs and creates read-lonly Firmare Volume Block protocol
5 instances for each of them.
7 Copyright (c) 2006 - 2008, Intel Corporation. <BR>
8 All rights reserved. This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 EFI_FW_VOL_BLOCK_DEVICE mFwVolBlock
= {
30 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
)),
31 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
) >> 8)
35 (EFI_PHYSICAL_ADDRESS
) 0,
36 (EFI_PHYSICAL_ADDRESS
) 0,
40 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
42 END_DEVICE_PATH_LENGTH
,
48 FwVolBlockGetAttributes
,
49 (EFI_FVB_SET_ATTRIBUTES
)FwVolBlockSetAttributes
,
50 FwVolBlockGetPhysicalAddress
,
51 FwVolBlockGetBlockSize
,
53 (EFI_FVB_WRITE
)FwVolBlockWriteBlock
,
54 (EFI_FVB_ERASE_BLOCKS
)FwVolBlockEraseBlock
,
66 Retrieves Volume attributes. No polarity translations are done.
68 @param This Calling context
69 @param Attributes output buffer which contains attributes
71 @retval EFI_SUCCESS The firmware volume attributes were returned.
76 FwVolBlockGetAttributes (
77 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
78 OUT EFI_FVB_ATTRIBUTES
*Attributes
81 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
83 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
86 // Since we are read only, it's safe to get attributes data from our in-memory copy.
88 *Attributes
= FvbDevice
->FvbAttributes
;
96 Modifies the current settings of the firmware volume according to the input parameter.
98 @param This Calling context
99 @param Attributes input buffer which contains attributes
101 @retval EFI_SUCCESS The firmware volume attributes were returned.
102 @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with
103 the capabilities as declared in the firmware
105 @retval EFI_UNSUPPORTED Not supported.
110 FwVolBlockSetAttributes (
111 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
112 IN CONST EFI_FVB_ATTRIBUTES
*Attributes
115 return EFI_UNSUPPORTED
;
121 The EraseBlock() function erases one or more blocks as denoted by the
122 variable argument list. The entire parameter list of blocks must be verified
123 prior to erasing any blocks. If a block is requested that does not exist
124 within the associated firmware volume (it has a larger index than the last
125 block of the firmware volume), the EraseBlock() function must return
126 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
128 @param This Calling context
129 @param ... Starting LBA followed by Number of Lba to erase.
130 a -1 to terminate the list.
132 @retval EFI_SUCCESS The erase request was successfully completed.
133 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
135 @retval EFI_DEVICE_ERROR The block device is not functioning correctly
136 and could not be written. The firmware device
137 may have been partially erased.
138 @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable
140 @retval EFI_UNSUPPORTED Not supported.
145 FwVolBlockEraseBlock (
146 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
150 return EFI_UNSUPPORTED
;
156 Read the specified number of bytes from the block to the input buffer.
158 @param This Indicates the calling context.
159 @param Lba The starting logical block index to read.
160 @param Offset Offset into the block at which to begin reading.
161 @param NumBytes Pointer to a UINT32. At entry, *NumBytes
162 contains the total size of the buffer. At exit,
163 *NumBytes contains the total number of bytes
165 @param Buffer Pinter to a caller-allocated buffer that
166 contains the destine for the read.
168 @retval EFI_SUCCESS The firmware volume was read successfully.
169 @retval EFI_BAD_BUFFER_SIZE The read was attempted across an LBA boundary.
170 @retval EFI_ACCESS_DENIED Access denied.
171 @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not
177 FwVolBlockReadBlock (
178 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
179 IN CONST EFI_LBA Lba
,
180 IN CONST UINTN Offset
,
181 IN OUT UINTN
*NumBytes
,
185 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
186 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
189 UINTN NumOfBytesRead
;
192 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
195 // Check if This FW can be read
197 if ((FvbDevice
->FvbAttributes
& EFI_FVB2_READ_STATUS
) == 0) {
198 return EFI_ACCESS_DENIED
;
201 LbaIndex
= (UINTN
) Lba
;
202 if (LbaIndex
>= FvbDevice
->NumBlocks
) {
204 // Invalid Lba, read nothing.
207 return EFI_BAD_BUFFER_SIZE
;
210 if (Offset
> FvbDevice
->LbaCache
[LbaIndex
].Length
) {
212 // all exceed boundry, read nothing.
215 return EFI_BAD_BUFFER_SIZE
;
218 NumOfBytesRead
= *NumBytes
;
219 if (Offset
+ NumOfBytesRead
> FvbDevice
->LbaCache
[LbaIndex
].Length
) {
221 // partial exceed boundry, read data from current postion to end.
223 NumOfBytesRead
= FvbDevice
->LbaCache
[LbaIndex
].Length
- Offset
;
226 LbaStart
= FvbDevice
->LbaCache
[LbaIndex
].Base
;
227 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)((UINTN
) FvbDevice
->BaseAddress
);
228 LbaOffset
= (UINT8
*) FwVolHeader
+ LbaStart
+ Offset
;
231 // Perform read operation
233 CopyMem (Buffer
, LbaOffset
, NumOfBytesRead
);
235 if (NumOfBytesRead
== *NumBytes
) {
239 *NumBytes
= NumOfBytesRead
;
240 return EFI_BAD_BUFFER_SIZE
;
246 Writes the specified number of bytes from the input buffer to the block.
248 @param This Indicates the calling context.
249 @param Lba The starting logical block index to write to.
250 @param Offset Offset into the block at which to begin writing.
251 @param NumBytes Pointer to a UINT32. At entry, *NumBytes
252 contains the total size of the buffer. At exit,
253 *NumBytes contains the total number of bytes
255 @param Buffer Pinter to a caller-allocated buffer that
256 contains the source for the write.
258 @retval EFI_SUCCESS The firmware volume was written successfully.
259 @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary.
260 On output, NumBytes contains the total number of
261 bytes actually written.
262 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
264 @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not
266 @retval EFI_UNSUPPORTED Not supported.
271 FwVolBlockWriteBlock (
272 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
275 IN OUT UINTN
*NumBytes
,
279 return EFI_UNSUPPORTED
;
285 Get Fvb's base address.
287 @param This Indicates the calling context.
288 @param Address Fvb device base address.
290 @retval EFI_SUCCESS Successfully got Fvb's base address.
291 @retval EFI_UNSUPPORTED Not supported.
296 FwVolBlockGetPhysicalAddress (
297 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
298 OUT EFI_PHYSICAL_ADDRESS
*Address
301 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
303 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
305 if (FvbDevice
->FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) {
306 *Address
= FvbDevice
->BaseAddress
;
310 return EFI_UNSUPPORTED
;
316 Retrieves the size in bytes of a specific block within a firmware volume.
318 @param This Indicates the calling context.
319 @param Lba Indicates the block for which to return the
321 @param BlockSize Pointer to a caller-allocated UINTN in which the
322 size of the block is returned.
323 @param NumberOfBlocks Pointer to a caller-allocated UINTN in which the
324 number of consecutive blocks starting with Lba
325 is returned. All blocks in this range have a
328 @retval EFI_SUCCESS The firmware volume base address is returned.
329 @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
334 FwVolBlockGetBlockSize (
335 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
336 IN CONST EFI_LBA Lba
,
337 IN OUT UINTN
*BlockSize
,
338 IN OUT UINTN
*NumberOfBlocks
342 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
343 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
344 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
346 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
349 // Do parameter checking
351 if (Lba
>= FvbDevice
->NumBlocks
) {
352 return EFI_INVALID_PARAMETER
;
355 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)((UINTN
)FvbDevice
->BaseAddress
);
357 PtrBlockMapEntry
= FwVolHeader
->BlockMap
;
360 // Search the block map for the given block
363 while ((PtrBlockMapEntry
->NumBlocks
!= 0) || (PtrBlockMapEntry
->Length
!=0 )) {
364 TotalBlocks
+= PtrBlockMapEntry
->NumBlocks
;
365 if (Lba
< TotalBlocks
) {
375 *BlockSize
= PtrBlockMapEntry
->Length
;
376 *NumberOfBlocks
= TotalBlocks
- (UINTN
)Lba
;
384 This routine produces a firmware volume block protocol on a given
387 @param BaseAddress base address of the firmware volume image
388 @param Length length of the firmware volume image
389 @param ParentHandle handle of parent firmware volume, if this image
390 came from an FV image file in another firmware
391 volume (ala capsules)
392 @param FvProtocol Firmware volume block protocol produced.
394 @retval EFI_VOLUME_CORRUPTED Volume corrupted.
395 @retval EFI_OUT_OF_RESOURCES No enough buffer to be allocated.
396 @retval EFI_SUCCESS Successfully produced a FVB protocol on given
401 ProduceFVBProtocolOnBuffer (
402 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
404 IN EFI_HANDLE ParentHandle
,
405 OUT EFI_HANDLE
*FvProtocol OPTIONAL
409 EFI_FW_VOL_BLOCK_DEVICE
*FvbDev
;
410 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
415 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
418 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
) BaseAddress
;
420 // Validate FV Header, if not as expected, return
422 if (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) {
423 return EFI_VOLUME_CORRUPTED
;
426 // Get FvHeader alignment
428 FvAlignment
= 1 << ((FwVolHeader
->Attributes
& EFI_FVB2_ALIGNMENT
) >> 16);
429 if (FvAlignment
< 8) {
432 if ((UINTN
)BaseAddress
% FvAlignment
!= 0) {
434 // FvImage buffer is not at its required alignment.
436 return EFI_VOLUME_CORRUPTED
;
439 // Allocate EFI_FW_VOL_BLOCK_DEVICE
441 FvbDev
= CoreAllocateCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE
), &mFwVolBlock
);
442 if (FvbDev
== NULL
) {
443 return EFI_OUT_OF_RESOURCES
;
446 FvbDev
->BaseAddress
= BaseAddress
;
447 FvbDev
->FvbAttributes
= FwVolHeader
->Attributes
;
448 FvbDev
->FwVolBlockInstance
.ParentHandle
= ParentHandle
;
451 // Init the block caching fields of the device
452 // First, count the number of blocks
454 FvbDev
->NumBlocks
= 0;
455 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
;
456 PtrBlockMapEntry
->NumBlocks
!= 0;
457 PtrBlockMapEntry
++) {
458 FvbDev
->NumBlocks
+= PtrBlockMapEntry
->NumBlocks
;
461 // Second, allocate the cache
463 FvbDev
->LbaCache
= CoreAllocateBootServicesPool (FvbDev
->NumBlocks
* sizeof (LBA_CACHE
));
464 if (FvbDev
->LbaCache
== NULL
) {
465 CoreFreePool (FvbDev
);
466 return EFI_OUT_OF_RESOURCES
;
469 // Last, fill in the cache with the linear address of the blocks
473 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
;
474 PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
475 for (BlockIndex2
= 0; BlockIndex2
< PtrBlockMapEntry
->NumBlocks
; BlockIndex2
++) {
476 FvbDev
->LbaCache
[BlockIndex
].Base
= LinearOffset
;
477 FvbDev
->LbaCache
[BlockIndex
].Length
= PtrBlockMapEntry
->Length
;
478 LinearOffset
+= PtrBlockMapEntry
->Length
;
484 // Set up the devicepath
486 FvbDev
->DevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
487 FvbDev
->DevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ FwVolHeader
->FvLength
- 1;
491 // Attach FvVolBlock Protocol to new handle
493 Status
= CoreInstallMultipleProtocolInterfaces (
495 &gEfiFirmwareVolumeBlockProtocolGuid
, &FvbDev
->FwVolBlockInstance
,
496 &gEfiDevicePathProtocolGuid
, &FvbDev
->DevicePath
,
497 &gEfiFirmwareVolumeDispatchProtocolGuid
, NULL
,
502 // If they want the handle back, set it.
504 if (FvProtocol
!= NULL
) {
505 *FvProtocol
= FvbDev
->Handle
;
514 This routine is the driver initialization entry point. It initializes the
515 libraries, consumes FV hobs and NT_NON_MM_FV environment variable and
516 produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate.
518 @param ImageHandle The image handle.
519 @param SystemTable The system table.
521 @retval EFI_SUCCESS Successfully initialized firmware volume block
527 FwVolBlockDriverInit (
528 IN EFI_HANDLE ImageHandle
,
529 IN EFI_SYSTEM_TABLE
*SystemTable
532 EFI_PEI_HOB_POINTERS FvHob
;
535 // Core Needs Firmware Volumes to function
537 FvHob
.Raw
= GetHobList ();
538 while ((FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
)) != NULL
) {
540 // Produce an FVB protocol for it
542 ProduceFVBProtocolOnBuffer (FvHob
.FirmwareVolume
->BaseAddress
, FvHob
.FirmwareVolume
->Length
, NULL
, NULL
);
543 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
552 This DXE service routine is used to process a firmware volume. In
553 particular, it can be called by BDS to process a single firmware
554 volume found in a capsule.
556 @param FvHeader pointer to a firmware volume header
557 @param Size the size of the buffer pointed to by FvHeader
558 @param FVProtocolHandle the handle on which a firmware volume protocol
559 was produced for the firmware volume passed in.
561 @retval EFI_OUT_OF_RESOURCES if an FVB could not be produced due to lack of
563 @retval EFI_VOLUME_CORRUPTED if the volume was corrupted
564 @retval EFI_SUCCESS a firmware volume protocol was produced for the
569 CoreProcessFirmwareVolume (
572 OUT EFI_HANDLE
*FVProtocolHandle
578 *FVProtocolHandle
= NULL
;
579 Status
= ProduceFVBProtocolOnBuffer (
580 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FvHeader
,
586 // Since in our implementation we use register-protocol-notify to put a
587 // FV protocol on the FVB protocol handle, we can't directly verify that
588 // the FV protocol was produced. Therefore here we will check the handle
589 // and make sure an FV protocol is on it. This indicates that all went
590 // well. Otherwise we have to assume that the volume was corrupted
593 if (!EFI_ERROR(Status
)) {
595 Status
= CoreHandleProtocol (*FVProtocolHandle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**) &Ptr
);
596 if (EFI_ERROR(Status
) || (Ptr
== NULL
)) {
597 return EFI_VOLUME_CORRUPTED
;