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