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