• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Firmware Volume Block Driver for Lakeport Platform.
3 
4   Firmware volume block driver for FWH or SPI device.
5   It depends on which Flash Device Library to be linked with this driver.
6 
7 Copyright (c) 2006  - 2014, Intel Corporation. All rights reserved.<BR>
8 
9 
10   This program and the accompanying materials are licensed and made available under
11 
12   the terms and conditions of the BSD License that accompanies this distribution.
13 
14   The full text of the license may be found at
15 
16   http://opensource.org/licenses/bsd-license.php.
17 
18 
19 
20   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
21 
22   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
23 
24 
25 
26 
27 **/
28 
29 #include "FvbService.h"
30 
31 //
32 // Global variable for this FVB driver  which contains
33 // the private data of all firmware volume block instances.
34 //
35 FWB_GLOBAL   mFvbModuleGlobal;
36 
37 //
38 // This platform driver knows there are 3 FVs on
39 // FD, which are FvRecovery, FvMain and FvNvStorage.
40 //
41 UINT32 mPlatformFvBaseAddress[] = {
42   FixedPcdGet32(PcdFlashNvStorageVariableBase),
43 };
44 
45 FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {
46   {
47     {
48       HARDWARE_DEVICE_PATH,
49       HW_MEMMAP_DP,
50       {
51         (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
52         (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
53       }
54     },
55     EfiMemoryMappedIO,
56     (EFI_PHYSICAL_ADDRESS) 0,
57     (EFI_PHYSICAL_ADDRESS) 0,
58   },
59   {
60     END_DEVICE_PATH_TYPE,
61     END_ENTIRE_DEVICE_PATH_SUBTYPE,
62     {
63       END_DEVICE_PATH_LENGTH,
64       0
65     }
66   }
67 };
68 
69 FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {
70   {
71     {
72       MEDIA_DEVICE_PATH,
73       MEDIA_PIWG_FW_VOL_DP,
74       {
75         (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
76         (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
77       }
78     },
79     { 0 }
80   },
81   {
82     END_DEVICE_PATH_TYPE,
83     END_ENTIRE_DEVICE_PATH_SUBTYPE,
84     {
85       END_DEVICE_PATH_LENGTH,
86       0
87     }
88   }
89 };
90 
91 //
92 // Template structure used when installing FVB protocol.
93 //
94 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {
95   FVB_DEVICE_SIGNATURE,
96   NULL,
97   0, // Instance
98   {
99     FvbProtocolGetAttributes,
100     FvbProtocolSetAttributes,
101     FvbProtocolGetPhysicalAddress,
102     FvbProtocolGetBlockSize,
103     FvbProtocolRead,
104     FvbProtocolWrite,
105     FvbProtocolEraseBlocks,
106     NULL
107   } // FwVolBlockInstance
108 };
109 
110 
111 /**
112   Get the pointer to EFI_FW_VOL_INSTANCE from the buffer pointed
113   by mFvbModuleGlobal.FvInstance based on a index.
GetFvbInstance(IN UINTN Instance)114   Each EFI_FW_VOL_INSTANCE is  with variable length as
115   we have a block map at the end of the EFI_FIRMWARE_VOLUME_HEADER.
116 
117   @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.
118 
119   @return A pointer to EFI_FW_VOL_INSTANCE.
120 
121 **/
122 EFI_FW_VOL_INSTANCE *
123 GetFvbInstance (
124   IN  UINTN             Instance
125   )
126 {
127   EFI_FW_VOL_INSTANCE   *FwhRecord;
128 
129   if ( Instance >= mFvbModuleGlobal.NumFv ) {
130     ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
131     return NULL;
132   }
133 
134   //
135   // Find the right instance of the FVB private data.
136   //
137   FwhRecord = mFvbModuleGlobal.FvInstance;
138   while ( Instance > 0 ) {
139     FwhRecord = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhRecord) +
140                 FwhRecord->VolumeHeader.HeaderLength +
141                 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));
142     Instance --;
143   }
144 
145   return FwhRecord;
146 
147 }
148 
149 
150 /**
FvbGetVolumeAttributes(IN UINTN Instance)151   Get the EFI_FVB_ATTRIBUTES_2 of a FV.
152 
153   @param[in]  The index of the EFI_FW_VOL_INSTANCE.
154 
155   @return     EFI_FVB_ATTRIBUTES_2 of the FV identified by Instance.
156 
157 **/
158 STATIC
159 EFI_FVB_ATTRIBUTES_2
160 FvbGetVolumeAttributes (
161   IN UINTN                                Instance
162   )
163 {
164   EFI_FW_VOL_INSTANCE *    FwInstance = NULL;
165   FwInstance = GetFvbInstance(Instance);
166   ASSERT (FwInstance != NULL);
167 
168   if ( FwInstance != NULL ) {
169     return FwInstance->VolumeHeader.Attributes;
170   } else {
171     return 0;
172   }
173 }
174 
175 
176 /**
177   Retrieves the starting address of an LBA in an FV. It also
178   return a few other attribut of the FV.
179 
180   @param[in]  Instance               The index of the EFI_FW_VOL_INSTANCE.
181   @param[in]  Lba                    The logical block address.
182   @param[out] LbaAddress             On output, contains the physical starting address
183                                      of the Lba.
184   @param[out] LbaLength              On output, contains the length of the block.
185   @param[out] NumOfBlocks            A pointer to a caller allocated UINTN in which the
186                                      number of consecutive blocks starting with Lba is
FvbGetLbaAddress(IN UINTN Instance,IN EFI_LBA Lba,OUT UINTN * LbaAddress,OUT UINTN * LbaLength,OUT UINTN * NumOfBlocks)187                                      returned. All blocks in this range have a size of
188                                      BlockSize.
189 
190   @retval  EFI_SUCCESS Successfully  returns.
191   @retval  EFI_INVALID_PARAMETER     Instance not found.
192 
193 **/
194 STATIC
195 EFI_STATUS
196 FvbGetLbaAddress (
197   IN  UINTN                               Instance,
198   IN  EFI_LBA                             Lba,
199   OUT UINTN                               *LbaAddress,
200   OUT UINTN                               *LbaLength,
201   OUT UINTN                               *NumOfBlocks
202   )
203 {
204   UINT32                                  NumBlocks = 0;
205   UINT32                                  BlockLength = 0;
206   UINTN                                   Offset;
207   EFI_LBA                                 StartLba;
208   EFI_LBA                                 NextLba;
209   EFI_FW_VOL_INSTANCE                     *FwhInstance;
210   EFI_FV_BLOCK_MAP_ENTRY                  *BlockMap = NULL;
211 
212   //
213   // Find the right instance of the FVB private data.
214   //
215   FwhInstance = GetFvbInstance (Instance);
216 
217   StartLba  = 0;
218   Offset    = 0;
219   BlockMap  = &(FwhInstance->VolumeHeader.BlockMap[0]);
220   ASSERT (BlockMap != NULL);
221 
222   //
223   // Parse the blockmap of the FV to find which map entry the Lba belongs to.
224   //
225   while (TRUE) {
226     if ( BlockMap != NULL) {
227       NumBlocks   = BlockMap->NumBlocks;
228       BlockLength = BlockMap->Length;
229     }
230 
231     if ( NumBlocks == 0 || BlockLength == 0) {
232       return EFI_INVALID_PARAMETER;
233     }
234 
235     NextLba = StartLba + NumBlocks;
236 
237     //
238     // The map entry found.
239     //
240     if (Lba >= StartLba && Lba < NextLba) {
241       Offset = Offset + (UINTN)MultU64x32((Lba - StartLba), BlockLength);
242       if ( LbaAddress && FwhInstance ) {
243         *LbaAddress = FwhInstance->FvBase + Offset;
244       }
245 
246       if (LbaLength ) {
247         *LbaLength = BlockLength;
248       }
249 
250       if (NumOfBlocks ) {
251         *NumOfBlocks = (UINTN)(NextLba - Lba);
252       }
253       return EFI_SUCCESS;
254     }
255 
256     StartLba  = NextLba;
257     Offset    = Offset + NumBlocks * BlockLength;
258     BlockMap++;
259   }
260 }
261 
262 
263 /**
264   Reads specified number of bytes into a buffer from the specified block.
265 
266   @param[in]      Instance               The FV instance to be read from.
267   @param[in]      Lba                    The logical block address to be read from.
268   @param[in]      BlockOffset            Offset into the block at which to begin reading.
269   @param[in]      NumBytes               Pointer that on input contains the total size of
270                                          the buffer. On output, it contains the total number
271                                          of bytes read.
272   @param[in]      Buffer                 Pointer to a caller allocated buffer that will be
273                                          used to hold the data read.
274 
275 
276   @retval         EFI_SUCCESS            The firmware volume was read successfully and
277                                          contents are in Buffer.
278   @retval         EFI_BAD_BUFFER_SIZE    Read attempted across a LBA boundary. On output,
279                                          NumBytes contains the total number of bytes returned
FvbReadBlock(IN UINTN Instance,IN EFI_LBA Lba,IN UINTN BlockOffset,IN OUT UINTN * NumBytes,IN UINT8 * Buffer)280                                          in Buffer.
281   @retval         EFI_ACCESS_DENIED      The firmware volume is in the ReadDisabled state.
282   @retval         EFI_DEVICE_ERROR       The block device is not functioning correctly and
283                                          could not be read.
284   @retval         EFI_INVALID_PARAMETER  Instance not found, or NumBytes, Buffer are NULL.
285 
286 **/
287 STATIC
288 EFI_STATUS
289 FvbReadBlock (
290   IN UINTN                                Instance,
291   IN EFI_LBA                              Lba,
292   IN UINTN                                BlockOffset,
293   IN OUT UINTN                            *NumBytes,
294   IN UINT8                                *Buffer
295   )
296 {
297   EFI_FVB_ATTRIBUTES_2                    Attributes;
298   UINTN                                   LbaAddress;
299   UINTN                                   LbaLength;
300   EFI_STATUS                              Status;
301 
302   if ( (NumBytes == NULL) || (Buffer == NULL)) {
303     return (EFI_INVALID_PARAMETER);
304   }
305   if (*NumBytes == 0) {
306     return (EFI_INVALID_PARAMETER);
307   }
308 
309   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);
310   if (EFI_ERROR(Status)) {
311     return Status;
312   }
313 
314   Attributes = FvbGetVolumeAttributes (Instance);
315 
316   if ( (Attributes & EFI_FVB2_READ_STATUS) == 0) {
317     return (EFI_ACCESS_DENIED);
318   }
319 
320   if (BlockOffset > LbaLength) {
321    return (EFI_INVALID_PARAMETER);
322   }
323 
324   if (LbaLength < ( *NumBytes + BlockOffset ) ) {
325     *NumBytes = (UINT32) (LbaLength - BlockOffset);
326     Status = EFI_BAD_BUFFER_SIZE;
327   }
328 
329   LibFvbFlashDeviceRead (LbaAddress + BlockOffset, NumBytes, Buffer);
330 
331   return Status;
332 }
333 
334 
335 /**
336   Writes specified number of bytes from the input buffer to the block.
337 
338   @param[in]  Instance               The FV instance to be written to.
339   @param[in]  Lba                    The starting logical block index to write to.
340   @param[in]  BlockOffset            Offset into the block at which to begin writing.
341   @param[in]  NumBytes               Pointer that on input contains the total size of
342                                      the buffer. On output, it contains the total number
343                                      of bytes actually written.
344   @param[in]  Buffer                 Pointer to a caller allocated buffer that contains
345                                      the source for the write.
346   @retval     EFI_SUCCESS            The firmware volume was written successfully.
347   @retval     EFI_BAD_BUFFER_SIZE    Write attempted across a LBA boundary. On output,
FvbWriteBlock(IN UINTN Instance,IN EFI_LBA Lba,IN UINTN BlockOffset,IN OUT UINTN * NumBytes,IN UINT8 * Buffer)348                                      NumBytes contains the total number of bytes
349                                      actually writte.
350   @retval     EFI_ACCESS_DENIED      The firmware volume is in the WriteDisabled state.
351   @retval     EFI_DEVICE_ERROR       The block device is not functioning correctly and
352                                      could not be written.
353   @retval     EFI_INVALID_PARAMETER  Instance not found, or NumBytes, Buffer are NULL.
354 
355 **/
356 EFI_STATUS
357 FvbWriteBlock (
358   IN UINTN                                Instance,
359   IN EFI_LBA                              Lba,
360   IN UINTN                                BlockOffset,
361   IN OUT UINTN                            *NumBytes,
362   IN UINT8                                *Buffer
363   )
364 {
365   EFI_FVB_ATTRIBUTES_2                    Attributes;
366   UINTN                                   LbaAddress;
367   UINTN                                   LbaLength;
368   EFI_STATUS                              Status;
369   EFI_STATUS                              Status1;
370 
371   if ( (NumBytes == NULL) || (Buffer == NULL)) {
372     return (EFI_INVALID_PARAMETER);
373   }
374   if (*NumBytes == 0) {
375     return (EFI_INVALID_PARAMETER);
376   }
377 
378   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);
379   if (EFI_ERROR(Status)) {
380     return Status;
381   }
382 
383   //
384   // Check if the FV is write enabled.
385   //
386   Attributes = FvbGetVolumeAttributes (Instance);
387   if ( (Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
388     return (EFI_ACCESS_DENIED);
389   }
390 
391   //
392   // Perform boundary checks and adjust NumBytes.
393   //
394   if (BlockOffset > LbaLength) {
395     return (EFI_INVALID_PARAMETER);
396   }
397 
398   if ( LbaLength < ( *NumBytes + BlockOffset ) ) {
399     DEBUG ((EFI_D_ERROR,
400       "FvWriteBlock: Reducing Numbytes from 0x%x to 0x%x\n",
401       *NumBytes,
402       (UINT32)(LbaLength-BlockOffset))
403       );
404     *NumBytes = (UINT32) (LbaLength - BlockOffset);
405     Status = EFI_BAD_BUFFER_SIZE;
406   }
407 
408   LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);
409 
410   Status1 = LibFvbFlashDeviceWrite (LbaAddress + BlockOffset, NumBytes, Buffer);
411 
412   LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);
413   WriteBackInvalidateDataCacheRange ((VOID *) (LbaAddress + BlockOffset), *NumBytes);
414 
415   if ( EFI_ERROR (Status1) ) {
416     return Status1;
417   }
418 
419   return Status;
420 }
421 
422 
423 /**
424   Erases and initializes a firmware volume block.
425 
426   @param[in]    Instance           The FV instance to be erased.
427   @param[in]    Lba                The logical block index to be erased.
428 
FvbEraseBlock(IN UINTN Instance,IN EFI_LBA Lba)429   @retval   EFI_SUCCESS            The erase request was successfully completed.
430   @retval   EFI_ACCESS_DENIED      The firmware volume is in the WriteDisabled state.
431   @retval   EFI_DEVICE_ERROR       The block device is not functioning correctly and
432                                    could not be written. Firmware device may have been
433                                    partially erased.
434   @retval   EFI_INVALID_PARAMETER  Instance not found.
435 
436 **/
437 EFI_STATUS
438 FvbEraseBlock (
439   IN UINTN                                Instance,
440   IN EFI_LBA                              Lba
441   )
442 {
443   EFI_FVB_ATTRIBUTES_2                    Attributes;
444   UINTN                                   LbaAddress;
445   UINTN                                   LbaLength;
446   EFI_STATUS                              Status;
447 
448   //
449   // Check if the FV is write enabled.
450   //
451   Attributes = FvbGetVolumeAttributes (Instance);
452 
453   if( (Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
454     return (EFI_ACCESS_DENIED);
455   }
456 
457   //
458   // Get the starting address of the block for erase.
459   //
460   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);
461   if (EFI_ERROR(Status)) {
462     return Status;
463   }
464 
465   LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);
466 
467   Status = LibFvbFlashDeviceBlockErase (LbaAddress, LbaLength);
468 
469   LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);
470 
471   WriteBackInvalidateDataCacheRange ((VOID *) LbaAddress, LbaLength);
472 
473   return Status;
474 }
475 
476 
477 /**
478   Modifies the current settings of the firmware volume according to the
479   input parameter, and returns the new setting of the volume.
480 
481   @param[in]  Instance              The FV instance whose attributes is going to be
482                                     modified.
483   @param[in]  Attributes            On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
484                                     containing the desired firmware volume settings.
485                                     On successful return, it contains the new settings
486                                     of the firmware volume.
487 
FvbSetVolumeAttributes(IN UINTN Instance,IN OUT EFI_FVB_ATTRIBUTES_2 * Attributes)488   @retval     EFI_SUCCESS           Successfully returns.
489   @retval     EFI_ACCESS_DENIED     The volume setting is locked and cannot be modified.
490   @retval     EFI_INVALID_PARAMETER Instance not found, or The attributes requested are
491                                     in conflict with the capabilities as declared in the
492                                     firmware volume header.
493 
494 **/
495 STATIC
496 EFI_STATUS
497 FvbSetVolumeAttributes (
498   IN UINTN                                Instance,
499   IN OUT EFI_FVB_ATTRIBUTES_2             *Attributes
500   )
501 {
502   EFI_FW_VOL_INSTANCE                       *FwhInstance = NULL;
503   EFI_FVB_ATTRIBUTES_2                      OldAttributes = 0;
504   EFI_FVB_ATTRIBUTES_2                      *AttribPtr = NULL;
505   EFI_FVB_ATTRIBUTES_2                      UnchangedAttributes;
506   UINT32                                    Capabilities;
507   UINT32                                    OldStatus, NewStatus;
508 
509   //
510   // Find the right instance of the FVB private data.
511   //
512   FwhInstance = GetFvbInstance (Instance);
513 
514   AttribPtr     = (EFI_FVB_ATTRIBUTES_2 *) & (FwhInstance->VolumeHeader.Attributes);
515   ASSERT (AttribPtr != NULL);
516 
517   if ( AttribPtr != NULL) {
518     OldAttributes = *AttribPtr;
519   }
520 
521   Capabilities  = OldAttributes & EFI_FVB2_CAPABILITIES;
522   OldStatus     = OldAttributes & EFI_FVB2_STATUS;
523   NewStatus     = *Attributes & EFI_FVB2_STATUS;
524 
525   UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP  | \
526                         EFI_FVB2_READ_ENABLED_CAP   | \
527                         EFI_FVB2_WRITE_DISABLED_CAP | \
528                         EFI_FVB2_WRITE_ENABLED_CAP  | \
529                         EFI_FVB2_LOCK_CAP           | \
530                         EFI_FVB2_STICKY_WRITE       | \
531                         EFI_FVB2_MEMORY_MAPPED      | \
532                         EFI_FVB2_ERASE_POLARITY     | \
533                         EFI_FVB2_READ_LOCK_CAP      | \
534                         EFI_FVB2_WRITE_LOCK_CAP     | \
535                         EFI_FVB2_ALIGNMENT;
536 
537   //
538   // Some attributes of FV is read only can *not* be set.
539   //
540   if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {
541     return EFI_INVALID_PARAMETER;
542   }
543 
544   //
545   // If firmware volume is locked, no status bit can be updated.
546   //
547   if ( OldAttributes & EFI_FVB2_LOCK_STATUS ) {
548     if ( OldStatus ^ NewStatus ) {
549       return EFI_ACCESS_DENIED;
550     }
551   }
552 
553   //
554   // Test read disable.
555   //
556   if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
557     if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
558       return EFI_INVALID_PARAMETER;
559     }
560   }
561 
562   //
563   // Test read enable.
564   //
565   if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
566     if (NewStatus & EFI_FVB2_READ_STATUS) {
567       return EFI_INVALID_PARAMETER;
568     }
569   }
570 
571   //
572   // Test write disable.
573   //
574   if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
575     if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
576       return EFI_INVALID_PARAMETER;
577     }
578   }
579 
580   //
581   // Test write enable.
582   //
583   if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
584     if (NewStatus & EFI_FVB2_WRITE_STATUS) {
585       return EFI_INVALID_PARAMETER;
586     }
587   }
588 
589   //
590   // Test lock.
591   //
592   if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
593     if (NewStatus & EFI_FVB2_LOCK_STATUS) {
594       return EFI_INVALID_PARAMETER;
595     }
596   }
597 
598   *AttribPtr  = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
599   *AttribPtr  = (*AttribPtr) | NewStatus;
600   *Attributes = *AttribPtr;
601 
602   return EFI_SUCCESS;
603 }
604 
605 //
606 // FVB protocol APIs.
607 //
608 /**
609   Retrieves the physical address of the device.
FvbProtocolGetPhysicalAddress(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,OUT EFI_PHYSICAL_ADDRESS * Address)610 
611   @param[in]  This    A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL.
612   @param[out] Address Output buffer containing the address.
613 
614   retval      EFI_SUCCESS The function always return successfully.
615 
616 **/
617 EFI_STATUS
618 EFIAPI
619 FvbProtocolGetPhysicalAddress (
620   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
621   OUT EFI_PHYSICAL_ADDRESS               *Address
622   )
623 {
624   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
625   EFI_FW_VOL_INSTANCE                   *FvInstance;
626 
627   FvbDevice = FVB_DEVICE_FROM_THIS (This);
628   FvInstance = GetFvbInstance(FvbDevice->Instance);
629 
630   if (FvInstance != NULL) {
631     *Address = FvInstance->FvBase;
632   }
633 
634   return EFI_SUCCESS;
635 }
636 
637 
638 /**
639   Retrieve the size of a logical block.
640 
641   @param[in]  This         Calling context.
642   @param[in]  Lba          Indicates which block to return the size for.
643   @param[out] BlockSize    A pointer to a caller allocated UINTN in which
644                            the size of the block is returned.
645   @param[out] NumOfBlocks  A pointer to a caller allocated UINTN in which the
FvbProtocolGetBlockSize(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN EFI_LBA Lba,OUT UINTN * BlockSize,OUT UINTN * NumOfBlocks)646                            number of consecutive blocks starting with Lba is
647                            returned. All blocks in this range have a size of
648                            BlockSize.
649 
650   @retval     EFI_SUCCESS  The function always return successfully.
651 
652 **/
653 EFI_STATUS
654 EFIAPI
655 FvbProtocolGetBlockSize (
656   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
657   IN  EFI_LBA                            Lba,
658   OUT UINTN                              *BlockSize,
659   OUT UINTN                              *NumOfBlocks
660   )
661 {
662   EFI_FW_VOL_BLOCK_DEVICE                 *FvbDevice;
663 
664   DEBUG((EFI_D_INFO,
665     "FvbProtocolGetBlockSize: Lba: 0x%lx BlockSize: 0x%x NumOfBlocks: 0x%x\n",
666     Lba,
667     BlockSize,
668     NumOfBlocks)
669     );
670 
671   FvbDevice = FVB_DEVICE_FROM_THIS (This);
672 
673   return FvbGetLbaAddress (
674            FvbDevice->Instance,
675            Lba,
676            NULL,
677            BlockSize,
678            NumOfBlocks
679            );
680 }
681 
682 
683 /**
684   Retrieves Volume attributes.  No polarity translations are done.
FvbProtocolGetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,OUT EFI_FVB_ATTRIBUTES_2 * Attributes)685 
686   @param[in]    This         Calling context.
687   @param[out]   Attributes   Output buffer which contains attributes.
688 
689   @retval       EFI_SUCCESS  The function always return successfully.
690 
691 **/
692 EFI_STATUS
693 EFIAPI
694 FvbProtocolGetAttributes (
695   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
696   OUT EFI_FVB_ATTRIBUTES_2                *Attributes
697   )
698 {
699   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
700 
701   FvbDevice = FVB_DEVICE_FROM_THIS (This);
702 
703   *Attributes = FvbGetVolumeAttributes (FvbDevice->Instance);
704 
705   DEBUG ((EFI_D_INFO,
706     "FvbProtocolGetAttributes: This: 0x%x Attributes: 0x%x\n",
707     This,
708     *Attributes)
709     );
710 
711   return EFI_SUCCESS;
712 }
713 
714 
715 /**
716   Sets Volume attributes. No polarity translations are done.
FvbProtocolSetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN OUT EFI_FVB_ATTRIBUTES_2 * Attributes)717 
718   @param[in]  This         Calling context.
719   @param[out] Attributes   Output buffer which contains attributes.
720 
721   @retval     EFI_SUCCESS  The function always return successfully.
722 
723 **/
724 EFI_STATUS
725 EFIAPI
726 FvbProtocolSetAttributes (
727   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
728   IN OUT EFI_FVB_ATTRIBUTES_2             *Attributes
729   )
730 {
731   EFI_STATUS                            Status;
732   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
733 
734   DEBUG((EFI_D_INFO,
735     "FvbProtocolSetAttributes: Before SET -  This: 0x%x Attributes: 0x%x\n",
736     This,
737     *Attributes)
738     );
739 
740   FvbDevice = FVB_DEVICE_FROM_THIS (This);
741 
742   Status = FvbSetVolumeAttributes (FvbDevice->Instance, Attributes);
743 
744   DEBUG((EFI_D_INFO,
745     "FvbProtocolSetAttributes: After SET -  This: 0x%x Attributes: 0x%x\n",
746     This,
747     *Attributes)
748     );
749 
750   return Status;
751 }
752 
753 
754 /**
755   The EraseBlock() function erases one or more blocks as denoted by the
756   variable argument list. The entire parameter list of blocks must be verified
757   prior to erasing any blocks.  If a block is requested that does not exist
758   within the associated firmware volume (it has a larger index than the last
759   block of the firmware volume), the EraseBlock() function must return
760   EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
761 
762   @param[in] This            Calling context.
763   @param[in] ...             Starting LBA followed by Number of Lba to erase.
764                              a -1 to terminate the list.
765 
FvbProtocolEraseBlocks(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,...)766   @retval EFI_SUCCESS        The erase request was successfully completed.
767   @retval EFI_ACCESS_DENIED  The firmware volume is in the WriteDisabled state.
768   @retval EFI_DEVICE_ERROR   The block device is not functioning correctly and
769                              could not be written. Firmware device may have been
770                              partially erased.
771 
772 **/
773 EFI_STATUS
774 EFIAPI
775 FvbProtocolEraseBlocks (
776   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *This,
777   ...
778   )
779 {
780   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
781   EFI_FW_VOL_INSTANCE                   *FwhInstance;
782   UINTN                                 NumOfBlocks = 0;
783   VA_LIST                               args;
784   EFI_LBA                               StartingLba;
785   UINTN                                 NumOfLba;
786   EFI_STATUS                            Status;
787 
788   DEBUG((EFI_D_INFO, "FvbProtocolEraseBlocks: \n"));
789   FvbDevice = FVB_DEVICE_FROM_THIS (This);
790 
791   FwhInstance  = GetFvbInstance (FvbDevice->Instance);
792 
793   if (FwhInstance != NULL) {
794     NumOfBlocks = FwhInstance->NumOfBlocks;
795   }
796 
797   VA_START (args, This);
798 
799   do {
800     StartingLba = VA_ARG (args, EFI_LBA);
801     if ( StartingLba == EFI_LBA_LIST_TERMINATOR ) {
802       break;
803     }
804 
805     NumOfLba = VA_ARG (args, UINT32);
806 
807     //
808     // Check input parameters.
809     //
810     if (NumOfLba == 0) {
811       VA_END (args);
812       return EFI_INVALID_PARAMETER;
813     }
814 
815     if ( ( StartingLba + NumOfLba ) > NumOfBlocks ) {
816       return EFI_INVALID_PARAMETER;
817     }
818   } while ( 1 );
819 
820   VA_END (args);
821 
822   VA_START (args, This);
823   do {
824     StartingLba = VA_ARG (args, EFI_LBA);
825     if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
826       break;
827     }
828 
829     NumOfLba = VA_ARG (args, UINT32);
830 
831     while ( NumOfLba > 0 ) {
832       Status = FvbEraseBlock (FvbDevice->Instance, StartingLba);
833       if ( EFI_ERROR(Status)) {
834         VA_END (args);
835         return Status;
836       }
837       StartingLba ++;
838       NumOfLba --;
839     }
840 
841   } while ( 1 );
842 
843   VA_END (args);
844 
845   return EFI_SUCCESS;
846 }
847 
848 
849 /**
850   Writes data beginning at Lba:Offset from FV. The write terminates either
851   when *NumBytes of data have been written, or when a block boundary is
852   reached.  *NumBytes is updated to reflect the actual number of bytes
853   written. The write opertion does not include erase. This routine will
854   attempt to write only the specified bytes. If the writes do not stick,
855   it will return an error.
856 
857   @param[in]      This      Calling context.
858   @param[in]      Lba       Block in which to begin write.
859   @param[in]      Offset    Offset in the block at which to begin write.
860   @param[in,out]  NumBytes  On input, indicates the requested write size. On
861                             output, indicates the actual number of bytes written
862   @param[in]      Buffer    Buffer containing source data for the write.
863 
864   @retval EFI_SUCCESS           The firmware volume was written successfully.
865   @retval EFI_BAD_BUFFER_SIZE   Write attempted across a LBA boundary. On output,
866                                 NumBytes contains the total number of bytes
FvbProtocolWrite(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Offset,IN OUT UINTN * NumBytes,IN UINT8 * Buffer)867                                 actually written.
868   @retval EFI_ACCESS_DENIED     The firmware volume is in the WriteDisabled state.
869   @retval EFI_DEVICE_ERROR      The block device is not functioning correctly and
870                                 could not be written.
871   @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL.
872 
873 **/
874 EFI_STATUS
875 EFIAPI
876 FvbProtocolWrite (
877   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
878   IN EFI_LBA                              Lba,
879   IN UINTN                                Offset,
880   IN OUT UINTN                            *NumBytes,
881   IN UINT8                                *Buffer
882   )
883 {
884 
885   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
886 
887   FvbDevice = FVB_DEVICE_FROM_THIS (This);
888 
889   DEBUG((EFI_D_INFO,
890     "FvbProtocolWrite: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x\n",
891     Lba,
892     Offset,
893     *NumBytes,
894     Buffer)
895     );
896 
897   return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer);
898 }
899 
900 
901 /**
902   Reads data beginning at Lba:Offset from FV. The Read terminates either
903   when *NumBytes of data have been read, or when a block boundary is
904   reached.  *NumBytes is updated to reflect the actual number of bytes
905   written. The write opertion does not include erase. This routine will
906   attempt to write only the specified bytes. If the writes do not stick,
907   it will return an error.
908 
909   @param[in]      This      Calling context.
910   @param[in]      Lba       Block in which to begin write.
911   @param[in]      Offset    Offset in the block at which to begin write
912   @param[in,out]  NumBytes  On input, indicates the requested write size. On
913                             output, indicates the actual number of bytes written.
914   @param[in]      Buffer    Buffer containing source data for the write.
915 
916 
917 Returns:
918   @retval EFI_SUCCESS            The firmware volume was read successfully and
919                                  contents are in Buffer.
920   @retval EFI_BAD_BUFFER_SIZE    Read attempted across a LBA boundary. On output,
921                                  NumBytes contains the total number of bytes returned
FvbProtocolRead(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Offset,IN OUT UINTN * NumBytes,OUT UINT8 * Buffer)922                                  in Buffer.
923   @retval EFI_ACCESS_DENIED      The firmware volume is in the ReadDisabled state
924   @retval EFI_DEVICE_ERROR       The block device is not functioning correctly and
925                                  could not be read.
926   @retval EFI_INVALID_PARAMETER  NumBytes or Buffer are NULL.
927 
928 **/
929 EFI_STATUS
930 EFIAPI
931 FvbProtocolRead (
932   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
933   IN EFI_LBA                              Lba,
934   IN UINTN                                Offset,
935   IN OUT UINTN                            *NumBytes,
936   OUT UINT8                                *Buffer
937   )
938 {
939 
940   EFI_FW_VOL_BLOCK_DEVICE   *FvbDevice;
941   EFI_STATUS                Status;
942 
943   FvbDevice = FVB_DEVICE_FROM_THIS (This);
944   Status = FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer);
945   DEBUG((EFI_D_INFO,
946     "FvbProtocolRead: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x\n",
947     Lba,
948     Offset,
949     *NumBytes,
950     Buffer)
951     );
952 
953   return Status;
954 }
955 
956 
957 /**
IsFvHeaderValid(IN EFI_PHYSICAL_ADDRESS FvBase,IN CONST EFI_FIRMWARE_VOLUME_HEADER * FwVolHeader)958   Check the integrity of firmware volume header.
959 
960   @param[in]  FwVolHeader   A pointer to a firmware volume header.
961 
962   @retval     TRUE          The firmware volume is consistent.
963   @retval     FALSE         The firmware volume has corrupted.
964 
965 **/
966 BOOLEAN
967 IsFvHeaderValid (
968   IN       EFI_PHYSICAL_ADDRESS          FvBase,
969   IN CONST EFI_FIRMWARE_VOLUME_HEADER    *FwVolHeader
970   )
971 {
972   if (FvBase == PcdGet32(PcdFlashNvStorageVariableBase)) {
973     if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid, sizeof(EFI_GUID)) != 0 ) {
974       return FALSE;
975     }
976   } else {
977     if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid, sizeof(EFI_GUID)) != 0 ) {
978       return FALSE;
979     }
980   }
981   if ( (FwVolHeader->Revision != EFI_FVH_REVISION)   ||
982        (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
983        (FwVolHeader->FvLength == ((UINTN) -1))       ||
984        ((FwVolHeader->HeaderLength & 0x01 ) !=0) ) {
985     return FALSE;
986   }
987 
988   if (CalculateCheckSum16 ((UINT16 *) FwVolHeader, FwVolHeader->HeaderLength) != 0) {
989     return FALSE;
990   }
991 
992   return TRUE;
993 }
994 
995 
FvbInitialize(VOID)996 /**
997   The function does the necessary initialization work for
998   Firmware Volume Block Driver.
999 
1000   @retval     EFI_SUCCESS       This funtion always return EFI_SUCCESS.
1001                                 It will ASSERT on errors.
1002 
1003 **/
1004 EFI_STATUS
1005 FvbInitialize (
1006   VOID
1007   )
1008 {
1009   EFI_FW_VOL_INSTANCE                   *FwhInstance;
1010   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
1011   EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
1012   EFI_FV_BLOCK_MAP_ENTRY                *PtrBlockMapEntry;
1013   EFI_PHYSICAL_ADDRESS                  BaseAddress;
1014   EFI_STATUS                            Status;
1015   UINTN                                 BufferSize;
1016   UINTN                                 TmpHeaderLength;
1017   UINTN                                 Idx;
1018   UINT32                                MaxLbaSize;
1019 
1020   //
1021   // Calculate the total size for all firmware volume block instances.
1022   //
1023   BufferSize = 0;
1024   for (Idx = 0; Idx < 1; Idx++) {
1025     FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) mPlatformFvBaseAddress[Idx];
1026     BufferSize +=  (FvHeader->HeaderLength +
1027                     sizeof (EFI_FW_VOL_INSTANCE) -
1028                     sizeof (EFI_FIRMWARE_VOLUME_HEADER)
1029                    );
1030   }
1031 
1032   mFvbModuleGlobal.FvInstance =  (EFI_FW_VOL_INSTANCE *) AllocateRuntimeZeroPool (BufferSize);
1033   ASSERT (NULL != mFvbModuleGlobal.FvInstance);
1034 
1035 
1036   MaxLbaSize      = 0;
1037   FwhInstance     = mFvbModuleGlobal.FvInstance;
1038   mFvbModuleGlobal.NumFv   = 0;
1039 
1040   for (Idx = 0; Idx < 1; Idx++) {
1041     BaseAddress = mPlatformFvBaseAddress[Idx];
1042     FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
1043 
1044     if (!IsFvHeaderValid (BaseAddress, FwVolHeader)) {
1045       //
1046       // If not valid, get FvbInfo from the information carried in
1047       // FVB driver.
1048       //
1049       DEBUG ((EFI_D_ERROR, "Fvb: FV header @ 0x%lx invalid\n", BaseAddress));
1050       Status          = GetFvbInfo (BaseAddress, &FwVolHeader);
1051       ASSERT_EFI_ERROR(Status);
1052       //
1053       //  Write back a healthy FV header.
1054       //
1055       DEBUG ((EFI_D_ERROR, "FwBlockService.c: Writing back healthy FV header\n"));
1056       LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length, FALSE);
1057 
1058       Status = LibFvbFlashDeviceBlockErase ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length);
1059 
1060       TmpHeaderLength = (UINTN) FwVolHeader->HeaderLength;
1061       Status = LibFvbFlashDeviceWrite (
1062                  (UINTN)BaseAddress,
1063                  &TmpHeaderLength,
1064                  (UINT8 *) FwVolHeader
1065                  );
1066 
1067       LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length, TRUE);
1068 
1069       WriteBackInvalidateDataCacheRange (
1070         (VOID *) (UINTN) BaseAddress,
1071         FwVolHeader->BlockMap->Length
1072         );
1073 
1074     }
1075 
1076     CopyMem (&(FwhInstance->VolumeHeader), FwVolHeader, FwVolHeader->HeaderLength);
1077 
1078     FwVolHeader = &(FwhInstance->VolumeHeader);
1079     FwhInstance->FvBase = (UINTN)BaseAddress;
1080 
1081     //
1082     // Process the block map for each FV.
1083     //
1084     FwhInstance->NumOfBlocks = 0;
1085     for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
1086       //
1087       // Get the maximum size of a block.
1088       //
1089       if (MaxLbaSize < PtrBlockMapEntry->Length) {
1090         MaxLbaSize  = PtrBlockMapEntry->Length;
1091       }
1092       FwhInstance->NumOfBlocks += PtrBlockMapEntry->NumBlocks;
1093     }
1094 
1095     //
1096     // Add a FVB Protocol Instance.
1097     //
1098     mFvbModuleGlobal.NumFv++;
1099     InstallFvbProtocol (FwhInstance, mFvbModuleGlobal.NumFv - 1);
1100 
1101     //
1102     // Move on to the next FwhInstance.
1103     //
1104     FwhInstance = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhInstance) +
1105                                           FwVolHeader->HeaderLength +
1106                                           (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));
1107 
1108   }
1109 
1110   return EFI_SUCCESS;
1111 }
1112 
1113