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