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