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