• 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_EFI_ERROR (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_EFI_ERROR (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_FW_VOL_INSTANCE                     *FwhInstance;
369   EFI_STATUS                              Status;
370   EFI_STATUS                              Status1;
371 
372   FwhInstance = GetFvbInstance (Instance);
373 
374   if ( (NumBytes == NULL) || (Buffer == NULL)) {
375     return (EFI_INVALID_PARAMETER);
376   }
377   if (*NumBytes == 0) {
378     return (EFI_INVALID_PARAMETER);
379   }
380 
381   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);
382   if (EFI_ERROR(Status)) {
383     return Status;
384   }
385 
386   //
387   // Check if the FV is write enabled.
388   //
389   Attributes = FvbGetVolumeAttributes (Instance);
390   if ( (Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
391     return (EFI_ACCESS_DENIED);
392   }
393 
394   //
395   // Perform boundary checks and adjust NumBytes.
396   //
397   if (BlockOffset > LbaLength) {
398     return (EFI_INVALID_PARAMETER);
399   }
400 
401   if ( LbaLength < ( *NumBytes + BlockOffset ) ) {
402     DEBUG ((EFI_D_ERROR,
403       "FvWriteBlock: Reducing Numbytes from 0x%x to 0x%x\n",
404       *NumBytes,
405       (UINT32)(LbaLength-BlockOffset))
406       );
407     *NumBytes = (UINT32) (LbaLength - BlockOffset);
408     Status = EFI_BAD_BUFFER_SIZE;
409   }
410 
411   LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);
412 
413   Status1 = LibFvbFlashDeviceWrite (LbaAddress + BlockOffset, NumBytes, Buffer);
414 
415   LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);
416   WriteBackInvalidateDataCacheRange ((VOID *) (LbaAddress + BlockOffset), *NumBytes);
417 
418   if ( EFI_ERROR (Status1) ) {
419     return Status1;
420   }
421 
422   return Status;
423 }
424 
425 
426 /**
427   Erases and initializes a firmware volume block.
428 
429   @param[in]    Instance           The FV instance to be erased.
430   @param[in]    Lba                The logical block index to be erased.
431 
FvbEraseBlock(IN UINTN Instance,IN EFI_LBA Lba)432   @retval   EFI_SUCCESS            The erase request was successfully completed.
433   @retval   EFI_ACCESS_DENIED      The firmware volume is in the WriteDisabled state.
434   @retval   EFI_DEVICE_ERROR       The block device is not functioning correctly and
435                                    could not be written. Firmware device may have been
436                                    partially erased.
437   @retval   EFI_INVALID_PARAMETER  Instance not found.
438 
439 **/
440 EFI_STATUS
441 FvbEraseBlock (
442   IN UINTN                                Instance,
443   IN EFI_LBA                              Lba
444   )
445 {
446   EFI_FVB_ATTRIBUTES_2                    Attributes;
447   UINTN                                   LbaAddress;
448   EFI_FW_VOL_INSTANCE                     *FwhInstance;
449   UINTN                                   LbaLength;
450   EFI_STATUS                              Status;
451 
452   //
453   // Find the right instance of the FVB private data.
454   //
455   FwhInstance = GetFvbInstance (Instance);
456 
457   //
458   // Check if the FV is write enabled.
459   //
460   Attributes = FvbGetVolumeAttributes (Instance);
461 
462   if( (Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
463     return (EFI_ACCESS_DENIED);
464   }
465 
466   //
467   // Get the starting address of the block for erase.
468   //
469   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);
470   if (EFI_ERROR(Status)) {
471     return Status;
472   }
473 
474   LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);
475 
476   Status = LibFvbFlashDeviceBlockErase (LbaAddress, LbaLength);
477 
478   LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);
479 
480   WriteBackInvalidateDataCacheRange ((VOID *) LbaAddress, LbaLength);
481 
482   return Status;
483 }
484 
485 
486 /**
487   Modifies the current settings of the firmware volume according to the
488   input parameter, and returns the new setting of the volume.
489 
490   @param[in]  Instance              The FV instance whose attributes is going to be
491                                     modified.
492   @param[in]  Attributes            On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
493                                     containing the desired firmware volume settings.
494                                     On successful return, it contains the new settings
495                                     of the firmware volume.
496 
FvbSetVolumeAttributes(IN UINTN Instance,IN OUT EFI_FVB_ATTRIBUTES_2 * Attributes)497   @retval     EFI_SUCCESS           Successfully returns.
498   @retval     EFI_ACCESS_DENIED     The volume setting is locked and cannot be modified.
499   @retval     EFI_INVALID_PARAMETER Instance not found, or The attributes requested are
500                                     in conflict with the capabilities as declared in the
501                                     firmware volume header.
502 
503 **/
504 STATIC
505 EFI_STATUS
506 FvbSetVolumeAttributes (
507   IN UINTN                                Instance,
508   IN OUT EFI_FVB_ATTRIBUTES_2             *Attributes
509   )
510 {
511   EFI_FW_VOL_INSTANCE                       *FwhInstance = NULL;
512   EFI_FVB_ATTRIBUTES_2                      OldAttributes = 0;
513   EFI_FVB_ATTRIBUTES_2                      *AttribPtr = NULL;
514   EFI_FVB_ATTRIBUTES_2                      UnchangedAttributes;
515   UINT32                                    Capabilities;
516   UINT32                                    OldStatus, NewStatus;
517 
518   //
519   // Find the right instance of the FVB private data.
520   //
521   FwhInstance = GetFvbInstance (Instance);
522 
523   AttribPtr     = (EFI_FVB_ATTRIBUTES_2 *) & (FwhInstance->VolumeHeader.Attributes);
524   ASSERT_EFI_ERROR (AttribPtr != NULL);
525 
526   if ( AttribPtr != NULL) {
527     OldAttributes = *AttribPtr;
528   }
529 
530   Capabilities  = OldAttributes & EFI_FVB2_CAPABILITIES;
531   OldStatus     = OldAttributes & EFI_FVB2_STATUS;
532   NewStatus     = *Attributes & EFI_FVB2_STATUS;
533 
534   UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP  | \
535                         EFI_FVB2_READ_ENABLED_CAP   | \
536                         EFI_FVB2_WRITE_DISABLED_CAP | \
537                         EFI_FVB2_WRITE_ENABLED_CAP  | \
538                         EFI_FVB2_LOCK_CAP           | \
539                         EFI_FVB2_STICKY_WRITE       | \
540                         EFI_FVB2_MEMORY_MAPPED      | \
541                         EFI_FVB2_ERASE_POLARITY     | \
542                         EFI_FVB2_READ_LOCK_CAP      | \
543                         EFI_FVB2_WRITE_LOCK_CAP     | \
544                         EFI_FVB2_ALIGNMENT;
545 
546   //
547   // Some attributes of FV is read only can *not* be set.
548   //
549   if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {
550     return EFI_INVALID_PARAMETER;
551   }
552 
553   //
554   // If firmware volume is locked, no status bit can be updated.
555   //
556   if ( OldAttributes & EFI_FVB2_LOCK_STATUS ) {
557     if ( OldStatus ^ NewStatus ) {
558       return EFI_ACCESS_DENIED;
559     }
560   }
561 
562   //
563   // Test read disable.
564   //
565   if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
566     if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
567       return EFI_INVALID_PARAMETER;
568     }
569   }
570 
571   //
572   // Test read enable.
573   //
574   if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
575     if (NewStatus & EFI_FVB2_READ_STATUS) {
576       return EFI_INVALID_PARAMETER;
577     }
578   }
579 
580   //
581   // Test write disable.
582   //
583   if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
584     if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
585       return EFI_INVALID_PARAMETER;
586     }
587   }
588 
589   //
590   // Test write enable.
591   //
592   if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
593     if (NewStatus & EFI_FVB2_WRITE_STATUS) {
594       return EFI_INVALID_PARAMETER;
595     }
596   }
597 
598   //
599   // Test lock.
600   //
601   if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
602     if (NewStatus & EFI_FVB2_LOCK_STATUS) {
603       return EFI_INVALID_PARAMETER;
604     }
605   }
606 
607   *AttribPtr  = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
608   *AttribPtr  = (*AttribPtr) | NewStatus;
609   *Attributes = *AttribPtr;
610 
611   return EFI_SUCCESS;
612 }
613 
614 //
615 // FVB protocol APIs.
616 //
617 /**
618   Retrieves the physical address of the device.
FvbProtocolGetPhysicalAddress(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,OUT EFI_PHYSICAL_ADDRESS * Address)619 
620   @param[in]  This    A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL.
621   @param[out] Address Output buffer containing the address.
622 
623   retval      EFI_SUCCESS The function always return successfully.
624 
625 **/
626 EFI_STATUS
627 EFIAPI
628 FvbProtocolGetPhysicalAddress (
629   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
630   OUT EFI_PHYSICAL_ADDRESS               *Address
631   )
632 {
633   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
634   EFI_FW_VOL_INSTANCE                   *FvInstance;
635 
636   FvbDevice = FVB_DEVICE_FROM_THIS (This);
637   FvInstance = GetFvbInstance(FvbDevice->Instance);
638 
639   if (FvInstance != NULL) {
640     *Address = FvInstance->FvBase;
641   }
642 
643   return EFI_SUCCESS;
644 }
645 
646 
647 /**
648   Retrieve the size of a logical block.
649 
650   @param[in]  This         Calling context.
651   @param[in]  Lba          Indicates which block to return the size for.
652   @param[out] BlockSize    A pointer to a caller allocated UINTN in which
653                            the size of the block is returned.
654   @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)655                            number of consecutive blocks starting with Lba is
656                            returned. All blocks in this range have a size of
657                            BlockSize.
658 
659   @retval     EFI_SUCCESS  The function always return successfully.
660 
661 **/
662 EFI_STATUS
663 EFIAPI
664 FvbProtocolGetBlockSize (
665   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
666   IN  EFI_LBA                            Lba,
667   OUT UINTN                              *BlockSize,
668   OUT UINTN                              *NumOfBlocks
669   )
670 {
671   EFI_FW_VOL_BLOCK_DEVICE                 *FvbDevice;
672 
673   DEBUG((EFI_D_INFO,
674     "FvbProtocolGetBlockSize: Lba: 0x%lx BlockSize: 0x%x NumOfBlocks: 0x%x\n",
675     Lba,
676     BlockSize,
677     NumOfBlocks)
678     );
679 
680   FvbDevice = FVB_DEVICE_FROM_THIS (This);
681 
682   return FvbGetLbaAddress (
683            FvbDevice->Instance,
684            Lba,
685            NULL,
686            BlockSize,
687            NumOfBlocks
688            );
689 }
690 
691 
692 /**
693   Retrieves Volume attributes.  No polarity translations are done.
FvbProtocolGetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,OUT EFI_FVB_ATTRIBUTES_2 * Attributes)694 
695   @param[in]    This         Calling context.
696   @param[out]   Attributes   Output buffer which contains attributes.
697 
698   @retval       EFI_SUCCESS  The function always return successfully.
699 
700 **/
701 EFI_STATUS
702 EFIAPI
703 FvbProtocolGetAttributes (
704   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
705   OUT EFI_FVB_ATTRIBUTES_2                *Attributes
706   )
707 {
708   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
709 
710   FvbDevice = FVB_DEVICE_FROM_THIS (This);
711 
712   *Attributes = FvbGetVolumeAttributes (FvbDevice->Instance);
713 
714   DEBUG ((EFI_D_INFO,
715     "FvbProtocolGetAttributes: This: 0x%x Attributes: 0x%x\n",
716     This,
717     *Attributes)
718     );
719 
720   return EFI_SUCCESS;
721 }
722 
723 
724 /**
725   Sets Volume attributes. No polarity translations are done.
FvbProtocolSetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN OUT EFI_FVB_ATTRIBUTES_2 * Attributes)726 
727   @param[in]  This         Calling context.
728   @param[out] Attributes   Output buffer which contains attributes.
729 
730   @retval     EFI_SUCCESS  The function always return successfully.
731 
732 **/
733 EFI_STATUS
734 EFIAPI
735 FvbProtocolSetAttributes (
736   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
737   IN OUT EFI_FVB_ATTRIBUTES_2             *Attributes
738   )
739 {
740   EFI_STATUS                            Status;
741   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
742 
743   DEBUG((EFI_D_INFO,
744     "FvbProtocolSetAttributes: Before SET -  This: 0x%x Attributes: 0x%x\n",
745     This,
746     *Attributes)
747     );
748 
749   FvbDevice = FVB_DEVICE_FROM_THIS (This);
750 
751   Status = FvbSetVolumeAttributes (FvbDevice->Instance, Attributes);
752 
753   DEBUG((EFI_D_INFO,
754     "FvbProtocolSetAttributes: After SET -  This: 0x%x Attributes: 0x%x\n",
755     This,
756     *Attributes)
757     );
758 
759   return Status;
760 }
761 
762 
763 /**
764   The EraseBlock() function erases one or more blocks as denoted by the
765   variable argument list. The entire parameter list of blocks must be verified
766   prior to erasing any blocks.  If a block is requested that does not exist
767   within the associated firmware volume (it has a larger index than the last
768   block of the firmware volume), the EraseBlock() function must return
769   EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
770 
771   @param[in] This            Calling context.
772   @param[in] ...             Starting LBA followed by Number of Lba to erase.
773                              a -1 to terminate the list.
774 
FvbProtocolEraseBlocks(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,...)775   @retval EFI_SUCCESS        The erase request was successfully completed.
776   @retval EFI_ACCESS_DENIED  The firmware volume is in the WriteDisabled state.
777   @retval EFI_DEVICE_ERROR   The block device is not functioning correctly and
778                              could not be written. Firmware device may have been
779                              partially erased.
780 
781 **/
782 EFI_STATUS
783 EFIAPI
784 FvbProtocolEraseBlocks (
785   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *This,
786   ...
787   )
788 {
789   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
790   EFI_FW_VOL_INSTANCE                   *FwhInstance;
791   UINTN                                 NumOfBlocks = 0;
792   VA_LIST                               args;
793   EFI_LBA                               StartingLba;
794   UINTN                                 NumOfLba;
795   EFI_STATUS                            Status;
796 
797   DEBUG((EFI_D_INFO, "FvbProtocolEraseBlocks: \n"));
798   FvbDevice = FVB_DEVICE_FROM_THIS (This);
799 
800   FwhInstance  = GetFvbInstance (FvbDevice->Instance);
801 
802   if (FwhInstance != NULL) {
803     NumOfBlocks = FwhInstance->NumOfBlocks;
804   }
805 
806   VA_START (args, This);
807 
808   do {
809     StartingLba = VA_ARG (args, EFI_LBA);
810     if ( StartingLba == EFI_LBA_LIST_TERMINATOR ) {
811       break;
812     }
813 
814     NumOfLba = VA_ARG (args, UINT32);
815 
816     //
817     // Check input parameters.
818     //
819     if (NumOfLba == 0) {
820       VA_END (args);
821       return EFI_INVALID_PARAMETER;
822     }
823 
824     if ( ( StartingLba + NumOfLba ) > NumOfBlocks ) {
825       return EFI_INVALID_PARAMETER;
826     }
827   } while ( 1 );
828 
829   VA_END (args);
830 
831   VA_START (args, This);
832   do {
833     StartingLba = VA_ARG (args, EFI_LBA);
834     if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
835       break;
836     }
837 
838     NumOfLba = VA_ARG (args, UINT32);
839 
840     while ( NumOfLba > 0 ) {
841       Status = FvbEraseBlock (FvbDevice->Instance, StartingLba);
842       if ( EFI_ERROR(Status)) {
843         VA_END (args);
844         return Status;
845       }
846       StartingLba ++;
847       NumOfLba --;
848     }
849 
850   } while ( 1 );
851 
852   VA_END (args);
853 
854   return EFI_SUCCESS;
855 }
856 
857 
858 /**
859   Writes data beginning at Lba:Offset from FV. The write terminates either
860   when *NumBytes of data have been written, or when a block boundary is
861   reached.  *NumBytes is updated to reflect the actual number of bytes
862   written. The write opertion does not include erase. This routine will
863   attempt to write only the specified bytes. If the writes do not stick,
864   it will return an error.
865 
866   @param[in]      This      Calling context.
867   @param[in]      Lba       Block in which to begin write.
868   @param[in]      Offset    Offset in the block at which to begin write.
869   @param[in,out]  NumBytes  On input, indicates the requested write size. On
870                             output, indicates the actual number of bytes written
871   @param[in]      Buffer    Buffer containing source data for the write.
872 
873   @retval EFI_SUCCESS           The firmware volume was written successfully.
874   @retval EFI_BAD_BUFFER_SIZE   Write attempted across a LBA boundary. On output,
875                                 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)876                                 actually written.
877   @retval EFI_ACCESS_DENIED     The firmware volume is in the WriteDisabled state.
878   @retval EFI_DEVICE_ERROR      The block device is not functioning correctly and
879                                 could not be written.
880   @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL.
881 
882 **/
883 EFI_STATUS
884 EFIAPI
885 FvbProtocolWrite (
886   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
887   IN EFI_LBA                              Lba,
888   IN UINTN                                Offset,
889   IN OUT UINTN                            *NumBytes,
890   IN UINT8                                *Buffer
891   )
892 {
893 
894   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
895 
896   FvbDevice = FVB_DEVICE_FROM_THIS (This);
897 
898   DEBUG((EFI_D_INFO,
899     "FvbProtocolWrite: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x\n",
900     Lba,
901     Offset,
902     *NumBytes,
903     Buffer)
904     );
905 
906   return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer);
907 }
908 
909 
910 /**
911   Reads data beginning at Lba:Offset from FV. The Read terminates either
912   when *NumBytes of data have been read, or when a block boundary is
913   reached.  *NumBytes is updated to reflect the actual number of bytes
914   written. The write opertion does not include erase. This routine will
915   attempt to write only the specified bytes. If the writes do not stick,
916   it will return an error.
917 
918   @param[in]      This      Calling context.
919   @param[in]      Lba       Block in which to begin write.
920   @param[in]      Offset    Offset in the block at which to begin write
921   @param[in,out]  NumBytes  On input, indicates the requested write size. On
922                             output, indicates the actual number of bytes written.
923   @param[in]      Buffer    Buffer containing source data for the write.
924 
925 
926 Returns:
927   @retval EFI_SUCCESS            The firmware volume was read successfully and
928                                  contents are in Buffer.
929   @retval EFI_BAD_BUFFER_SIZE    Read attempted across a LBA boundary. On output,
930                                  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)931                                  in Buffer.
932   @retval EFI_ACCESS_DENIED      The firmware volume is in the ReadDisabled state
933   @retval EFI_DEVICE_ERROR       The block device is not functioning correctly and
934                                  could not be read.
935   @retval EFI_INVALID_PARAMETER  NumBytes or Buffer are NULL.
936 
937 **/
938 EFI_STATUS
939 EFIAPI
940 FvbProtocolRead (
941   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
942   IN EFI_LBA                              Lba,
943   IN UINTN                                Offset,
944   IN OUT UINTN                            *NumBytes,
945   OUT UINT8                                *Buffer
946   )
947 {
948 
949   EFI_FW_VOL_BLOCK_DEVICE   *FvbDevice;
950   EFI_STATUS                Status;
951 
952   FvbDevice = FVB_DEVICE_FROM_THIS (This);
953   Status = FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer);
954   DEBUG((EFI_D_INFO,
955     "FvbProtocolRead: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x\n",
956     Lba,
957     Offset,
958     *NumBytes,
959     Buffer)
960     );
961 
962   return Status;
963 }
964 
965 
966 /**
IsFvHeaderValid(IN EFI_PHYSICAL_ADDRESS FvBase,IN CONST EFI_FIRMWARE_VOLUME_HEADER * FwVolHeader)967   Check the integrity of firmware volume header.
968 
969   @param[in]  FwVolHeader   A pointer to a firmware volume header.
970 
971   @retval     TRUE          The firmware volume is consistent.
972   @retval     FALSE         The firmware volume has corrupted.
973 
974 **/
975 BOOLEAN
976 IsFvHeaderValid (
977   IN       EFI_PHYSICAL_ADDRESS          FvBase,
978   IN CONST EFI_FIRMWARE_VOLUME_HEADER    *FwVolHeader
979   )
980 {
981   if (FvBase == PcdGet32(PcdFlashNvStorageVariableBase)) {
982     if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid, sizeof(EFI_GUID)) != 0 ) {
983       return FALSE;
984     }
985   } else {
986     if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid, sizeof(EFI_GUID)) != 0 ) {
987       return FALSE;
988     }
989   }
990   if ( (FwVolHeader->Revision != EFI_FVH_REVISION)   ||
991        (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
992        (FwVolHeader->FvLength == ((UINTN) -1))       ||
993        ((FwVolHeader->HeaderLength & 0x01 ) !=0) ) {
994     return FALSE;
995   }
996 
997   if (CalculateCheckSum16 ((UINT16 *) FwVolHeader, FwVolHeader->HeaderLength) != 0) {
998     return FALSE;
999   }
1000 
1001   return TRUE;
1002 }
1003 
1004 
FvbInitialize(VOID)1005 /**
1006   The function does the necessary initialization work for
1007   Firmware Volume Block Driver.
1008 
1009   @retval     EFI_SUCCESS       This funtion always return EFI_SUCCESS.
1010                                 It will ASSERT on errors.
1011 
1012 **/
1013 EFI_STATUS
1014 FvbInitialize (
1015   VOID
1016   )
1017 {
1018   EFI_FW_VOL_INSTANCE                   *FwhInstance;
1019   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
1020   EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
1021   EFI_FV_BLOCK_MAP_ENTRY                *PtrBlockMapEntry;
1022   EFI_PHYSICAL_ADDRESS                  BaseAddress;
1023   EFI_STATUS                            Status;
1024   UINTN                                 BufferSize;
1025   UINTN                                 TmpHeaderLength;
1026   UINTN                                 Idx;
1027   UINT32                                MaxLbaSize;
1028   BOOLEAN                               FvHeaderValid;
1029 
1030   //
1031   // Calculate the total size for all firmware volume block instances.
1032   //
1033   BufferSize = 0;
1034   for (Idx = 0; Idx < 1; Idx++) {
1035     FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) mPlatformFvBaseAddress[Idx];
1036     BufferSize +=  (FvHeader->HeaderLength +
1037                     sizeof (EFI_FW_VOL_INSTANCE) -
1038                     sizeof (EFI_FIRMWARE_VOLUME_HEADER)
1039                    );
1040   }
1041 
1042   mFvbModuleGlobal.FvInstance =  (EFI_FW_VOL_INSTANCE *) AllocateRuntimeZeroPool (BufferSize);
1043   ASSERT (NULL != mFvbModuleGlobal.FvInstance);
1044 
1045 
1046   MaxLbaSize      = 0;
1047   FwhInstance     = mFvbModuleGlobal.FvInstance;
1048   mFvbModuleGlobal.NumFv   = 0;
1049 
1050   for (Idx = 0; Idx < 1; Idx++) {
1051     BaseAddress = mPlatformFvBaseAddress[Idx];
1052     FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
1053 
1054     if (!IsFvHeaderValid (BaseAddress, FwVolHeader)) {
1055       FvHeaderValid = FALSE;
1056       //
1057       // If not valid, get FvbInfo from the information carried in
1058       // FVB driver.
1059       //
1060       DEBUG ((EFI_D_ERROR, "Fvb: FV header @ 0x%lx invalid\n", BaseAddress));
1061       Status          = GetFvbInfo (BaseAddress, &FwVolHeader);
1062       ASSERT_EFI_ERROR(Status);
1063       //
1064       //  Write back a healthy FV header.
1065       //
1066       DEBUG ((EFI_D_ERROR, "FwBlockService.c: Writing back healthy FV header\n"));
1067       LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length, FALSE);
1068 
1069       Status = LibFvbFlashDeviceBlockErase ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length);
1070 
1071       TmpHeaderLength = (UINTN) FwVolHeader->HeaderLength;
1072       Status = LibFvbFlashDeviceWrite (
1073                  (UINTN)BaseAddress,
1074                  &TmpHeaderLength,
1075                  (UINT8 *) FwVolHeader
1076                  );
1077 
1078       LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length, TRUE);
1079 
1080       WriteBackInvalidateDataCacheRange (
1081         (VOID *) (UINTN) BaseAddress,
1082         FwVolHeader->BlockMap->Length
1083         );
1084 
1085     }
1086 
1087     CopyMem (&(FwhInstance->VolumeHeader), FwVolHeader, FwVolHeader->HeaderLength);
1088 
1089     FwVolHeader = &(FwhInstance->VolumeHeader);
1090     FwhInstance->FvBase = (UINTN)BaseAddress;
1091 
1092     //
1093     // Process the block map for each FV.
1094     //
1095     FwhInstance->NumOfBlocks = 0;
1096     for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
1097       //
1098       // Get the maximum size of a block.
1099       //
1100       if (MaxLbaSize < PtrBlockMapEntry->Length) {
1101         MaxLbaSize  = PtrBlockMapEntry->Length;
1102       }
1103       FwhInstance->NumOfBlocks += PtrBlockMapEntry->NumBlocks;
1104     }
1105 
1106     //
1107     // Add a FVB Protocol Instance.
1108     //
1109     mFvbModuleGlobal.NumFv++;
1110     InstallFvbProtocol (FwhInstance, mFvbModuleGlobal.NumFv - 1);
1111 
1112     //
1113     // Move on to the next FwhInstance.
1114     //
1115     FwhInstance = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhInstance) +
1116                                           FwVolHeader->HeaderLength +
1117                                           (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));
1118 
1119   }
1120 
1121   return EFI_SUCCESS;
1122 }
1123 
1124