2 Handle services to image file.
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
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.
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.
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.
31 CoreDevicePathToInterface (
32 IN EFI_GUID
*Protocol
,
33 IN EFI_DEVICE_PATH_PROTOCOL
**FilePath
,
35 OUT EFI_HANDLE
*Handle
40 Status
= CoreLocateDevicePath (Protocol
, FilePath
, Handle
);
41 if (!EFI_ERROR (Status
)) {
42 Status
= CoreHandleProtocol (*Handle
, Protocol
, Interface
);
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.
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
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.
64 @retval EFI_SUCCESS Image file successfully opened.
65 @retval EFI_LOAD_ERROR If the caller passed a copy of the file, and
67 @retval EFI_INVALID_PARAMETER File path is not valid.
68 @retval EFI_NOT_FOUND File not found.
73 IN BOOLEAN BootPolicy
,
74 IN VOID
*SourceBuffer OPTIONAL
,
76 IN OUT EFI_DEVICE_PATH_PROTOCOL
**FilePath
,
77 OUT EFI_HANDLE
*DeviceHandle
,
78 IN IMAGE_FILE_HANDLE
*ImageFileHandle
,
79 OUT UINT32
*AuthenticationStatus
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
;
95 EFI_FV_FILE_ATTRIBUTES Attrib
;
96 EFI_FILE_INFO
*FileInfo
;
99 FILEPATH_DEVICE_PATH
*OriginalFilePathNode
;
101 OriginalFilePathNode
= NULL
;
102 *AuthenticationStatus
= 0;
103 ZeroMem (ImageFileHandle
, sizeof (IMAGE_FILE_HANDLE
));
104 ImageFileHandle
->Signature
= IMAGE_FILE_HANDLE_SIGNATURE
;
107 // If the caller passed a copy of the file, then just use it
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
;
117 Status
= EFI_LOAD_ERROR
;
123 // Make sure FilePath is valid
125 if (*FilePath
== NULL
) {
126 return EFI_INVALID_PARAMETER
;
130 // Check to see if it's in a Firmware Volume
132 FwVolFilePathNode
= (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) *FilePath
;
133 Status
= CoreDevicePathToInterface (
134 &gEfiFirmwareVolume2ProtocolGuid
,
135 (EFI_DEVICE_PATH_PROTOCOL
**)&FwVolFilePathNode
,
139 if (!EFI_ERROR (Status
)) {
141 // For FwVol File system there is only a single file name that is a GUID.
143 NameGuid
= EfiGetNameGuidFromFwVolDevicePathNode (FwVolFilePathNode
);
144 if (NameGuid
!= NULL
) {
146 SectionType
= EFI_SECTION_PE32
;
148 Status
= FwVol
->ReadSection (
153 (VOID
**)&Pe32Buffer
,
157 if (EFI_ERROR (Status
)) {
159 // Try a raw file, since a PE32 SECTION does not exist
161 if (Pe32Buffer
!= NULL
) {
162 CoreFreePool (Pe32Buffer
);
163 *AuthenticationStatus
= 0;
166 Status
= FwVol
->ReadFile (
169 (VOID
**)&Pe32Buffer
,
177 if (!EFI_ERROR (Status
)) {
179 // One of the reads passed so we are done
181 ImageFileHandle
->Source
= Pe32Buffer
;
182 ImageFileHandle
->SourceSize
= Pe32BufferSize
;
183 ImageFileHandle
->FreeBuffer
= TRUE
;
190 // Attempt to access the file via a file system interface
192 FilePathNode
= (FILEPATH_DEVICE_PATH
*) *FilePath
;
193 Status
= CoreDevicePathToInterface (
194 &gEfiSimpleFileSystemProtocolGuid
,
195 (EFI_DEVICE_PATH_PROTOCOL
**)&FilePathNode
,
199 if (!EFI_ERROR (Status
)) {
201 // Open the Volume to get the File System handle
203 Status
= Volume
->OpenVolume (Volume
, &FileHandle
);
204 if (!EFI_ERROR (Status
)) {
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.
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
;
215 OriginalFilePathNode
= FilePathNode
;
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
221 while (!IsDevicePathEnd (&FilePathNode
->Header
)) {
222 if (DevicePathType (&FilePathNode
->Header
) != MEDIA_DEVICE_PATH
||
223 DevicePathSubType (&FilePathNode
->Header
) != MEDIA_FILEPATH_DP
) {
224 Status
= EFI_UNSUPPORTED
;
227 if (EFI_ERROR (Status
)) {
229 // Exit loop on Error
234 LastHandle
= FileHandle
;
237 Status
= LastHandle
->Open (
240 FilePathNode
->PathName
,
246 // Close the previous node
248 LastHandle
->Close (LastHandle
);
250 FilePathNode
= (FILEPATH_DEVICE_PATH
*) NextDevicePathNode (&FilePathNode
->Header
);
253 // Free the allocated memory pool
255 CoreFreePool(OriginalFilePathNode
);
258 if (!EFI_ERROR (Status
)) {
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.
264 FileInfoSize
= sizeof (EFI_FILE_INFO
);
265 while (CoreGrowBuffer (&Status
, (VOID
**)&FileInfo
, FileInfoSize
)) {
267 // Automatically allocate buffer of the correct size and make the call
269 Status
= FileHandle
->GetInfo (
276 if (!EFI_ERROR (Status
)) {
278 // Allocate space for the file
280 ImageFileHandle
->Source
= AllocatePool ((UINTN
)FileInfo
->FileSize
);
281 if (ImageFileHandle
->Source
!= NULL
) {
283 // Read the file into the buffer we allocated
285 ImageFileHandle
->SourceSize
= (UINTN
) FileInfo
->FileSize
;
286 ImageFileHandle
->FreeBuffer
= TRUE
;
287 Status
= FileHandle
->Read (FileHandle
, &ImageFileHandle
->SourceSize
, ImageFileHandle
->Source
);
290 // Close the file since we are done
292 FileHandle
->Close (FileHandle
);
294 Status
= EFI_OUT_OF_RESOURCES
;
305 // Try LoadFile style
308 TempFilePath
= *FilePath
;
309 Status
= CoreDevicePathToInterface (
310 &gEfiLoadFileProtocolGuid
,
315 if (!EFI_ERROR (Status
)) {
317 // Call LoadFile with the correct buffer size
319 while (CoreGrowBuffer (&Status
, (VOID
**)&ImageFileHandle
->Source
, ImageFileHandle
->SourceSize
)) {
320 Status
= LoadFile
->LoadFile (
324 &ImageFileHandle
->SourceSize
,
325 ImageFileHandle
->Source
328 // If success or other error happens, stop loop
330 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
335 if (!EFI_ERROR (Status
) || Status
== EFI_ALREADY_STARTED
) {
336 ImageFileHandle
->FreeBuffer
= TRUE
;
342 // Nothing else to try
344 DEBUG ((DEBUG_LOAD
|DEBUG_WARN
, "CoreOpenImageFile: Device did not support a known load protocol\n"));
345 Status
= EFI_NOT_FOUND
;
350 // If the file was not accessed, clean up
352 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
353 if (ImageFileHandle
->FreeBuffer
) {
355 // Free the source buffer if we allocated it
357 CoreFreePool (ImageFileHandle
->Source
);
367 Read image file (specified by UserHandle) into user specified buffer with specified offset
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
376 @retval EFI_SUCCESS Successfully read the specified part of file
385 IN OUT UINTN
*ReadSize
,
390 IMAGE_FILE_HANDLE
*FHand
;
392 FHand
= (IMAGE_FILE_HANDLE
*)UserHandle
;
393 ASSERT (FHand
->Signature
== IMAGE_FILE_HANDLE_SIGNATURE
);
396 // Move data from our local copy of the file
398 EndPosition
= Offset
+ *ReadSize
;
399 if (EndPosition
> FHand
->SourceSize
) {
400 *ReadSize
= (UINT32
)(FHand
->SourceSize
- Offset
);
402 if (Offset
>= FHand
->SourceSize
) {
406 CopyMem (Buffer
, (CHAR8
*)FHand
->Source
+ Offset
, *ReadSize
);
411 Helper function called as part of the code needed
412 to allocate the proper sized buffer for various
415 @param Status Current status
416 @param Buffer Current allocated buffer, or NULL
417 @param BufferSize Current buffer size needed
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.
427 IN OUT EFI_STATUS
*Status
,
428 IN OUT VOID
**Buffer
,
436 // If this is an initial request, buffer will be null with a new buffer size
438 if (*Buffer
== NULL
) {
439 *Status
= EFI_BUFFER_TOO_SMALL
;
442 if (BufferSize
== 0) {
447 // If the status code is "buffer too small", resize the buffer
449 if (*Status
== EFI_BUFFER_TOO_SMALL
) {
450 if (*Buffer
!= NULL
) {
451 CoreFreePool (*Buffer
);
454 *Buffer
= AllocatePool (BufferSize
);
455 if (*Buffer
!= NULL
) {
458 *Status
= EFI_OUT_OF_RESOURCES
;
463 // If there's an error, free the buffer
465 if ((!TryAgain
) && (EFI_ERROR (*Status
)) && (*Buffer
!= NULL
)) {
466 CoreFreePool (*Buffer
);