]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvb.c
db8eb595f4b8e32c6dbf8696b4f18faf82ca5916
[mirror_edk2.git] / ArmPlatformPkg / Drivers / NorFlashDxe / NorFlashFvb.c
1 /*++ @file NorFlashFvbDxe.c
2
3 Copyright (c) 2011 - 2021, Arm Limited. All rights reserved.<BR>
4
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 --*/
8
9 #include <PiDxe.h>
10
11 #include <Library/PcdLib.h>
12 #include <Library/BaseLib.h>
13 #include <Library/UefiLib.h>
14 #include <Library/BaseMemoryLib.h>
15 #include <Library/MemoryAllocationLib.h>
16
17 #include <Guid/VariableFormat.h>
18 #include <Guid/SystemNvDataGuid.h>
19 #include <Guid/NvVarStoreFormatted.h>
20
21 #include "NorFlash.h"
22
23 extern UINTN mFlashNvStorageVariableBase;
24 ///
25 /// The Firmware Volume Block Protocol is the low-level interface
26 /// to a firmware volume. File-level access to a firmware volume
27 /// should not be done using the Firmware Volume Block Protocol.
28 /// Normal access to a firmware volume must use the Firmware
29 /// Volume Protocol. Typically, only the file system driver that
30 /// produces the Firmware Volume Protocol will bind to the
31 /// Firmware Volume Block Protocol.
32 ///
33
34 /**
35 Initialises the FV Header and Variable Store Header
36 to support variable operations.
37
38 @param[in] Ptr - Location to initialise the headers
39
40 **/
41 EFI_STATUS
42 InitializeFvAndVariableStoreHeaders (
43 IN NOR_FLASH_INSTANCE *Instance
44 )
45 {
46 EFI_STATUS Status;
47 VOID* Headers;
48 UINTN HeadersLength;
49 EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader;
50 VARIABLE_STORE_HEADER *VariableStoreHeader;
51 UINT32 NvStorageFtwSpareSize;
52 UINT32 NvStorageFtwWorkingSize;
53 UINT32 NvStorageVariableSize;
54 UINT64 NvStorageFtwSpareBase;
55 UINT64 NvStorageFtwWorkingBase;
56 UINT64 NvStorageVariableBase;
57
58 HeadersLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(VARIABLE_STORE_HEADER);
59 Headers = AllocateZeroPool(HeadersLength);
60
61 NvStorageFtwWorkingSize = PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
62 NvStorageFtwSpareSize = PcdGet32 (PcdFlashNvStorageFtwSpareSize);
63 NvStorageVariableSize = PcdGet32 (PcdFlashNvStorageVariableSize);
64
65 NvStorageFtwSpareBase = (PcdGet64 (PcdFlashNvStorageFtwSpareBase64) != 0) ?
66 PcdGet64 (PcdFlashNvStorageFtwSpareBase64) : PcdGet32 (PcdFlashNvStorageFtwSpareBase);
67 NvStorageFtwWorkingBase = (PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) != 0) ?
68 PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) : PcdGet32 (PcdFlashNvStorageFtwWorkingBase);
69 NvStorageVariableBase = (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0) ?
70 PcdGet64 (PcdFlashNvStorageVariableBase64) : PcdGet32 (PcdFlashNvStorageVariableBase);
71
72 // FirmwareVolumeHeader->FvLength is declared to have the Variable area AND the FTW working area AND the FTW Spare contiguous.
73 if ((NvStorageVariableBase + NvStorageVariableSize) != NvStorageFtwWorkingBase) {
74 DEBUG ((DEBUG_ERROR, "%a: NvStorageFtwWorkingBase is not contiguous with NvStorageVariableBase region\n",
75 __FUNCTION__));
76 return EFI_INVALID_PARAMETER;
77 }
78
79 if ((NvStorageFtwWorkingBase + NvStorageFtwWorkingSize) != NvStorageFtwSpareBase) {
80 DEBUG ((DEBUG_ERROR, "%a: NvStorageFtwSpareBase is not contiguous with NvStorageFtwWorkingBase region\n",
81 __FUNCTION__));
82 return EFI_INVALID_PARAMETER;
83 }
84
85 // Check if the size of the area is at least one block size
86 if ((NvStorageVariableSize <= 0) || (NvStorageVariableSize / Instance->Media.BlockSize <= 0)) {
87 DEBUG ((DEBUG_ERROR, "%a: NvStorageVariableSize is 0x%x, should be atleast one block size\n", __FUNCTION__,
88 NvStorageVariableSize));
89 return EFI_INVALID_PARAMETER;
90 }
91
92 if ((NvStorageFtwWorkingSize <= 0) || (NvStorageFtwWorkingSize / Instance->Media.BlockSize <= 0)) {
93 DEBUG ((DEBUG_ERROR, "%a: NvStorageFtwWorkingSize is 0x%x, should be atleast one block size\n", __FUNCTION__,
94 NvStorageFtwWorkingSize));
95 return EFI_INVALID_PARAMETER;
96 }
97
98 if ((NvStorageFtwSpareSize <= 0) || (NvStorageFtwSpareSize / Instance->Media.BlockSize <= 0)) {
99 DEBUG ((DEBUG_ERROR, "%a: NvStorageFtwSpareSize is 0x%x, should be atleast one block size\n", __FUNCTION__,
100 NvStorageFtwSpareSize));
101 return EFI_INVALID_PARAMETER;
102 }
103
104 // Ensure the Variable area Base Addresses are aligned on a block size boundaries
105 if ((NvStorageVariableBase % Instance->Media.BlockSize != 0) ||
106 (NvStorageFtwWorkingBase % Instance->Media.BlockSize != 0) ||
107 (NvStorageFtwSpareBase % Instance->Media.BlockSize != 0)) {
108 DEBUG ((DEBUG_ERROR, "%a: NvStorage Base addresses must be aligned to block size boundaries", __FUNCTION__));
109 return EFI_INVALID_PARAMETER;
110 }
111
112 //
113 // EFI_FIRMWARE_VOLUME_HEADER
114 //
115 FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Headers;
116 CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid);
117 FirmwareVolumeHeader->FvLength =
118 PcdGet32(PcdFlashNvStorageVariableSize) +
119 PcdGet32(PcdFlashNvStorageFtwWorkingSize) +
120 PcdGet32(PcdFlashNvStorageFtwSpareSize);
121 FirmwareVolumeHeader->Signature = EFI_FVH_SIGNATURE;
122 FirmwareVolumeHeader->Attributes = (EFI_FVB_ATTRIBUTES_2) (
123 EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled
124 EFI_FVB2_READ_STATUS | // Reads are currently enabled
125 EFI_FVB2_STICKY_WRITE | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY
126 EFI_FVB2_MEMORY_MAPPED | // It is memory mapped
127 EFI_FVB2_ERASE_POLARITY | // After erasure all bits take this value (i.e. '1')
128 EFI_FVB2_WRITE_STATUS | // Writes are currently enabled
129 EFI_FVB2_WRITE_ENABLED_CAP // Writes may be enabled
130 );
131 FirmwareVolumeHeader->HeaderLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY);
132 FirmwareVolumeHeader->Revision = EFI_FVH_REVISION;
133 FirmwareVolumeHeader->BlockMap[0].NumBlocks = Instance->Media.LastBlock + 1;
134 FirmwareVolumeHeader->BlockMap[0].Length = Instance->Media.BlockSize;
135 FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0;
136 FirmwareVolumeHeader->BlockMap[1].Length = 0;
137 FirmwareVolumeHeader->Checksum = CalculateCheckSum16 ((UINT16*)FirmwareVolumeHeader,FirmwareVolumeHeader->HeaderLength);
138
139 //
140 // VARIABLE_STORE_HEADER
141 //
142 VariableStoreHeader = (VARIABLE_STORE_HEADER*)((UINTN)Headers + FirmwareVolumeHeader->HeaderLength);
143 CopyGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid);
144 VariableStoreHeader->Size = PcdGet32(PcdFlashNvStorageVariableSize) - FirmwareVolumeHeader->HeaderLength;
145 VariableStoreHeader->Format = VARIABLE_STORE_FORMATTED;
146 VariableStoreHeader->State = VARIABLE_STORE_HEALTHY;
147
148 // Install the combined super-header in the NorFlash
149 Status = FvbWrite (&Instance->FvbProtocol, 0, 0, &HeadersLength, Headers);
150
151 FreePool (Headers);
152 return Status;
153 }
154
155 /**
156 Check the integrity of firmware volume header.
157
158 @param[in] FwVolHeader - A pointer to a firmware volume header
159
160 @retval EFI_SUCCESS - The firmware volume is consistent
161 @retval EFI_NOT_FOUND - The firmware volume has been corrupted.
162
163 **/
164 EFI_STATUS
165 ValidateFvHeader (
166 IN NOR_FLASH_INSTANCE *Instance
167 )
168 {
169 UINT16 Checksum;
170 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
171 VARIABLE_STORE_HEADER *VariableStoreHeader;
172 UINTN VariableStoreLength;
173 UINTN FvLength;
174
175 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Instance->RegionBaseAddress;
176
177 FvLength = PcdGet32(PcdFlashNvStorageVariableSize) + PcdGet32(PcdFlashNvStorageFtwWorkingSize) +
178 PcdGet32(PcdFlashNvStorageFtwSpareSize);
179
180 //
181 // Verify the header revision, header signature, length
182 // Length of FvBlock cannot be 2**64-1
183 // HeaderLength cannot be an odd number
184 //
185 if ( (FwVolHeader->Revision != EFI_FVH_REVISION)
186 || (FwVolHeader->Signature != EFI_FVH_SIGNATURE)
187 || (FwVolHeader->FvLength != FvLength)
188 )
189 {
190 DEBUG ((EFI_D_INFO, "%a: No Firmware Volume header present\n",
191 __FUNCTION__));
192 return EFI_NOT_FOUND;
193 }
194
195 // Check the Firmware Volume Guid
196 if( CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid) == FALSE ) {
197 DEBUG ((EFI_D_INFO, "%a: Firmware Volume Guid non-compatible\n",
198 __FUNCTION__));
199 return EFI_NOT_FOUND;
200 }
201
202 // Verify the header checksum
203 Checksum = CalculateSum16((UINT16*)FwVolHeader, FwVolHeader->HeaderLength);
204 if (Checksum != 0) {
205 DEBUG ((EFI_D_INFO, "%a: FV checksum is invalid (Checksum:0x%X)\n",
206 __FUNCTION__, Checksum));
207 return EFI_NOT_FOUND;
208 }
209
210 VariableStoreHeader = (VARIABLE_STORE_HEADER*)((UINTN)FwVolHeader + FwVolHeader->HeaderLength);
211
212 // Check the Variable Store Guid
213 if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) &&
214 !CompareGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid)) {
215 DEBUG ((EFI_D_INFO, "%a: Variable Store Guid non-compatible\n",
216 __FUNCTION__));
217 return EFI_NOT_FOUND;
218 }
219
220 VariableStoreLength = PcdGet32 (PcdFlashNvStorageVariableSize) - FwVolHeader->HeaderLength;
221 if (VariableStoreHeader->Size != VariableStoreLength) {
222 DEBUG ((EFI_D_INFO, "%a: Variable Store Length does not match\n",
223 __FUNCTION__));
224 return EFI_NOT_FOUND;
225 }
226
227 return EFI_SUCCESS;
228 }
229
230 /**
231 The GetAttributes() function retrieves the attributes and
232 current settings of the block.
233
234 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
235
236 @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes and
237 current settings are returned.
238 Type EFI_FVB_ATTRIBUTES_2 is defined in EFI_FIRMWARE_VOLUME_HEADER.
239
240 @retval EFI_SUCCESS The firmware volume attributes were returned.
241
242 **/
243 EFI_STATUS
244 EFIAPI
245 FvbGetAttributes(
246 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
247 OUT EFI_FVB_ATTRIBUTES_2 *Attributes
248 )
249 {
250 EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes;
251 NOR_FLASH_INSTANCE *Instance;
252
253 Instance = INSTANCE_FROM_FVB_THIS(This);
254
255 FlashFvbAttributes = (EFI_FVB_ATTRIBUTES_2) (
256
257 EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled
258 EFI_FVB2_READ_STATUS | // Reads are currently enabled
259 EFI_FVB2_STICKY_WRITE | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY
260 EFI_FVB2_MEMORY_MAPPED | // It is memory mapped
261 EFI_FVB2_ERASE_POLARITY // After erasure all bits take this value (i.e. '1')
262
263 );
264
265 // Check if it is write protected
266 if (Instance->Media.ReadOnly != TRUE) {
267
268 FlashFvbAttributes = FlashFvbAttributes |
269 EFI_FVB2_WRITE_STATUS | // Writes are currently enabled
270 EFI_FVB2_WRITE_ENABLED_CAP; // Writes may be enabled
271 }
272
273 *Attributes = FlashFvbAttributes;
274
275 DEBUG ((DEBUG_BLKIO, "FvbGetAttributes(0x%X)\n", *Attributes));
276
277 return EFI_SUCCESS;
278 }
279
280 /**
281 The SetAttributes() function sets configurable firmware volume attributes
282 and returns the new settings of the firmware volume.
283
284
285 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
286
287 @param Attributes On input, Attributes is a pointer to EFI_FVB_ATTRIBUTES_2
288 that contains the desired firmware volume settings.
289 On successful return, it contains the new settings of
290 the firmware volume.
291 Type EFI_FVB_ATTRIBUTES_2 is defined in EFI_FIRMWARE_VOLUME_HEADER.
292
293 @retval EFI_SUCCESS The firmware volume attributes were returned.
294
295 @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with the capabilities
296 as declared in the firmware volume header.
297
298 **/
299 EFI_STATUS
300 EFIAPI
301 FvbSetAttributes(
302 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
303 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
304 )
305 {
306 DEBUG ((DEBUG_BLKIO, "FvbSetAttributes(0x%X) is not supported\n",*Attributes));
307 return EFI_UNSUPPORTED;
308 }
309
310 /**
311 The GetPhysicalAddress() function retrieves the base address of
312 a memory-mapped firmware volume. This function should be called
313 only for memory-mapped firmware volumes.
314
315 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
316
317 @param Address Pointer to a caller-allocated
318 EFI_PHYSICAL_ADDRESS that, on successful
319 return from GetPhysicalAddress(), contains the
320 base address of the firmware volume.
321
322 @retval EFI_SUCCESS The firmware volume base address was returned.
323
324 @retval EFI_NOT_SUPPORTED The firmware volume is not memory mapped.
325
326 **/
327 EFI_STATUS
328 EFIAPI
329 FvbGetPhysicalAddress (
330 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
331 OUT EFI_PHYSICAL_ADDRESS *Address
332 )
333 {
334 NOR_FLASH_INSTANCE *Instance;
335
336 Instance = INSTANCE_FROM_FVB_THIS(This);
337
338 DEBUG ((DEBUG_BLKIO, "FvbGetPhysicalAddress(BaseAddress=0x%08x)\n", Instance->RegionBaseAddress));
339
340 ASSERT(Address != NULL);
341
342 *Address = mFlashNvStorageVariableBase;
343 return EFI_SUCCESS;
344 }
345
346 /**
347 The GetBlockSize() function retrieves the size of the requested
348 block. It also returns the number of additional blocks with
349 the identical size. The GetBlockSize() function is used to
350 retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).
351
352
353 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
354
355 @param Lba Indicates the block for which to return the size.
356
357 @param BlockSize Pointer to a caller-allocated UINTN in which
358 the size of the block is returned.
359
360 @param NumberOfBlocks Pointer to a caller-allocated UINTN in
361 which the number of consecutive blocks,
362 starting with Lba, is returned. All
363 blocks in this range have a size of
364 BlockSize.
365
366
367 @retval EFI_SUCCESS The firmware volume base address was returned.
368
369 @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
370
371 **/
372 EFI_STATUS
373 EFIAPI
374 FvbGetBlockSize (
375 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
376 IN EFI_LBA Lba,
377 OUT UINTN *BlockSize,
378 OUT UINTN *NumberOfBlocks
379 )
380 {
381 EFI_STATUS Status;
382 NOR_FLASH_INSTANCE *Instance;
383
384 Instance = INSTANCE_FROM_FVB_THIS(This);
385
386 DEBUG ((DEBUG_BLKIO, "FvbGetBlockSize(Lba=%ld, BlockSize=0x%x, LastBlock=%ld)\n", Lba, Instance->Media.BlockSize, Instance->Media.LastBlock));
387
388 if (Lba > Instance->Media.LastBlock) {
389 DEBUG ((EFI_D_ERROR, "FvbGetBlockSize: ERROR - Parameter LBA %ld is beyond the last Lba (%ld).\n", Lba, Instance->Media.LastBlock));
390 Status = EFI_INVALID_PARAMETER;
391 } else {
392 // This is easy because in this platform each NorFlash device has equal sized blocks.
393 *BlockSize = (UINTN) Instance->Media.BlockSize;
394 *NumberOfBlocks = (UINTN) (Instance->Media.LastBlock - Lba + 1);
395
396 DEBUG ((DEBUG_BLKIO, "FvbGetBlockSize: *BlockSize=0x%x, *NumberOfBlocks=0x%x.\n", *BlockSize, *NumberOfBlocks));
397
398 Status = EFI_SUCCESS;
399 }
400
401 return Status;
402 }
403
404 /**
405 Reads the specified number of bytes into a buffer from the specified block.
406
407 The Read() function reads the requested number of bytes from the
408 requested block and stores them in the provided buffer.
409 Implementations should be mindful that the firmware volume
410 might be in the ReadDisabled state. If it is in this state,
411 the Read() function must return the status code
412 EFI_ACCESS_DENIED without modifying the contents of the
413 buffer. The Read() function must also prevent spanning block
414 boundaries. If a read is requested that would span a block
415 boundary, the read must read up to the boundary but not
416 beyond. The output parameter NumBytes must be set to correctly
417 indicate the number of bytes actually read. The caller must be
418 aware that a read may be partially completed.
419
420 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
421
422 @param Lba The starting logical block index from which to read.
423
424 @param Offset Offset into the block at which to begin reading.
425
426 @param NumBytes Pointer to a UINTN.
427 At entry, *NumBytes contains the total size of the buffer.
428 At exit, *NumBytes contains the total number of bytes read.
429
430 @param Buffer Pointer to a caller-allocated buffer that will be used
431 to hold the data that is read.
432
433 @retval EFI_SUCCESS The firmware volume was read successfully, and contents are
434 in Buffer.
435
436 @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA boundary.
437 On output, NumBytes contains the total number of bytes
438 returned in Buffer.
439
440 @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state.
441
442 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be read.
443
444 **/
445 EFI_STATUS
446 EFIAPI
447 FvbRead (
448 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
449 IN EFI_LBA Lba,
450 IN UINTN Offset,
451 IN OUT UINTN *NumBytes,
452 IN OUT UINT8 *Buffer
453 )
454 {
455 EFI_STATUS TempStatus;
456 UINTN BlockSize;
457 NOR_FLASH_INSTANCE *Instance;
458
459 Instance = INSTANCE_FROM_FVB_THIS(This);
460
461 DEBUG ((DEBUG_BLKIO, "FvbRead(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Instance->StartLba + Lba, Offset, *NumBytes, Buffer));
462
463 TempStatus = EFI_SUCCESS;
464
465 // Cache the block size to avoid de-referencing pointers all the time
466 BlockSize = Instance->Media.BlockSize;
467
468 DEBUG ((DEBUG_BLKIO, "FvbRead: Check if (Offset=0x%x + NumBytes=0x%x) <= BlockSize=0x%x\n", Offset, *NumBytes, BlockSize ));
469
470 // The read must not span block boundaries.
471 // We need to check each variable individually because adding two large values together overflows.
472 if ((Offset >= BlockSize) ||
473 (*NumBytes > BlockSize) ||
474 ((Offset + *NumBytes) > BlockSize)) {
475 DEBUG ((EFI_D_ERROR, "FvbRead: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize ));
476 return EFI_BAD_BUFFER_SIZE;
477 }
478
479 // We must have some bytes to read
480 if (*NumBytes == 0) {
481 return EFI_BAD_BUFFER_SIZE;
482 }
483
484 // Decide if we are doing full block reads or not.
485 if (*NumBytes % BlockSize != 0) {
486 TempStatus = NorFlashRead (Instance, Instance->StartLba + Lba, Offset, *NumBytes, Buffer);
487 if (EFI_ERROR (TempStatus)) {
488 return EFI_DEVICE_ERROR;
489 }
490 } else {
491 // Read NOR Flash data into shadow buffer
492 TempStatus = NorFlashReadBlocks (Instance, Instance->StartLba + Lba, BlockSize, Buffer);
493 if (EFI_ERROR (TempStatus)) {
494 // Return one of the pre-approved error statuses
495 return EFI_DEVICE_ERROR;
496 }
497 }
498 return EFI_SUCCESS;
499 }
500
501 /**
502 Writes the specified number of bytes from the input buffer to the block.
503
504 The Write() function writes the specified number of bytes from
505 the provided buffer to the specified block and offset. If the
506 firmware volume is sticky write, the caller must ensure that
507 all the bits of the specified range to write are in the
508 EFI_FVB_ERASE_POLARITY state before calling the Write()
509 function, or else the result will be unpredictable. This
510 unpredictability arises because, for a sticky-write firmware
511 volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY
512 state but cannot flip it back again. Before calling the
513 Write() function, it is recommended for the caller to first call
514 the EraseBlocks() function to erase the specified block to
515 write. A block erase cycle will transition bits from the
516 (NOT)EFI_FVB_ERASE_POLARITY state back to the
517 EFI_FVB_ERASE_POLARITY state. Implementations should be
518 mindful that the firmware volume might be in the WriteDisabled
519 state. If it is in this state, the Write() function must
520 return the status code EFI_ACCESS_DENIED without modifying the
521 contents of the firmware volume. The Write() function must
522 also prevent spanning block boundaries. If a write is
523 requested that spans a block boundary, the write must store up
524 to the boundary but not beyond. The output parameter NumBytes
525 must be set to correctly indicate the number of bytes actually
526 written. The caller must be aware that a write may be
527 partially completed. All writes, partial or otherwise, must be
528 fully flushed to the hardware before the Write() service
529 returns.
530
531 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
532
533 @param Lba The starting logical block index to write to.
534
535 @param Offset Offset into the block at which to begin writing.
536
537 @param NumBytes The pointer to a UINTN.
538 At entry, *NumBytes contains the total size of the buffer.
539 At exit, *NumBytes contains the total number of bytes actually written.
540
541 @param Buffer The pointer to a caller-allocated buffer that contains the source for the write.
542
543 @retval EFI_SUCCESS The firmware volume was written successfully.
544
545 @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary.
546 On output, NumBytes contains the total number of bytes
547 actually written.
548
549 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.
550
551 @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not be written.
552
553
554 **/
555 EFI_STATUS
556 EFIAPI
557 FvbWrite (
558 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
559 IN EFI_LBA Lba,
560 IN UINTN Offset,
561 IN OUT UINTN *NumBytes,
562 IN UINT8 *Buffer
563 )
564 {
565 NOR_FLASH_INSTANCE *Instance;
566
567 Instance = INSTANCE_FROM_FVB_THIS (This);
568
569 return NorFlashWriteSingleBlock (Instance, Instance->StartLba + Lba, Offset, NumBytes, Buffer);
570 }
571
572 /**
573 Erases and initialises a firmware volume block.
574
575 The EraseBlocks() function erases one or more blocks as denoted
576 by the variable argument list. The entire parameter list of
577 blocks must be verified before erasing any blocks. If a block is
578 requested that does not exist within the associated firmware
579 volume (it has a larger index than the last block of the
580 firmware volume), the EraseBlocks() function must return the
581 status code EFI_INVALID_PARAMETER without modifying the contents
582 of the firmware volume. Implementations should be mindful that
583 the firmware volume might be in the WriteDisabled state. If it
584 is in this state, the EraseBlocks() function must return the
585 status code EFI_ACCESS_DENIED without modifying the contents of
586 the firmware volume. All calls to EraseBlocks() must be fully
587 flushed to the hardware before the EraseBlocks() service
588 returns.
589
590 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
591 instance.
592
593 @param ... The variable argument list is a list of tuples.
594 Each tuple describes a range of LBAs to erase
595 and consists of the following:
596 - An EFI_LBA that indicates the starting LBA
597 - A UINTN that indicates the number of blocks to erase.
598
599 The list is terminated with an EFI_LBA_LIST_TERMINATOR.
600 For example, the following indicates that two ranges of blocks
601 (5-7 and 10-11) are to be erased:
602 EraseBlocks (This, 5, 3, 10, 2, EFI_LBA_LIST_TERMINATOR);
603
604 @retval EFI_SUCCESS The erase request successfully completed.
605
606 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.
607
608 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be written.
609 The firmware device may have been partially erased.
610
611 @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable argument list do
612 not exist in the firmware volume.
613
614 **/
615 EFI_STATUS
616 EFIAPI
617 FvbEraseBlocks (
618 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
619 ...
620 )
621 {
622 EFI_STATUS Status;
623 VA_LIST Args;
624 UINTN BlockAddress; // Physical address of Lba to erase
625 EFI_LBA StartingLba; // Lba from which we start erasing
626 UINTN NumOfLba; // Number of Lba blocks to erase
627 NOR_FLASH_INSTANCE *Instance;
628
629 Instance = INSTANCE_FROM_FVB_THIS(This);
630
631 DEBUG ((DEBUG_BLKIO, "FvbEraseBlocks()\n"));
632
633 Status = EFI_SUCCESS;
634
635 // Detect WriteDisabled state
636 if (Instance->Media.ReadOnly == TRUE) {
637 // Firmware volume is in WriteDisabled state
638 DEBUG ((EFI_D_ERROR, "FvbEraseBlocks: ERROR - Device is in WriteDisabled state.\n"));
639 return EFI_ACCESS_DENIED;
640 }
641
642 // Before erasing, check the entire list of parameters to ensure all specified blocks are valid
643
644 VA_START (Args, This);
645 do {
646 // Get the Lba from which we start erasing
647 StartingLba = VA_ARG (Args, EFI_LBA);
648
649 // Have we reached the end of the list?
650 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
651 //Exit the while loop
652 break;
653 }
654
655 // How many Lba blocks are we requested to erase?
656 NumOfLba = VA_ARG (Args, UINTN);
657
658 // All blocks must be within range
659 DEBUG ((
660 DEBUG_BLKIO,
661 "FvbEraseBlocks: Check if: ( StartingLba=%ld + NumOfLba=%Lu - 1 ) > LastBlock=%ld.\n",
662 Instance->StartLba + StartingLba,
663 (UINT64)NumOfLba,
664 Instance->Media.LastBlock
665 ));
666 if ((NumOfLba == 0) || ((Instance->StartLba + StartingLba + NumOfLba - 1) > Instance->Media.LastBlock)) {
667 VA_END (Args);
668 DEBUG ((EFI_D_ERROR, "FvbEraseBlocks: ERROR - Lba range goes past the last Lba.\n"));
669 Status = EFI_INVALID_PARAMETER;
670 goto EXIT;
671 }
672 } while (TRUE);
673 VA_END (Args);
674
675 //
676 // To get here, all must be ok, so start erasing
677 //
678 VA_START (Args, This);
679 do {
680 // Get the Lba from which we start erasing
681 StartingLba = VA_ARG (Args, EFI_LBA);
682
683 // Have we reached the end of the list?
684 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
685 // Exit the while loop
686 break;
687 }
688
689 // How many Lba blocks are we requested to erase?
690 NumOfLba = VA_ARG (Args, UINTN);
691
692 // Go through each one and erase it
693 while (NumOfLba > 0) {
694
695 // Get the physical address of Lba to erase
696 BlockAddress = GET_NOR_BLOCK_ADDRESS (
697 Instance->RegionBaseAddress,
698 Instance->StartLba + StartingLba,
699 Instance->Media.BlockSize
700 );
701
702 // Erase it
703 DEBUG ((DEBUG_BLKIO, "FvbEraseBlocks: Erasing Lba=%ld @ 0x%08x.\n", Instance->StartLba + StartingLba, BlockAddress));
704 Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);
705 if (EFI_ERROR(Status)) {
706 VA_END (Args);
707 Status = EFI_DEVICE_ERROR;
708 goto EXIT;
709 }
710
711 // Move to the next Lba
712 StartingLba++;
713 NumOfLba--;
714 }
715 } while (TRUE);
716 VA_END (Args);
717
718 EXIT:
719 return Status;
720 }
721
722 /**
723 Fixup internal data so that EFI can be call in virtual mode.
724 Call the passed in Child Notify event and convert any pointers in
725 lib to virtual mode.
726
727 @param[in] Event The Event that is being processed
728 @param[in] Context Event Context
729 **/
730 VOID
731 EFIAPI
732 FvbVirtualNotifyEvent (
733 IN EFI_EVENT Event,
734 IN VOID *Context
735 )
736 {
737 EfiConvertPointer (0x0, (VOID**)&mFlashNvStorageVariableBase);
738 return;
739 }
740