1/**@file
2
3Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
4This program and the accompanying materials
5are licensed and made available under the terms and conditions of the BSD License
6which accompanies this distribution.  The full text of the license may be found at
7http://opensource.org/licenses/bsd-license.php
8
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12Module Name:
13
14  FWBlockService.c
15
16Abstract:
17
18Revision History
19
20**/
21
22//
23// The package level header files this module uses
24//
25#include <PiDxe.h>
26#include <WinNtDxe.h>
27//
28// The protocols, PPI and GUID defintions for this module
29//
30#include <Guid/EventGroup.h>
31#include <Protocol/FirmwareVolumeBlock.h>
32#include <Protocol/DevicePath.h>
33//
34// The Library classes this module consumes
35//
36#include <Library/UefiLib.h>
37#include <Library/UefiDriverEntryPoint.h>
38#include <Library/BaseLib.h>
39#include <Library/DxeServicesTableLib.h>
40#include <Library/UefiRuntimeLib.h>
41#include <Library/DebugLib.h>
42#include <Library/HobLib.h>
43#include <Library/BaseMemoryLib.h>
44#include <Library/MemoryAllocationLib.h>
45#include <Library/UefiBootServicesTableLib.h>
46#include <Library/DevicePathLib.h>
47
48#include "FWBlockService.h"
49
50#define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
51
52ESAL_FWB_GLOBAL         *mFvbModuleGlobal;
53
54FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {
55  {
56    {
57      HARDWARE_DEVICE_PATH,
58      HW_MEMMAP_DP,
59      {
60        (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
61        (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
62      }
63    },
64    EfiMemoryMappedIO,
65    (EFI_PHYSICAL_ADDRESS) 0,
66    (EFI_PHYSICAL_ADDRESS) 0,
67  },
68  {
69    END_DEVICE_PATH_TYPE,
70    END_ENTIRE_DEVICE_PATH_SUBTYPE,
71    {
72      END_DEVICE_PATH_LENGTH,
73      0
74    }
75  }
76};
77
78FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {
79  {
80    {
81      MEDIA_DEVICE_PATH,
82      MEDIA_PIWG_FW_VOL_DP,
83      {
84        (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
85        (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
86      }
87    },
88    { 0 }
89  },
90  {
91    END_DEVICE_PATH_TYPE,
92    END_ENTIRE_DEVICE_PATH_SUBTYPE,
93    {
94      END_DEVICE_PATH_LENGTH,
95      0
96    }
97  }
98};
99
100EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {
101  FVB_DEVICE_SIGNATURE,
102  NULL,
103  0,
104  {
105    FvbProtocolGetAttributes,
106    FvbProtocolSetAttributes,
107    FvbProtocolGetPhysicalAddress,
108    FvbProtocolGetBlockSize,
109    FvbProtocolRead,
110    FvbProtocolWrite,
111    FvbProtocolEraseBlocks,
112    NULL
113  }
114};
115
116
117
118VOID
119EFIAPI
120FvbVirtualddressChangeEvent (
121  IN EFI_EVENT        Event,
122  IN VOID             *Context
123  )
124/*++
125
126Routine Description:
127
128  Fixup internal data so that EFI and SAL can be call in virtual mode.
129  Call the passed in Child Notify event and convert the mFvbModuleGlobal
130  date items to there virtual address.
131
132  mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]  - Physical copy of instance data
133  mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]   - Virtual pointer to common
134                                                instance data.
135
136Arguments:
137
138  (Standard EFI notify event - EFI_EVENT_NOTIFY)
139
140Returns:
141
142  None
143
144--*/
145{
146  EFI_FW_VOL_INSTANCE *FwhInstance;
147  UINTN               Index;
148
149  EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]);
150
151  //
152  // Convert the base address of all the instances
153  //
154  Index       = 0;
155  FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
156  while (Index < mFvbModuleGlobal->NumFv) {
157    EfiConvertPointer (0x0, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]);
158    FwhInstance = (EFI_FW_VOL_INSTANCE *)
159      (
160        (UINTN) ((UINT8 *) FwhInstance) + FwhInstance->VolumeHeader.HeaderLength +
161          (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
162      );
163    Index++;
164  }
165
166  EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL]);
167  EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal);
168}
169
170EFI_STATUS
171GetFvbInstance (
172  IN  UINTN                               Instance,
173  IN  ESAL_FWB_GLOBAL                     *Global,
174  OUT EFI_FW_VOL_INSTANCE                 **FwhInstance,
175  IN BOOLEAN                              Virtual
176  )
177/*++
178
179Routine Description:
180  Retrieves the physical address of a memory mapped FV
181
182Arguments:
183  Instance              - The FV instance whose base address is going to be
184                          returned
185  Global                - Pointer to ESAL_FWB_GLOBAL that contains all
186                          instance data
187  FwhInstance           - The EFI_FW_VOL_INSTANCE fimrware instance structure
188  Virtual               - Whether CPU is in virtual or physical mode
189
190Returns:
191  EFI_SUCCESS           - Successfully returns
192  EFI_INVALID_PARAMETER - Instance not found
193
194--*/
195{
196  EFI_FW_VOL_INSTANCE *FwhRecord;
197
198  if (Instance >= Global->NumFv) {
199    return EFI_INVALID_PARAMETER;
200  }
201  //
202  // Find the right instance of the FVB private data
203  //
204  FwhRecord = Global->FvInstance[Virtual];
205  while (Instance > 0) {
206    FwhRecord = (EFI_FW_VOL_INSTANCE *)
207      (
208        (UINTN) ((UINT8 *) FwhRecord) + FwhRecord->VolumeHeader.HeaderLength +
209          (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
210      );
211    Instance--;
212  }
213
214  *FwhInstance = FwhRecord;
215
216  return EFI_SUCCESS;
217}
218
219EFI_STATUS
220FvbGetPhysicalAddress (
221  IN UINTN                                Instance,
222  OUT EFI_PHYSICAL_ADDRESS                *Address,
223  IN ESAL_FWB_GLOBAL                      *Global,
224  IN BOOLEAN                              Virtual
225  )
226/*++
227
228Routine Description:
229  Retrieves the physical address of a memory mapped FV
230
231Arguments:
232  Instance              - The FV instance whose base address is going to be
233                          returned
234  Address               - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
235                          that on successful return, contains the base address
236                          of the firmware volume.
237  Global                - Pointer to ESAL_FWB_GLOBAL that contains all
238                          instance data
239  Virtual               - Whether CPU is in virtual or physical mode
240
241Returns:
242  EFI_SUCCESS           - Successfully returns
243  EFI_INVALID_PARAMETER - Instance not found
244
245--*/
246{
247  EFI_FW_VOL_INSTANCE *FwhInstance;
248  EFI_STATUS          Status;
249
250  //
251  // Find the right instance of the FVB private data
252  //
253  Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
254  ASSERT_EFI_ERROR (Status);
255  *Address = FwhInstance->FvBase[Virtual];
256
257  return EFI_SUCCESS;
258}
259
260EFI_STATUS
261FvbGetVolumeAttributes (
262  IN UINTN                                Instance,
263  OUT EFI_FVB_ATTRIBUTES_2                *Attributes,
264  IN ESAL_FWB_GLOBAL                      *Global,
265  IN BOOLEAN                              Virtual
266  )
267/*++
268
269Routine Description:
270  Retrieves attributes, insures positive polarity of attribute bits, returns
271  resulting attributes in output parameter
272
273Arguments:
274  Instance              - The FV instance whose attributes is going to be
275                          returned
276  Attributes            - Output buffer which contains attributes
277  Global                - Pointer to ESAL_FWB_GLOBAL that contains all
278                          instance data
279  Virtual               - Whether CPU is in virtual or physical mode
280
281Returns:
282  EFI_SUCCESS           - Successfully returns
283  EFI_INVALID_PARAMETER - Instance not found
284
285--*/
286{
287  EFI_FW_VOL_INSTANCE *FwhInstance;
288  EFI_STATUS          Status;
289
290  //
291  // Find the right instance of the FVB private data
292  //
293  Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
294  ASSERT_EFI_ERROR (Status);
295  *Attributes = FwhInstance->VolumeHeader.Attributes;
296
297  return EFI_SUCCESS;
298}
299
300EFI_STATUS
301FvbGetLbaAddress (
302  IN  UINTN                               Instance,
303  IN  EFI_LBA                             Lba,
304  OUT UINTN                               *LbaAddress,
305  OUT UINTN                               *LbaLength,
306  OUT UINTN                               *NumOfBlocks,
307  IN  ESAL_FWB_GLOBAL                     *Global,
308  IN  BOOLEAN                             Virtual
309  )
310/*++
311
312Routine Description:
313  Retrieves the starting address of an LBA in an FV
314
315Arguments:
316  Instance              - The FV instance which the Lba belongs to
317  Lba                   - The logical block address
318  LbaAddress            - On output, contains the physical starting address
319                          of the Lba
320  LbaLength             - On output, contains the length of the block
321  NumOfBlocks           - A pointer to a caller allocated UINTN in which the
322                          number of consecutive blocks starting with Lba is
323                          returned. All blocks in this range have a size of
324                          BlockSize
325  Global                - Pointer to ESAL_FWB_GLOBAL that contains all
326                          instance data
327  Virtual               - Whether CPU is in virtual or physical mode
328
329Returns:
330  EFI_SUCCESS           - Successfully returns
331  EFI_INVALID_PARAMETER - Instance not found
332
333--*/
334{
335  UINT32                  NumBlocks;
336  UINT32                  BlockLength;
337  UINTN                   Offset;
338  EFI_LBA                 StartLba;
339  EFI_LBA                 NextLba;
340  EFI_FW_VOL_INSTANCE     *FwhInstance;
341  EFI_FV_BLOCK_MAP_ENTRY  *BlockMap;
342  EFI_STATUS              Status;
343
344  //
345  // Find the right instance of the FVB private data
346  //
347  Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
348  ASSERT_EFI_ERROR (Status);
349
350  StartLba  = 0;
351  Offset    = 0;
352  BlockMap  = &(FwhInstance->VolumeHeader.BlockMap[0]);
353
354  //
355  // Parse the blockmap of the FV to find which map entry the Lba belongs to
356  //
357  while (TRUE) {
358    NumBlocks   = BlockMap->NumBlocks;
359    BlockLength = BlockMap->Length;
360
361    if (NumBlocks == 0 || BlockLength == 0) {
362      return EFI_INVALID_PARAMETER;
363    }
364
365    NextLba = StartLba + NumBlocks;
366
367    //
368    // The map entry found
369    //
370    if (Lba >= StartLba && Lba < NextLba) {
371      Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength);
372      if (LbaAddress != NULL) {
373        *LbaAddress = FwhInstance->FvBase[Virtual] + Offset;
374      }
375
376      if (LbaLength != NULL) {
377        *LbaLength = BlockLength;
378      }
379
380      if (NumOfBlocks != NULL) {
381        *NumOfBlocks = (UINTN) (NextLba - Lba);
382      }
383
384      return EFI_SUCCESS;
385    }
386
387    StartLba  = NextLba;
388    Offset    = Offset + NumBlocks * BlockLength;
389    BlockMap++;
390  }
391}
392
393EFI_STATUS
394FvbReadBlock (
395  IN UINTN                                Instance,
396  IN EFI_LBA                              Lba,
397  IN UINTN                                BlockOffset,
398  IN OUT UINTN                            *NumBytes,
399  IN UINT8                                *Buffer,
400  IN ESAL_FWB_GLOBAL                      *Global,
401  IN BOOLEAN                              Virtual
402  )
403/*++
404
405Routine Description:
406  Reads specified number of bytes into a buffer from the specified block
407
408Arguments:
409  Instance              - The FV instance to be read from
410  Lba                   - The logical block address to be read from
411  BlockOffset           - Offset into the block at which to begin reading
412  NumBytes              - Pointer that on input contains the total size of
413                          the buffer. On output, it contains the total number
414                          of bytes read
415  Buffer                - Pointer to a caller allocated buffer that will be
416                          used to hold the data read
417  Global                - Pointer to ESAL_FWB_GLOBAL that contains all
418                          instance data
419  Virtual               - Whether CPU is in virtual or physical mode
420
421Returns:
422  EFI_SUCCESS           - The firmware volume was read successfully and
423                          contents are in Buffer
424  EFI_BAD_BUFFER_SIZE   - Read attempted across a LBA boundary. On output,
425                          NumBytes contains the total number of bytes returned
426                          in Buffer
427  EFI_ACCESS_DENIED     - The firmware volume is in the ReadDisabled state
428  EFI_DEVICE_ERROR      - The block device is not functioning correctly and
429                          could not be read
430  EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
431
432--*/
433{
434  EFI_FVB_ATTRIBUTES_2  Attributes;
435  UINTN                 LbaAddress;
436  UINTN                 LbaLength;
437  EFI_STATUS            Status;
438
439  //
440  // Check for invalid conditions
441  //
442  if ((NumBytes == NULL) || (Buffer == NULL)) {
443    return EFI_INVALID_PARAMETER;
444  }
445
446  if (*NumBytes == 0) {
447    return EFI_INVALID_PARAMETER;
448  }
449
450  Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
451  if (EFI_ERROR (Status)) {
452    return Status;
453  }
454  //
455  // Check if the FV is read enabled
456  //
457  FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
458
459  if ((Attributes & EFI_FVB2_READ_STATUS) == 0) {
460    return EFI_ACCESS_DENIED;
461  }
462  //
463  // Perform boundary checks and adjust NumBytes
464  //
465  if (BlockOffset > LbaLength) {
466    return EFI_INVALID_PARAMETER;
467  }
468
469  if (LbaLength < (*NumBytes + BlockOffset)) {
470    *NumBytes = (UINT32) (LbaLength - BlockOffset);
471    Status    = EFI_BAD_BUFFER_SIZE;
472  }
473
474  CopyMem (Buffer, (UINT8 *) (LbaAddress + BlockOffset), (UINTN) (*NumBytes));
475
476  return Status;
477}
478
479EFI_STATUS
480FvbWriteBlock (
481  IN UINTN                                Instance,
482  IN EFI_LBA                              Lba,
483  IN UINTN                                BlockOffset,
484  IN OUT UINTN                            *NumBytes,
485  IN UINT8                                *Buffer,
486  IN ESAL_FWB_GLOBAL                      *Global,
487  IN BOOLEAN                              Virtual
488  )
489/*++
490
491Routine Description:
492  Writes specified number of bytes from the input buffer to the block
493
494Arguments:
495  Instance              - The FV instance to be written to
496  Lba                   - The starting logical block index to write to
497  BlockOffset           - Offset into the block at which to begin writing
498  NumBytes              - Pointer that on input contains the total size of
499                          the buffer. On output, it contains the total number
500                          of bytes actually written
501  Buffer                - Pointer to a caller allocated buffer that contains
502                          the source for the write
503  Global                - Pointer to ESAL_FWB_GLOBAL that contains all
504                          instance data
505  Virtual               - Whether CPU is in virtual or physical mode
506
507Returns:
508  EFI_SUCCESS           - The firmware volume was written successfully
509  EFI_BAD_BUFFER_SIZE   - Write attempted across a LBA boundary. On output,
510                          NumBytes contains the total number of bytes
511                          actually written
512  EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
513  EFI_DEVICE_ERROR      - The block device is not functioning correctly and
514                          could not be written
515  EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
516
517--*/
518{
519  EFI_FVB_ATTRIBUTES_2  Attributes;
520  UINTN                 LbaAddress;
521  UINTN                 LbaLength;
522  EFI_STATUS            Status;
523
524  //
525  // Check for invalid conditions
526  //
527  if ((NumBytes == NULL) || (Buffer == NULL)) {
528    return EFI_INVALID_PARAMETER;
529  }
530
531  if (*NumBytes == 0) {
532    return EFI_INVALID_PARAMETER;
533  }
534
535  Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
536  if (EFI_ERROR (Status)) {
537    return Status;
538  }
539  //
540  // Check if the FV is write enabled
541  //
542  FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
543
544  if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
545    return EFI_ACCESS_DENIED;
546  }
547  //
548  // Perform boundary checks and adjust NumBytes
549  //
550  if (BlockOffset > LbaLength) {
551    return EFI_INVALID_PARAMETER;
552  }
553
554  if (LbaLength < (*NumBytes + BlockOffset)) {
555    *NumBytes = (UINT32) (LbaLength - BlockOffset);
556    Status    = EFI_BAD_BUFFER_SIZE;
557  }
558  //
559  // Write data
560  //
561  CopyMem ((UINT8 *) (LbaAddress + BlockOffset), Buffer, (UINTN) (*NumBytes));
562
563  return Status;
564}
565
566EFI_STATUS
567FvbEraseBlock (
568  IN UINTN                                Instance,
569  IN EFI_LBA                              Lba,
570  IN ESAL_FWB_GLOBAL                      *Global,
571  IN BOOLEAN                              Virtual
572  )
573/*++
574
575Routine Description:
576  Erases and initializes a firmware volume block
577
578Arguments:
579  Instance              - The FV instance to be erased
580  Lba                   - The logical block index to be erased
581  Global                - Pointer to ESAL_FWB_GLOBAL that contains all
582                          instance data
583  Virtual               - Whether CPU is in virtual or physical mode
584
585Returns:
586  EFI_SUCCESS           - The erase request was successfully completed
587  EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
588  EFI_DEVICE_ERROR      - The block device is not functioning correctly and
589                          could not be written. Firmware device may have been
590                          partially erased
591  EFI_INVALID_PARAMETER - Instance not found
592
593--*/
594{
595
596  EFI_FVB_ATTRIBUTES_2  Attributes;
597  UINTN                 LbaAddress;
598  UINTN                 LbaLength;
599  EFI_STATUS            Status;
600  UINT8                 Data;
601
602  //
603  // Check if the FV is write enabled
604  //
605  FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
606
607  if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
608    return EFI_ACCESS_DENIED;
609  }
610  //
611  // Get the starting address of the block for erase.
612  //
613  Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
614
615  if (EFI_ERROR (Status)) {
616    return Status;
617  }
618
619  if ((Attributes & EFI_FVB2_ERASE_POLARITY) != 0) {
620    Data = 0xFF;
621  } else {
622    Data = 0x0;
623  }
624
625  SetMem ((UINT8 *) LbaAddress, LbaLength, Data);
626
627  return EFI_SUCCESS;
628}
629
630EFI_STATUS
631FvbSetVolumeAttributes (
632  IN UINTN                                  Instance,
633  IN OUT EFI_FVB_ATTRIBUTES_2               *Attributes,
634  IN ESAL_FWB_GLOBAL                        *Global,
635  IN BOOLEAN                                Virtual
636  )
637/*++
638
639Routine Description:
640  Modifies the current settings of the firmware volume according to the
641  input parameter, and returns the new setting of the volume
642
643Arguments:
644  Instance              - The FV instance whose attributes is going to be
645                          modified
646  Attributes            - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
647                          containing the desired firmware volume settings.
648                          On successful return, it contains the new settings
649                          of the firmware volume
650  Global                - Pointer to ESAL_FWB_GLOBAL that contains all
651                          instance data
652  Virtual               - Whether CPU is in virtual or physical mode
653
654Returns:
655  EFI_SUCCESS           - Successfully returns
656  EFI_ACCESS_DENIED     - The volume setting is locked and cannot be modified
657  EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
658                          in conflict with the capabilities as declared in the
659                          firmware volume header
660
661--*/
662{
663  EFI_FW_VOL_INSTANCE   *FwhInstance;
664  EFI_FVB_ATTRIBUTES_2  OldAttributes;
665  EFI_FVB_ATTRIBUTES_2  *AttribPtr;
666  UINT32                Capabilities;
667  UINT32                OldStatus;
668  UINT32                NewStatus;
669  EFI_STATUS            Status;
670  EFI_FVB_ATTRIBUTES_2  UnchangedAttributes;
671
672  //
673  // Find the right instance of the FVB private data
674  //
675  Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
676  ASSERT_EFI_ERROR (Status);
677
678  AttribPtr     = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);
679  OldAttributes = *AttribPtr;
680  Capabilities  = OldAttributes & (EFI_FVB2_READ_DISABLED_CAP | \
681                                   EFI_FVB2_READ_ENABLED_CAP | \
682                                   EFI_FVB2_WRITE_DISABLED_CAP | \
683                                   EFI_FVB2_WRITE_ENABLED_CAP | \
684                                   EFI_FVB2_LOCK_CAP \
685                                   );
686  OldStatus     = OldAttributes & EFI_FVB2_STATUS;
687  NewStatus     = *Attributes & EFI_FVB2_STATUS;
688
689  UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP  | \
690                        EFI_FVB2_READ_ENABLED_CAP   | \
691                        EFI_FVB2_WRITE_DISABLED_CAP | \
692                        EFI_FVB2_WRITE_ENABLED_CAP  | \
693                        EFI_FVB2_LOCK_CAP           | \
694                        EFI_FVB2_STICKY_WRITE       | \
695                        EFI_FVB2_MEMORY_MAPPED      | \
696                        EFI_FVB2_ERASE_POLARITY     | \
697                        EFI_FVB2_READ_LOCK_CAP      | \
698                        EFI_FVB2_WRITE_LOCK_CAP     | \
699                        EFI_FVB2_ALIGNMENT;
700
701  //
702  // Some attributes of FV is read only can *not* be set
703  //
704  if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {
705    return EFI_INVALID_PARAMETER;
706  }
707  //
708  // If firmware volume is locked, no status bit can be updated
709  //
710  if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
711    if (OldStatus ^ NewStatus) {
712      return EFI_ACCESS_DENIED;
713    }
714  }
715  //
716  // Test read disable
717  //
718  if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
719    if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
720      return EFI_INVALID_PARAMETER;
721    }
722  }
723  //
724  // Test read enable
725  //
726  if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
727    if (NewStatus & EFI_FVB2_READ_STATUS) {
728      return EFI_INVALID_PARAMETER;
729    }
730  }
731  //
732  // Test write disable
733  //
734  if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
735    if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
736      return EFI_INVALID_PARAMETER;
737    }
738  }
739  //
740  // Test write enable
741  //
742  if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
743    if (NewStatus & EFI_FVB2_WRITE_STATUS) {
744      return EFI_INVALID_PARAMETER;
745    }
746  }
747  //
748  // Test lock
749  //
750  if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
751    if (NewStatus & EFI_FVB2_LOCK_STATUS) {
752      return EFI_INVALID_PARAMETER;
753    }
754  }
755
756  *AttribPtr  = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
757  *AttribPtr  = (*AttribPtr) | NewStatus;
758  *Attributes = *AttribPtr;
759
760  return EFI_SUCCESS;
761}
762//
763// FVB protocol APIs
764//
765EFI_STATUS
766EFIAPI
767FvbProtocolGetPhysicalAddress (
768  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL           *This,
769  OUT EFI_PHYSICAL_ADDRESS                        *Address
770  )
771/*++
772
773Routine Description:
774
775  Retrieves the physical address of the device.
776
777Arguments:
778
779  This                  - Calling context
780  Address               - Output buffer containing the address.
781
782Returns:
783
784Returns:
785  EFI_SUCCESS           - Successfully returns
786
787--*/
788{
789  EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
790
791  FvbDevice = FVB_DEVICE_FROM_THIS (This);
792
793  return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ());
794}
795
796EFI_STATUS
797EFIAPI
798FvbProtocolGetBlockSize (
799  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL           *This,
800  IN CONST EFI_LBA                                     Lba,
801  OUT UINTN                                       *BlockSize,
802  OUT UINTN                                       *NumOfBlocks
803  )
804/*++
805
806Routine Description:
807  Retrieve the size of a logical block
808
809Arguments:
810  This                  - Calling context
811  Lba                   - Indicates which block to return the size for.
812  BlockSize             - A pointer to a caller allocated UINTN in which
813                          the size of the block is returned
814  NumOfBlocks           - a pointer to a caller allocated UINTN in which the
815                          number of consecutive blocks starting with Lba is
816                          returned. All blocks in this range have a size of
817                          BlockSize
818
819Returns:
820  EFI_SUCCESS           - The firmware volume was read successfully and
821                          contents are in Buffer
822
823--*/
824{
825  EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
826
827  FvbDevice = FVB_DEVICE_FROM_THIS (This);
828
829  return FvbGetLbaAddress (
830          FvbDevice->Instance,
831          Lba,
832          NULL,
833          BlockSize,
834          NumOfBlocks,
835          mFvbModuleGlobal,
836          EfiGoneVirtual ()
837          );
838}
839
840EFI_STATUS
841EFIAPI
842FvbProtocolGetAttributes (
843  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL           *This,
844  OUT EFI_FVB_ATTRIBUTES_2                              *Attributes
845  )
846/*++
847
848Routine Description:
849    Retrieves Volume attributes.  No polarity translations are done.
850
851Arguments:
852    This                - Calling context
853    Attributes          - output buffer which contains attributes
854
855Returns:
856  EFI_SUCCESS           - Successfully returns
857
858--*/
859{
860  EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
861
862  FvbDevice = FVB_DEVICE_FROM_THIS (This);
863
864  return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
865}
866
867EFI_STATUS
868EFIAPI
869FvbProtocolSetAttributes (
870  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL           *This,
871  IN OUT EFI_FVB_ATTRIBUTES_2                           *Attributes
872  )
873/*++
874
875Routine Description:
876  Sets Volume attributes. No polarity translations are done.
877
878Arguments:
879  This                  - Calling context
880  Attributes            - output buffer which contains attributes
881
882Returns:
883  EFI_SUCCESS           - Successfully returns
884
885--*/
886{
887  EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
888
889  FvbDevice = FVB_DEVICE_FROM_THIS (This);
890
891  return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
892}
893
894EFI_STATUS
895EFIAPI
896FvbProtocolEraseBlocks (
897  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *This,
898  ...
899  )
900/*++
901
902Routine Description:
903
904  The EraseBlock() function erases one or more blocks as denoted by the
905  variable argument list. The entire parameter list of blocks must be verified
906  prior to erasing any blocks.  If a block is requested that does not exist
907  within the associated firmware volume (it has a larger index than the last
908  block of the firmware volume), the EraseBlock() function must return
909  EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
910
911Arguments:
912  This                  - Calling context
913  ...                   - Starting LBA followed by Number of Lba to erase.
914                          a -1 to terminate the list.
915
916Returns:
917  EFI_SUCCESS           - The erase request was successfully completed
918  EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
919  EFI_DEVICE_ERROR      - The block device is not functioning correctly and
920                          could not be written. Firmware device may have been
921                          partially erased
922
923--*/
924{
925  EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
926  EFI_FW_VOL_INSTANCE     *FwhInstance;
927  UINTN                   NumOfBlocks;
928  VA_LIST                 args;
929  EFI_LBA                 StartingLba;
930  UINTN                   NumOfLba;
931  EFI_STATUS              Status;
932
933  FvbDevice = FVB_DEVICE_FROM_THIS (This);
934
935  Status    = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());
936  ASSERT_EFI_ERROR (Status);
937
938  NumOfBlocks = FwhInstance->NumOfBlocks;
939
940  VA_START (args, This);
941
942  do {
943    StartingLba = VA_ARG (args, EFI_LBA);
944    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
945      break;
946    }
947
948    NumOfLba = VA_ARG (args, UINT32);
949
950    //
951    // Check input parameters
952    //
953    if ((NumOfLba == 0) || ((StartingLba + NumOfLba) > NumOfBlocks)) {
954      VA_END (args);
955      return EFI_INVALID_PARAMETER;
956    }
957  } while (1);
958
959  VA_END (args);
960
961  VA_START (args, This);
962  do {
963    StartingLba = VA_ARG (args, EFI_LBA);
964    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
965      break;
966    }
967
968    NumOfLba = VA_ARG (args, UINT32);
969
970    while (NumOfLba > 0) {
971      Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());
972      if (EFI_ERROR (Status)) {
973        VA_END (args);
974        return Status;
975      }
976
977      StartingLba++;
978      NumOfLba--;
979    }
980
981  } while (1);
982
983  VA_END (args);
984
985  return EFI_SUCCESS;
986}
987
988EFI_STATUS
989EFIAPI
990FvbProtocolWrite (
991  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL           *This,
992  IN       EFI_LBA                                      Lba,
993  IN       UINTN                                        Offset,
994  IN OUT   UINTN                                    *NumBytes,
995  IN       UINT8                                        *Buffer
996  )
997/*++
998
999Routine Description:
1000
1001  Writes data beginning at Lba:Offset from FV. The write terminates either
1002  when *NumBytes of data have been written, or when a block boundary is
1003  reached.  *NumBytes is updated to reflect the actual number of bytes
1004  written. The write opertion does not include erase. This routine will
1005  attempt to write only the specified bytes. If the writes do not stick,
1006  it will return an error.
1007
1008Arguments:
1009  This                  - Calling context
1010  Lba                   - Block in which to begin write
1011  Offset                - Offset in the block at which to begin write
1012  NumBytes              - On input, indicates the requested write size. On
1013                          output, indicates the actual number of bytes written
1014  Buffer                - Buffer containing source data for the write.
1015
1016Returns:
1017  EFI_SUCCESS           - The firmware volume was written successfully
1018  EFI_BAD_BUFFER_SIZE   - Write attempted across a LBA boundary. On output,
1019                          NumBytes contains the total number of bytes
1020                          actually written
1021  EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
1022  EFI_DEVICE_ERROR      - The block device is not functioning correctly and
1023                          could not be written
1024  EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1025
1026--*/
1027{
1028
1029  EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1030
1031  FvbDevice = FVB_DEVICE_FROM_THIS (This);
1032
1033  return FvbWriteBlock (FvbDevice->Instance, (EFI_LBA)Lba, (UINTN)Offset, NumBytes, (UINT8 *)Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
1034}
1035
1036EFI_STATUS
1037EFIAPI
1038FvbProtocolRead (
1039  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL           *This,
1040  IN CONST EFI_LBA                                      Lba,
1041  IN CONST UINTN                                        Offset,
1042  IN OUT UINTN                                    *NumBytes,
1043  IN UINT8                                        *Buffer
1044  )
1045/*++
1046
1047Routine Description:
1048
1049  Reads data beginning at Lba:Offset from FV. The Read terminates either
1050  when *NumBytes of data have been read, or when a block boundary is
1051  reached.  *NumBytes is updated to reflect the actual number of bytes
1052  written. The write opertion does not include erase. This routine will
1053  attempt to write only the specified bytes. If the writes do not stick,
1054  it will return an error.
1055
1056Arguments:
1057  This                  - Calling context
1058  Lba                   - Block in which to begin Read
1059  Offset                - Offset in the block at which to begin Read
1060  NumBytes              - On input, indicates the requested write size. On
1061                          output, indicates the actual number of bytes Read
1062  Buffer                - Buffer containing source data for the Read.
1063
1064Returns:
1065  EFI_SUCCESS           - The firmware volume was read successfully and
1066                          contents are in Buffer
1067  EFI_BAD_BUFFER_SIZE   - Read attempted across a LBA boundary. On output,
1068                          NumBytes contains the total number of bytes returned
1069                          in Buffer
1070  EFI_ACCESS_DENIED     - The firmware volume is in the ReadDisabled state
1071  EFI_DEVICE_ERROR      - The block device is not functioning correctly and
1072                          could not be read
1073  EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1074
1075--*/
1076{
1077
1078  EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1079
1080  FvbDevice = FVB_DEVICE_FROM_THIS (This);
1081
1082  return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
1083}
1084
1085EFI_STATUS
1086ValidateFvHeader (
1087  EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader
1088  )
1089/*++
1090
1091Routine Description:
1092  Check the integrity of firmware volume header
1093
1094Arguments:
1095  FwVolHeader           - A pointer to a firmware volume header
1096
1097Returns:
1098  EFI_SUCCESS           - The firmware volume is consistent
1099  EFI_NOT_FOUND         - The firmware volume has corrupted. So it is not an FV
1100
1101--*/
1102{
1103  //
1104  // Verify the header revision, header signature, length
1105  // Length of FvBlock cannot be 2**64-1
1106  // HeaderLength cannot be an odd number
1107  //
1108  if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
1109      (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
1110      (FwVolHeader->FvLength == ((UINTN) -1)) ||
1111      ((FwVolHeader->HeaderLength & 0x01) != 0)
1112      ) {
1113    return EFI_NOT_FOUND;
1114  }
1115
1116  //
1117  // Verify the header checksum
1118  //
1119  if (CalculateCheckSum16 ((UINT16 *) FwVolHeader, FwVolHeader->HeaderLength) != 0) {
1120    return EFI_NOT_FOUND;
1121  }
1122
1123  return EFI_SUCCESS;
1124}
1125
1126EFI_STATUS
1127EFIAPI
1128FvbInitialize (
1129  IN EFI_HANDLE         ImageHandle,
1130  IN EFI_SYSTEM_TABLE   *SystemTable
1131  )
1132/*++
1133
1134Routine Description:
1135  This function does common initialization for FVB services
1136
1137Arguments:
1138
1139Returns:
1140
1141--*/
1142{
1143  EFI_STATUS                          Status;
1144  EFI_FW_VOL_INSTANCE                 *FwhInstance;
1145  EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;
1146  EFI_DXE_SERVICES                    *DxeServices;
1147  EFI_GCD_MEMORY_SPACE_DESCRIPTOR     Descriptor;
1148  UINT32                              BufferSize;
1149  EFI_FV_BLOCK_MAP_ENTRY              *PtrBlockMapEntry;
1150  EFI_HANDLE                          FwbHandle;
1151  EFI_FW_VOL_BLOCK_DEVICE             *FvbDevice;
1152  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *OldFwbInterface;
1153  UINT32                              MaxLbaSize;
1154  EFI_PHYSICAL_ADDRESS                BaseAddress;
1155  UINT64                              Length;
1156  UINTN                               NumOfBlocks;
1157  EFI_PEI_HOB_POINTERS                FvHob;
1158
1159  //
1160  // Get the DXE services table
1161  //
1162  DxeServices = gDS;
1163
1164  //
1165  // Allocate runtime services data for global variable, which contains
1166  // the private data of all firmware volume block instances
1167  //
1168  mFvbModuleGlobal = AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL));
1169  ASSERT (mFvbModuleGlobal != NULL);
1170
1171  //
1172  // Calculate the total size for all firmware volume block instances
1173  //
1174  BufferSize            = 0;
1175
1176  FvHob.Raw = GetHobList ();
1177  while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {
1178    BaseAddress = FvHob.FirmwareVolume->BaseAddress;
1179    Length      = FvHob.FirmwareVolume->Length;
1180    //
1181    // Check if it is a "real" flash
1182    //
1183    Status = DxeServices->GetMemorySpaceDescriptor (
1184                            BaseAddress,
1185                            &Descriptor
1186                            );
1187    if (EFI_ERROR (Status)) {
1188      break;
1189    }
1190
1191    if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {
1192      FvHob.Raw = GET_NEXT_HOB (FvHob);
1193      continue;
1194    }
1195
1196    FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
1197    Status      = ValidateFvHeader (FwVolHeader);
1198    if (EFI_ERROR (Status)) {
1199      //
1200      // Get FvbInfo
1201      //
1202      Status = GetFvbInfo (Length, &FwVolHeader);
1203      if (EFI_ERROR (Status)) {
1204        FvHob.Raw = GET_NEXT_HOB (FvHob);
1205        continue;
1206      }
1207    }
1208
1209    BufferSize += (sizeof (EFI_FW_VOL_INSTANCE) + FwVolHeader->HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER));
1210    FvHob.Raw = GET_NEXT_HOB (FvHob);
1211  }
1212
1213  //
1214  // Only need to allocate once. There is only one copy of physical memory for
1215  // the private data of each FV instance. But in virtual mode or in physical
1216  // mode, the address of the the physical memory may be different.
1217  //
1218  mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] = AllocateRuntimePool (BufferSize);
1219  ASSERT (mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] != NULL);
1220
1221  //
1222  // Make a virtual copy of the FvInstance pointer.
1223  //
1224  FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
1225  mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;
1226
1227  mFvbModuleGlobal->NumFv                   = 0;
1228  MaxLbaSize = 0;
1229
1230  FvHob.Raw = GetHobList ();
1231  while (NULL != (FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw))) {
1232    BaseAddress = FvHob.FirmwareVolume->BaseAddress;
1233    Length      = FvHob.FirmwareVolume->Length;
1234    //
1235    // Check if it is a "real" flash
1236    //
1237    Status = DxeServices->GetMemorySpaceDescriptor (
1238                            BaseAddress,
1239                            &Descriptor
1240                            );
1241    if (EFI_ERROR (Status)) {
1242      break;
1243    }
1244
1245    if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {
1246      FvHob.Raw = GET_NEXT_HOB (FvHob);
1247      continue;
1248    }
1249
1250    FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
1251    Status      = ValidateFvHeader (FwVolHeader);
1252    if (EFI_ERROR (Status)) {
1253      //
1254      // Get FvbInfo to provide in FwhInstance.
1255      //
1256      Status = GetFvbInfo (Length, &FwVolHeader);
1257      if (EFI_ERROR (Status)) {
1258        FvHob.Raw = GET_NEXT_HOB (FvHob);
1259        continue;
1260      }
1261      //
1262      //  Write healthy FV header back.
1263      //
1264      CopyMem (
1265        (VOID *) (UINTN) BaseAddress,
1266        (VOID *) FwVolHeader,
1267        FwVolHeader->HeaderLength
1268        );
1269    }
1270
1271    FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;
1272    FwhInstance->FvBase[FVB_VIRTUAL]  = (UINTN) BaseAddress;
1273
1274    CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);
1275    FwVolHeader = &(FwhInstance->VolumeHeader);
1276    EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);
1277
1278    NumOfBlocks = 0;
1279
1280    for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
1281      //
1282      // Get the maximum size of a block.
1283      //
1284      if (MaxLbaSize < PtrBlockMapEntry->Length) {
1285        MaxLbaSize = PtrBlockMapEntry->Length;
1286      }
1287
1288      NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;
1289    }
1290    //
1291    // The total number of blocks in the FV.
1292    //
1293    FwhInstance->NumOfBlocks = NumOfBlocks;
1294
1295    //
1296    // Add a FVB Protocol Instance
1297    //
1298    FvbDevice = AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE));
1299    ASSERT (FvbDevice != NULL);
1300
1301    CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));
1302
1303    FvbDevice->Instance = mFvbModuleGlobal->NumFv;
1304    mFvbModuleGlobal->NumFv++;
1305
1306
1307    //
1308    // Set up the devicepath
1309    //
1310    if (FwVolHeader->ExtHeaderOffset == 0) {
1311        //
1312        // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
1313        //
1314      FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate);
1315      ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.StartingAddress = BaseAddress;
1316      ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.EndingAddress   = BaseAddress + FwVolHeader->FvLength - 1;
1317    } else {
1318      FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate);
1319      CopyGuid (
1320        &((FV_PIWG_DEVICE_PATH *)FvbDevice->DevicePath)->FvDevPath.FvName,
1321        (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)
1322        );
1323    }
1324    //
1325    // Find a handle with a matching device path that has supports FW Block protocol
1326    //
1327    Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &FvbDevice->DevicePath, &FwbHandle);
1328    if (EFI_ERROR (Status)) {
1329      //
1330      // LocateDevicePath fails so install a new interface and device path
1331      //
1332      FwbHandle = NULL;
1333      Status = gBS->InstallMultipleProtocolInterfaces (
1334                      &FwbHandle,
1335                      &gEfiFirmwareVolumeBlockProtocolGuid,
1336                      &FvbDevice->FwVolBlockInstance,
1337                      &gEfiDevicePathProtocolGuid,
1338                      FvbDevice->DevicePath,
1339                      NULL
1340                      );
1341      ASSERT_EFI_ERROR (Status);
1342    } else if (IsDevicePathEnd (FvbDevice->DevicePath)) {
1343      //
1344      // Device allready exists, so reinstall the FVB protocol
1345      //
1346      Status = gBS->HandleProtocol (
1347                      FwbHandle,
1348                      &gEfiFirmwareVolumeBlockProtocolGuid,
1349                      (VOID**)&OldFwbInterface
1350                      );
1351      ASSERT_EFI_ERROR (Status);
1352
1353      Status = gBS->ReinstallProtocolInterface (
1354                      FwbHandle,
1355                      &gEfiFirmwareVolumeBlockProtocolGuid,
1356                      OldFwbInterface,
1357                      &FvbDevice->FwVolBlockInstance
1358                      );
1359      ASSERT_EFI_ERROR (Status);
1360
1361    } else {
1362      //
1363      // There was a FVB protocol on an End Device Path node
1364      //
1365      ASSERT (FALSE);
1366    }
1367
1368    FwhInstance = (EFI_FW_VOL_INSTANCE *)
1369      (
1370        (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
1371          (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
1372      );
1373
1374    FvHob.Raw = GET_NEXT_HOB (FvHob);
1375  }
1376
1377  return EFI_SUCCESS;
1378}
1379