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