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