1 /** @file
2 UEFI PI specification supersedes Inte's Framework Specification.
3 EFI_FIRMWARE_VOLUME_PROTOCOL defined in Intel Framework Pkg is replaced by
4 EFI_FIRMWARE_VOLUME2_PROTOCOL in MdePkg.
5 This module produces FV on top of FV2. This module is used on platform when both of
6 these two conditions are true:
7 1) Framework module consuming FV is present
8 2) And the platform only produces FV2
9 
10 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
11 This program and the accompanying materials
12 are licensed and made available under the terms and conditions of the BSD License
13 which accompanies this distribution.  The full text of the license may be found at
14 http://opensource.org/licenses/bsd-license.php
15 
16 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
17 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Module Name:
19 
20 **/
21 
22 #include <PiDxe.h>
23 #include <Protocol/FirmwareVolume2.h>
24 #include <Protocol/FirmwareVolume.h>
25 #include <Library/BaseLib.h>
26 #include <Library/DebugLib.h>
27 #include <Library/UefiBootServicesTableLib.h>
28 #include <Library/UefiDriverEntryPoint.h>
29 #include <Library/UefiLib.h>
30 #include <Library/MemoryAllocationLib.h>
31 
32 #define FIRMWARE_VOLUME_PRIVATE_DATA_SIGNATURE  SIGNATURE_32 ('f', 'v', 't', 'h')
33 
34 typedef struct {
35   UINTN                          Signature;
36   EFI_FIRMWARE_VOLUME_PROTOCOL   FirmwareVolume;
37   EFI_FIRMWARE_VOLUME2_PROTOCOL  *FirmwareVolume2;
38 } FIRMWARE_VOLUME_PRIVATE_DATA;
39 
40 #define FIRMWARE_VOLUME_PRIVATE_DATA_FROM_THIS(a) CR (a, FIRMWARE_VOLUME_PRIVATE_DATA, FirmwareVolume, FIRMWARE_VOLUME_PRIVATE_DATA_SIGNATURE)
41 
42 /**
43   Convert FV attrbiutes to FV2 attributes.
44 
45   @param Fv2Attributes FV2 attributes.
46 
47   @return FV attributes.
48 
49 **/
50 FRAMEWORK_EFI_FV_ATTRIBUTES
Fv2AttributesToFvAttributes(IN EFI_FV_ATTRIBUTES Fv2Attributes)51 Fv2AttributesToFvAttributes (
52   IN  EFI_FV_ATTRIBUTES Fv2Attributes
53   )
54 {
55   //
56   // Clear those filed that is not defined in Framework FV spec and Alignment conversion.
57   //
58   return (Fv2Attributes & 0x1ff) | ((UINTN) EFI_FV_ALIGNMENT_2 << RShiftU64((Fv2Attributes & EFI_FV2_ALIGNMENT), 16));
59 }
60 
61 /**
62   Retrieves attributes, insures positive polarity of attribute bits, returns
63   resulting attributes in output parameter.
64 
65   @param  This                  Calling context
66   @param  Attributes            output buffer which contains attributes
67 
68   @retval EFI_SUCCESS           The firmware volume attributes were returned.
69 
70 **/
71 EFI_STATUS
72 EFIAPI
FvGetVolumeAttributes(IN EFI_FIRMWARE_VOLUME_PROTOCOL * This,OUT FRAMEWORK_EFI_FV_ATTRIBUTES * Attributes)73 FvGetVolumeAttributes (
74   IN  EFI_FIRMWARE_VOLUME_PROTOCOL  *This,
75   OUT FRAMEWORK_EFI_FV_ATTRIBUTES   *Attributes
76   )
77 {
78   EFI_STATUS                     Status;
79   FIRMWARE_VOLUME_PRIVATE_DATA   *Private;
80   EFI_FIRMWARE_VOLUME2_PROTOCOL  *FirmwareVolume2;
81 
82   Private = FIRMWARE_VOLUME_PRIVATE_DATA_FROM_THIS (This);
83   FirmwareVolume2 = Private->FirmwareVolume2;
84 
85   Status = FirmwareVolume2->GetVolumeAttributes (
86                               FirmwareVolume2,
87                               Attributes
88                               );
89   if (!EFI_ERROR (Status)) {
90     *Attributes = Fv2AttributesToFvAttributes (*Attributes);
91   }
92   return Status;
93 }
94 
95 /**
96   Sets volume attributes.
97 
98   @param  This                  Calling context
99   @param  Attributes            Buffer which contains attributes
100 
101   @retval EFI_INVALID_PARAMETER A bit in Attributes was invalid
102   @retval EFI_SUCCESS           The requested firmware volume attributes were set
103                                 and the resulting EFI_FV_ATTRIBUTES is returned in
104                                 Attributes.
105   @retval EFI_ACCESS_DENIED     The Device is locked and does not permit modification.
106 
107 **/
108 EFI_STATUS
109 EFIAPI
FvSetVolumeAttributes(IN EFI_FIRMWARE_VOLUME_PROTOCOL * This,IN OUT FRAMEWORK_EFI_FV_ATTRIBUTES * Attributes)110 FvSetVolumeAttributes (
111   IN EFI_FIRMWARE_VOLUME_PROTOCOL     *This,
112   IN OUT FRAMEWORK_EFI_FV_ATTRIBUTES  *Attributes
113   )
114 {
115   FIRMWARE_VOLUME_PRIVATE_DATA   *Private;
116   EFI_FIRMWARE_VOLUME2_PROTOCOL  *FirmwareVolume2;
117   EFI_FV_ATTRIBUTES              Fv2Attributes;
118   EFI_STATUS                     Status;
119 
120   Private = FIRMWARE_VOLUME_PRIVATE_DATA_FROM_THIS (This);
121   FirmwareVolume2 = Private->FirmwareVolume2;
122 
123   Fv2Attributes = (*Attributes & 0x1ff);
124   Status = FirmwareVolume2->SetVolumeAttributes (
125                             FirmwareVolume2,
126                             &Fv2Attributes
127                             );
128 
129   *Attributes = Fv2AttributesToFvAttributes (Fv2Attributes);
130 
131   return Status;
132 }
133 
134 /**
135   Read the requested file (NameGuid) and returns data in Buffer.
136 
137   @param  This                  Calling context
138   @param  NameGuid              Filename identifying which file to read
139   @param  Buffer                Pointer to pointer to buffer in which contents of file are returned.
140                                 <br>
141                                 If Buffer is NULL, only type, attributes, and size are returned as
142                                 there is no output buffer.
143                                 <br>
144                                 If Buffer != NULL and *Buffer == NULL, the output buffer is allocated
145                                 from BS pool by ReadFile
146                                 <br>
147                                 If Buffer != NULL and *Buffer != NULL, the output buffer has been
148                                 allocated by the caller and is being passed in.
149   @param  BufferSize            Indicates the buffer size passed in, and on output the size
150                                 required to complete the read
151   @param  FoundType             Indicates the type of the file who's data is returned
152   @param  FileAttributes        Indicates the attributes of the file who's data is resturned
153   @param  AuthenticationStatus  Indicates the authentication status of the data
154 
155   @retval EFI_SUCCESS               The call completed successfully
156   @retval EFI_WARN_BUFFER_TOO_SMALL The buffer is too small to contain the requested output.
157                                     The buffer is filled and the output is truncated.
158   @retval EFI_NOT_FOUND             NameGuid was not found in the firmware volume.
159   @retval EFI_DEVICE_ERROR          A hardware error occurred when attempting to access the firmware volume.
160   @retval EFI_ACCESS_DENIED         The firmware volume is configured to disallow reads.
161   @retval EFI_OUT_OF_RESOURCES      An allocation failure occurred.
162 
163 **/
164 EFI_STATUS
165 EFIAPI
FvReadFile(IN EFI_FIRMWARE_VOLUME_PROTOCOL * This,IN EFI_GUID * NameGuid,IN OUT VOID ** Buffer,IN OUT UINTN * BufferSize,OUT EFI_FV_FILETYPE * FoundType,OUT EFI_FV_FILE_ATTRIBUTES * FileAttributes,OUT UINT32 * AuthenticationStatus)166 FvReadFile (
167   IN EFI_FIRMWARE_VOLUME_PROTOCOL   *This,
168   IN EFI_GUID                       *NameGuid,
169   IN OUT VOID                       **Buffer,
170   IN OUT UINTN                      *BufferSize,
171   OUT EFI_FV_FILETYPE               *FoundType,
172   OUT EFI_FV_FILE_ATTRIBUTES        *FileAttributes,
173   OUT UINT32                        *AuthenticationStatus
174   )
175 {
176   FIRMWARE_VOLUME_PRIVATE_DATA   *Private;
177   EFI_FIRMWARE_VOLUME2_PROTOCOL  *FirmwareVolume2;
178   EFI_STATUS                     Status;
179 
180   Private = FIRMWARE_VOLUME_PRIVATE_DATA_FROM_THIS (This);
181   FirmwareVolume2 = Private->FirmwareVolume2;
182 
183   Status = FirmwareVolume2->ReadFile (
184                             FirmwareVolume2,
185                             NameGuid,
186                             Buffer,
187                             BufferSize,
188                             FoundType,
189                             FileAttributes,
190                             AuthenticationStatus
191                             );
192 
193   //
194   // For Framework FV attrbutes, only alignment fields are valid.
195   //
196   *FileAttributes = *FileAttributes & EFI_FV_FILE_ATTRIB_ALIGNMENT;
197 
198   return Status;
199 }
200 
201 /**
202   Read the requested section from the specified file and returns data in Buffer.
203 
204   @param  This                  Calling context
205   @param  NameGuid              Filename identifying the file from which to read
206   @param  SectionType           Indicates what section type to retrieve
207   @param  SectionInstance       Indicates which instance of SectionType to retrieve
208   @param  Buffer                Pointer to pointer to buffer in which contents of file are returned.
209                                 <br>
210                                 If Buffer is NULL, only type, attributes, and size are returned as
211                                 there is no output buffer.
212                                 <br>
213                                 If Buffer != NULL and *Buffer == NULL, the output buffer is allocated
214                                 from BS pool by ReadFile
215                                 <br>
216                                 If Buffer != NULL and *Buffer != NULL, the output buffer has been
217                                 allocated by the caller and is being passed in.
218   @param  BufferSize            Indicates the buffer size passed in, and on output the size
219                                 required to complete the read
220   @param  AuthenticationStatus  Indicates the authentication status of the data
221 
222   @retval EFI_SUCCESS                The call completed successfully.
223   @retval EFI_WARN_BUFFER_TOO_SMALL  The buffer is too small to contain the requested output.
224                                      The buffer is filled and the output is truncated.
225   @retval EFI_OUT_OF_RESOURCES       An allocation failure occurred.
226   @retval EFI_NOT_FOUND              Name was not found in the firmware volume.
227   @retval EFI_DEVICE_ERROR           A hardware error occurred when attempting to access the firmware volume.
228   @retval EFI_ACCESS_DENIED          The firmware volume is configured to disallow reads.
229 
230 **/
231 EFI_STATUS
232 EFIAPI
FvReadSection(IN EFI_FIRMWARE_VOLUME_PROTOCOL * This,IN EFI_GUID * NameGuid,IN EFI_SECTION_TYPE SectionType,IN UINTN SectionInstance,IN OUT VOID ** Buffer,IN OUT UINTN * BufferSize,OUT UINT32 * AuthenticationStatus)233 FvReadSection (
234   IN EFI_FIRMWARE_VOLUME_PROTOCOL   *This,
235   IN EFI_GUID                       *NameGuid,
236   IN EFI_SECTION_TYPE               SectionType,
237   IN UINTN                          SectionInstance,
238   IN OUT VOID                       **Buffer,
239   IN OUT UINTN                      *BufferSize,
240   OUT UINT32                        *AuthenticationStatus
241   )
242 {
243   FIRMWARE_VOLUME_PRIVATE_DATA   *Private;
244   EFI_FIRMWARE_VOLUME2_PROTOCOL  *FirmwareVolume2;
245 
246   Private = FIRMWARE_VOLUME_PRIVATE_DATA_FROM_THIS (This);
247   FirmwareVolume2 = Private->FirmwareVolume2;
248 
249   return FirmwareVolume2->ReadSection (
250                             FirmwareVolume2,
251                             NameGuid,
252                             SectionType,
253                             SectionInstance,
254                             Buffer,
255                             BufferSize,
256                             AuthenticationStatus
257                             );
258 }
259 
260 /**
261   Write the supplied file (NameGuid) to the FV.
262 
263   @param  This                  Calling context
264   @param  NumberOfFiles         Indicates the number of file records pointed to by FileData
265   @param  WritePolicy           Indicates the level of reliability of the write with respect to
266                                 things like power failure events.
267   @param  FileData              A pointer to an array of EFI_FV_WRITE_FILE_DATA structures. Each
268                                 element in the array indicates a file to write, and there are
269                                 NumberOfFiles elements in the input array.
270 
271   @retval EFI_SUCCESS           The write completed successfully.
272   @retval EFI_OUT_OF_RESOURCES  The firmware volume does not have enough free space to store file(s).
273   @retval EFI_DEVICE_ERROR      A hardware error occurred when attempting to access the firmware volume.
274   @retval EFI_WRITE_PROTECTED   The firmware volume is configured to disallow writes.
275   @retval EFI_NOT_FOUND         A delete was requested, but the requested file was not
276                                 found in the firmware volume.
277   @retval EFI_INVALID_PARAMETER A delete was requested with a multiple file write.
278                                 An unsupported WritePolicy was requested.
279                                 An unknown file type was specified.
280                                 A file system specific error has occurred.
281 
282 **/
283 EFI_STATUS
284 EFIAPI
FvWriteFile(IN EFI_FIRMWARE_VOLUME_PROTOCOL * This,IN UINT32 NumberOfFiles,IN FRAMEWORK_EFI_FV_WRITE_POLICY WritePolicy,IN FRAMEWORK_EFI_FV_WRITE_FILE_DATA * FileData)285 FvWriteFile (
286   IN EFI_FIRMWARE_VOLUME_PROTOCOL      *This,
287   IN UINT32                            NumberOfFiles,
288   IN FRAMEWORK_EFI_FV_WRITE_POLICY     WritePolicy,
289   IN FRAMEWORK_EFI_FV_WRITE_FILE_DATA  *FileData
290   )
291 {
292   FIRMWARE_VOLUME_PRIVATE_DATA   *Private;
293   EFI_FIRMWARE_VOLUME2_PROTOCOL  *FirmwareVolume2;
294   EFI_FV_WRITE_FILE_DATA         *PiFileData;
295   EFI_STATUS                     Status;
296   UINTN                          Index;
297 
298   Private = FIRMWARE_VOLUME_PRIVATE_DATA_FROM_THIS (This);
299   FirmwareVolume2 = Private->FirmwareVolume2;
300 
301   PiFileData = AllocateCopyPool (sizeof (EFI_FV_WRITE_FILE_DATA), FileData);
302   ASSERT (PiFileData != NULL);
303 
304   //
305   // Framework Spec assume firmware files are Memory-Mapped.
306   //
307   for (Index = 0; Index < NumberOfFiles; Index++) {
308     PiFileData[Index].FileAttributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
309   }
310 
311   Status = FirmwareVolume2->WriteFile (
312                             FirmwareVolume2,
313                             NumberOfFiles,
314                             WritePolicy,
315                             (EFI_FV_WRITE_FILE_DATA *)FileData
316                             );
317 
318   FreePool (PiFileData);
319   return Status;
320 }
321 
322 /**
323   Given the input key, search for the next matching file in the volume.
324 
325   @param  This                  Calling context
326   @param  Key                   Pointer to a caller allocated buffer that contains an implementation
327                                 specific key that is used to track where to begin searching on
328                                 successive calls.
329   @param  FileType              Indicates the file type to filter for
330   @param  NameGuid              Guid filename of the file found
331   @param  Attributes            Attributes of the file found
332   @param  Size                  Size in bytes of the file found
333 
334   @retval EFI_SUCCESS           The output parameters are filled with data obtained from
335                                 the first matching file that was found.
336   @retval EFI_NOT_FOUND         No files of type FileType were found.
337   @retval EFI_DEVICE_ERROR      A hardware error occurred when attempting to access
338                                 the firmware volume.
339   @retval EFI_ACCESS_DENIED     The firmware volume is configured to disallow reads.
340 
341 **/
342 EFI_STATUS
343 EFIAPI
FvGetNextFile(IN EFI_FIRMWARE_VOLUME_PROTOCOL * This,IN OUT VOID * Key,IN OUT EFI_FV_FILETYPE * FileType,OUT EFI_GUID * NameGuid,OUT EFI_FV_FILE_ATTRIBUTES * Attributes,OUT UINTN * Size)344 FvGetNextFile (
345   IN EFI_FIRMWARE_VOLUME_PROTOCOL   *This,
346   IN OUT VOID                       *Key,
347   IN OUT EFI_FV_FILETYPE            *FileType,
348   OUT EFI_GUID                      *NameGuid,
349   OUT EFI_FV_FILE_ATTRIBUTES        *Attributes,
350   OUT UINTN                         *Size
351   )
352 {
353   FIRMWARE_VOLUME_PRIVATE_DATA   *Private;
354   EFI_FIRMWARE_VOLUME2_PROTOCOL  *FirmwareVolume2;
355   EFI_STATUS                     Status;
356 
357   Private = FIRMWARE_VOLUME_PRIVATE_DATA_FROM_THIS (This);
358   FirmwareVolume2 = Private->FirmwareVolume2;
359 
360   Status = FirmwareVolume2->GetNextFile (
361                             FirmwareVolume2,
362                             Key,
363                             FileType,
364                             NameGuid,
365                             Attributes,
366                             Size
367                             );
368 
369   //
370   // For Framework FV attrbutes, only alignment fields are valid.
371   //
372   *Attributes = *Attributes & EFI_FV_FILE_ATTRIB_ALIGNMENT;
373 
374   return Status;
375 }
376 
377 //
378 // Firmware Volume Protocol template
379 //
380 EFI_EVENT  mFvRegistration;
381 
382 FIRMWARE_VOLUME_PRIVATE_DATA gFirmwareVolumePrivateDataTemplate = {
383   FIRMWARE_VOLUME_PRIVATE_DATA_SIGNATURE,
384   {
385     FvGetVolumeAttributes,
386     FvSetVolumeAttributes,
387     FvReadFile,
388     FvReadSection,
389     FvWriteFile,
390     FvGetNextFile,
391     0,
392     NULL
393   },
394   NULL
395 };
396 
397 //
398 // Module globals
399 //
400 /**
401   This notification function is invoked when an instance of the
402   EFI_FIRMWARE_VOLUME2_PROTOCOL is produced. It installs another instance of the
403   EFI_FIRMWARE_VOLUME_PROTOCOL on the same handle.
404 
405   @param  Event                 The event that occured
406   @param  Context               Context of event. Not used in this nofication function.
407 
408 **/
409 VOID
410 EFIAPI
FvNotificationEvent(IN EFI_EVENT Event,IN VOID * Context)411 FvNotificationEvent (
412   IN  EFI_EVENT       Event,
413   IN  VOID            *Context
414   )
415 {
416   EFI_STATUS                    Status;
417   UINTN                         BufferSize;
418   EFI_HANDLE                    Handle;
419   FIRMWARE_VOLUME_PRIVATE_DATA  *Private;
420   EFI_FIRMWARE_VOLUME_PROTOCOL  *FirmwareVolume;
421 
422   while (TRUE) {
423     BufferSize = sizeof (Handle);
424     Status = gBS->LocateHandle (
425                     ByRegisterNotify,
426                     &gEfiFirmwareVolume2ProtocolGuid,
427                     mFvRegistration,
428                     &BufferSize,
429                     &Handle
430                     );
431     if (EFI_ERROR (Status)) {
432       //
433       // Exit Path of While Loop....
434       //
435       break;
436     }
437 
438     //
439     // Skip this handle if the Firmware Volume Protocol is already installed
440     //
441     Status = gBS->HandleProtocol (
442                     Handle,
443                     &gEfiFirmwareVolumeProtocolGuid,
444                     (VOID **)&FirmwareVolume
445                     );
446     if (!EFI_ERROR (Status)) {
447       continue;
448     }
449 
450     //
451     // Allocate private data structure
452     //
453     Private = AllocateCopyPool (sizeof (FIRMWARE_VOLUME_PRIVATE_DATA), &gFirmwareVolumePrivateDataTemplate);
454     if (Private == NULL) {
455       continue;
456     }
457 
458     //
459     // Retrieve the Firmware Volume2 Protocol
460     //
461     Status = gBS->HandleProtocol (
462                     Handle,
463                     &gEfiFirmwareVolume2ProtocolGuid,
464                     (VOID **)&Private->FirmwareVolume2
465                     );
466     ASSERT_EFI_ERROR (Status);
467 
468     //
469     // Fill in rest of private data structure
470     //
471     Private->FirmwareVolume.KeySize      = Private->FirmwareVolume2->KeySize;
472     Private->FirmwareVolume.ParentHandle = Private->FirmwareVolume2->ParentHandle;
473 
474     //
475     // Install Firmware Volume Protocol onto same handle
476     //
477     Status = gBS->InstallMultipleProtocolInterfaces (
478                     &Handle,
479                     &gEfiFirmwareVolumeProtocolGuid,
480                     &Private->FirmwareVolume,
481                     NULL
482                     );
483     ASSERT_EFI_ERROR (Status);
484   }
485 }
486 
487 
488 /**
489   The user Entry Point for DXE driver. The user code starts with this function
490   as the real entry point for the image goes into a library that calls this
491   function.
492 
493   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
494   @param[in] SystemTable    A pointer to the EFI System Table.
495 
496   @retval EFI_SUCCESS       The entry point is executed successfully.
497   @retval other             Some error occurs when executing this entry point.
498 
499 **/
500 EFI_STATUS
501 EFIAPI
InitializeFirmwareVolume2(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)502 InitializeFirmwareVolume2 (
503   IN EFI_HANDLE        ImageHandle,
504   IN EFI_SYSTEM_TABLE  *SystemTable
505   )
506 {
507   EfiCreateProtocolNotifyEvent (
508     &gEfiFirmwareVolume2ProtocolGuid,
509     TPL_CALLBACK,
510     FvNotificationEvent,
511     NULL,
512     &mFvRegistration
513     );
514   return EFI_SUCCESS;
515 }
516