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 - 2014, 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 boundry, 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 boundry, 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       return EFI_VOLUME_CORRUPTED;
499     }
500   }
501 
502   //
503   // Allocate EFI_FW_VOL_BLOCK_DEVICE
504   //
505   FvbDev = AllocateCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE), &mFwVolBlock);
506   if (FvbDev == NULL) {
507     return EFI_OUT_OF_RESOURCES;
508   }
509 
510   FvbDev->BaseAddress   = BaseAddress;
511   FvbDev->FvbAttributes = FwVolHeader->Attributes;
512   FvbDev->FwVolBlockInstance.ParentHandle = ParentHandle;
513   if (ParentHandle != NULL) {
514     FvbDev->AuthenticationStatus = AuthenticationStatus;
515   }
516 
517   //
518   // Init the block caching fields of the device
519   // First, count the number of blocks
520   //
521   FvbDev->NumBlocks = 0;
522   for (PtrBlockMapEntry = FwVolHeader->BlockMap;
523        PtrBlockMapEntry->NumBlocks != 0;
524        PtrBlockMapEntry++) {
525     FvbDev->NumBlocks += PtrBlockMapEntry->NumBlocks;
526   }
527 
528   //
529   // Second, allocate the cache
530   //
531   if (FvbDev->NumBlocks >= (MAX_ADDRESS / sizeof (LBA_CACHE))) {
532     CoreFreePool (FvbDev);
533     return EFI_OUT_OF_RESOURCES;
534   }
535   FvbDev->LbaCache = AllocatePool (FvbDev->NumBlocks * sizeof (LBA_CACHE));
536   if (FvbDev->LbaCache == NULL) {
537     CoreFreePool (FvbDev);
538     return EFI_OUT_OF_RESOURCES;
539   }
540 
541   //
542   // Last, fill in the cache with the linear address of the blocks
543   //
544   BlockIndex = 0;
545   LinearOffset = 0;
546   for (PtrBlockMapEntry = FwVolHeader->BlockMap;
547        PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
548     for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {
549       FvbDev->LbaCache[BlockIndex].Base = LinearOffset;
550       FvbDev->LbaCache[BlockIndex].Length = PtrBlockMapEntry->Length;
551       LinearOffset += PtrBlockMapEntry->Length;
552       BlockIndex++;
553     }
554   }
555 
556   //
557   // Judget whether FV name guid is produced in Fv extension header
558   //
559   if (FwVolHeader->ExtHeaderOffset == 0) {
560     //
561     // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
562     //
563     FvbDev->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate);
564     if (FvbDev->DevicePath == NULL) {
565       FreePool (FvbDev);
566       return EFI_OUT_OF_RESOURCES;
567     }
568     ((FV_MEMMAP_DEVICE_PATH *) FvbDev->DevicePath)->MemMapDevPath.StartingAddress = BaseAddress;
569     ((FV_MEMMAP_DEVICE_PATH *) FvbDev->DevicePath)->MemMapDevPath.EndingAddress   = BaseAddress + FwVolHeader->FvLength - 1;
570   } else {
571     //
572     // FV contains extension header, then produce MEDIA_FW_VOL_DEVICE_PATH
573     //
574     FvbDev->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate);
575     if (FvbDev->DevicePath == NULL) {
576       FreePool (FvbDev);
577       return EFI_OUT_OF_RESOURCES;
578     }
579     CopyGuid (
580       &((FV_PIWG_DEVICE_PATH *)FvbDev->DevicePath)->FvDevPath.FvName,
581       (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)
582       );
583   }
584 
585   //
586   //
587   // Attach FvVolBlock Protocol to new handle
588   //
589   Status = CoreInstallMultipleProtocolInterfaces (
590              &FvbDev->Handle,
591              &gEfiFirmwareVolumeBlockProtocolGuid,     &FvbDev->FwVolBlockInstance,
592              &gEfiDevicePathProtocolGuid,              FvbDev->DevicePath,
593              NULL
594              );
595 
596   //
597   // If they want the handle back, set it.
598   //
599   if (FvProtocol != NULL) {
600     *FvProtocol = FvbDev->Handle;
601   }
602 
603   return Status;
604 }
605 
606 
607 
608 /**
609   This routine consumes FV hobs and produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate.
610 
611   @param  ImageHandle            The image handle.
612   @param  SystemTable            The system table.
613 
614   @retval EFI_SUCCESS            Successfully initialized firmware volume block
615                                  driver.
616 
617 **/
618 EFI_STATUS
619 EFIAPI
FwVolBlockDriverInit(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)620 FwVolBlockDriverInit (
621   IN EFI_HANDLE                 ImageHandle,
622   IN EFI_SYSTEM_TABLE           *SystemTable
623   )
624 {
625   EFI_PEI_HOB_POINTERS          FvHob;
626 
627   //
628   // Core Needs Firmware Volumes to function
629   //
630   FvHob.Raw = GetHobList ();
631   while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {
632     //
633     // Produce an FVB protocol for it
634     //
635     ProduceFVBProtocolOnBuffer (FvHob.FirmwareVolume->BaseAddress, FvHob.FirmwareVolume->Length, NULL, 0, NULL);
636     FvHob.Raw = GET_NEXT_HOB (FvHob);
637   }
638 
639   return EFI_SUCCESS;
640 }
641 
642 
643 
644 /**
645   This DXE service routine is used to process a firmware volume. In
646   particular, it can be called by BDS to process a single firmware
647   volume found in a capsule.
648 
649   Caution: The caller need validate the input firmware volume to follow
650   PI specification.
651   DxeCore will trust the input data and process firmware volume directly.
652 
653   @param  FvHeader               pointer to a firmware volume header
654   @param  Size                   the size of the buffer pointed to by FvHeader
655   @param  FVProtocolHandle       the handle on which a firmware volume protocol
656                                  was produced for the firmware volume passed in.
657 
658   @retval EFI_OUT_OF_RESOURCES   if an FVB could not be produced due to lack of
659                                  system resources
660   @retval EFI_VOLUME_CORRUPTED   if the volume was corrupted
661   @retval EFI_SUCCESS            a firmware volume protocol was produced for the
662                                  firmware volume
663 
664 **/
665 EFI_STATUS
666 EFIAPI
CoreProcessFirmwareVolume(IN VOID * FvHeader,IN UINTN Size,OUT EFI_HANDLE * FVProtocolHandle)667 CoreProcessFirmwareVolume (
668   IN VOID                             *FvHeader,
669   IN UINTN                            Size,
670   OUT EFI_HANDLE                      *FVProtocolHandle
671   )
672 {
673   VOID        *Ptr;
674   EFI_STATUS  Status;
675 
676   *FVProtocolHandle = NULL;
677   Status = ProduceFVBProtocolOnBuffer (
678             (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
679             (UINT64)Size,
680             NULL,
681             0,
682             FVProtocolHandle
683             );
684   //
685   // Since in our implementation we use register-protocol-notify to put a
686   // FV protocol on the FVB protocol handle, we can't directly verify that
687   // the FV protocol was produced. Therefore here we will check the handle
688   // and make sure an FV protocol is on it. This indicates that all went
689   // well. Otherwise we have to assume that the volume was corrupted
690   // somehow.
691   //
692   if (!EFI_ERROR(Status)) {
693     ASSERT (*FVProtocolHandle != NULL);
694     Ptr = NULL;
695     Status = CoreHandleProtocol (*FVProtocolHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **) &Ptr);
696     if (EFI_ERROR(Status) || (Ptr == NULL)) {
697       return EFI_VOLUME_CORRUPTED;
698     }
699     return EFI_SUCCESS;
700   }
701   return Status;
702 }
703 
704 
705 
706