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