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