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
7Copyright (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//
35FWB_GLOBAL   mFvbModuleGlobal;
36
37//
38// This platform driver knows there are 3 FVs on
39// FD, which are FvRecovery, FvMain and FvNvStorage.
40//
41UINT32 mPlatformFvBaseAddress[] = {
42  FixedPcdGet32(PcdFlashNvStorageVariableBase),
43};
44
45FV_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
69FV_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//
94EFI_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.
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**/
122EFI_FW_VOL_INSTANCE *
123GetFvbInstance (
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/**
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**/
158STATIC
159EFI_FVB_ATTRIBUTES_2
160FvbGetVolumeAttributes (
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
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**/
194STATIC
195EFI_STATUS
196FvbGetLbaAddress (
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
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**/
287STATIC
288EFI_STATUS
289FvbReadBlock (
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,
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**/
356EFI_STATUS
357FvbWriteBlock (
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
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**/
440EFI_STATUS
441FvbEraseBlock (
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
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**/
504STATIC
505EFI_STATUS
506FvbSetVolumeAttributes (
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.
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**/
626EFI_STATUS
627EFIAPI
628FvbProtocolGetPhysicalAddress (
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
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**/
662EFI_STATUS
663EFIAPI
664FvbProtocolGetBlockSize (
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.
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**/
701EFI_STATUS
702EFIAPI
703FvbProtocolGetAttributes (
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.
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**/
733EFI_STATUS
734EFIAPI
735FvbProtocolSetAttributes (
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
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**/
782EFI_STATUS
783EFIAPI
784FvbProtocolEraseBlocks (
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
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**/
883EFI_STATUS
884EFIAPI
885FvbProtocolWrite (
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
926Returns:
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
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**/
938EFI_STATUS
939EFIAPI
940FvbProtocolRead (
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/**
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**/
975BOOLEAN
976IsFvHeaderValid (
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
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**/
1013EFI_STATUS
1014FvbInitialize (
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