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