3 Copyright (c) 2006, 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.
18 Firmware Volume Block protocol.. Consumes FV hobs and creates
19 appropriate block protocols.
21 Also consumes NT_NON_MM_FV envinronment variable and produces appropriate
22 block protocols fro them also... (this is TBD)
29 EFI_FW_VOL_BLOCK_DEVICE mFwVolBlock
= {
37 { (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
)), (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
) >> 8) }
40 (EFI_PHYSICAL_ADDRESS
)0,
41 (EFI_PHYSICAL_ADDRESS
)0,
45 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
46 { END_DEVICE_PATH_LENGTH
, 0 }
50 FwVolBlockGetAttributes
,
51 (EFI_FVB_SET_ATTRIBUTES
)FwVolBlockSetAttributes
,
52 FwVolBlockGetPhysicalAddress
,
53 FwVolBlockGetBlockSize
,
55 (EFI_FVB_WRITE
)FwVolBlockWriteBlock
,
56 (EFI_FVB_ERASE_BLOCKS
)FwVolBlockEraseBlock
,
70 FwVolBlockGetAttributes (
71 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
72 OUT EFI_FVB_ATTRIBUTES
*Attributes
77 Retrieves Volume attributes. No polarity translations are done.
80 This - Calling context
81 Attributes - output buffer which contains attributes
84 EFI_SUCCESS - The firmware volume attributes were returned.
88 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
90 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
93 // Since we are read only, it's safe to get attributes data from our in-memory copy.
95 *Attributes
= FvbDevice
->FvbAttributes
;
103 FwVolBlockSetAttributes (
104 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
105 IN EFI_FVB_ATTRIBUTES
*Attributes
110 Modifies the current settings of the firmware volume according to the input parameter.
113 This - Calling context
114 Attributes - input buffer which contains attributes
117 EFI_SUCCESS - The firmware volume attributes were returned.
118 EFI_INVALID_PARAMETER - The attributes requested are in conflict with the capabilities as
119 declared in the firmware volume header.
120 EFI_UNSUPPORTED - Not supported.
123 return EFI_UNSUPPORTED
;
129 FwVolBlockEraseBlock (
130 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
136 The EraseBlock() function erases one or more blocks as denoted by the
137 variable argument list. The entire parameter list of blocks must be verified
138 prior to erasing any blocks. If a block is requested that does not exist
139 within the associated firmware volume (it has a larger index than the last
140 block of the firmware volume), the EraseBlock() function must return
141 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
144 This - Calling context
145 ... - Starting LBA followed by Number of Lba to erase. a -1 to terminate
149 EFI_SUCCESS - The erase request was successfully completed.
150 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state.
151 EFI_DEVICE_ERROR - The block device is not functioning correctly and could not be
152 written. The firmware device may have been partially erased.
153 EFI_INVALID_PARAMETER - One or more of the LBAs listed in the variable argument list do
154 EFI_UNSUPPORTED - Not supported.
158 return EFI_UNSUPPORTED
;
164 FwVolBlockReadBlock (
165 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
168 IN OUT UINTN
*NumBytes
,
174 Read the specified number of bytes from the block to the input buffer.
177 This - Indicates the calling context.
178 Lba - The starting logical block index to read.
179 Offset - Offset into the block at which to begin reading.
180 NumBytes - Pointer to a UINT32. At entry, *NumBytes contains the
181 total size of the buffer. At exit, *NumBytes contains the
182 total number of bytes actually read.
183 Buffer - Pinter to a caller-allocated buffer that contains the destine
187 EFI_SUCCESS - The firmware volume was read successfully.
188 EFI_BAD_BUFFER_SIZE - The read was attempted across an LBA boundary.
189 EFI_ACCESS_DENIED - Access denied.
190 EFI_DEVICE_ERROR - The block device is malfunctioning and could not be read.
193 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
194 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
197 UINTN NumOfBytesRead
;
200 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
203 // Check if This FW can be read
205 if ((FvbDevice
->FvbAttributes
& EFI_FVB_READ_STATUS
) == 0) {
206 return EFI_ACCESS_DENIED
;
209 LbaIndex
= (UINTN
)Lba
;
210 if (LbaIndex
>= FvbDevice
->NumBlocks
) {
212 // Invalid Lba, read nothing.
215 return EFI_BAD_BUFFER_SIZE
;
218 if (Offset
> FvbDevice
->LbaCache
[LbaIndex
].Length
) {
220 // all exceed boundry, read nothing.
223 return EFI_BAD_BUFFER_SIZE
;
226 NumOfBytesRead
= *NumBytes
;
227 if (Offset
+ NumOfBytesRead
> FvbDevice
->LbaCache
[LbaIndex
].Length
) {
229 // partial exceed boundry, read data from current postion to end.
231 NumOfBytesRead
= FvbDevice
->LbaCache
[LbaIndex
].Length
- Offset
;
234 LbaStart
= FvbDevice
->LbaCache
[LbaIndex
].Base
;
235 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)((UINTN
)FvbDevice
->BaseAddress
);
236 LbaOffset
= (UINT8
*)FwVolHeader
+ LbaStart
+ Offset
;
239 // Perform read operation
241 CopyMem (Buffer
, LbaOffset
, NumOfBytesRead
);
243 if (NumOfBytesRead
== *NumBytes
) {
247 *NumBytes
= NumOfBytesRead
;
248 return EFI_BAD_BUFFER_SIZE
;
254 FwVolBlockWriteBlock (
255 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
258 IN OUT UINTN
*NumBytes
,
264 Writes the specified number of bytes from the input buffer to the block.
267 This - Indicates the calling context.
268 Lba - The starting logical block index to write to.
269 Offset - Offset into the block at which to begin writing.
270 NumBytes - Pointer to a UINT32. At entry, *NumBytes contains the
271 total size of the buffer. At exit, *NumBytes contains the
272 total number of bytes actually written.
273 Buffer - Pinter to a caller-allocated buffer that contains the source
277 EFI_SUCCESS - The firmware volume was written successfully.
278 EFI_BAD_BUFFER_SIZE - The write was attempted across an LBA boundary. On output,
279 NumBytes contains the total number of bytes actually written.
280 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state.
281 EFI_DEVICE_ERROR - The block device is malfunctioning and could not be written.
282 EFI_UNSUPPORTED - Not supported.
285 return EFI_UNSUPPORTED
;
291 FwVolBlockGetPhysicalAddress (
292 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
293 OUT EFI_PHYSICAL_ADDRESS
*Address
298 Get Fvb's base address.
301 This - Indicates the calling context.
302 Address - Fvb device base address.
305 EFI_SUCCESS - Successfully got Fvb's base address.
306 EFI_UNSUPPORTED - Not supported.
309 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
311 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
313 if (FvbDevice
->FvbAttributes
& EFI_FVB_MEMORY_MAPPED
) {
314 *Address
= FvbDevice
->BaseAddress
;
318 return EFI_UNSUPPORTED
;
324 FwVolBlockGetBlockSize (
325 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*This
,
327 OUT UINTN
*BlockSize
,
328 OUT UINTN
*NumberOfBlocks
333 Retrieves the size in bytes of a specific block within a firmware volume.
336 This - Indicates the calling context.
337 Lba - Indicates the block for which to return the size.
338 BlockSize - Pointer to a caller-allocated UINTN in which the size of the
340 NumberOfBlocks - Pointer to a caller-allocated UINTN in which the number of
341 consecutive blocks starting with Lba is returned. All blocks
342 in this range have a size of BlockSize.
344 EFI_SUCCESS - The firmware volume base address is returned.
345 EFI_INVALID_PARAMETER - The requested LBA is out of range.
349 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
350 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
351 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
353 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
356 // Do parameter checking
358 if (Lba
>= FvbDevice
->NumBlocks
) {
359 return EFI_INVALID_PARAMETER
;
362 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)((UINTN
)FvbDevice
->BaseAddress
);
364 PtrBlockMapEntry
= FwVolHeader
->FvBlockMap
;
367 // Search the block map for the given block
370 while ((PtrBlockMapEntry
->NumBlocks
!= 0) || (PtrBlockMapEntry
->BlockLength
!=0 )) {
371 TotalBlocks
+= PtrBlockMapEntry
->NumBlocks
;
372 if (Lba
< TotalBlocks
) {
382 *BlockSize
= PtrBlockMapEntry
->BlockLength
;
383 *NumberOfBlocks
= TotalBlocks
- (UINTN
)Lba
;
390 ProduceFVBProtocolOnBuffer (
391 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
393 IN EFI_HANDLE ParentHandle
,
394 OUT EFI_HANDLE
*FvProtocol OPTIONAL
399 This routine produces a firmware volume block protocol on a given
403 BaseAddress - base address of the firmware volume image
404 Length - length of the firmware volume image
405 ParentHandle - handle of parent firmware volume, if this
406 image came from an FV image file in another
407 firmware volume (ala capsules)
408 FvProtocol - Firmware volume block protocol produced.
411 EFI_VOLUME_CORRUPTED - Volume corrupted.
412 EFI_OUT_OF_RESOURCES - No enough buffer to be allocated.
413 EFI_SUCCESS - Successfully produced a FVB protocol on given buffer.
418 EFI_FW_VOL_BLOCK_DEVICE
*FvbDev
;
419 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
423 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
425 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)BaseAddress
;
427 // Validate FV Header, if not as expected, return
429 if (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) {
430 return EFI_VOLUME_CORRUPTED
;
433 // Allocate EFI_FW_VOL_BLOCK_DEVICE
435 FvbDev
= CoreAllocateCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE
), &mFwVolBlock
);
436 if (FvbDev
== NULL
) {
437 return EFI_OUT_OF_RESOURCES
;
440 FvbDev
->BaseAddress
= BaseAddress
;
441 FvbDev
->FvbAttributes
= FwVolHeader
->Attributes
;
442 FvbDev
->FwVolBlockInstance
.ParentHandle
= ParentHandle
;
445 // Init the block caching fields of the device
446 // First, count the number of blocks
448 FvbDev
->NumBlocks
= 0;
449 for (PtrBlockMapEntry
= FwVolHeader
->FvBlockMap
;
450 PtrBlockMapEntry
->NumBlocks
!= 0;
451 PtrBlockMapEntry
++) {
452 FvbDev
->NumBlocks
+= PtrBlockMapEntry
->NumBlocks
;
455 // Second, allocate the cache
457 FvbDev
->LbaCache
= CoreAllocateBootServicesPool (FvbDev
->NumBlocks
* sizeof (LBA_CACHE
));
458 if (FvbDev
->LbaCache
== NULL
) {
459 CoreFreePool (FvbDev
);
460 return EFI_OUT_OF_RESOURCES
;
463 // Last, fill in the cache with the linear address of the blocks
467 for (PtrBlockMapEntry
= FwVolHeader
->FvBlockMap
;
468 PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
469 for (BlockIndex2
= 0; BlockIndex2
< PtrBlockMapEntry
->NumBlocks
; BlockIndex2
++) {
470 FvbDev
->LbaCache
[BlockIndex
].Base
= LinearOffset
;
471 FvbDev
->LbaCache
[BlockIndex
].Length
= PtrBlockMapEntry
->BlockLength
;
472 LinearOffset
+= PtrBlockMapEntry
->BlockLength
;
478 // Set up the devicepath
480 FvbDev
->DevicePath
.MemMapDevPath
.StartingAddress
= BaseAddress
;
481 FvbDev
->DevicePath
.MemMapDevPath
.EndingAddress
= BaseAddress
+ FwVolHeader
->FvLength
- 1;
485 // Attach FvVolBlock Protocol to new handle
487 Status
= CoreInstallMultipleProtocolInterfaces (
489 &gEfiFirmwareVolumeBlockProtocolGuid
, &FvbDev
->FwVolBlockInstance
,
490 &gEfiDevicePathProtocolGuid
, &FvbDev
->DevicePath
,
491 &gEfiFirmwareVolumeDispatchProtocolGuid
, NULL
,
496 // If they want the handle back, set it.
498 if (FvProtocol
!= NULL
) {
499 *FvProtocol
= FvbDev
->Handle
;
508 FwVolBlockDriverInit (
509 IN EFI_HANDLE ImageHandle
,
510 IN EFI_SYSTEM_TABLE
*SystemTable
515 This routine is the driver initialization entry point. It initializes the
516 libraries, consumes FV hobs and NT_NON_MM_FV environment variable and
517 produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate.
519 ImageHandle - The image handle.
520 SystemTable - The system table.
522 EFI_SUCCESS - Successfully initialized firmware volume block driver.
525 EFI_PEI_HOB_POINTERS FvHob
;
527 // Core Needs Firmware Volumes to function
529 FvHob
.Raw
= GetHobList ();
530 while ((FvHob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV
, FvHob
.Raw
)) != NULL
) {
532 // Produce an FVB protocol for it
534 ProduceFVBProtocolOnBuffer (FvHob
.FirmwareVolume
->BaseAddress
, FvHob
.FirmwareVolume
->Length
, NULL
, NULL
);
535 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
542 CoreProcessFirmwareVolume (
545 OUT EFI_HANDLE
*FVProtocolHandle
550 This DXE service routine is used to process a firmware volume. In
551 particular, it can be called by BDS to process a single firmware
552 volume found in a capsule.
555 FvHeader - pointer to a firmware volume header
556 Size - the size of the buffer pointed to by FvHeader
557 FVProtocolHandle - the handle on which a firmware volume protocol
558 was produced for the firmware volume passed in.
561 EFI_OUT_OF_RESOURCES - if an FVB could not be produced due to lack of
563 EFI_VOLUME_CORRUPTED - if the volume was corrupted
564 EFI_SUCCESS - a firmware volume protocol was produced for the
572 *FVProtocolHandle
= NULL
;
573 Status
= ProduceFVBProtocolOnBuffer (
574 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FvHeader
,
580 // Since in our implementation we use register-protocol-notify to put a
581 // FV protocol on the FVB protocol handle, we can't directly verify that
582 // the FV protocol was produced. Therefore here we will check the handle
583 // and make sure an FV protocol is on it. This indicates that all went
584 // well. Otherwise we have to assume that the volume was corrupted
587 if (!EFI_ERROR(Status
)) {
589 Status
= CoreHandleProtocol (*FVProtocolHandle
, &gEfiFirmwareVolumeProtocolGuid
, (VOID
**)&Ptr
);
590 if (EFI_ERROR(Status
) || (Ptr
== NULL
)) {
591 return EFI_VOLUME_CORRUPTED
;