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