2 Produce Load File Protocol for UEFI Applications in Firmware Volumes
4 Copyright (c) 2011 - 2013, Intel Corporation
5 All rights reserved. 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
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.
17 #include <Guid/LzmaDecompress.h>
18 #include <Protocol/LoadFile.h>
19 #include <Protocol/DevicePath.h>
20 #include <Protocol/FirmwareVolume2.h>
21 #include <Protocol/FirmwareVolumeBlock.h>
23 #include <Library/DebugLib.h>
24 #include <Library/UefiLib.h>
25 #include <Library/BaseMemoryLib.h>
26 #include <Library/UefiDriverEntryPoint.h>
27 #include <Library/UefiBootServicesTableLib.h>
28 #include <Library/MemoryAllocationLib.h>
29 #include <Library/DevicePathLib.h>
31 #define LOAD_FILE_ON_FV2_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('l', 'f', 'f', 'v')
35 EFI_LOAD_FILE_PROTOCOL LoadFile
;
36 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
37 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
40 } LOAD_FILE_ON_FV2_PRIVATE_DATA
;
42 #define LOAD_FILE_ON_FV2_PRIVATE_DATA_FROM_THIS(a) CR (a, LOAD_FILE_ON_FV2_PRIVATE_DATA, LoadFile, LOAD_FILE_ON_FV2_PRIVATE_DATA_SIGNATURE)
43 #define LOAD_FILE_ON_FV2_PRIVATE_DATA_FROM_LINK(a) CR (a, LOAD_FILE_ON_FV2_PRIVATE_DATA, Link, LOAD_FILE_ON_FV2_PRIVATE_DATA_SIGNATURE)
45 EFI_EVENT mFvRegistration
;
46 LIST_ENTRY mPrivateDataList
;
49 Causes the driver to load a specified file from firmware volume.
51 @param[in] This Protocol instance pointer.
52 @param[in] FilePath The device specific path of the file to load.
53 @param[in] BootPolicy If TRUE, indicates that the request originates from the
54 boot manager is attempting to load FilePath as a boot
55 selection. If FALSE, then FilePath must match an exact file
57 @param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return
58 code of EFI_SUCCESS, the amount of data transferred to
59 Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
60 the size of Buffer required to retrieve the requested file.
61 @param[in] Buffer The memory buffer to transfer the file to. IF Buffer is NULL,
62 then no the size of the requested file is returned in
65 @retval EFI_SUCCESS The file was loaded.
66 @retval EFI_UNSUPPORTED The device does not support the provided BootPolicy.
67 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
69 @retval EFI_DEVICE_ERROR The file was not loaded due to a device error.
70 @retval EFI_NOT_FOUND The file was not found.
71 @retval EFI_OUT_OF_RESOURCES An allocation failure occurred.
72 @retval EFI_ACCESS_DENIED The firmware volume is configured to
77 LoadFileOnFv2LoadFile (
78 IN EFI_LOAD_FILE_PROTOCOL
*This
,
79 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
80 IN BOOLEAN BootPolicy
,
81 IN OUT UINTN
*BufferSize
,
82 IN VOID
*Buffer OPTIONAL
86 LOAD_FILE_ON_FV2_PRIVATE_DATA
*Private
;
89 UINT32 AuthenticationStatus
;
91 if (This
== NULL
|| BufferSize
== NULL
) {
92 return EFI_INVALID_PARAMETER
;
96 // Only support BootPolicy
99 return EFI_UNSUPPORTED
;
103 // Get private context data
105 Private
= LOAD_FILE_ON_FV2_PRIVATE_DATA_FROM_THIS (This
);
108 // Determine the size of the PE32 section
112 Status
= Private
->Fv
->ReadSection (
119 &AuthenticationStatus
121 if (EFI_ERROR (Status
)) {
126 // If the buffer passed in is not large enough, return the size of the required
127 // buffer in BufferSize and return EFI_BUFFER_TOO_SMALL
129 if (*BufferSize
< Pe32BufferSize
|| Buffer
== NULL
) {
130 *BufferSize
= Pe32BufferSize
;
131 return EFI_BUFFER_TOO_SMALL
;
135 // The buffer passed in is large enough, so read the PE32 section directly into
136 // the buffer, update BufferSize with the actual size read, and return the status
137 // from ReadSection()
139 return Private
->Fv
->ReadSection (
146 &AuthenticationStatus
150 LOAD_FILE_ON_FV2_PRIVATE_DATA mLoadFileOnFv2PrivateDataTemplate
= {
151 LOAD_FILE_ON_FV2_PRIVATE_DATA_SIGNATURE
,
153 LoadFileOnFv2LoadFile
158 Check if the FFS has been installed LoadFileProtocol for it.
160 @param EFI_GUID File GUID.
162 @retval TRUE The FFS's FileLoadProtocol is in list.
163 @retval FALSE The FFS's FileLoadProtocol is not in list.
169 IN EFI_GUID
*NameGuid
173 LOAD_FILE_ON_FV2_PRIVATE_DATA
*PrivateData
;
175 if (IsListEmpty (&mPrivateDataList
)) {
179 for(Entry
= (&mPrivateDataList
)->ForwardLink
; Entry
!= (&mPrivateDataList
); Entry
= Entry
->ForwardLink
) {
180 PrivateData
= LOAD_FILE_ON_FV2_PRIVATE_DATA_FROM_LINK (Entry
);
181 if (CompareGuid (NameGuid
, &PrivateData
->NameGuid
)) {
182 DEBUG ((DEBUG_INFO
, "LoadFileOnFv2:FileLoadProtocol has been installed in:%g\n", NameGuid
));
190 Create file device path based on FFS file GUID and UI name.
192 @param Device Handle to Firmware Volume.
193 @param NameGuid Point to FFS file GUID.
194 @param FileName Point to FFS UI section name.
196 @return the combined device path
198 EFI_DEVICE_PATH_PROTOCOL
*
200 CreateFileDevicePath (
201 IN EFI_HANDLE Device
,
202 IN EFI_GUID
*NameGuid
,
203 IN CONST CHAR16
*FileName
207 FILEPATH_DEVICE_PATH
*FilePath
;
208 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
209 EFI_DEVICE_PATH_PROTOCOL
*FileDevicePath
;
210 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
212 EfiInitializeFwVolDevicepathNode (&FileNode
, NameGuid
);
213 DevicePath
= AppendDevicePathNode (
214 DevicePathFromHandle (Device
),
215 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
218 Size
= StrSize (FileName
);
219 FileDevicePath
= AllocatePool (Size
+ SIZE_OF_FILEPATH_DEVICE_PATH
+ END_DEVICE_PATH_LENGTH
);
220 if (FileDevicePath
!= NULL
) {
221 FilePath
= (FILEPATH_DEVICE_PATH
*) FileDevicePath
;
222 FilePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
223 FilePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
224 CopyMem (&FilePath
->PathName
, FileName
, Size
);
225 SetDevicePathNodeLength (&FilePath
->Header
, Size
+ SIZE_OF_FILEPATH_DEVICE_PATH
);
226 SetDevicePathEndNode (NextDevicePathNode (&FilePath
->Header
));
228 DevicePath
= AppendDevicePath (DevicePath
, FileDevicePath
);
229 FreePool (FileDevicePath
);
236 Install LoadFile Protocol for Application FFS.
238 @param Handle FV Handle.
243 InstallFileLoadProtocol (
248 LOAD_FILE_ON_FV2_PRIVATE_DATA
*Private
;
249 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
250 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
251 EFI_PHYSICAL_ADDRESS Address
;
252 EFI_FV_FILETYPE FileType
;
255 EFI_FV_FILE_ATTRIBUTES Attributes
;
257 EFI_HANDLE LoadFileHandle
;
258 UINT32 AuthenticationStatus
;
262 DEBUG ((DEBUG_INFO
, "LoadFileOnFv2:Find a FV!\n"));
263 Status
= gBS
->HandleProtocol (Handle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&Fv
);
264 ASSERT_EFI_ERROR (Status
);
265 Status
= gBS
->HandleProtocol (Handle
, &gEfiFirmwareVolumeBlockProtocolGuid
, (VOID
**)&Fvb
);
266 Fvb
->GetPhysicalAddress (Fvb
, &Address
);
267 DEBUG ((DEBUG_INFO
, "LoadFileOnFv2:Fvb->Address=%x \n", Address
));
270 // Use Firmware Volume 2 Protocol to search for a FFS files of type
271 // EFI_FV_FILETYPE_APPLICATION and produce a LoadFile protocol for
274 FileType
= EFI_FV_FILETYPE_APPLICATION
;
277 Status
= Fv
->GetNextFile (Fv
, &Key
, &FileType
, &NameGuid
, &Attributes
, &Size
);
278 if (EFI_ERROR (Status
)) {
283 Status
= Fv
->ReadSection (
286 EFI_SECTION_USER_INTERFACE
,
290 &AuthenticationStatus
292 if (EFI_ERROR (Status
)) {
295 if (!IsInPrivateList (&NameGuid
)) {
296 Private
= (LOAD_FILE_ON_FV2_PRIVATE_DATA
*)AllocateCopyPool (sizeof (mLoadFileOnFv2PrivateDataTemplate
), &mLoadFileOnFv2PrivateDataTemplate
);
297 ASSERT (Private
!= NULL
);
299 Private
->DevicePath
= CreateFileDevicePath (Handle
, &NameGuid
, UiName
);
300 CopyGuid (&Private
->NameGuid
, &NameGuid
);
301 LoadFileHandle
= NULL
;
302 DEBUG ((DEBUG_INFO
, "Find a APPLICATION in this FV!\n"));
303 Status
= gBS
->InstallMultipleProtocolInterfaces (
305 &gEfiDevicePathProtocolGuid
, Private
->DevicePath
,
306 &gEfiLoadFileProtocolGuid
, &Private
->LoadFile
,
309 if (!EFI_ERROR (Status
)) {
310 InsertTailList (&mPrivateDataList
, &Private
->Link
);
312 DEBUG ((DEBUG_ERROR
, "Application with the same name %s has been installed.!\n", UiName
));
313 FreePool (Private
->DevicePath
);
321 This notification function is invoked when an instance of the
322 LzmaCustomDecompressGuid is produced. It installs another instance of the
323 EFI_FIRMWARE_VOLUME_PROTOCOL on the handle of the FFS. This notification function
324 also handles the situation when LZMA decoder driver loaded later than FirmwareVolume driver.
326 @param Event The event that occured
327 @param Context Context of event. Not used in this nofication function.
332 FvNotificationEvent (
341 EFI_HANDLE
*CurHandle
;
346 BufferSize
= sizeof (EFI_HANDLE
);
347 Handle
= AllocateZeroPool (BufferSize
);
348 Status
= gBS
->LocateHandle (
350 &gEfiFirmwareVolume2ProtocolGuid
,
355 if (EFI_BUFFER_TOO_SMALL
== Status
) {
357 Handle
= AllocateZeroPool (BufferSize
);
358 Status
= gBS
->LocateHandle (
360 &gEfiFirmwareVolume2ProtocolGuid
,
365 if (EFI_ERROR (Status
)) {
368 } else if (EFI_ERROR (Status
)) {
373 for (Index
=0; Index
< BufferSize
/sizeof (EFI_HANDLE
); Index
++) {
374 CurHandle
= Handle
+ Index
;
376 // Install LoadFile Protocol
378 InstallFileLoadProtocol (*CurHandle
);
380 if (Handle
!= NULL
) {
386 Entry point function initializes global variables and installs notifications.
388 @param[in] ImageHandle The firmware allocated handle for the EFI image.
389 @param[in] SystemTable A pointer to the EFI System Table.
391 @retval EFI_SUCCESS The entry point is executed successfully.
392 @retval other Some error occurs when executing this entry point.
396 LoadFileOnFv2Intialize (
397 IN EFI_HANDLE ImageHandle
,
398 IN EFI_SYSTEM_TABLE
*SystemTable
401 InitializeListHead (&mPrivateDataList
);
403 EfiCreateProtocolNotifyEvent (
404 &gEfiFirmwareVolume2ProtocolGuid
,
411 EfiCreateProtocolNotifyEvent (
412 &gLzmaCustomDecompressGuid
,