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