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