2 Produce Load File Protocol for UEFI Applications in Firmware Volumes
4 Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include <Guid/LzmaDecompress.h>
12 #include <Protocol/LoadFile.h>
13 #include <Protocol/DevicePath.h>
14 #include <Protocol/FirmwareVolume2.h>
15 #include <Protocol/FirmwareVolumeBlock.h>
17 #include <Library/DebugLib.h>
18 #include <Library/UefiLib.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/UefiDriverEntryPoint.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/MemoryAllocationLib.h>
23 #include <Library/DevicePathLib.h>
25 #define LOAD_FILE_ON_FV2_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('l', 'f', 'f', 'v')
29 EFI_LOAD_FILE_PROTOCOL LoadFile
;
30 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
31 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
34 } LOAD_FILE_ON_FV2_PRIVATE_DATA
;
36 #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)
37 #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)
39 EFI_EVENT mFvRegistration
;
40 LIST_ENTRY mPrivateDataList
;
43 Causes the driver to load a specified file from firmware volume.
45 @param[in] This Protocol instance pointer.
46 @param[in] FilePath The device specific path of the file to load.
47 @param[in] BootPolicy If TRUE, indicates that the request originates from the
48 boot manager is attempting to load FilePath as a boot
49 selection. If FALSE, then FilePath must match an exact file
51 @param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return
52 code of EFI_SUCCESS, the amount of data transferred to
53 Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
54 the size of Buffer required to retrieve the requested file.
55 @param[in] Buffer The memory buffer to transfer the file to. IF Buffer is NULL,
56 then no the size of the requested file is returned in
59 @retval EFI_SUCCESS The file was loaded.
60 @retval EFI_UNSUPPORTED The device does not support the provided BootPolicy.
61 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
63 @retval EFI_DEVICE_ERROR The file was not loaded due to a device error.
64 @retval EFI_NOT_FOUND The file was not found.
65 @retval EFI_OUT_OF_RESOURCES An allocation failure occurred.
66 @retval EFI_ACCESS_DENIED The firmware volume is configured to
71 LoadFileOnFv2LoadFile (
72 IN EFI_LOAD_FILE_PROTOCOL
*This
,
73 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
74 IN BOOLEAN BootPolicy
,
75 IN OUT UINTN
*BufferSize
,
76 IN VOID
*Buffer OPTIONAL
80 LOAD_FILE_ON_FV2_PRIVATE_DATA
*Private
;
83 UINT32 AuthenticationStatus
;
85 if (This
== NULL
|| BufferSize
== NULL
) {
86 return EFI_INVALID_PARAMETER
;
90 // Only support BootPolicy
93 return EFI_UNSUPPORTED
;
97 // Get private context data
99 Private
= LOAD_FILE_ON_FV2_PRIVATE_DATA_FROM_THIS (This
);
102 // Determine the size of the PE32 section
106 Status
= Private
->Fv
->ReadSection (
113 &AuthenticationStatus
115 if (EFI_ERROR (Status
)) {
120 // If the buffer passed in is not large enough, return the size of the required
121 // buffer in BufferSize and return EFI_BUFFER_TOO_SMALL
123 if (*BufferSize
< Pe32BufferSize
|| Buffer
== NULL
) {
124 *BufferSize
= Pe32BufferSize
;
125 return EFI_BUFFER_TOO_SMALL
;
129 // The buffer passed in is large enough, so read the PE32 section directly into
130 // the buffer, update BufferSize with the actual size read, and return the status
131 // from ReadSection()
133 return Private
->Fv
->ReadSection (
140 &AuthenticationStatus
144 LOAD_FILE_ON_FV2_PRIVATE_DATA mLoadFileOnFv2PrivateDataTemplate
= {
145 LOAD_FILE_ON_FV2_PRIVATE_DATA_SIGNATURE
,
147 LoadFileOnFv2LoadFile
152 Check if the FFS has been installed LoadFileProtocol for it.
154 @param[in] NameGuid Point to FFS File GUID to be checked.
156 @retval TRUE The FFS's FileLoadProtocol is in list.
157 @retval FALSE The FFS's FileLoadProtocol is not in list.
163 IN EFI_GUID
*NameGuid
167 LOAD_FILE_ON_FV2_PRIVATE_DATA
*PrivateData
;
169 if (IsListEmpty (&mPrivateDataList
)) {
173 for(Entry
= (&mPrivateDataList
)->ForwardLink
; Entry
!= (&mPrivateDataList
); Entry
= Entry
->ForwardLink
) {
174 PrivateData
= LOAD_FILE_ON_FV2_PRIVATE_DATA_FROM_LINK (Entry
);
175 if (CompareGuid (NameGuid
, &PrivateData
->NameGuid
)) {
176 DEBUG ((DEBUG_INFO
, "LoadFileOnFv2:FileLoadProtocol has been installed in:%g\n", NameGuid
));
184 Create file device path based on FFS file GUID and UI name.
186 @param Device Handle to Firmware Volume.
187 @param NameGuid Point to FFS file GUID.
188 @param FileName Point to FFS UI section name.
190 @return the combined device path
192 EFI_DEVICE_PATH_PROTOCOL
*
194 CreateFileDevicePath (
195 IN EFI_HANDLE Device
,
196 IN EFI_GUID
*NameGuid
,
197 IN CONST CHAR16
*FileName
201 FILEPATH_DEVICE_PATH
*FilePath
;
202 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
203 EFI_DEVICE_PATH_PROTOCOL
*FileDevicePath
;
204 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
206 EfiInitializeFwVolDevicepathNode (&FileNode
, NameGuid
);
207 DevicePath
= AppendDevicePathNode (
208 DevicePathFromHandle (Device
),
209 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
212 Size
= StrSize (FileName
);
213 FileDevicePath
= AllocatePool (Size
+ SIZE_OF_FILEPATH_DEVICE_PATH
+ END_DEVICE_PATH_LENGTH
);
214 if (FileDevicePath
!= NULL
) {
215 FilePath
= (FILEPATH_DEVICE_PATH
*) FileDevicePath
;
216 FilePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
217 FilePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
218 CopyMem (&FilePath
->PathName
, FileName
, Size
);
219 SetDevicePathNodeLength (&FilePath
->Header
, Size
+ SIZE_OF_FILEPATH_DEVICE_PATH
);
220 SetDevicePathEndNode (NextDevicePathNode (&FilePath
->Header
));
222 DevicePath
= AppendDevicePath (DevicePath
, FileDevicePath
);
223 FreePool (FileDevicePath
);
230 Install LoadFile Protocol for Application FFS.
232 @param Handle FV Handle.
237 InstallFileLoadProtocol (
242 LOAD_FILE_ON_FV2_PRIVATE_DATA
*Private
;
243 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
244 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
245 EFI_PHYSICAL_ADDRESS Address
;
246 EFI_FV_FILETYPE FileType
;
249 EFI_FV_FILE_ATTRIBUTES Attributes
;
251 EFI_HANDLE LoadFileHandle
;
252 UINT32 AuthenticationStatus
;
256 DEBUG ((DEBUG_INFO
, "LoadFileOnFv2:Find a FV!\n"));
257 Status
= gBS
->HandleProtocol (Handle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&Fv
);
258 ASSERT_EFI_ERROR (Status
);
259 Status
= gBS
->HandleProtocol (Handle
, &gEfiFirmwareVolumeBlockProtocolGuid
, (VOID
**)&Fvb
);
260 Fvb
->GetPhysicalAddress (Fvb
, &Address
);
261 DEBUG ((DEBUG_INFO
, "LoadFileOnFv2:Fvb->Address=%x \n", Address
));
264 // Use Firmware Volume 2 Protocol to search for a FFS files of type
265 // EFI_FV_FILETYPE_APPLICATION and produce a LoadFile protocol for
268 FileType
= EFI_FV_FILETYPE_APPLICATION
;
271 Status
= Fv
->GetNextFile (Fv
, &Key
, &FileType
, &NameGuid
, &Attributes
, &Size
);
272 if (EFI_ERROR (Status
)) {
277 Status
= Fv
->ReadSection (
280 EFI_SECTION_USER_INTERFACE
,
284 &AuthenticationStatus
286 if (EFI_ERROR (Status
)) {
289 if (!IsInPrivateList (&NameGuid
)) {
290 Private
= (LOAD_FILE_ON_FV2_PRIVATE_DATA
*)AllocateCopyPool (sizeof (mLoadFileOnFv2PrivateDataTemplate
), &mLoadFileOnFv2PrivateDataTemplate
);
291 ASSERT (Private
!= NULL
);
293 Private
->DevicePath
= CreateFileDevicePath (Handle
, &NameGuid
, UiName
);
294 CopyGuid (&Private
->NameGuid
, &NameGuid
);
295 LoadFileHandle
= NULL
;
296 DEBUG ((DEBUG_INFO
, "Find a APPLICATION in this FV!\n"));
297 Status
= gBS
->InstallMultipleProtocolInterfaces (
299 &gEfiDevicePathProtocolGuid
, Private
->DevicePath
,
300 &gEfiLoadFileProtocolGuid
, &Private
->LoadFile
,
303 if (!EFI_ERROR (Status
)) {
304 InsertTailList (&mPrivateDataList
, &Private
->Link
);
306 DEBUG ((DEBUG_ERROR
, "Application with the same name %s has been installed.!\n", UiName
));
307 FreePool (Private
->DevicePath
);
315 This notification function is invoked when an instance of the
316 LzmaCustomDecompressGuid is produced. It installs another instance of the
317 EFI_FIRMWARE_VOLUME_PROTOCOL on the handle of the FFS. This notification function
318 also handles the situation when LZMA decoder driver loaded later than FirmwareVolume driver.
320 @param Event The event that occured
321 @param Context Context of event. Not used in this nofication function.
326 FvNotificationEvent (
335 EFI_HANDLE
*CurHandle
;
340 BufferSize
= sizeof (EFI_HANDLE
);
341 Handle
= AllocateZeroPool (BufferSize
);
342 if (Handle
== NULL
) {
345 Status
= gBS
->LocateHandle (
347 &gEfiFirmwareVolume2ProtocolGuid
,
352 if (EFI_BUFFER_TOO_SMALL
== Status
) {
354 Handle
= AllocateZeroPool (BufferSize
);
355 if (Handle
== NULL
) {
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
,