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