]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Image/ImageFile.c
Fixed HSD201555
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Image / ImageFile.c
CommitLineData
504214c4 1/** @file\r
23c98c94 2 Handle services to image file.\r
3\r
4Copyright (c) 2006 - 2008, Intel Corporation. <BR>\r
cfe9de52 5All rights reserved. This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
28a00297 12\r
504214c4 13**/\r
28a00297 14\r
9c4ac31c 15#include "DxeMain.h"\r
28a00297 16\r
c0a23f8c 17/**\r
18 Search a handle to a device on a specified device path that supports a specified protocol,\r
19 interface of that protocol on that handle is another output.\r
20\r
21 @param Protocol The protocol to search for\r
22 @param FilePath The specified device path\r
23 @param Interface Interface of the protocol on the handle\r
24 @param Handle The handle to the device on the specified device\r
25 path that supports the protocol.\r
26\r
27 @return Status code.\r
28\r
29**/\r
30EFI_STATUS\r
31CoreDevicePathToInterface (\r
32 IN EFI_GUID *Protocol,\r
33 IN EFI_DEVICE_PATH_PROTOCOL **FilePath,\r
34 OUT VOID **Interface,\r
35 OUT EFI_HANDLE *Handle\r
36 )\r
37{\r
38 EFI_STATUS Status;\r
39\r
40 Status = CoreLocateDevicePath (Protocol, FilePath, Handle);\r
41 if (!EFI_ERROR (Status)) {\r
42 Status = CoreHandleProtocol (*Handle, Protocol, Interface);\r
43 }\r
44 return Status;\r
45}\r
46\r
162ed594 47\r
48/**\r
49 Opens a file for (simple) reading. The simple read abstraction\r
50 will access the file either from a memory copy, from a file\r
51 system interface, or from the load file interface.\r
52\r
022c6d45 53 @param BootPolicy Policy for Open Image File.\r
54 @param SourceBuffer Pointer to the memory location containing copy\r
55 of the image to be loaded.\r
56 @param SourceSize The size in bytes of SourceBuffer.\r
57 @param FilePath The specific file path from which the image is\r
58 loaded\r
59 @param DeviceHandle Pointer to the return device handle.\r
60 @param ImageFileHandle Pointer to the image file handle.\r
61 @param AuthenticationStatus Pointer to a caller-allocated UINT32 in which\r
62 the authentication status is returned.\r
63\r
64 @retval EFI_SUCCESS Image file successfully opened.\r
65 @retval EFI_LOAD_ERROR If the caller passed a copy of the file, and\r
66 SourceSize is 0.\r
67 @retval EFI_INVALID_PARAMETER File path is not valid.\r
162ed594 68 @retval EFI_NOT_FOUND File not found.\r
69\r
70**/\r
28a00297 71EFI_STATUS\r
72CoreOpenImageFile (\r
73 IN BOOLEAN BootPolicy,\r
74 IN VOID *SourceBuffer OPTIONAL,\r
75 IN UINTN SourceSize,\r
cfe9de52 76 IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,\r
28a00297 77 OUT EFI_HANDLE *DeviceHandle,\r
78 IN IMAGE_FILE_HANDLE *ImageFileHandle,\r
79 OUT UINT32 *AuthenticationStatus\r
80 )\r
28a00297 81{\r
82 EFI_STATUS Status;\r
83 EFI_DEVICE_PATH_PROTOCOL *TempFilePath;\r
84 FILEPATH_DEVICE_PATH *FilePathNode;\r
85 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FwVolFilePathNode;\r
86 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;\r
87 EFI_FILE_HANDLE FileHandle;\r
88 EFI_FILE_HANDLE LastHandle;\r
89 EFI_LOAD_FILE_PROTOCOL *LoadFile;\r
0c2b5da8 90 EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;\r
28a00297 91 EFI_SECTION_TYPE SectionType;\r
92 UINT8 *Pe32Buffer;\r
93 UINTN Pe32BufferSize;\r
94 EFI_FV_FILETYPE Type;\r
95 EFI_FV_FILE_ATTRIBUTES Attrib;\r
96 EFI_FILE_INFO *FileInfo;\r
97 UINTN FileInfoSize;\r
98 EFI_GUID *NameGuid;\r
1564e9ac 99 FILEPATH_DEVICE_PATH *OriginalFilePathNode;\r
28a00297 100\r
1564e9ac 101 OriginalFilePathNode = NULL;\r
28a00297 102 *AuthenticationStatus = 0;\r
103 ZeroMem (ImageFileHandle, sizeof (IMAGE_FILE_HANDLE));\r
104 ImageFileHandle->Signature = IMAGE_FILE_HANDLE_SIGNATURE;\r
105\r
106 //\r
107 // If the caller passed a copy of the file, then just use it\r
108 //\r
109 if (SourceBuffer != NULL) {\r
110 ImageFileHandle->Source = SourceBuffer;\r
111 ImageFileHandle->SourceSize = SourceSize;\r
e94a9ff7 112 *DeviceHandle = NULL;\r
cfe9de52 113 CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, FilePath, DeviceHandle);\r
28a00297 114 if (SourceSize > 0) {\r
115 Status = EFI_SUCCESS;\r
116 } else {\r
117 Status = EFI_LOAD_ERROR;\r
118 }\r
119 goto Done;\r
120 }\r
121\r
122 //\r
123 // Make sure FilePath is valid\r
124 //\r
cfe9de52 125 if (*FilePath == NULL) {\r
28a00297 126 return EFI_INVALID_PARAMETER;\r
127 }\r
128\r
129 //\r
130 // Check to see if it's in a Firmware Volume\r
131 //\r
cfe9de52 132 FwVolFilePathNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) *FilePath;\r
28a00297 133 Status = CoreDevicePathToInterface (\r
cfe9de52 134 &gEfiFirmwareVolume2ProtocolGuid,\r
135 (EFI_DEVICE_PATH_PROTOCOL **)&FwVolFilePathNode,\r
136 (VOID*)&FwVol,\r
28a00297 137 DeviceHandle\r
138 );\r
139 if (!EFI_ERROR (Status)) {\r
140 //\r
141 // For FwVol File system there is only a single file name that is a GUID.\r
142 //\r
143 NameGuid = EfiGetNameGuidFromFwVolDevicePathNode (FwVolFilePathNode);\r
144 if (NameGuid != NULL) {\r
145\r
146 SectionType = EFI_SECTION_PE32;\r
147 Pe32Buffer = NULL;\r
148 Status = FwVol->ReadSection (\r
cfe9de52 149 FwVol,\r
150 NameGuid,\r
151 SectionType,\r
28a00297 152 0,\r
153 (VOID **)&Pe32Buffer,\r
154 &Pe32BufferSize,\r
155 AuthenticationStatus\r
156 );\r
157 if (EFI_ERROR (Status)) {\r
158 //\r
159 // Try a raw file, since a PE32 SECTION does not exist\r
160 //\r
161 if (Pe32Buffer != NULL) {\r
162 CoreFreePool (Pe32Buffer);\r
163 *AuthenticationStatus = 0;\r
164 }\r
165 Pe32Buffer = NULL;\r
166 Status = FwVol->ReadFile (\r
cfe9de52 167 FwVol,\r
168 NameGuid,\r
28a00297 169 (VOID **)&Pe32Buffer,\r
170 &Pe32BufferSize,\r
171 &Type,\r
172 &Attrib,\r
173 AuthenticationStatus\r
174 );\r
175 }\r
cfe9de52 176\r
28a00297 177 if (!EFI_ERROR (Status)) {\r
178 //\r
179 // One of the reads passed so we are done\r
180 //\r
181 ImageFileHandle->Source = Pe32Buffer;\r
182 ImageFileHandle->SourceSize = Pe32BufferSize;\r
183 ImageFileHandle->FreeBuffer = TRUE;\r
184 goto Done;\r
185 }\r
186 }\r
187 }\r
188\r
189 //\r
190 // Attempt to access the file via a file system interface\r
191 //\r
cfe9de52 192 FilePathNode = (FILEPATH_DEVICE_PATH *) *FilePath;\r
28a00297 193 Status = CoreDevicePathToInterface (\r
cfe9de52 194 &gEfiSimpleFileSystemProtocolGuid,\r
195 (EFI_DEVICE_PATH_PROTOCOL **)&FilePathNode,\r
196 (VOID*)&Volume,\r
28a00297 197 DeviceHandle\r
198 );\r
199 if (!EFI_ERROR (Status)) {\r
200 //\r
201 // Open the Volume to get the File System handle\r
202 //\r
203 Status = Volume->OpenVolume (Volume, &FileHandle);\r
204 if (!EFI_ERROR (Status)) {\r
28a00297 205 //\r
1564e9ac 206 // Duplicate the device path to avoid the access to unaligned device path node.\r
207 // Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH\r
022c6d45 208 // nodes, It assures the fields in device path nodes are 2 byte aligned.\r
28a00297 209 //\r
9c4ac31c 210 FilePathNode = (FILEPATH_DEVICE_PATH *)DuplicateDevicePath((EFI_DEVICE_PATH_PROTOCOL *)(UINTN)FilePathNode);\r
1564e9ac 211 if (FilePathNode == NULL) {\r
212 FileHandle->Close (FileHandle);\r
213 Status = EFI_OUT_OF_RESOURCES;\r
214 } else {\r
215 OriginalFilePathNode = FilePathNode;\r
216 //\r
217 // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the\r
218 // directory information and filename can be seperate. The goal is to inch\r
219 // our way down each device path node and close the previous node\r
220 //\r
221 while (!IsDevicePathEnd (&FilePathNode->Header)) {\r
222 if (DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH ||\r
223 DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP) {\r
224 Status = EFI_UNSUPPORTED;\r
225 }\r
226\r
227 if (EFI_ERROR (Status)) {\r
228 //\r
229 // Exit loop on Error\r
230 //\r
231 break;\r
232 }\r
233\r
234 LastHandle = FileHandle;\r
235 FileHandle = NULL;\r
236\r
237 Status = LastHandle->Open (\r
238 LastHandle,\r
239 &FileHandle,\r
240 FilePathNode->PathName,\r
241 EFI_FILE_MODE_READ,\r
242 0\r
243 );\r
28a00297 244\r
28a00297 245 //\r
1564e9ac 246 // Close the previous node\r
28a00297 247 //\r
1564e9ac 248 LastHandle->Close (LastHandle);\r
28a00297 249\r
1564e9ac 250 FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header);\r
251 }\r
28a00297 252 //\r
022c6d45 253 // Free the allocated memory pool\r
28a00297 254 //\r
1564e9ac 255 CoreFreePool(OriginalFilePathNode);\r
28a00297 256 }\r
257\r
258 if (!EFI_ERROR (Status)) {\r
259 //\r
260 // We have found the file. Now we need to read it. Before we can read the file we need to\r
261 // figure out how big the file is.\r
262 //\r
263 FileInfo = NULL;\r
264 FileInfoSize = sizeof (EFI_FILE_INFO);\r
265 while (CoreGrowBuffer (&Status, (VOID **)&FileInfo, FileInfoSize)) {\r
266 //\r
267 // Automatically allocate buffer of the correct size and make the call\r
268 //\r
269 Status = FileHandle->GetInfo (\r
270 FileHandle,\r
271 &gEfiFileInfoGuid,\r
272 &FileInfoSize,\r
cfe9de52 273 FileInfo\r
28a00297 274 );\r
275 }\r
276 if (!EFI_ERROR (Status)) {\r
277 //\r
278 // Allocate space for the file\r
279 //\r
9c4ac31c 280 ImageFileHandle->Source = AllocatePool ((UINTN)FileInfo->FileSize);\r
28a00297 281 if (ImageFileHandle->Source != NULL) {\r
282 //\r
283 // Read the file into the buffer we allocated\r
284 //\r
e94a9ff7 285 ImageFileHandle->SourceSize = (UINTN) FileInfo->FileSize;\r
28a00297 286 ImageFileHandle->FreeBuffer = TRUE;\r
287 Status = FileHandle->Read (FileHandle, &ImageFileHandle->SourceSize, ImageFileHandle->Source);\r
288\r
289 //\r
290 // Close the file since we are done\r
291 //\r
292 FileHandle->Close (FileHandle);\r
293 } else {\r
294 Status = EFI_OUT_OF_RESOURCES;\r
295 }\r
296\r
297 goto Done;\r
298 }\r
299 }\r
300 }\r
cfe9de52 301 }\r
28a00297 302\r
303\r
304 //\r
305 // Try LoadFile style\r
306 //\r
307\r
cfe9de52 308 TempFilePath = *FilePath;\r
28a00297 309 Status = CoreDevicePathToInterface (\r
e94a9ff7 310 &gEfiLoadFileProtocolGuid,\r
311 &TempFilePath,\r
312 (VOID*) &LoadFile,\r
313 DeviceHandle\r
314 );\r
28a00297 315 if (!EFI_ERROR (Status)) {\r
316 //\r
317 // Call LoadFile with the correct buffer size\r
318 //\r
319 while (CoreGrowBuffer (&Status, (VOID **)&ImageFileHandle->Source, ImageFileHandle->SourceSize)) {\r
320 Status = LoadFile->LoadFile (\r
321 LoadFile,\r
322 TempFilePath,\r
323 BootPolicy,\r
324 &ImageFileHandle->SourceSize,\r
325 ImageFileHandle->Source\r
326 );\r
327 //\r
328 // If success or other error happens, stop loop\r
329 //\r
330 if (Status != EFI_BUFFER_TOO_SMALL) {\r
331 break;\r
332 }\r
333 }\r
334\r
2ce854f5 335 if (!EFI_ERROR (Status)) {\r
28a00297 336 ImageFileHandle->FreeBuffer = TRUE;\r
337 goto Done;\r
338 }\r
339 }\r
340\r
341 //\r
342 // Nothing else to try\r
343 //\r
2ce854f5 344 DEBUG ((DEBUG_LOAD | DEBUG_WARN, "CoreOpenImageFile: Device did not support a known load protocol\n"));\r
28a00297 345 Status = EFI_NOT_FOUND;\r
346\r
347Done:\r
348\r
349 //\r
350 // If the file was not accessed, clean up\r
351 //\r
2ce854f5 352 if (EFI_ERROR (Status)) {\r
28a00297 353 if (ImageFileHandle->FreeBuffer) {\r
354 //\r
355 // Free the source buffer if we allocated it\r
356 //\r
357 CoreFreePool (ImageFileHandle->Source);\r
358 }\r
359 }\r
360\r
361 return Status;\r
362}\r
363\r
364\r
365\r
162ed594 366/**\r
367 Read image file (specified by UserHandle) into user specified buffer with specified offset\r
368 and length.\r
369\r
022c6d45 370 @param UserHandle Image file handle\r
371 @param Offset Offset to the source file\r
372 @param ReadSize For input, pointer of size to read; For output,\r
373 pointer of size actually read.\r
374 @param Buffer Buffer to write into\r
162ed594 375\r
022c6d45 376 @retval EFI_SUCCESS Successfully read the specified part of file\r
162ed594 377 into buffer.\r
378\r
379**/\r
28a00297 380EFI_STATUS\r
381EFIAPI\r
382CoreReadImageFile (\r
383 IN VOID *UserHandle,\r
384 IN UINTN Offset,\r
385 IN OUT UINTN *ReadSize,\r
386 OUT VOID *Buffer\r
387 )\r
28a00297 388{\r
389 UINTN EndPosition;\r
390 IMAGE_FILE_HANDLE *FHand;\r
391\r
392 FHand = (IMAGE_FILE_HANDLE *)UserHandle;\r
393 ASSERT (FHand->Signature == IMAGE_FILE_HANDLE_SIGNATURE);\r
394\r
395 //\r
396 // Move data from our local copy of the file\r
397 //\r
398 EndPosition = Offset + *ReadSize;\r
399 if (EndPosition > FHand->SourceSize) {\r
400 *ReadSize = (UINT32)(FHand->SourceSize - Offset);\r
cfe9de52 401 }\r
28a00297 402 if (Offset >= FHand->SourceSize) {\r
403 *ReadSize = 0;\r
404 }\r
405\r
406 CopyMem (Buffer, (CHAR8 *)FHand->Source + Offset, *ReadSize);\r
407 return EFI_SUCCESS;\r
408}\r
409\r
162ed594 410/**\r
411 Helper function called as part of the code needed\r
412 to allocate the proper sized buffer for various\r
413 EFI interfaces.\r
414\r
022c6d45 415 @param Status Current status\r
416 @param Buffer Current allocated buffer, or NULL\r
417 @param BufferSize Current buffer size needed\r
162ed594 418\r
022c6d45 419 @retval TRUE if the buffer was reallocated and the caller\r
420 should try the API again.\r
421 @retval FALSE buffer could not be allocated and the caller\r
162ed594 422 should not try the API again.\r
423\r
424**/\r
28a00297 425BOOLEAN\r
426CoreGrowBuffer (\r
427 IN OUT EFI_STATUS *Status,\r
428 IN OUT VOID **Buffer,\r
429 IN UINTN BufferSize\r
430 )\r
28a00297 431{\r
432 BOOLEAN TryAgain;\r
433\r
434 TryAgain = FALSE;\r
435 //\r
436 // If this is an initial request, buffer will be null with a new buffer size\r
437 //\r
438 if (*Buffer == NULL) {\r
439 *Status = EFI_BUFFER_TOO_SMALL;\r
440 }\r
441\r
442 if (BufferSize == 0) {\r
443 return TRUE;\r
444 }\r
445\r
446 //\r
447 // If the status code is "buffer too small", resize the buffer\r
448 //\r
28a00297 449 if (*Status == EFI_BUFFER_TOO_SMALL) {\r
450 if (*Buffer != NULL) {\r
451 CoreFreePool (*Buffer);\r
452 }\r
453\r
9c4ac31c 454 *Buffer = AllocatePool (BufferSize);\r
28a00297 455 if (*Buffer != NULL) {\r
456 TryAgain = TRUE;\r
cfe9de52 457 } else {\r
28a00297 458 *Status = EFI_OUT_OF_RESOURCES;\r
cfe9de52 459 }\r
28a00297 460 }\r
461\r
462 //\r
463 // If there's an error, free the buffer\r
464 //\r
71f68914 465 if ((!TryAgain) && (EFI_ERROR (*Status)) && (*Buffer != NULL)) {\r
28a00297 466 CoreFreePool (*Buffer);\r
467 *Buffer = NULL;\r
468 }\r
469\r
470 return TryAgain;\r
471}\r
472\r
162ed594 473\r