]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / LoadFileOnFv2 / LoadFileOnFv2.c
CommitLineData
7c844f31
LG
1/** @file\r
2 Produce Load File Protocol for UEFI Applications in Firmware Volumes\r
3\r
b40ad7b5 4 Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>\r
9d510e61 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7c844f31
LG
6\r
7**/\r
8\r
9#include <PiDxe.h>\r
10\r
11#include <Guid/LzmaDecompress.h>\r
12#include <Protocol/LoadFile.h>\r
13#include <Protocol/DevicePath.h>\r
14#include <Protocol/FirmwareVolume2.h>\r
15#include <Protocol/FirmwareVolumeBlock.h>\r
16\r
17#include <Library/DebugLib.h>\r
18#include <Library/UefiLib.h>\r
19#include <Library/BaseMemoryLib.h>\r
20#include <Library/UefiDriverEntryPoint.h>\r
21#include <Library/UefiBootServicesTableLib.h>\r
22#include <Library/MemoryAllocationLib.h>\r
23#include <Library/DevicePathLib.h>\r
24\r
25#define LOAD_FILE_ON_FV2_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('l', 'f', 'f', 'v')\r
26\r
27typedef struct {\r
1436aea4
MK
28 UINTN Signature;\r
29 EFI_LOAD_FILE_PROTOCOL LoadFile;\r
30 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
31 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
32 EFI_GUID NameGuid;\r
33 LIST_ENTRY Link;\r
7c844f31
LG
34} LOAD_FILE_ON_FV2_PRIVATE_DATA;\r
35\r
1436aea4
MK
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)\r
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)\r
7c844f31 38\r
1436aea4
MK
39VOID *mFvRegistration;\r
40LIST_ENTRY mPrivateDataList;\r
7c844f31
LG
41\r
42/**\r
43 Causes the driver to load a specified file from firmware volume.\r
44\r
45 @param[in] This Protocol instance pointer.\r
46 @param[in] FilePath The device specific path of the file to load.\r
47 @param[in] BootPolicy If TRUE, indicates that the request originates from the\r
48 boot manager is attempting to load FilePath as a boot\r
49 selection. If FALSE, then FilePath must match an exact file\r
50 to be loaded.\r
51 @param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return\r
52 code of EFI_SUCCESS, the amount of data transferred to\r
53 Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,\r
54 the size of Buffer required to retrieve the requested file.\r
55 @param[in] Buffer The memory buffer to transfer the file to. IF Buffer is NULL,\r
56 then no the size of the requested file is returned in\r
57 BufferSize.\r
58\r
59 @retval EFI_SUCCESS The file was loaded.\r
60 @retval EFI_UNSUPPORTED The device does not support the provided BootPolicy.\r
61 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or\r
62 BufferSize is NULL.\r
63 @retval EFI_DEVICE_ERROR The file was not loaded due to a device error.\r
64 @retval EFI_NOT_FOUND The file was not found.\r
65 @retval EFI_OUT_OF_RESOURCES An allocation failure occurred.\r
66 @retval EFI_ACCESS_DENIED The firmware volume is configured to\r
67 disallow reads.\r
68**/\r
69EFI_STATUS\r
70EFIAPI\r
71LoadFileOnFv2LoadFile (\r
72 IN EFI_LOAD_FILE_PROTOCOL *This,\r
73 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
74 IN BOOLEAN BootPolicy,\r
75 IN OUT UINTN *BufferSize,\r
76 IN VOID *Buffer OPTIONAL\r
77 )\r
78{\r
79 EFI_STATUS Status;\r
80 LOAD_FILE_ON_FV2_PRIVATE_DATA *Private;\r
81 VOID *Pe32Buffer;\r
82 UINTN Pe32BufferSize;\r
83 UINT32 AuthenticationStatus;\r
84\r
1436aea4 85 if ((This == NULL) || (BufferSize == NULL)) {\r
7c844f31
LG
86 return EFI_INVALID_PARAMETER;\r
87 }\r
88\r
89 //\r
90 // Only support BootPolicy\r
91 //\r
92 if (!BootPolicy) {\r
93 return EFI_UNSUPPORTED;\r
94 }\r
95\r
96 //\r
97 // Get private context data\r
98 //\r
99 Private = LOAD_FILE_ON_FV2_PRIVATE_DATA_FROM_THIS (This);\r
100\r
101 //\r
102 // Determine the size of the PE32 section\r
103 //\r
104 Pe32Buffer = NULL;\r
105 Pe32BufferSize = 0;\r
1436aea4
MK
106 Status = Private->Fv->ReadSection (\r
107 Private->Fv,\r
108 &Private->NameGuid,\r
109 EFI_SECTION_PE32,\r
110 0,\r
111 &Pe32Buffer,\r
112 &Pe32BufferSize,\r
113 &AuthenticationStatus\r
114 );\r
7c844f31
LG
115 if (EFI_ERROR (Status)) {\r
116 return Status;\r
117 }\r
118\r
119 //\r
120 // If the buffer passed in is not large enough, return the size of the required\r
121 // buffer in BufferSize and return EFI_BUFFER_TOO_SMALL\r
122 //\r
1436aea4 123 if ((*BufferSize < Pe32BufferSize) || (Buffer == NULL)) {\r
7c844f31
LG
124 *BufferSize = Pe32BufferSize;\r
125 return EFI_BUFFER_TOO_SMALL;\r
126 }\r
127\r
128 //\r
129 // The buffer passed in is large enough, so read the PE32 section directly into\r
130 // the buffer, update BufferSize with the actual size read, and return the status\r
131 // from ReadSection()\r
132 //\r
133 return Private->Fv->ReadSection (\r
134 Private->Fv,\r
135 &Private->NameGuid,\r
136 EFI_SECTION_PE32,\r
137 0,\r
138 &Buffer,\r
139 BufferSize,\r
140 &AuthenticationStatus\r
141 );\r
142}\r
143\r
144LOAD_FILE_ON_FV2_PRIVATE_DATA mLoadFileOnFv2PrivateDataTemplate = {\r
145 LOAD_FILE_ON_FV2_PRIVATE_DATA_SIGNATURE,\r
146 {\r
147 LoadFileOnFv2LoadFile\r
148 }\r
149};\r
150\r
151/**\r
152 Check if the FFS has been installed LoadFileProtocol for it.\r
153\r
635d8ec3 154 @param[in] NameGuid Point to FFS File GUID to be checked.\r
7c844f31
LG
155\r
156 @retval TRUE The FFS's FileLoadProtocol is in list.\r
157 @retval FALSE The FFS's FileLoadProtocol is not in list.\r
158\r
159**/\r
160BOOLEAN\r
161EFIAPI\r
162IsInPrivateList (\r
1436aea4
MK
163 IN EFI_GUID *NameGuid\r
164 )\r
7c844f31 165{\r
1436aea4
MK
166 LIST_ENTRY *Entry;\r
167 LOAD_FILE_ON_FV2_PRIVATE_DATA *PrivateData;\r
168\r
169 if (IsListEmpty (&mPrivateDataList)) {\r
170 return FALSE;\r
171 }\r
172\r
173 for (Entry = (&mPrivateDataList)->ForwardLink; Entry != (&mPrivateDataList); Entry = Entry->ForwardLink) {\r
174 PrivateData = LOAD_FILE_ON_FV2_PRIVATE_DATA_FROM_LINK (Entry);\r
175 if (CompareGuid (NameGuid, &PrivateData->NameGuid)) {\r
176 DEBUG ((DEBUG_INFO, "LoadFileOnFv2:FileLoadProtocol has been installed in:%g\n", NameGuid));\r
177 return TRUE;\r
178 }\r
179 }\r
180\r
181 return FALSE;\r
7c844f31
LG
182}\r
183\r
184/**\r
185 Create file device path based on FFS file GUID and UI name.\r
186\r
187 @param Device Handle to Firmware Volume.\r
188 @param NameGuid Point to FFS file GUID.\r
189 @param FileName Point to FFS UI section name.\r
190\r
191 @return the combined device path\r
192**/\r
193EFI_DEVICE_PATH_PROTOCOL *\r
194EFIAPI\r
195CreateFileDevicePath (\r
1436aea4
MK
196 IN EFI_HANDLE Device,\r
197 IN EFI_GUID *NameGuid,\r
198 IN CONST CHAR16 *FileName\r
7c844f31
LG
199 )\r
200{\r
1436aea4
MK
201 UINTN Size;\r
202 FILEPATH_DEVICE_PATH *FilePath;\r
203 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
204 EFI_DEVICE_PATH_PROTOCOL *FileDevicePath;\r
205 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;\r
7c844f31
LG
206\r
207 EfiInitializeFwVolDevicepathNode (&FileNode, NameGuid);\r
208 DevicePath = AppendDevicePathNode (\r
209 DevicePathFromHandle (Device),\r
1436aea4 210 (EFI_DEVICE_PATH_PROTOCOL *)&FileNode\r
7c844f31
LG
211 );\r
212\r
1436aea4 213 Size = StrSize (FileName);\r
7c844f31
LG
214 FileDevicePath = AllocatePool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + END_DEVICE_PATH_LENGTH);\r
215 if (FileDevicePath != NULL) {\r
1436aea4 216 FilePath = (FILEPATH_DEVICE_PATH *)FileDevicePath;\r
7c844f31
LG
217 FilePath->Header.Type = MEDIA_DEVICE_PATH;\r
218 FilePath->Header.SubType = MEDIA_FILEPATH_DP;\r
219 CopyMem (&FilePath->PathName, FileName, Size);\r
220 SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH);\r
221 SetDevicePathEndNode (NextDevicePathNode (&FilePath->Header));\r
222\r
223 DevicePath = AppendDevicePath (DevicePath, FileDevicePath);\r
224 FreePool (FileDevicePath);\r
225 }\r
226\r
227 return DevicePath;\r
228}\r
229\r
230/**\r
231 Install LoadFile Protocol for Application FFS.\r
232\r
233 @param Handle FV Handle.\r
234\r
235**/\r
236VOID\r
237EFIAPI\r
238InstallFileLoadProtocol (\r
1436aea4
MK
239 EFI_HANDLE Handle\r
240 )\r
7c844f31 241{\r
1436aea4
MK
242 EFI_STATUS Status;\r
243 LOAD_FILE_ON_FV2_PRIVATE_DATA *Private;\r
244 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
245 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
246 EFI_PHYSICAL_ADDRESS Address;\r
247 EFI_FV_FILETYPE FileType;\r
248 UINTN Key;\r
249 EFI_GUID NameGuid;\r
250 EFI_FV_FILE_ATTRIBUTES Attributes;\r
251 UINTN Size;\r
252 EFI_HANDLE LoadFileHandle;\r
253 UINT32 AuthenticationStatus;\r
254 CHAR16 *UiName;\r
255 UINTN UiNameSize;\r
7c844f31
LG
256\r
257 DEBUG ((DEBUG_INFO, "LoadFileOnFv2:Find a FV!\n"));\r
258 Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);\r
259 ASSERT_EFI_ERROR (Status);\r
260 Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);\r
261 Fvb->GetPhysicalAddress (Fvb, &Address);\r
262 DEBUG ((DEBUG_INFO, "LoadFileOnFv2:Fvb->Address=%x \n", Address));\r
263\r
264 //\r
265 // Use Firmware Volume 2 Protocol to search for a FFS files of type\r
266 // EFI_FV_FILETYPE_APPLICATION and produce a LoadFile protocol for\r
267 // each one found.\r
268 //\r
269 FileType = EFI_FV_FILETYPE_APPLICATION;\r
1436aea4 270 Key = 0;\r
7c844f31
LG
271 while (TRUE) {\r
272 Status = Fv->GetNextFile (Fv, &Key, &FileType, &NameGuid, &Attributes, &Size);\r
273 if (EFI_ERROR (Status)) {\r
274 break;\r
275 }\r
276\r
277 UiName = NULL;\r
278 Status = Fv->ReadSection (\r
279 Fv,\r
280 &NameGuid,\r
281 EFI_SECTION_USER_INTERFACE,\r
282 0,\r
283 (VOID **)&UiName,\r
284 &UiNameSize,\r
285 &AuthenticationStatus\r
286 );\r
287 if (EFI_ERROR (Status)) {\r
288 continue;\r
289 }\r
1436aea4 290\r
7c844f31
LG
291 if (!IsInPrivateList (&NameGuid)) {\r
292 Private = (LOAD_FILE_ON_FV2_PRIVATE_DATA *)AllocateCopyPool (sizeof (mLoadFileOnFv2PrivateDataTemplate), &mLoadFileOnFv2PrivateDataTemplate);\r
293 ASSERT (Private != NULL);\r
1436aea4 294 Private->Fv = Fv;\r
7c844f31
LG
295 Private->DevicePath = CreateFileDevicePath (Handle, &NameGuid, UiName);\r
296 CopyGuid (&Private->NameGuid, &NameGuid);\r
297 LoadFileHandle = NULL;\r
298 DEBUG ((DEBUG_INFO, "Find a APPLICATION in this FV!\n"));\r
299 Status = gBS->InstallMultipleProtocolInterfaces (\r
300 &LoadFileHandle,\r
1436aea4
MK
301 &gEfiDevicePathProtocolGuid,\r
302 Private->DevicePath,\r
303 &gEfiLoadFileProtocolGuid,\r
304 &Private->LoadFile,\r
7c844f31
LG
305 NULL\r
306 );\r
307 if (!EFI_ERROR (Status)) {\r
308 InsertTailList (&mPrivateDataList, &Private->Link);\r
309 } else {\r
310 DEBUG ((DEBUG_ERROR, "Application with the same name %s has been installed.!\n", UiName));\r
311 FreePool (Private->DevicePath);\r
312 FreePool (Private);\r
313 }\r
314 }\r
315 }\r
316}\r
317\r
318/**\r
319 This notification function is invoked when an instance of the\r
320 LzmaCustomDecompressGuid is produced. It installs another instance of the\r
321 EFI_FIRMWARE_VOLUME_PROTOCOL on the handle of the FFS. This notification function\r
322 also handles the situation when LZMA decoder driver loaded later than FirmwareVolume driver.\r
323\r
d181539b 324 @param Event The event that occurred\r
7c844f31
LG
325 @param Context Context of event. Not used in this nofication function.\r
326\r
327**/\r
328VOID\r
329EFIAPI\r
330FvNotificationEvent (\r
1436aea4
MK
331 IN EFI_EVENT Event,\r
332 IN VOID *Context\r
7c844f31
LG
333 )\r
334{\r
1436aea4
MK
335 EFI_STATUS Status;\r
336 UINTN BufferSize;\r
337 EFI_HANDLE *Handle;\r
338 UINTN Index;\r
339 EFI_HANDLE *CurHandle;\r
7c844f31
LG
340\r
341 Handle = NULL;\r
342 Index = 0;\r
343 BufferSize = sizeof (EFI_HANDLE);\r
344 Handle = AllocateZeroPool (BufferSize);\r
deaacda3
LG
345 if (Handle == NULL) {\r
346 return;\r
347 }\r
1436aea4 348\r
7c844f31 349 Status = gBS->LocateHandle (\r
1436aea4
MK
350 ByProtocol,\r
351 &gEfiFirmwareVolume2ProtocolGuid,\r
352 NULL,\r
353 &BufferSize,\r
354 Handle\r
355 );\r
7c844f31
LG
356 if (EFI_BUFFER_TOO_SMALL == Status) {\r
357 FreePool (Handle);\r
358 Handle = AllocateZeroPool (BufferSize);\r
deaacda3
LG
359 if (Handle == NULL) {\r
360 return;\r
361 }\r
1436aea4 362\r
7c844f31
LG
363 Status = gBS->LocateHandle (\r
364 ByProtocol,\r
365 &gEfiFirmwareVolume2ProtocolGuid,\r
366 NULL,\r
367 &BufferSize,\r
368 Handle\r
369 );\r
370 if (EFI_ERROR (Status)) {\r
371 return;\r
372 }\r
373 } else if (EFI_ERROR (Status)) {\r
374 return;\r
375 }\r
376\r
377 CurHandle = Handle;\r
1436aea4 378 for (Index = 0; Index < BufferSize/sizeof (EFI_HANDLE); Index++) {\r
7c844f31
LG
379 CurHandle = Handle + Index;\r
380 //\r
381 // Install LoadFile Protocol\r
382 //\r
383 InstallFileLoadProtocol (*CurHandle);\r
384 }\r
1436aea4 385\r
7c844f31
LG
386 if (Handle != NULL) {\r
387 FreePool (Handle);\r
388 }\r
389}\r
390\r
391/**\r
392 Entry point function initializes global variables and installs notifications.\r
393\r
394 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
395 @param[in] SystemTable A pointer to the EFI System Table.\r
396\r
397 @retval EFI_SUCCESS The entry point is executed successfully.\r
398 @retval other Some error occurs when executing this entry point.\r
399**/\r
400EFI_STATUS\r
401EFIAPI\r
402LoadFileOnFv2Intialize (\r
403 IN EFI_HANDLE ImageHandle,\r
404 IN EFI_SYSTEM_TABLE *SystemTable\r
405 )\r
406{\r
407 InitializeListHead (&mPrivateDataList);\r
408\r
409 EfiCreateProtocolNotifyEvent (\r
410 &gEfiFirmwareVolume2ProtocolGuid,\r
411 TPL_CALLBACK,\r
412 FvNotificationEvent,\r
413 NULL,\r
414 &mFvRegistration\r
415 );\r
416\r
417 EfiCreateProtocolNotifyEvent (\r
1436aea4
MK
418 &gLzmaCustomDecompressGuid,\r
419 TPL_CALLBACK,\r
420 FvNotificationEvent,\r
421 NULL,\r
422 &mFvRegistration\r
7c844f31
LG
423 );\r
424\r
425 return EFI_SUCCESS;\r
426}\r