2 Firmware Volume Block protocol.. Consumes FV hobs and creates
3 appropriate block protocols.
5 Also consumes NT_NON_MM_FV envinronment variable and produces appropriate
6 block protocols fro them also... (this is TBD)
8 Copyright (c) 2006, Intel Corporation
9 All rights reserved. This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
22 EFI_FW_VOL_BLOCK_DEVICE mFwVolBlock
= {
30 { (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
)), (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
) >> 8) }
33 (EFI_PHYSICAL_ADDRESS
)0,
34 (EFI_PHYSICAL_ADDRESS
)0,
38 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
39 { END_DEVICE_PATH_LENGTH
, 0 }
43 FwVolBlockGetAttributes
,
44 (EFI_FVB_SET_ATTRIBUTES
)FwVolBlockSetAttributes
,
45 FwVolBlockGetPhysicalAddress
,
46 FwVolBlockGetBlockSize
,
48 (EFI_FVB_WRITE
)FwVolBlockWriteBlock
,
49 (EFI_FVB_ERASE_BLOCKS
)FwVolBlockEraseBlock
,
63 FwVolBlockGetAttributes (
64 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
65 OUT EFI_FVB_ATTRIBUTES
*Attributes
70 Retrieves Volume attributes. No polarity translations are done.
73 This - Calling context
74 Attributes - output buffer which contains attributes
77 EFI_SUCCESS - The firmware volume attributes were returned.
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 FwVolBlockSetAttributes (
97 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
98 IN CONST EFI_FVB_ATTRIBUTES
*Attributes
103 Modifies the current settings of the firmware volume according to the input parameter.
106 This - Calling context
107 Attributes - input buffer which contains attributes
110 EFI_SUCCESS - The firmware volume attributes were returned.
111 EFI_INVALID_PARAMETER - The attributes requested are in conflict with the capabilities as
112 declared in the firmware volume header.
113 EFI_UNSUPPORTED - Not supported.
116 return EFI_UNSUPPORTED
;
122 FwVolBlockEraseBlock (
123 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
129 The EraseBlock() function erases one or more blocks as denoted by the
130 variable argument list. The entire parameter list of blocks must be verified
131 prior to erasing any blocks. If a block is requested that does not exist
132 within the associated firmware volume (it has a larger index than the last
133 block of the firmware volume), the EraseBlock() function must return
134 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
137 This - Calling context
138 ... - Starting LBA followed by Number of Lba to erase. a -1 to terminate
142 EFI_SUCCESS - The erase request was successfully completed.
143 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state.
144 EFI_DEVICE_ERROR - The block device is not functioning correctly and could not be
145 written. The firmware device may have been partially erased.
146 EFI_INVALID_PARAMETER - One or more of the LBAs listed in the variable argument list do
147 EFI_UNSUPPORTED - Not supported.
151 return EFI_UNSUPPORTED
;
157 FwVolBlockReadBlock (
158 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
159 IN CONST EFI_LBA Lba
,
160 IN CONST UINTN Offset
,
161 IN OUT UINTN
*NumBytes
,
167 Read the specified number of bytes from the block to the input buffer.
170 This - Indicates the calling context.
171 Lba - The starting logical block index to read.
172 Offset - Offset into the block at which to begin reading.
173 NumBytes - Pointer to a UINT32. At entry, *NumBytes contains the
174 total size of the buffer. At exit, *NumBytes contains the
175 total number of bytes actually read.
176 Buffer - Pinter to a caller-allocated buffer that contains the destine
180 EFI_SUCCESS - The firmware volume was read successfully.
181 EFI_BAD_BUFFER_SIZE - The read was attempted across an LBA boundary.
182 EFI_ACCESS_DENIED - Access denied.
183 EFI_DEVICE_ERROR - The block device is malfunctioning and could not be read.
186 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
187 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
190 UINTN NumOfBytesRead
;
193 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
196 // Check if This FW can be read
198 if ((FvbDevice
->FvbAttributes
& EFI_FVB2_READ_STATUS
) == 0) {
199 return EFI_ACCESS_DENIED
;
202 LbaIndex
= (UINTN
)Lba
;
203 if (LbaIndex
>= FvbDevice
->NumBlocks
) {
205 // Invalid Lba, read nothing.
208 return EFI_BAD_BUFFER_SIZE
;
211 if (Offset
> FvbDevice
->LbaCache
[LbaIndex
].Length
) {
213 // all exceed boundry, read nothing.
216 return EFI_BAD_BUFFER_SIZE
;
219 NumOfBytesRead
= *NumBytes
;
220 if (Offset
+ NumOfBytesRead
> FvbDevice
->LbaCache
[LbaIndex
].Length
) {
222 // partial exceed boundry, read data from current postion to end.
224 NumOfBytesRead
= FvbDevice
->LbaCache
[LbaIndex
].Length
- Offset
;
227 LbaStart
= FvbDevice
->LbaCache
[LbaIndex
].Base
;
228 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)((UINTN
)FvbDevice
->BaseAddress
);
229 LbaOffset
= (UINT8
*)FwVolHeader
+ LbaStart
+ Offset
;
232 // Perform read operation
234 CopyMem (Buffer
, LbaOffset
, NumOfBytesRead
);
236 if (NumOfBytesRead
== *NumBytes
) {
240 *NumBytes
= NumOfBytesRead
;
241 return EFI_BAD_BUFFER_SIZE
;
247 FwVolBlockWriteBlock (
248 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
251 IN OUT UINTN
*NumBytes
,
257 Writes the specified number of bytes from the input buffer to the block.
260 This - Indicates the calling context.
261 Lba - The starting logical block index to write to.
262 Offset - Offset into the block at which to begin writing.
263 NumBytes - Pointer to a UINT32. At entry, *NumBytes contains the
264 total size of the buffer. At exit, *NumBytes contains the
265 total number of bytes actually written.
266 Buffer - Pinter to a caller-allocated buffer that contains the source
270 EFI_SUCCESS - The firmware volume was written successfully.
271 EFI_BAD_BUFFER_SIZE - The write was attempted across an LBA boundary. On output,
272 NumBytes contains the total number of bytes actually written.
273 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state.
274 EFI_DEVICE_ERROR - The block device is malfunctioning and could not be written.
275 EFI_UNSUPPORTED - Not supported.
278 return EFI_UNSUPPORTED
;
284 FwVolBlockGetPhysicalAddress (
285 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
286 OUT EFI_PHYSICAL_ADDRESS
*Address
291 Get Fvb's base address.
294 This - Indicates the calling context.
295 Address - Fvb device base address.
298 EFI_SUCCESS - Successfully got Fvb's base address.
299 EFI_UNSUPPORTED - Not supported.
302 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
304 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
306 if (FvbDevice
->FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) {
307 *Address
= FvbDevice
->BaseAddress
;
311 return EFI_UNSUPPORTED
;
317 FwVolBlockGetBlockSize (
318 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
319 IN CONST EFI_LBA Lba
,
320 IN OUT UINTN
*BlockSize
,
321 IN OUT UINTN
*NumberOfBlocks
326 Retrieves the size in bytes of a specific block within a firmware volume.
329 This - Indicates the calling context.
330 Lba - Indicates the block for which to return the size.
331 BlockSize - Pointer to a caller-allocated UINTN in which the size of the
333 NumberOfBlocks - Pointer to a caller-allocated UINTN in which the number of
334 consecutive blocks starting with Lba is returned. All blocks
335 in this range have a size of BlockSize.
337 EFI_SUCCESS - The firmware volume base address is returned.
338 EFI_INVALID_PARAMETER - The requested LBA is out of range.
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
;
383 ProduceFVBProtocolOnBuffer (
384 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
386 IN EFI_HANDLE ParentHandle
,
387 OUT EFI_HANDLE
*FvProtocol OPTIONAL
392 This routine produces a firmware volume block protocol on a given
396 BaseAddress - base address of the firmware volume image
397 Length - length of the firmware volume image
398 ParentHandle - handle of parent firmware volume, if this
399 image came from an FV image file in another
400 firmware volume (ala capsules)
401 FvProtocol - Firmware volume block protocol produced.
404 EFI_VOLUME_CORRUPTED - Volume corrupted.
405 EFI_OUT_OF_RESOURCES - No enough buffer to be allocated.
406 EFI_SUCCESS - Successfully produced a FVB protocol on given buffer.
411 EFI_FW_VOL_BLOCK_DEVICE
*FvbDev
;
412 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
416 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 // Allocate EFI_FW_VOL_BLOCK_DEVICE
428 FvbDev
= CoreAllocateCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE
), &mFwVolBlock
);
429 if (FvbDev
== NULL
) {
430 return EFI_OUT_OF_RESOURCES
;
433 FvbDev
->BaseAddress
= BaseAddress
;
434 FvbDev
->FvbAttributes
= FwVolHeader
->Attributes
;
435 FvbDev
->FwVolBlockInstance
.ParentHandle
= ParentHandle
;
438 // Init the block caching fields of the device
439 // First, count the number of blocks
441 FvbDev
->NumBlocks
= 0;
442 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
;
443 PtrBlockMapEntry
->NumBlocks
!= 0;
444 PtrBlockMapEntry
++) {
445 FvbDev
->NumBlocks
+= PtrBlockMapEntry
->NumBlocks
;
448 // Second, allocate the cache
450 FvbDev
->LbaCache
= CoreAllocateBootServicesPool (FvbDev
->NumBlocks
* sizeof (LBA_CACHE
));
451 if (FvbDev
->LbaCache
== NULL
) {
452 CoreFreePool (FvbDev
);
453 return EFI_OUT_OF_RESOURCES
;
456 // Last, fill in the cache with the linear address of the blocks
460 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
;
461 PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
462 for (BlockIndex2
= 0; BlockIndex2
< PtrBlockMapEntry
->NumBlocks
; BlockIndex2
++) {
463 FvbDev
->LbaCache
[BlockIndex
].Base
= LinearOffset
;
464 FvbDev
->LbaCache
[BlockIndex
].Length
= PtrBlockMapEntry
->Length
;
465 LinearOffset
+= PtrBlockMapEntry
->Length
;
471 // Set up the devicepath
473 FvbDev
->DevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
474 FvbDev
->DevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ FwVolHeader
->FvLength
- 1;
478 // Attach FvVolBlock Protocol to new handle
480 Status
= CoreInstallMultipleProtocolInterfaces (
482 &gEfiFirmwareVolumeBlockProtocolGuid
, &FvbDev
->FwVolBlockInstance
,
483 &gEfiDevicePathProtocolGuid
, &FvbDev
->DevicePath
,
484 &gEfiFirmwareVolumeDispatchProtocolGuid
, NULL
,
489 // If they want the handle back, set it.
491 if (FvProtocol
!= NULL
) {
492 *FvProtocol
= FvbDev
->Handle
;
501 FwVolBlockDriverInit (
502 IN EFI_HANDLE ImageHandle
,
503 IN EFI_SYSTEM_TABLE
*SystemTable
508 This routine is the driver initialization entry point. It initializes the
509 libraries, consumes FV hobs and NT_NON_MM_FV environment variable and
510 produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate.
512 ImageHandle - The image handle.
513 SystemTable - The system table.
515 EFI_SUCCESS - Successfully initialized firmware volume block driver.
518 EFI_PEI_HOB_POINTERS FvHob
;
520 // Core Needs Firmware Volumes to function
522 FvHob
.Raw
= GetHobList ();
523 while ((FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
)) != NULL
) {
525 // Produce an FVB protocol for it
527 ProduceFVBProtocolOnBuffer (FvHob
.FirmwareVolume
->BaseAddress
, FvHob
.FirmwareVolume
->Length
, NULL
, NULL
);
528 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
535 CoreProcessFirmwareVolume (
538 OUT EFI_HANDLE
*FVProtocolHandle
543 This DXE service routine is used to process a firmware volume. In
544 particular, it can be called by BDS to process a single firmware
545 volume found in a capsule.
548 FvHeader - pointer to a firmware volume header
549 Size - the size of the buffer pointed to by FvHeader
550 FVProtocolHandle - the handle on which a firmware volume protocol
551 was produced for the firmware volume passed in.
554 EFI_OUT_OF_RESOURCES - if an FVB could not be produced due to lack of
556 EFI_VOLUME_CORRUPTED - if the volume was corrupted
557 EFI_SUCCESS - a firmware volume protocol was produced for the
565 *FVProtocolHandle
= NULL
;
566 Status
= ProduceFVBProtocolOnBuffer (
567 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FvHeader
,
573 // Since in our implementation we use register-protocol-notify to put a
574 // FV protocol on the FVB protocol handle, we can't directly verify that
575 // the FV protocol was produced. Therefore here we will check the handle
576 // and make sure an FV protocol is on it. This indicates that all went
577 // well. Otherwise we have to assume that the volume was corrupted
580 if (!EFI_ERROR(Status
)) {
582 Status
= CoreHandleProtocol (*FVProtocolHandle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&Ptr
);
583 if (EFI_ERROR(Status
) || (Ptr
== NULL
)) {
584 return EFI_VOLUME_CORRUPTED
;