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