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