• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Implementations for Firmware Volume Block protocol.
3 
4   It consumes FV HOBs and creates read-only Firmare Volume Block protocol
5   instances for each of them.
6 
7 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution.  The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12 
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 
16 **/
17 
18 #include "DxeMain.h"
19 #include "FwVolBlock.h"
20 
21 FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {
22   {
23     {
24       HARDWARE_DEVICE_PATH,
25       HW_MEMMAP_DP,
26       {
27         (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
28         (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
29       }
30     },
31     EfiMemoryMappedIO,
32     (EFI_PHYSICAL_ADDRESS) 0,
33     (EFI_PHYSICAL_ADDRESS) 0,
34   },
35   {
36     END_DEVICE_PATH_TYPE,
37     END_ENTIRE_DEVICE_PATH_SUBTYPE,
38     {
39       END_DEVICE_PATH_LENGTH,
40       0
41     }
42   }
43 };
44 
45 FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {
46   {
47     {
48       MEDIA_DEVICE_PATH,
49       MEDIA_PIWG_FW_VOL_DP,
50       {
51         (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
52         (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
53       }
54     },
55     { 0 }
56   },
57   {
58     END_DEVICE_PATH_TYPE,
59     END_ENTIRE_DEVICE_PATH_SUBTYPE,
60     {
61       END_DEVICE_PATH_LENGTH,
62       0
63     }
64   }
65 };
66 
67 EFI_FW_VOL_BLOCK_DEVICE  mFwVolBlock = {
68   FVB_DEVICE_SIGNATURE,
69   NULL,
70   NULL,
71   {
72     FwVolBlockGetAttributes,
73     (EFI_FVB_SET_ATTRIBUTES)FwVolBlockSetAttributes,
74     FwVolBlockGetPhysicalAddress,
75     FwVolBlockGetBlockSize,
76     FwVolBlockReadBlock,
77     (EFI_FVB_WRITE)FwVolBlockWriteBlock,
78     (EFI_FVB_ERASE_BLOCKS)FwVolBlockEraseBlock,
79     NULL
80   },
81   0,
82   NULL,
83   0,
84   0,
85   0
86 };
87 
88 
89 
90 /**
91   Retrieves Volume attributes.  No polarity translations are done.
92 
93   @param  This                   Calling context
94   @param  Attributes             output buffer which contains attributes
95 
96   @retval EFI_SUCCESS            The firmware volume attributes were returned.
97 
98 **/
99 EFI_STATUS
100 EFIAPI
FwVolBlockGetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,OUT EFI_FVB_ATTRIBUTES_2 * Attributes)101 FwVolBlockGetAttributes (
102   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
103   OUT       EFI_FVB_ATTRIBUTES_2                *Attributes
104   )
105 {
106   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
107 
108   FvbDevice = FVB_DEVICE_FROM_THIS (This);
109 
110   //
111   // Since we are read only, it's safe to get attributes data from our in-memory copy.
112   //
113   *Attributes = FvbDevice->FvbAttributes & ~EFI_FVB2_WRITE_STATUS;
114 
115   return EFI_SUCCESS;
116 }
117 
118 
119 
120 /**
121   Modifies the current settings of the firmware volume according to the input parameter.
122 
123   @param  This                   Calling context
124   @param  Attributes             input buffer which contains attributes
125 
126   @retval EFI_SUCCESS            The firmware volume attributes were returned.
127   @retval EFI_INVALID_PARAMETER  The attributes requested are in conflict with
128                                  the capabilities as declared in the firmware
129                                  volume header.
130   @retval EFI_UNSUPPORTED        Not supported.
131 
132 **/
133 EFI_STATUS
134 EFIAPI
FwVolBlockSetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN CONST EFI_FVB_ATTRIBUTES_2 * Attributes)135 FwVolBlockSetAttributes (
136   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
137   IN CONST  EFI_FVB_ATTRIBUTES_2                *Attributes
138   )
139 {
140   return EFI_UNSUPPORTED;
141 }
142 
143 
144 
145 /**
146   The EraseBlock() function erases one or more blocks as denoted by the
147   variable argument list. The entire parameter list of blocks must be verified
148   prior to erasing any blocks.  If a block is requested that does not exist
149   within the associated firmware volume (it has a larger index than the last
150   block of the firmware volume), the EraseBlock() function must return
151   EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
152 
153   @param  This                   Calling context
154   @param  ...                    Starting LBA followed by Number of Lba to erase.
155                                  a -1 to terminate the list.
156 
157   @retval EFI_SUCCESS            The erase request was successfully completed.
158   @retval EFI_ACCESS_DENIED      The firmware volume is in the WriteDisabled
159                                  state.
160   @retval EFI_DEVICE_ERROR       The block device is not functioning correctly
161                                  and could not be written. The firmware device
162                                  may have been partially erased.
163   @retval EFI_INVALID_PARAMETER  One or more of the LBAs listed in the variable
164                                  argument list do
165   @retval EFI_UNSUPPORTED        Not supported.
166 
167 **/
168 EFI_STATUS
169 EFIAPI
FwVolBlockEraseBlock(IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,...)170 FwVolBlockEraseBlock (
171   IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *This,
172   ...
173   )
174 {
175   return EFI_UNSUPPORTED;
176 }
177 
178 
179 
180 /**
181   Read the specified number of bytes from the block to the input buffer.
182 
183   @param  This                   Indicates the calling context.
184   @param  Lba                    The starting logical block index to read.
185   @param  Offset                 Offset into the block at which to begin reading.
186   @param  NumBytes               Pointer to a UINT32. At entry, *NumBytes
187                                  contains the total size of the buffer. At exit,
188                                  *NumBytes contains the total number of bytes
189                                  actually read.
190   @param  Buffer                 Pinter to a caller-allocated buffer that
191                                  contains the destine for the read.
192 
193   @retval EFI_SUCCESS            The firmware volume was read successfully.
194   @retval EFI_BAD_BUFFER_SIZE    The read was attempted across an LBA boundary.
195   @retval EFI_ACCESS_DENIED      Access denied.
196   @retval EFI_DEVICE_ERROR       The block device is malfunctioning and could not
197                                  be read.
198 
199 **/
200 EFI_STATUS
201 EFIAPI
FwVolBlockReadBlock(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN CONST EFI_LBA Lba,IN CONST UINTN Offset,IN OUT UINTN * NumBytes,IN OUT UINT8 * Buffer)202 FwVolBlockReadBlock (
203   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
204   IN CONST  EFI_LBA                              Lba,
205   IN CONST  UINTN                                Offset,
206   IN OUT    UINTN                                *NumBytes,
207   IN OUT    UINT8                                *Buffer
208   )
209 {
210   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
211   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
212   UINT8                                 *LbaOffset;
213   UINTN                                 LbaStart;
214   UINTN                                 NumOfBytesRead;
215   UINTN                                 LbaIndex;
216 
217   FvbDevice = FVB_DEVICE_FROM_THIS (This);
218 
219   //
220   // Check if This FW can be read
221   //
222   if ((FvbDevice->FvbAttributes & EFI_FVB2_READ_STATUS) == 0) {
223     return EFI_ACCESS_DENIED;
224   }
225 
226   LbaIndex = (UINTN) Lba;
227   if (LbaIndex >= FvbDevice->NumBlocks) {
228     //
229     // Invalid Lba, read nothing.
230     //
231     *NumBytes = 0;
232     return EFI_BAD_BUFFER_SIZE;
233   }
234 
235   if (Offset > FvbDevice->LbaCache[LbaIndex].Length) {
236     //
237     // all exceed boundary, read nothing.
238     //
239     *NumBytes = 0;
240     return EFI_BAD_BUFFER_SIZE;
241   }
242 
243   NumOfBytesRead = *NumBytes;
244   if (Offset + NumOfBytesRead > FvbDevice->LbaCache[LbaIndex].Length) {
245     //
246     // partial exceed boundary, read data from current postion to end.
247     //
248     NumOfBytesRead = FvbDevice->LbaCache[LbaIndex].Length - Offset;
249   }
250 
251   LbaStart = FvbDevice->LbaCache[LbaIndex].Base;
252   FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN) FvbDevice->BaseAddress);
253   LbaOffset = (UINT8 *) FwVolHeader + LbaStart + Offset;
254 
255   //
256   // Perform read operation
257   //
258   CopyMem (Buffer, LbaOffset, NumOfBytesRead);
259 
260   if (NumOfBytesRead == *NumBytes) {
261     return EFI_SUCCESS;
262   }
263 
264   *NumBytes = NumOfBytesRead;
265   return EFI_BAD_BUFFER_SIZE;
266 }
267 
268 
269 
270 /**
271   Writes the specified number of bytes from the input buffer to the block.
272 
273   @param  This                   Indicates the calling context.
274   @param  Lba                    The starting logical block index to write to.
275   @param  Offset                 Offset into the block at which to begin writing.
276   @param  NumBytes               Pointer to a UINT32. At entry, *NumBytes
277                                  contains the total size of the buffer. At exit,
278                                  *NumBytes contains the total number of bytes
279                                  actually written.
280   @param  Buffer                 Pinter to a caller-allocated buffer that
281                                  contains the source for the write.
282 
283   @retval EFI_SUCCESS            The firmware volume was written successfully.
284   @retval EFI_BAD_BUFFER_SIZE    The write was attempted across an LBA boundary.
285                                  On output, NumBytes contains the total number of
286                                  bytes actually written.
287   @retval EFI_ACCESS_DENIED      The firmware volume is in the WriteDisabled
288                                  state.
289   @retval EFI_DEVICE_ERROR       The block device is malfunctioning and could not
290                                  be written.
291   @retval EFI_UNSUPPORTED        Not supported.
292 
293 **/
294 EFI_STATUS
295 EFIAPI
FwVolBlockWriteBlock(IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Offset,IN OUT UINTN * NumBytes,IN UINT8 * Buffer)296 FwVolBlockWriteBlock (
297   IN     EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
298   IN     EFI_LBA                              Lba,
299   IN     UINTN                                Offset,
300   IN OUT UINTN                                *NumBytes,
301   IN     UINT8                                *Buffer
302   )
303 {
304   return EFI_UNSUPPORTED;
305 }
306 
307 
308 
309 /**
310   Get Fvb's base address.
311 
312   @param  This                   Indicates the calling context.
313   @param  Address                Fvb device base address.
314 
315   @retval EFI_SUCCESS            Successfully got Fvb's base address.
316   @retval EFI_UNSUPPORTED        Not supported.
317 
318 **/
319 EFI_STATUS
320 EFIAPI
FwVolBlockGetPhysicalAddress(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,OUT EFI_PHYSICAL_ADDRESS * Address)321 FwVolBlockGetPhysicalAddress (
322   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
323   OUT       EFI_PHYSICAL_ADDRESS                *Address
324   )
325 {
326   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
327 
328   FvbDevice = FVB_DEVICE_FROM_THIS (This);
329 
330   if ((FvbDevice->FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
331     *Address = FvbDevice->BaseAddress;
332     return EFI_SUCCESS;
333   }
334 
335   return EFI_UNSUPPORTED;
336 }
337 
338 
339 
340 /**
341   Retrieves the size in bytes of a specific block within a firmware volume.
342 
343   @param  This                   Indicates the calling context.
344   @param  Lba                    Indicates the block for which to return the
345                                  size.
346   @param  BlockSize              Pointer to a caller-allocated UINTN in which the
347                                  size of the block is returned.
348   @param  NumberOfBlocks         Pointer to a caller-allocated UINTN in which the
349                                  number of consecutive blocks starting with Lba
350                                  is returned. All blocks in this range have a
351                                  size of BlockSize.
352 
353   @retval EFI_SUCCESS            The firmware volume base address is returned.
354   @retval EFI_INVALID_PARAMETER  The requested LBA is out of range.
355 
356 **/
357 EFI_STATUS
358 EFIAPI
FwVolBlockGetBlockSize(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN CONST EFI_LBA Lba,IN OUT UINTN * BlockSize,IN OUT UINTN * NumberOfBlocks)359 FwVolBlockGetBlockSize (
360   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
361   IN CONST  EFI_LBA                             Lba,
362   IN OUT    UINTN                               *BlockSize,
363   IN OUT    UINTN                               *NumberOfBlocks
364   )
365 {
366   UINTN                                 TotalBlocks;
367   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
368   EFI_FV_BLOCK_MAP_ENTRY                *PtrBlockMapEntry;
369   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
370 
371   FvbDevice = FVB_DEVICE_FROM_THIS (This);
372 
373   //
374   // Do parameter checking
375   //
376   if (Lba >= FvbDevice->NumBlocks) {
377     return EFI_INVALID_PARAMETER;
378   }
379 
380   FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbDevice->BaseAddress);
381 
382   PtrBlockMapEntry = FwVolHeader->BlockMap;
383 
384   //
385   // Search the block map for the given block
386   //
387   TotalBlocks = 0;
388   while ((PtrBlockMapEntry->NumBlocks != 0) || (PtrBlockMapEntry->Length !=0 )) {
389     TotalBlocks += PtrBlockMapEntry->NumBlocks;
390     if (Lba < TotalBlocks) {
391       //
392       // We find the range
393       //
394       break;
395     }
396 
397     PtrBlockMapEntry++;
398   }
399 
400   *BlockSize = PtrBlockMapEntry->Length;
401   *NumberOfBlocks = TotalBlocks - (UINTN)Lba;
402 
403   return EFI_SUCCESS;
404 }
405 
406 /**
407 
408   Get FVB authentication status
409 
410   @param FvbProtocol    FVB protocol.
411 
412   @return Authentication status.
413 
414 **/
415 UINT32
GetFvbAuthenticationStatus(IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * FvbProtocol)416 GetFvbAuthenticationStatus (
417   IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL     *FvbProtocol
418   )
419 {
420   EFI_FW_VOL_BLOCK_DEVICE   *FvbDevice;
421   UINT32                    AuthenticationStatus;
422 
423   AuthenticationStatus = 0;
424   FvbDevice = BASE_CR (FvbProtocol, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance);
425   if (FvbDevice->Signature == FVB_DEVICE_SIGNATURE) {
426     AuthenticationStatus = FvbDevice->AuthenticationStatus;
427   }
428 
429   return AuthenticationStatus;
430 }
431 
432 /**
433   This routine produces a firmware volume block protocol on a given
434   buffer.
435 
436   @param  BaseAddress            base address of the firmware volume image
437   @param  Length                 length of the firmware volume image
438   @param  ParentHandle           handle of parent firmware volume, if this image
439                                  came from an FV image file and section in another firmware
440                                  volume (ala capsules)
441   @param  AuthenticationStatus   Authentication status inherited, if this image
442                                  came from an FV image file and section in another firmware volume.
443   @param  FvProtocol             Firmware volume block protocol produced.
444 
445   @retval EFI_VOLUME_CORRUPTED   Volume corrupted.
446   @retval EFI_OUT_OF_RESOURCES   No enough buffer to be allocated.
447   @retval EFI_SUCCESS            Successfully produced a FVB protocol on given
448                                  buffer.
449 
450 **/
451 EFI_STATUS
ProduceFVBProtocolOnBuffer(IN EFI_PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN EFI_HANDLE ParentHandle,IN UINT32 AuthenticationStatus,OUT EFI_HANDLE * FvProtocol OPTIONAL)452 ProduceFVBProtocolOnBuffer (
453   IN EFI_PHYSICAL_ADDRESS   BaseAddress,
454   IN UINT64                 Length,
455   IN EFI_HANDLE             ParentHandle,
456   IN UINT32                 AuthenticationStatus,
457   OUT EFI_HANDLE            *FvProtocol  OPTIONAL
458   )
459 {
460   EFI_STATUS                    Status;
461   EFI_FW_VOL_BLOCK_DEVICE       *FvbDev;
462   EFI_FIRMWARE_VOLUME_HEADER    *FwVolHeader;
463   UINTN                         BlockIndex;
464   UINTN                         BlockIndex2;
465   UINTN                         LinearOffset;
466   UINT32                        FvAlignment;
467   EFI_FV_BLOCK_MAP_ENTRY        *PtrBlockMapEntry;
468 
469   FvAlignment = 0;
470   FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN) BaseAddress;
471   //
472   // Validate FV Header, if not as expected, return
473   //
474   if (FwVolHeader->Signature != EFI_FVH_SIGNATURE) {
475     return EFI_VOLUME_CORRUPTED;
476   }
477 
478   //
479   // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
480   // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
481   // its initial linked location and maintain its alignment.
482   //
483   if ((FwVolHeader->Attributes & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
484     //
485     // Get FvHeader alignment
486     //
487     FvAlignment = 1 << ((FwVolHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
488     //
489     // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
490     //
491     if (FvAlignment < 8) {
492       FvAlignment = 8;
493     }
494     if ((UINTN)BaseAddress % FvAlignment != 0) {
495       //
496       // FvImage buffer is not at its required alignment.
497       //
498       DEBUG ((
499         DEBUG_ERROR,
500         "Unaligned FvImage found at 0x%lx:0x%lx, the required alignment is 0x%x\n",
501         BaseAddress,
502         Length,
503         FvAlignment
504         ));
505       return EFI_VOLUME_CORRUPTED;
506     }
507   }
508 
509   //
510   // Allocate EFI_FW_VOL_BLOCK_DEVICE
511   //
512   FvbDev = AllocateCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE), &mFwVolBlock);
513   if (FvbDev == NULL) {
514     return EFI_OUT_OF_RESOURCES;
515   }
516 
517   FvbDev->BaseAddress   = BaseAddress;
518   FvbDev->FvbAttributes = FwVolHeader->Attributes;
519   FvbDev->FwVolBlockInstance.ParentHandle = ParentHandle;
520   if (ParentHandle != NULL) {
521     FvbDev->AuthenticationStatus = AuthenticationStatus;
522   }
523 
524   //
525   // Init the block caching fields of the device
526   // First, count the number of blocks
527   //
528   FvbDev->NumBlocks = 0;
529   for (PtrBlockMapEntry = FwVolHeader->BlockMap;
530        PtrBlockMapEntry->NumBlocks != 0;
531        PtrBlockMapEntry++) {
532     FvbDev->NumBlocks += PtrBlockMapEntry->NumBlocks;
533   }
534 
535   //
536   // Second, allocate the cache
537   //
538   if (FvbDev->NumBlocks >= (MAX_ADDRESS / sizeof (LBA_CACHE))) {
539     CoreFreePool (FvbDev);
540     return EFI_OUT_OF_RESOURCES;
541   }
542   FvbDev->LbaCache = AllocatePool (FvbDev->NumBlocks * sizeof (LBA_CACHE));
543   if (FvbDev->LbaCache == NULL) {
544     CoreFreePool (FvbDev);
545     return EFI_OUT_OF_RESOURCES;
546   }
547 
548   //
549   // Last, fill in the cache with the linear address of the blocks
550   //
551   BlockIndex = 0;
552   LinearOffset = 0;
553   for (PtrBlockMapEntry = FwVolHeader->BlockMap;
554        PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
555     for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {
556       FvbDev->LbaCache[BlockIndex].Base = LinearOffset;
557       FvbDev->LbaCache[BlockIndex].Length = PtrBlockMapEntry->Length;
558       LinearOffset += PtrBlockMapEntry->Length;
559       BlockIndex++;
560     }
561   }
562 
563   //
564   // Judget whether FV name guid is produced in Fv extension header
565   //
566   if (FwVolHeader->ExtHeaderOffset == 0) {
567     //
568     // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
569     //
570     FvbDev->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate);
571     if (FvbDev->DevicePath == NULL) {
572       FreePool (FvbDev);
573       return EFI_OUT_OF_RESOURCES;
574     }
575     ((FV_MEMMAP_DEVICE_PATH *) FvbDev->DevicePath)->MemMapDevPath.StartingAddress = BaseAddress;
576     ((FV_MEMMAP_DEVICE_PATH *) FvbDev->DevicePath)->MemMapDevPath.EndingAddress   = BaseAddress + FwVolHeader->FvLength - 1;
577   } else {
578     //
579     // FV contains extension header, then produce MEDIA_FW_VOL_DEVICE_PATH
580     //
581     FvbDev->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate);
582     if (FvbDev->DevicePath == NULL) {
583       FreePool (FvbDev);
584       return EFI_OUT_OF_RESOURCES;
585     }
586     CopyGuid (
587       &((FV_PIWG_DEVICE_PATH *)FvbDev->DevicePath)->FvDevPath.FvName,
588       (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)
589       );
590   }
591 
592   //
593   //
594   // Attach FvVolBlock Protocol to new handle
595   //
596   Status = CoreInstallMultipleProtocolInterfaces (
597              &FvbDev->Handle,
598              &gEfiFirmwareVolumeBlockProtocolGuid,     &FvbDev->FwVolBlockInstance,
599              &gEfiDevicePathProtocolGuid,              FvbDev->DevicePath,
600              NULL
601              );
602 
603   //
604   // If they want the handle back, set it.
605   //
606   if (FvProtocol != NULL) {
607     *FvProtocol = FvbDev->Handle;
608   }
609 
610   return Status;
611 }
612 
613 
614 
615 /**
616   This routine consumes FV hobs and produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate.
617 
618   @param  ImageHandle            The image handle.
619   @param  SystemTable            The system table.
620 
621   @retval EFI_SUCCESS            Successfully initialized firmware volume block
622                                  driver.
623 
624 **/
625 EFI_STATUS
626 EFIAPI
FwVolBlockDriverInit(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)627 FwVolBlockDriverInit (
628   IN EFI_HANDLE                 ImageHandle,
629   IN EFI_SYSTEM_TABLE           *SystemTable
630   )
631 {
632   EFI_PEI_HOB_POINTERS          FvHob;
633 
634   //
635   // Core Needs Firmware Volumes to function
636   //
637   FvHob.Raw = GetHobList ();
638   while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {
639     //
640     // Produce an FVB protocol for it
641     //
642     ProduceFVBProtocolOnBuffer (FvHob.FirmwareVolume->BaseAddress, FvHob.FirmwareVolume->Length, NULL, 0, NULL);
643     FvHob.Raw = GET_NEXT_HOB (FvHob);
644   }
645 
646   return EFI_SUCCESS;
647 }
648 
649 
650 
651 /**
652   This DXE service routine is used to process a firmware volume. In
653   particular, it can be called by BDS to process a single firmware
654   volume found in a capsule.
655 
656   Caution: The caller need validate the input firmware volume to follow
657   PI specification.
658   DxeCore will trust the input data and process firmware volume directly.
659 
660   @param  FvHeader               pointer to a firmware volume header
661   @param  Size                   the size of the buffer pointed to by FvHeader
662   @param  FVProtocolHandle       the handle on which a firmware volume protocol
663                                  was produced for the firmware volume passed in.
664 
665   @retval EFI_OUT_OF_RESOURCES   if an FVB could not be produced due to lack of
666                                  system resources
667   @retval EFI_VOLUME_CORRUPTED   if the volume was corrupted
668   @retval EFI_SUCCESS            a firmware volume protocol was produced for the
669                                  firmware volume
670 
671 **/
672 EFI_STATUS
673 EFIAPI
CoreProcessFirmwareVolume(IN VOID * FvHeader,IN UINTN Size,OUT EFI_HANDLE * FVProtocolHandle)674 CoreProcessFirmwareVolume (
675   IN VOID                             *FvHeader,
676   IN UINTN                            Size,
677   OUT EFI_HANDLE                      *FVProtocolHandle
678   )
679 {
680   VOID        *Ptr;
681   EFI_STATUS  Status;
682 
683   *FVProtocolHandle = NULL;
684   Status = ProduceFVBProtocolOnBuffer (
685             (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
686             (UINT64)Size,
687             NULL,
688             0,
689             FVProtocolHandle
690             );
691   //
692   // Since in our implementation we use register-protocol-notify to put a
693   // FV protocol on the FVB protocol handle, we can't directly verify that
694   // the FV protocol was produced. Therefore here we will check the handle
695   // and make sure an FV protocol is on it. This indicates that all went
696   // well. Otherwise we have to assume that the volume was corrupted
697   // somehow.
698   //
699   if (!EFI_ERROR(Status)) {
700     ASSERT (*FVProtocolHandle != NULL);
701     Ptr = NULL;
702     Status = CoreHandleProtocol (*FVProtocolHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **) &Ptr);
703     if (EFI_ERROR(Status) || (Ptr == NULL)) {
704       return EFI_VOLUME_CORRUPTED;
705     }
706     return EFI_SUCCESS;
707   }
708   return Status;
709 }
710 
711 
712 
713