]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Image/ImageFile.c
Add assertion to ensure pointer dereference has been checked against NULL pointer.
[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 ASSERT (FileInfo != NULL);
294 ImageFileHandle->Source = AllocatePool ((UINTN)FileInfo->FileSize);
295 if (ImageFileHandle->Source != NULL) {
296 //
297 // Read the file into the buffer we allocated
298 //
299 ImageFileHandle->SourceSize = (UINTN) FileInfo->FileSize;
300 ImageFileHandle->FreeBuffer = TRUE;
301 Status = FileHandle->Read (FileHandle, &ImageFileHandle->SourceSize, ImageFileHandle->Source);
302
303 //
304 // Close the file since we are done
305 //
306 FileHandle->Close (FileHandle);
307 CoreFreePool (FileInfo);
308 } else {
309 Status = EFI_OUT_OF_RESOURCES;
310 }
311
312 goto Done;
313 }
314 }
315 }
316 }
317
318
319 //
320 // Try LoadFile style
321 //
322
323 TempFilePath = *FilePath;
324 Status = CoreDevicePathToInterface (
325 &gEfiLoadFileProtocolGuid,
326 &TempFilePath,
327 (VOID*) &LoadFile,
328 DeviceHandle
329 );
330 if (!EFI_ERROR (Status)) {
331 //
332 // Call LoadFile with the correct buffer size
333 //
334 ASSERT (ImageFileHandle->SourceSize == 0);
335 ASSERT (ImageFileHandle->Source == NULL);
336 Status = LoadFile->LoadFile (
337 LoadFile,
338 TempFilePath,
339 BootPolicy,
340 &ImageFileHandle->SourceSize,
341 ImageFileHandle->Source
342 );
343 if (Status == EFI_BUFFER_TOO_SMALL) {
344 ImageFileHandle->Source = AllocatePool (ImageFileHandle->SourceSize);
345 if (ImageFileHandle->Source == NULL) {
346 Status = EFI_OUT_OF_RESOURCES;
347 } else {
348 Status = LoadFile->LoadFile (
349 LoadFile,
350 TempFilePath,
351 BootPolicy,
352 &ImageFileHandle->SourceSize,
353 ImageFileHandle->Source
354 );
355 }
356 }
357
358 if (!EFI_ERROR (Status)) {
359 ImageFileHandle->FreeBuffer = TRUE;
360 goto Done;
361 }
362 }
363
364 //
365 // Nothing else to try
366 //
367 DEBUG ((DEBUG_LOAD|DEBUG_WARN, "CoreOpenImageFile: Device did not support a known load protocol\n"));
368 Status = EFI_NOT_FOUND;
369
370 Done:
371 //
372 // If the file was not accessed, clean up
373 //
374 if (EFI_ERROR (Status)) {
375 if (ImageFileHandle->FreeBuffer) {
376 //
377 // Free the source buffer if we allocated it
378 //
379 CoreFreePool (ImageFileHandle->Source);
380 }
381 }
382
383 return Status;
384 }
385
386
387
388 /**
389 Read image file (specified by UserHandle) into user specified buffer with specified offset
390 and length.
391
392 @param UserHandle Image file handle
393 @param Offset Offset to the source file
394 @param ReadSize For input, pointer of size to read; For output,
395 pointer of size actually read.
396 @param Buffer Buffer to write into
397
398 @retval EFI_SUCCESS Successfully read the specified part of file
399 into buffer.
400
401 **/
402 EFI_STATUS
403 EFIAPI
404 CoreReadImageFile (
405 IN VOID *UserHandle,
406 IN UINTN Offset,
407 IN OUT UINTN *ReadSize,
408 OUT VOID *Buffer
409 )
410 {
411 UINTN EndPosition;
412 IMAGE_FILE_HANDLE *FHand;
413
414 FHand = (IMAGE_FILE_HANDLE *)UserHandle;
415 ASSERT (FHand->Signature == IMAGE_FILE_HANDLE_SIGNATURE);
416
417 //
418 // Move data from our local copy of the file
419 //
420 EndPosition = Offset + *ReadSize;
421 if (EndPosition > FHand->SourceSize) {
422 *ReadSize = (UINT32)(FHand->SourceSize - Offset);
423 }
424 if (Offset >= FHand->SourceSize) {
425 *ReadSize = 0;
426 }
427
428 CopyMem (Buffer, (CHAR8 *)FHand->Source + Offset, *ReadSize);
429 return EFI_SUCCESS;
430 }
431