1 /**@file
2 
3 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution.  The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8 
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 Module Name:
13 
14   FWBlockService.c
15 
16 Abstract:
17 
18 Revision 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 
52 ESAL_FWB_GLOBAL         *mFvbModuleGlobal;
53 
54 FV_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 
78 FV_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 
100 EFI_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 
118 VOID
119 EFIAPI
FvbVirtualddressChangeEvent(IN EFI_EVENT Event,IN VOID * Context)120 FvbVirtualddressChangeEvent (
121   IN EFI_EVENT        Event,
122   IN VOID             *Context
123   )
124 /*++
125 
126 Routine 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 
136 Arguments:
137 
138   (Standard EFI notify event - EFI_EVENT_NOTIFY)
139 
140 Returns:
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 
170 EFI_STATUS
GetFvbInstance(IN UINTN Instance,IN ESAL_FWB_GLOBAL * Global,OUT EFI_FW_VOL_INSTANCE ** FwhInstance,IN BOOLEAN Virtual)171 GetFvbInstance (
172   IN  UINTN                               Instance,
173   IN  ESAL_FWB_GLOBAL                     *Global,
174   OUT EFI_FW_VOL_INSTANCE                 **FwhInstance,
175   IN BOOLEAN                              Virtual
176   )
177 /*++
178 
179 Routine Description:
180   Retrieves the physical address of a memory mapped FV
181 
182 Arguments:
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 
190 Returns:
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 
219 EFI_STATUS
FvbGetPhysicalAddress(IN UINTN Instance,OUT EFI_PHYSICAL_ADDRESS * Address,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)220 FvbGetPhysicalAddress (
221   IN UINTN                                Instance,
222   OUT EFI_PHYSICAL_ADDRESS                *Address,
223   IN ESAL_FWB_GLOBAL                      *Global,
224   IN BOOLEAN                              Virtual
225   )
226 /*++
227 
228 Routine Description:
229   Retrieves the physical address of a memory mapped FV
230 
231 Arguments:
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 
241 Returns:
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 
260 EFI_STATUS
FvbGetVolumeAttributes(IN UINTN Instance,OUT EFI_FVB_ATTRIBUTES_2 * Attributes,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)261 FvbGetVolumeAttributes (
262   IN UINTN                                Instance,
263   OUT EFI_FVB_ATTRIBUTES_2                *Attributes,
264   IN ESAL_FWB_GLOBAL                      *Global,
265   IN BOOLEAN                              Virtual
266   )
267 /*++
268 
269 Routine Description:
270   Retrieves attributes, insures positive polarity of attribute bits, returns
271   resulting attributes in output parameter
272 
273 Arguments:
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 
281 Returns:
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 
300 EFI_STATUS
FvbGetLbaAddress(IN UINTN Instance,IN EFI_LBA Lba,OUT UINTN * LbaAddress,OUT UINTN * LbaLength,OUT UINTN * NumOfBlocks,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)301 FvbGetLbaAddress (
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 
312 Routine Description:
313   Retrieves the starting address of an LBA in an FV
314 
315 Arguments:
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 
329 Returns:
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 
393 EFI_STATUS
FvbReadBlock(IN UINTN Instance,IN EFI_LBA Lba,IN UINTN BlockOffset,IN OUT UINTN * NumBytes,IN UINT8 * Buffer,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)394 FvbReadBlock (
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 
405 Routine Description:
406   Reads specified number of bytes into a buffer from the specified block
407 
408 Arguments:
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 
421 Returns:
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 
479 EFI_STATUS
FvbWriteBlock(IN UINTN Instance,IN EFI_LBA Lba,IN UINTN BlockOffset,IN OUT UINTN * NumBytes,IN UINT8 * Buffer,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)480 FvbWriteBlock (
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 
491 Routine Description:
492   Writes specified number of bytes from the input buffer to the block
493 
494 Arguments:
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 
507 Returns:
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 
566 EFI_STATUS
FvbEraseBlock(IN UINTN Instance,IN EFI_LBA Lba,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)567 FvbEraseBlock (
568   IN UINTN                                Instance,
569   IN EFI_LBA                              Lba,
570   IN ESAL_FWB_GLOBAL                      *Global,
571   IN BOOLEAN                              Virtual
572   )
573 /*++
574 
575 Routine Description:
576   Erases and initializes a firmware volume block
577 
578 Arguments:
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 
585 Returns:
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 
630 EFI_STATUS
FvbSetVolumeAttributes(IN UINTN Instance,IN OUT EFI_FVB_ATTRIBUTES_2 * Attributes,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)631 FvbSetVolumeAttributes (
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 
639 Routine 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 
643 Arguments:
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 
654 Returns:
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 //
765 EFI_STATUS
766 EFIAPI
FvbProtocolGetPhysicalAddress(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,OUT EFI_PHYSICAL_ADDRESS * Address)767 FvbProtocolGetPhysicalAddress (
768   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL           *This,
769   OUT EFI_PHYSICAL_ADDRESS                        *Address
770   )
771 /*++
772 
773 Routine Description:
774 
775   Retrieves the physical address of the device.
776 
777 Arguments:
778 
779   This                  - Calling context
780   Address               - Output buffer containing the address.
781 
782 Returns:
783 
784 Returns:
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 
796 EFI_STATUS
797 EFIAPI
FvbProtocolGetBlockSize(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN CONST EFI_LBA Lba,OUT UINTN * BlockSize,OUT UINTN * NumOfBlocks)798 FvbProtocolGetBlockSize (
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 
806 Routine Description:
807   Retrieve the size of a logical block
808 
809 Arguments:
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 
819 Returns:
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 
840 EFI_STATUS
841 EFIAPI
FvbProtocolGetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,OUT EFI_FVB_ATTRIBUTES_2 * Attributes)842 FvbProtocolGetAttributes (
843   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL           *This,
844   OUT EFI_FVB_ATTRIBUTES_2                              *Attributes
845   )
846 /*++
847 
848 Routine Description:
849     Retrieves Volume attributes.  No polarity translations are done.
850 
851 Arguments:
852     This                - Calling context
853     Attributes          - output buffer which contains attributes
854 
855 Returns:
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 
867 EFI_STATUS
868 EFIAPI
FvbProtocolSetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN OUT EFI_FVB_ATTRIBUTES_2 * Attributes)869 FvbProtocolSetAttributes (
870   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL           *This,
871   IN OUT EFI_FVB_ATTRIBUTES_2                           *Attributes
872   )
873 /*++
874 
875 Routine Description:
876   Sets Volume attributes. No polarity translations are done.
877 
878 Arguments:
879   This                  - Calling context
880   Attributes            - output buffer which contains attributes
881 
882 Returns:
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 
894 EFI_STATUS
895 EFIAPI
FvbProtocolEraseBlocks(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,...)896 FvbProtocolEraseBlocks (
897   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *This,
898   ...
899   )
900 /*++
901 
902 Routine 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 
911 Arguments:
912   This                  - Calling context
913   ...                   - Starting LBA followed by Number of Lba to erase.
914                           a -1 to terminate the list.
915 
916 Returns:
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 
988 EFI_STATUS
989 EFIAPI
FvbProtocolWrite(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Offset,IN OUT UINTN * NumBytes,IN UINT8 * Buffer)990 FvbProtocolWrite (
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 
999 Routine 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 
1008 Arguments:
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 
1016 Returns:
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 
1036 EFI_STATUS
1037 EFIAPI
FvbProtocolRead(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN CONST EFI_LBA Lba,IN CONST UINTN Offset,IN OUT UINTN * NumBytes,IN UINT8 * Buffer)1038 FvbProtocolRead (
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 
1047 Routine 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 
1056 Arguments:
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 
1064 Returns:
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 
1085 EFI_STATUS
ValidateFvHeader(EFI_FIRMWARE_VOLUME_HEADER * FwVolHeader)1086 ValidateFvHeader (
1087   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader
1088   )
1089 /*++
1090 
1091 Routine Description:
1092   Check the integrity of firmware volume header
1093 
1094 Arguments:
1095   FwVolHeader           - A pointer to a firmware volume header
1096 
1097 Returns:
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 
1126 EFI_STATUS
1127 EFIAPI
FvbInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1128 FvbInitialize (
1129   IN EFI_HANDLE         ImageHandle,
1130   IN EFI_SYSTEM_TABLE   *SystemTable
1131   )
1132 /*++
1133 
1134 Routine Description:
1135   This function does common initialization for FVB services
1136 
1137 Arguments:
1138 
1139 Returns:
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