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