1 /*++ @file NorFlashFvbDxe.c
3 Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include <Library/PcdLib.h>
18 #include <Library/BaseLib.h>
19 #include <Library/HobLib.h>
20 #include <Library/UefiLib.h>
21 #include <Library/BaseMemoryLib.h>
22 #include <Library/MemoryAllocationLib.h>
23 #include <Library/DxeServicesTableLib.h>
24 #include <Library/UefiBootServicesTableLib.h>
26 #include <Guid/VariableFormat.h>
27 #include <Guid/SystemNvDataGuid.h>
29 #include "NorFlashDxe.h"
31 STATIC EFI_EVENT mFvbVirtualAddrChangeEvent
;
32 STATIC UINTN mFlashNvStorageVariableBase
;
35 /// The Firmware Volume Block Protocol is the low-level interface
36 /// to a firmware volume. File-level access to a firmware volume
37 /// should not be done using the Firmware Volume Block Protocol.
38 /// Normal access to a firmware volume must use the Firmware
39 /// Volume Protocol. Typically, only the file system driver that
40 /// produces the Firmware Volume Protocol will bind to the
41 /// Firmware Volume Block Protocol.
45 Initialises the FV Header and Variable Store Header
46 to support variable operations.
48 @param[in] Ptr - Location to initialise the headers
52 InitializeFvAndVariableStoreHeaders (
53 IN NOR_FLASH_INSTANCE
*Instance
59 EFI_FIRMWARE_VOLUME_HEADER
*FirmwareVolumeHeader
;
60 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
62 if (!Instance
->Initialized
&& Instance
->Initialize
) {
63 Instance
->Initialize (Instance
);
66 HeadersLength
= sizeof(EFI_FIRMWARE_VOLUME_HEADER
) + sizeof(EFI_FV_BLOCK_MAP_ENTRY
) + sizeof(VARIABLE_STORE_HEADER
);
67 Headers
= AllocateZeroPool(HeadersLength
);
69 // FirmwareVolumeHeader->FvLength is declared to have the Variable area AND the FTW working area AND the FTW Spare contiguous.
70 ASSERT(PcdGet32(PcdFlashNvStorageVariableBase
) + PcdGet32(PcdFlashNvStorageVariableSize
) == PcdGet32(PcdFlashNvStorageFtwWorkingBase
));
71 ASSERT(PcdGet32(PcdFlashNvStorageFtwWorkingBase
) + PcdGet32(PcdFlashNvStorageFtwWorkingSize
) == PcdGet32(PcdFlashNvStorageFtwSpareBase
));
73 // Check if the size of the area is at least one block size
74 ASSERT((PcdGet32(PcdFlashNvStorageVariableSize
) > 0) && (PcdGet32(PcdFlashNvStorageVariableSize
) / Instance
->Media
.BlockSize
> 0));
75 ASSERT((PcdGet32(PcdFlashNvStorageFtwWorkingSize
) > 0) && (PcdGet32(PcdFlashNvStorageFtwWorkingSize
) / Instance
->Media
.BlockSize
> 0));
76 ASSERT((PcdGet32(PcdFlashNvStorageFtwSpareSize
) > 0) && (PcdGet32(PcdFlashNvStorageFtwSpareSize
) / Instance
->Media
.BlockSize
> 0));
78 // Ensure the Variable area Base Addresses are aligned on a block size boundaries
79 ASSERT(PcdGet32(PcdFlashNvStorageVariableBase
) % Instance
->Media
.BlockSize
== 0);
80 ASSERT(PcdGet32(PcdFlashNvStorageFtwWorkingBase
) % Instance
->Media
.BlockSize
== 0);
81 ASSERT(PcdGet32(PcdFlashNvStorageFtwSpareBase
) % Instance
->Media
.BlockSize
== 0);
84 // EFI_FIRMWARE_VOLUME_HEADER
86 FirmwareVolumeHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)Headers
;
87 CopyGuid (&FirmwareVolumeHeader
->FileSystemGuid
, &gEfiSystemNvDataFvGuid
);
88 FirmwareVolumeHeader
->FvLength
=
89 PcdGet32(PcdFlashNvStorageVariableSize
) +
90 PcdGet32(PcdFlashNvStorageFtwWorkingSize
) +
91 PcdGet32(PcdFlashNvStorageFtwSpareSize
);
92 FirmwareVolumeHeader
->Signature
= EFI_FVH_SIGNATURE
;
93 FirmwareVolumeHeader
->Attributes
= (EFI_FVB_ATTRIBUTES_2
) (
94 EFI_FVB2_READ_ENABLED_CAP
| // Reads may be enabled
95 EFI_FVB2_READ_STATUS
| // Reads are currently enabled
96 EFI_FVB2_STICKY_WRITE
| // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY
97 EFI_FVB2_MEMORY_MAPPED
| // It is memory mapped
98 EFI_FVB2_ERASE_POLARITY
| // After erasure all bits take this value (i.e. '1')
99 EFI_FVB2_WRITE_STATUS
| // Writes are currently enabled
100 EFI_FVB2_WRITE_ENABLED_CAP
// Writes may be enabled
102 FirmwareVolumeHeader
->HeaderLength
= sizeof(EFI_FIRMWARE_VOLUME_HEADER
) + sizeof(EFI_FV_BLOCK_MAP_ENTRY
);
103 FirmwareVolumeHeader
->Revision
= EFI_FVH_REVISION
;
104 FirmwareVolumeHeader
->BlockMap
[0].NumBlocks
= Instance
->Media
.LastBlock
+ 1;
105 FirmwareVolumeHeader
->BlockMap
[0].Length
= Instance
->Media
.BlockSize
;
106 FirmwareVolumeHeader
->BlockMap
[1].NumBlocks
= 0;
107 FirmwareVolumeHeader
->BlockMap
[1].Length
= 0;
108 FirmwareVolumeHeader
->Checksum
= CalculateCheckSum16 ((UINT16
*)FirmwareVolumeHeader
,FirmwareVolumeHeader
->HeaderLength
);
111 // VARIABLE_STORE_HEADER
113 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*)((UINTN
)Headers
+ FirmwareVolumeHeader
->HeaderLength
);
114 CopyGuid (&VariableStoreHeader
->Signature
, mNorFlashVariableGuid
);
115 VariableStoreHeader
->Size
= PcdGet32(PcdFlashNvStorageVariableSize
) - FirmwareVolumeHeader
->HeaderLength
;
116 VariableStoreHeader
->Format
= VARIABLE_STORE_FORMATTED
;
117 VariableStoreHeader
->State
= VARIABLE_STORE_HEALTHY
;
119 // Install the combined super-header in the NorFlash
120 Status
= FvbWrite (&Instance
->FvbProtocol
, 0, 0, &HeadersLength
, Headers
);
127 Check the integrity of firmware volume header.
129 @param[in] FwVolHeader - A pointer to a firmware volume header
131 @retval EFI_SUCCESS - The firmware volume is consistent
132 @retval EFI_NOT_FOUND - The firmware volume has been corrupted.
137 IN NOR_FLASH_INSTANCE
*Instance
141 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
142 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
143 UINTN VariableStoreLength
;
146 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)Instance
->RegionBaseAddress
;
148 FvLength
= PcdGet32(PcdFlashNvStorageVariableSize
) + PcdGet32(PcdFlashNvStorageFtwWorkingSize
) +
149 PcdGet32(PcdFlashNvStorageFtwSpareSize
);
152 // Verify the header revision, header signature, length
153 // Length of FvBlock cannot be 2**64-1
154 // HeaderLength cannot be an odd number
156 if ( (FwVolHeader
->Revision
!= EFI_FVH_REVISION
)
157 || (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
)
158 || (FwVolHeader
->FvLength
!= FvLength
)
161 DEBUG ((EFI_D_ERROR
, "ValidateFvHeader: No Firmware Volume header present\n"));
162 return EFI_NOT_FOUND
;
165 // Check the Firmware Volume Guid
166 if( CompareGuid (&FwVolHeader
->FileSystemGuid
, &gEfiSystemNvDataFvGuid
) == FALSE
) {
167 DEBUG ((EFI_D_ERROR
, "ValidateFvHeader: Firmware Volume Guid non-compatible\n"));
168 return EFI_NOT_FOUND
;
171 // Verify the header checksum
172 Checksum
= CalculateSum16((UINT16
*)FwVolHeader
, FwVolHeader
->HeaderLength
);
174 DEBUG ((EFI_D_ERROR
, "ValidateFvHeader: FV checksum is invalid (Checksum:0x%X)\n",Checksum
));
175 return EFI_NOT_FOUND
;
178 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*)((UINTN
)FwVolHeader
+ FwVolHeader
->HeaderLength
);
180 // Check the Variable Store Guid
181 if (!CompareGuid (&VariableStoreHeader
->Signature
, mNorFlashVariableGuid
)) {
182 DEBUG ((EFI_D_ERROR
, "ValidateFvHeader: Variable Store Guid non-compatible\n"));
183 return EFI_NOT_FOUND
;
186 VariableStoreLength
= PcdGet32 (PcdFlashNvStorageVariableSize
) - FwVolHeader
->HeaderLength
;
187 if (VariableStoreHeader
->Size
!= VariableStoreLength
) {
188 DEBUG ((EFI_D_ERROR
, "ValidateFvHeader: Variable Store Length does not match\n"));
189 return EFI_NOT_FOUND
;
196 The GetAttributes() function retrieves the attributes and
197 current settings of the block.
199 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
201 @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes and
202 current settings are returned.
203 Type EFI_FVB_ATTRIBUTES_2 is defined in EFI_FIRMWARE_VOLUME_HEADER.
205 @retval EFI_SUCCESS The firmware volume attributes were returned.
211 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
*This
,
212 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
215 EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes
;
216 NOR_FLASH_INSTANCE
*Instance
;
218 Instance
= INSTANCE_FROM_FVB_THIS(This
);
220 FlashFvbAttributes
= (EFI_FVB_ATTRIBUTES_2
) (
222 EFI_FVB2_READ_ENABLED_CAP
| // Reads may be enabled
223 EFI_FVB2_READ_STATUS
| // Reads are currently enabled
224 EFI_FVB2_STICKY_WRITE
| // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY
225 EFI_FVB2_MEMORY_MAPPED
| // It is memory mapped
226 EFI_FVB2_ERASE_POLARITY
// After erasure all bits take this value (i.e. '1')
230 // Check if it is write protected
231 if (Instance
->Media
.ReadOnly
!= TRUE
) {
233 FlashFvbAttributes
= FlashFvbAttributes
|
234 EFI_FVB2_WRITE_STATUS
| // Writes are currently enabled
235 EFI_FVB2_WRITE_ENABLED_CAP
; // Writes may be enabled
238 *Attributes
= FlashFvbAttributes
;
240 DEBUG ((DEBUG_BLKIO
, "FvbGetAttributes(0x%X)\n", *Attributes
));
246 The SetAttributes() function sets configurable firmware volume attributes
247 and returns the new settings of the firmware volume.
250 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
252 @param Attributes On input, Attributes is a pointer to EFI_FVB_ATTRIBUTES_2
253 that contains the desired firmware volume settings.
254 On successful return, it contains the new settings of
256 Type EFI_FVB_ATTRIBUTES_2 is defined in EFI_FIRMWARE_VOLUME_HEADER.
258 @retval EFI_SUCCESS The firmware volume attributes were returned.
260 @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with the capabilities
261 as declared in the firmware volume header.
267 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
*This
,
268 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
271 DEBUG ((DEBUG_BLKIO
, "FvbSetAttributes(0x%X) is not supported\n",*Attributes
));
272 return EFI_UNSUPPORTED
;
276 The GetPhysicalAddress() function retrieves the base address of
277 a memory-mapped firmware volume. This function should be called
278 only for memory-mapped firmware volumes.
280 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
282 @param Address Pointer to a caller-allocated
283 EFI_PHYSICAL_ADDRESS that, on successful
284 return from GetPhysicalAddress(), contains the
285 base address of the firmware volume.
287 @retval EFI_SUCCESS The firmware volume base address was returned.
289 @retval EFI_NOT_SUPPORTED The firmware volume is not memory mapped.
294 FvbGetPhysicalAddress (
295 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
*This
,
296 OUT EFI_PHYSICAL_ADDRESS
*Address
299 NOR_FLASH_INSTANCE
*Instance
;
301 Instance
= INSTANCE_FROM_FVB_THIS(This
);
303 DEBUG ((DEBUG_BLKIO
, "FvbGetPhysicalAddress(BaseAddress=0x%08x)\n", Instance
->RegionBaseAddress
));
305 ASSERT(Address
!= NULL
);
307 *Address
= mFlashNvStorageVariableBase
;
312 The GetBlockSize() function retrieves the size of the requested
313 block. It also returns the number of additional blocks with
314 the identical size. The GetBlockSize() function is used to
315 retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).
318 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
320 @param Lba Indicates the block for which to return the size.
322 @param BlockSize Pointer to a caller-allocated UINTN in which
323 the size of the block is returned.
325 @param NumberOfBlocks Pointer to a caller-allocated UINTN in
326 which the number of consecutive blocks,
327 starting with Lba, is returned. All
328 blocks in this range have a size of
332 @retval EFI_SUCCESS The firmware volume base address was returned.
334 @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
340 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
*This
,
342 OUT UINTN
*BlockSize
,
343 OUT UINTN
*NumberOfBlocks
347 NOR_FLASH_INSTANCE
*Instance
;
349 Instance
= INSTANCE_FROM_FVB_THIS(This
);
351 DEBUG ((DEBUG_BLKIO
, "FvbGetBlockSize(Lba=%ld, BlockSize=0x%x, LastBlock=%ld)\n", Lba
, Instance
->Media
.BlockSize
, Instance
->Media
.LastBlock
));
353 if (Lba
> Instance
->Media
.LastBlock
) {
354 DEBUG ((EFI_D_ERROR
, "FvbGetBlockSize: ERROR - Parameter LBA %ld is beyond the last Lba (%ld).\n", Lba
, Instance
->Media
.LastBlock
));
355 Status
= EFI_INVALID_PARAMETER
;
357 // This is easy because in this platform each NorFlash device has equal sized blocks.
358 *BlockSize
= (UINTN
) Instance
->Media
.BlockSize
;
359 *NumberOfBlocks
= (UINTN
) (Instance
->Media
.LastBlock
- Lba
+ 1);
361 DEBUG ((DEBUG_BLKIO
, "FvbGetBlockSize: *BlockSize=0x%x, *NumberOfBlocks=0x%x.\n", *BlockSize
, *NumberOfBlocks
));
363 Status
= EFI_SUCCESS
;
370 Reads the specified number of bytes into a buffer from the specified block.
372 The Read() function reads the requested number of bytes from the
373 requested block and stores them in the provided buffer.
374 Implementations should be mindful that the firmware volume
375 might be in the ReadDisabled state. If it is in this state,
376 the Read() function must return the status code
377 EFI_ACCESS_DENIED without modifying the contents of the
378 buffer. The Read() function must also prevent spanning block
379 boundaries. If a read is requested that would span a block
380 boundary, the read must read up to the boundary but not
381 beyond. The output parameter NumBytes must be set to correctly
382 indicate the number of bytes actually read. The caller must be
383 aware that a read may be partially completed.
385 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
387 @param Lba The starting logical block index from which to read.
389 @param Offset Offset into the block at which to begin reading.
391 @param NumBytes Pointer to a UINTN.
392 At entry, *NumBytes contains the total size of the buffer.
393 At exit, *NumBytes contains the total number of bytes read.
395 @param Buffer Pointer to a caller-allocated buffer that will be used
396 to hold the data that is read.
398 @retval EFI_SUCCESS The firmware volume was read successfully, and contents are
401 @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA boundary.
402 On output, NumBytes contains the total number of bytes
405 @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state.
407 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be read.
413 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
*This
,
416 IN OUT UINTN
*NumBytes
,
420 EFI_STATUS TempStatus
;
422 NOR_FLASH_INSTANCE
*Instance
;
424 Instance
= INSTANCE_FROM_FVB_THIS(This
);
426 DEBUG ((DEBUG_BLKIO
, "FvbRead(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Instance
->StartLba
+ Lba
, Offset
, *NumBytes
, Buffer
));
428 if (!Instance
->Initialized
&& Instance
->Initialize
) {
429 Instance
->Initialize(Instance
);
432 TempStatus
= EFI_SUCCESS
;
434 // Cache the block size to avoid de-referencing pointers all the time
435 BlockSize
= Instance
->Media
.BlockSize
;
437 DEBUG ((DEBUG_BLKIO
, "FvbRead: Check if (Offset=0x%x + NumBytes=0x%x) <= BlockSize=0x%x\n", Offset
, *NumBytes
, BlockSize
));
439 // The read must not span block boundaries.
440 // We need to check each variable individually because adding two large values together overflows.
441 if ((Offset
>= BlockSize
) ||
442 (*NumBytes
> BlockSize
) ||
443 ((Offset
+ *NumBytes
) > BlockSize
)) {
444 DEBUG ((EFI_D_ERROR
, "FvbRead: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset
, *NumBytes
, BlockSize
));
445 return EFI_BAD_BUFFER_SIZE
;
448 // We must have some bytes to read
449 if (*NumBytes
== 0) {
450 return EFI_BAD_BUFFER_SIZE
;
453 // Decide if we are doing full block reads or not.
454 if (*NumBytes
% BlockSize
!= 0) {
455 TempStatus
= NorFlashRead (Instance
, Instance
->StartLba
+ Lba
, Offset
, *NumBytes
, Buffer
);
456 if (EFI_ERROR (TempStatus
)) {
457 return EFI_DEVICE_ERROR
;
460 // Read NOR Flash data into shadow buffer
461 TempStatus
= NorFlashReadBlocks (Instance
, Instance
->StartLba
+ Lba
, BlockSize
, Buffer
);
462 if (EFI_ERROR (TempStatus
)) {
463 // Return one of the pre-approved error statuses
464 return EFI_DEVICE_ERROR
;
471 Writes the specified number of bytes from the input buffer to the block.
473 The Write() function writes the specified number of bytes from
474 the provided buffer to the specified block and offset. If the
475 firmware volume is sticky write, the caller must ensure that
476 all the bits of the specified range to write are in the
477 EFI_FVB_ERASE_POLARITY state before calling the Write()
478 function, or else the result will be unpredictable. This
479 unpredictability arises because, for a sticky-write firmware
480 volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY
481 state but cannot flip it back again. Before calling the
482 Write() function, it is recommended for the caller to first call
483 the EraseBlocks() function to erase the specified block to
484 write. A block erase cycle will transition bits from the
485 (NOT)EFI_FVB_ERASE_POLARITY state back to the
486 EFI_FVB_ERASE_POLARITY state. Implementations should be
487 mindful that the firmware volume might be in the WriteDisabled
488 state. If it is in this state, the Write() function must
489 return the status code EFI_ACCESS_DENIED without modifying the
490 contents of the firmware volume. The Write() function must
491 also prevent spanning block boundaries. If a write is
492 requested that spans a block boundary, the write must store up
493 to the boundary but not beyond. The output parameter NumBytes
494 must be set to correctly indicate the number of bytes actually
495 written. The caller must be aware that a write may be
496 partially completed. All writes, partial or otherwise, must be
497 fully flushed to the hardware before the Write() service
500 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
502 @param Lba The starting logical block index to write to.
504 @param Offset Offset into the block at which to begin writing.
506 @param NumBytes The pointer to a UINTN.
507 At entry, *NumBytes contains the total size of the buffer.
508 At exit, *NumBytes contains the total number of bytes actually written.
510 @param Buffer The pointer to a caller-allocated buffer that contains the source for the write.
512 @retval EFI_SUCCESS The firmware volume was written successfully.
514 @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary.
515 On output, NumBytes contains the total number of bytes
518 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.
520 @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not be written.
527 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
*This
,
530 IN OUT UINTN
*NumBytes
,
534 NOR_FLASH_INSTANCE
*Instance
;
536 Instance
= INSTANCE_FROM_FVB_THIS (This
);
538 return NorFlashWriteSingleBlock (Instance
, Instance
->StartLba
+ Lba
, Offset
, NumBytes
, Buffer
);
542 Erases and initialises a firmware volume block.
544 The EraseBlocks() function erases one or more blocks as denoted
545 by the variable argument list. The entire parameter list of
546 blocks must be verified before erasing any blocks. If a block is
547 requested that does not exist within the associated firmware
548 volume (it has a larger index than the last block of the
549 firmware volume), the EraseBlocks() function must return the
550 status code EFI_INVALID_PARAMETER without modifying the contents
551 of the firmware volume. Implementations should be mindful that
552 the firmware volume might be in the WriteDisabled state. If it
553 is in this state, the EraseBlocks() function must return the
554 status code EFI_ACCESS_DENIED without modifying the contents of
555 the firmware volume. All calls to EraseBlocks() must be fully
556 flushed to the hardware before the EraseBlocks() service
559 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
562 @param ... The variable argument list is a list of tuples.
563 Each tuple describes a range of LBAs to erase
564 and consists of the following:
565 - An EFI_LBA that indicates the starting LBA
566 - A UINTN that indicates the number of blocks to erase.
568 The list is terminated with an EFI_LBA_LIST_TERMINATOR.
569 For example, the following indicates that two ranges of blocks
570 (5-7 and 10-11) are to be erased:
571 EraseBlocks (This, 5, 3, 10, 2, EFI_LBA_LIST_TERMINATOR);
573 @retval EFI_SUCCESS The erase request successfully completed.
575 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.
577 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be written.
578 The firmware device may have been partially erased.
580 @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable argument list do
581 not exist in the firmware volume.
587 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
*This
,
593 UINTN BlockAddress
; // Physical address of Lba to erase
594 EFI_LBA StartingLba
; // Lba from which we start erasing
595 UINTN NumOfLba
; // Number of Lba blocks to erase
596 NOR_FLASH_INSTANCE
*Instance
;
598 Instance
= INSTANCE_FROM_FVB_THIS(This
);
600 DEBUG ((DEBUG_BLKIO
, "FvbEraseBlocks()\n"));
602 Status
= EFI_SUCCESS
;
604 // Detect WriteDisabled state
605 if (Instance
->Media
.ReadOnly
== TRUE
) {
606 // Firmware volume is in WriteDisabled state
607 DEBUG ((EFI_D_ERROR
, "FvbEraseBlocks: ERROR - Device is in WriteDisabled state.\n"));
608 return EFI_ACCESS_DENIED
;
611 // Before erasing, check the entire list of parameters to ensure all specified blocks are valid
613 VA_START (Args
, This
);
615 // Get the Lba from which we start erasing
616 StartingLba
= VA_ARG (Args
, EFI_LBA
);
618 // Have we reached the end of the list?
619 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
620 //Exit the while loop
624 // How many Lba blocks are we requested to erase?
625 NumOfLba
= VA_ARG (Args
, UINT32
);
627 // All blocks must be within range
628 DEBUG ((DEBUG_BLKIO
, "FvbEraseBlocks: Check if: ( StartingLba=%ld + NumOfLba=%d - 1 ) > LastBlock=%ld.\n", Instance
->StartLba
+ StartingLba
, NumOfLba
, Instance
->Media
.LastBlock
));
629 if ((NumOfLba
== 0) || ((Instance
->StartLba
+ StartingLba
+ NumOfLba
- 1) > Instance
->Media
.LastBlock
)) {
631 DEBUG ((EFI_D_ERROR
, "FvbEraseBlocks: ERROR - Lba range goes past the last Lba.\n"));
632 Status
= EFI_INVALID_PARAMETER
;
639 // To get here, all must be ok, so start erasing
641 VA_START (Args
, This
);
643 // Get the Lba from which we start erasing
644 StartingLba
= VA_ARG (Args
, EFI_LBA
);
646 // Have we reached the end of the list?
647 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
648 // Exit the while loop
652 // How many Lba blocks are we requested to erase?
653 NumOfLba
= VA_ARG (Args
, UINT32
);
655 // Go through each one and erase it
656 while (NumOfLba
> 0) {
658 // Get the physical address of Lba to erase
659 BlockAddress
= GET_NOR_BLOCK_ADDRESS (
660 Instance
->RegionBaseAddress
,
661 Instance
->StartLba
+ StartingLba
,
662 Instance
->Media
.BlockSize
666 DEBUG ((DEBUG_BLKIO
, "FvbEraseBlocks: Erasing Lba=%ld @ 0x%08x.\n", Instance
->StartLba
+ StartingLba
, BlockAddress
));
667 Status
= NorFlashUnlockAndEraseSingleBlock (Instance
, BlockAddress
);
668 if (EFI_ERROR(Status
)) {
670 Status
= EFI_DEVICE_ERROR
;
674 // Move to the next Lba
686 Fixup internal data so that EFI can be call in virtual mode.
687 Call the passed in Child Notify event and convert any pointers in
690 @param[in] Event The Event that is being processed
691 @param[in] Context Event Context
695 FvbVirtualNotifyEvent (
700 EfiConvertPointer (0x0, (VOID
**)&mFlashNvStorageVariableBase
);
706 NorFlashFvbInitialize (
707 IN NOR_FLASH_INSTANCE
* Instance
712 EFI_BOOT_MODE BootMode
;
713 UINTN RuntimeMmioRegionSize
;
715 DEBUG((DEBUG_BLKIO
,"NorFlashFvbInitialize\n"));
717 Instance
->Initialized
= TRUE
;
718 mFlashNvStorageVariableBase
= FixedPcdGet32 (PcdFlashNvStorageVariableBase
);
720 // Set the index of the first LBA for the FVB
721 Instance
->StartLba
= (PcdGet32 (PcdFlashNvStorageVariableBase
) - Instance
->RegionBaseAddress
) / Instance
->Media
.BlockSize
;
723 BootMode
= GetBootModeHob ();
724 if (BootMode
== BOOT_WITH_DEFAULT_SETTINGS
) {
725 Status
= EFI_INVALID_PARAMETER
;
727 // Determine if there is a valid header at the beginning of the NorFlash
728 Status
= ValidateFvHeader (Instance
);
731 // Install the Default FVB header if required
732 if (EFI_ERROR(Status
)) {
733 // There is no valid header, so time to install one.
734 DEBUG((EFI_D_ERROR
,"NorFlashFvbInitialize: ERROR - The FVB Header is not valid. Installing a correct one for this volume.\n"));
736 // Erase all the NorFlash that is reserved for variable storage
737 FvbNumLba
= (PcdGet32(PcdFlashNvStorageVariableSize
) + PcdGet32(PcdFlashNvStorageFtwWorkingSize
) + PcdGet32(PcdFlashNvStorageFtwSpareSize
)) / Instance
->Media
.BlockSize
;
739 Status
= FvbEraseBlocks (&Instance
->FvbProtocol
, (EFI_LBA
)0, FvbNumLba
, EFI_LBA_LIST_TERMINATOR
);
740 if (EFI_ERROR(Status
)) {
744 // Install all appropriate headers
745 Status
= InitializeFvAndVariableStoreHeaders (Instance
);
746 if (EFI_ERROR(Status
)) {
752 // Declare the Non-Volatile storage as EFI_MEMORY_RUNTIME
755 // Note: all the NOR Flash region needs to be reserved into the UEFI Runtime memory;
756 // even if we only use the small block region at the top of the NOR Flash.
757 // The reason is when the NOR Flash memory is set into program mode, the command
758 // is written as the base of the flash region (ie: Instance->DeviceBaseAddress)
759 RuntimeMmioRegionSize
= (Instance
->RegionBaseAddress
- Instance
->DeviceBaseAddress
) + Instance
->Size
;
761 Status
= gDS
->AddMemorySpace (
762 EfiGcdMemoryTypeMemoryMappedIo
,
763 Instance
->DeviceBaseAddress
, RuntimeMmioRegionSize
,
764 EFI_MEMORY_UC
| EFI_MEMORY_RUNTIME
766 ASSERT_EFI_ERROR (Status
);
768 Status
= gDS
->SetMemorySpaceAttributes (
769 Instance
->DeviceBaseAddress
, RuntimeMmioRegionSize
,
770 EFI_MEMORY_UC
| EFI_MEMORY_RUNTIME
);
771 ASSERT_EFI_ERROR (Status
);
774 // Register for the virtual address change event
776 Status
= gBS
->CreateEventEx (
779 FvbVirtualNotifyEvent
,
781 &gEfiEventVirtualAddressChangeGuid
,
782 &mFvbVirtualAddrChangeEvent
784 ASSERT_EFI_ERROR (Status
);