]> git.proxmox.com Git - mirror_edk2.git/blame - MdePkg/Library/BasePeCoffLib/BasePeCoff.c
Remove the useless code.
[mirror_edk2.git] / MdePkg / Library / BasePeCoffLib / BasePeCoff.c
CommitLineData
d071fb19 1/** @file\r
2bfb6009 2 Base PE/COFF loader supports loading any PE32/PE32+ or TE image, but\r
030cd1a2 3 only supports relocating IA32, x64, IPF, and EBC images.\r
d071fb19 4\r
dc204d5a
JY
5 Caution: This file requires additional review when modified.\r
6 This library will have external input - PE/COFF image.\r
7 This external input must be validated carefully to avoid security issue like\r
8 buffer overflow, integer overflow.\r
9\r
10 The basic guideline is that caller need provide ImageContext->ImageRead () with the\r
11 necessary data range check, to make sure when this library reads PE/COFF image, the\r
12 PE image buffer is always in valid range.\r
13 This library will also do some additional check for PE header fields.\r
14\r
15 PeCoffLoaderGetPeHeader() routine will do basic check for PE/COFF header.\r
16 PeCoffLoaderGetImageInfo() routine will do basic check for whole PE/COFF image.\r
17\r
be30ddf7 18 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
acf57dec
HT
19 Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
20 This program and the accompanying materials\r
d071fb19 21 are licensed and made available under the terms and conditions of the BSD License\r
22 which accompanies this distribution. The full text of the license may be found at\r
2fc59a00 23 http://opensource.org/licenses/bsd-license.php.\r
d071fb19 24\r
25 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
26 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
27\r
d071fb19 28**/\r
29\r
d071fb19 30#include "BasePeCoffLibInternals.h"\r
31\r
32/**\r
33 Retrieves the magic value from the PE/COFF header.\r
34\r
35 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.\r
36\r
37 @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32\r
38 @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+\r
39\r
40**/\r
41UINT16\r
42PeCoffLoaderGetPeHeaderMagicValue (\r
43 IN EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr\r
44 )\r
45{\r
46 //\r
47 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value \r
48 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the \r
49 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
50 // then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
51 //\r
4ab0dff3 52 if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
d071fb19 53 return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
54 }\r
55 //\r
56 // Return the magic value from the PC/COFF Optional Header\r
57 //\r
58 return Hdr.Pe32->OptionalHeader.Magic;\r
59}\r
60\r
61\r
62/**\r
28186d45 63 Retrieves the PE or TE Header from a PE/COFF or TE image. \r
dc204d5a
JY
64\r
65 Caution: This function may receive untrusted input.\r
66 PE/COFF image is external input, so this routine will \r
67 also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader, \r
28186d45 68 SizeOfHeader, Section Data Region and Security Data Region be in PE image range. \r
d071fb19 69\r
70 @param ImageContext The context of the image being loaded.\r
71 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.\r
72\r
73 @retval RETURN_SUCCESS The PE or TE Header is read.\r
74 @retval Other The error status from reading the PE/COFF or TE image using the ImageRead function.\r
75\r
76**/\r
77RETURN_STATUS\r
78PeCoffLoaderGetPeHeader (\r
79 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
80 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr\r
81 )\r
82{\r
83 RETURN_STATUS Status;\r
84 EFI_IMAGE_DOS_HEADER DosHdr;\r
85 UINTN Size;\r
3acb1985 86 UINTN ReadSize;\r
d071fb19 87 UINT16 Magic;\r
28186d45
ED
88 UINT32 SectionHeaderOffset;\r
89 UINT32 Index;\r
90 CHAR8 BufferData;\r
00b7e3e3 91 UINTN NumberOfSections;\r
28186d45 92 EFI_IMAGE_SECTION_HEADER SectionHeader;\r
d071fb19 93\r
94 //\r
50cd68df 95 // Read the DOS image header to check for its existence\r
d071fb19 96 //\r
97 Size = sizeof (EFI_IMAGE_DOS_HEADER);\r
3acb1985 98 ReadSize = Size;\r
d071fb19 99 Status = ImageContext->ImageRead (\r
100 ImageContext->Handle,\r
101 0,\r
102 &Size,\r
103 &DosHdr\r
104 );\r
3acb1985 105 if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
d071fb19 106 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
0054ce56
ED
107 if (Size != ReadSize) {\r
108 Status = RETURN_UNSUPPORTED;\r
109 }\r
d071fb19 110 return Status;\r
111 }\r
112\r
113 ImageContext->PeCoffHeaderOffset = 0;\r
114 if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
115 //\r
116 // DOS image header is present, so read the PE header after the DOS image\r
117 // header\r
118 //\r
119 ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;\r
120 }\r
121\r
122 //\r
123 // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much\r
b4500f6e 124 // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic\r
125 // determines if this is a PE32 or PE32+ image. The magic is in the same\r
d071fb19 126 // location in both images.\r
127 //\r
128 Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);\r
3acb1985 129 ReadSize = Size;\r
d071fb19 130 Status = ImageContext->ImageRead (\r
131 ImageContext->Handle,\r
132 ImageContext->PeCoffHeaderOffset,\r
133 &Size,\r
134 Hdr.Pe32\r
135 );\r
3acb1985 136 if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
d071fb19 137 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
0054ce56
ED
138 if (Size != ReadSize) {\r
139 Status = RETURN_UNSUPPORTED;\r
140 }\r
d071fb19 141 return Status;\r
142 }\r
143\r
144 //\r
145 // Use Signature to figure out if we understand the image format\r
146 //\r
147 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
148 ImageContext->IsTeImage = TRUE;\r
149 ImageContext->Machine = Hdr.Te->Machine;\r
150 ImageContext->ImageType = (UINT16)(Hdr.Te->Subsystem);\r
2bfb6009
LG
151 //\r
152 // For TeImage, SectionAlignment is undefined to be set to Zero\r
153 // ImageSize can be calculated.\r
154 //\r
d071fb19 155 ImageContext->ImageSize = 0;\r
2bfb6009 156 ImageContext->SectionAlignment = 0;\r
d071fb19 157 ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;\r
158\r
159 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
160 ImageContext->IsTeImage = FALSE;\r
161 ImageContext->Machine = Hdr.Pe32->FileHeader.Machine;\r
162\r
163 Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);\r
164\r
165 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
28186d45
ED
166 //\r
167 // 1. Check FileHeader.SizeOfOptionalHeader filed.\r
168 //\r
169 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {\r
0054ce56 170 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
28186d45
ED
171 return RETURN_UNSUPPORTED;\r
172 }\r
173\r
28186d45
ED
174 //\r
175 // 2. Check the OptionalHeader.SizeOfHeaders field.\r
176 // This field will be use like the following mode, so just compare the result.\r
177 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.\r
178 //\r
179 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1 < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {\r
180 if (Hdr.Pe32->OptionalHeader.SizeOfHeaders < (UINT32)((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINT8 *) &Hdr)) {\r
0054ce56 181 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
28186d45
ED
182 return RETURN_UNSUPPORTED;\r
183 }\r
184 }\r
185\r
186 //\r
3acb1985 187 // 2.2 Read last byte of Hdr.Pe32.OptionalHeader.SizeOfHeaders from the file.\r
28186d45
ED
188 //\r
189 Size = 1;\r
3acb1985 190 ReadSize = Size;\r
28186d45
ED
191 Status = ImageContext->ImageRead (\r
192 ImageContext->Handle,\r
193 Hdr.Pe32->OptionalHeader.SizeOfHeaders - 1,\r
194 &Size,\r
195 &BufferData\r
196 );\r
3acb1985 197 if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
0054ce56
ED
198 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
199 if (Size != ReadSize) {\r
200 Status = RETURN_UNSUPPORTED;\r
201 }\r
28186d45
ED
202 return Status;\r
203 }\r
204\r
205 //\r
206 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.\r
207 // Read the last byte to make sure the data is in the image region.\r
208 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.\r
209 //\r
210 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {\r
211 if (Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size != 0) {\r
212 //\r
213 // Check the member data to avoid overflow.\r
214 //\r
215 if ((UINT32) (~0) - Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress <\r
216 Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {\r
0054ce56
ED
217 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
218 return RETURN_UNSUPPORTED;\r
28186d45
ED
219 }\r
220\r
221 //\r
3acb1985 222 // Read last byte of section header from file\r
28186d45
ED
223 //\r
224 Size = 1;\r
3acb1985 225 ReadSize = Size;\r
28186d45
ED
226 Status = ImageContext->ImageRead (\r
227 ImageContext->Handle,\r
228 Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress +\r
229 Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - 1,\r
230 &Size,\r
231 &BufferData\r
232 );\r
3acb1985 233 if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
0054ce56
ED
234 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
235 if (Size != ReadSize) {\r
236 Status = RETURN_UNSUPPORTED;\r
237 }\r
28186d45
ED
238 return Status;\r
239 }\r
240 }\r
241 }\r
242\r
d071fb19 243 //\r
244 // Use PE32 offset\r
245 //\r
246 ImageContext->ImageType = Hdr.Pe32->OptionalHeader.Subsystem;\r
247 ImageContext->ImageSize = (UINT64)Hdr.Pe32->OptionalHeader.SizeOfImage;\r
248 ImageContext->SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;\r
249 ImageContext->SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;\r
250\r
251 } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
28186d45
ED
252 //\r
253 // 1. Check FileHeader.SizeOfOptionalHeader filed.\r
254 //\r
255 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {\r
0054ce56 256 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
28186d45
ED
257 return RETURN_UNSUPPORTED;\r
258 }\r
259\r
28186d45
ED
260 //\r
261 // 2. Check the OptionalHeader.SizeOfHeaders field.\r
262 // This field will be use like the following mode, so just compare the result.\r
263 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.\r
264 //\r
265 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1 < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {\r
266 if (Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders < (UINT32)((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINT8 *) &Hdr)) {\r
0054ce56 267 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
28186d45
ED
268 return RETURN_UNSUPPORTED;\r
269 }\r
270 }\r
271\r
272 //\r
3acb1985 273 // 2.2 Read last byte of Hdr.Pe32Plus.OptionalHeader.SizeOfHeaders from the file.\r
28186d45
ED
274 //\r
275 Size = 1;\r
3acb1985 276 ReadSize = Size;\r
28186d45
ED
277 Status = ImageContext->ImageRead (\r
278 ImageContext->Handle,\r
279 Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - 1,\r
280 &Size,\r
281 &BufferData\r
282 );\r
3acb1985 283 if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
0054ce56
ED
284 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
285 if (Size != ReadSize) {\r
286 Status = RETURN_UNSUPPORTED;\r
287 }\r
28186d45
ED
288 return Status;\r
289 }\r
290\r
291 //\r
292 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.\r
293 // Read the last byte to make sure the data is in the image region.\r
294 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.\r
295 //\r
296 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {\r
297 if (Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size != 0) {\r
298 //\r
299 // Check the member data to avoid overflow.\r
300 //\r
301 if ((UINT32) (~0) - Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress <\r
302 Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {\r
0054ce56
ED
303 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
304 return RETURN_UNSUPPORTED;\r
28186d45
ED
305 }\r
306\r
307 //\r
3acb1985 308 // Read last byte of section header from file\r
28186d45
ED
309 //\r
310 Size = 1;\r
3acb1985 311 ReadSize = Size;\r
28186d45
ED
312 Status = ImageContext->ImageRead (\r
313 ImageContext->Handle,\r
314 Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress +\r
315 Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - 1,\r
316 &Size,\r
317 &BufferData\r
318 );\r
3acb1985 319 if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
0054ce56
ED
320 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
321 if (Size != ReadSize) {\r
322 Status = RETURN_UNSUPPORTED;\r
323 }\r
28186d45
ED
324 return Status;\r
325 }\r
326 }\r
327 }\r
328\r
d071fb19 329 //\r
330 // Use PE32+ offset\r
331 //\r
332 ImageContext->ImageType = Hdr.Pe32Plus->OptionalHeader.Subsystem;\r
333 ImageContext->ImageSize = (UINT64) Hdr.Pe32Plus->OptionalHeader.SizeOfImage;\r
334 ImageContext->SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;\r
335 ImageContext->SizeOfHeaders = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;\r
336 } else {\r
337 ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;\r
338 return RETURN_UNSUPPORTED;\r
339 }\r
340 } else {\r
341 ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;\r
342 return RETURN_UNSUPPORTED;\r
343 }\r
344\r
345 if (!PeCoffLoaderImageFormatSupported (ImageContext->Machine)) {\r
346 //\r
347 // If the PE/COFF loader does not support the image type return\r
b4500f6e 348 // unsupported. This library can support lots of types of images\r
d071fb19 349 // this does not mean the user of this library can call the entry\r
350 // point of the image.\r
351 //\r
352 return RETURN_UNSUPPORTED;\r
353 }\r
354\r
28186d45
ED
355 //\r
356 // Check each section field.\r
357 //\r
00b7e3e3
ED
358 if (ImageContext->IsTeImage) {\r
359 SectionHeaderOffset = sizeof(EFI_TE_IMAGE_HEADER);\r
360 NumberOfSections = (UINTN) (Hdr.Te->NumberOfSections);\r
361 } else {\r
362 SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32->FileHeader.SizeOfOptionalHeader;\r
363 NumberOfSections = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections);\r
364 }\r
365\r
366 for (Index = 0; Index < NumberOfSections; Index++) {\r
28186d45
ED
367 //\r
368 // Read section header from file\r
369 //\r
370 Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
3acb1985 371 ReadSize = Size;\r
28186d45
ED
372 Status = ImageContext->ImageRead (\r
373 ImageContext->Handle,\r
374 SectionHeaderOffset,\r
375 &Size,\r
376 &SectionHeader\r
377 );\r
3acb1985 378 if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
0054ce56
ED
379 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
380 if (Size != ReadSize) {\r
381 Status = RETURN_UNSUPPORTED;\r
382 }\r
28186d45
ED
383 return Status;\r
384 }\r
385\r
386 if (SectionHeader.SizeOfRawData > 0) {\r
387 //\r
388 // Check the member data to avoid overflow.\r
389 //\r
390 if ((UINT32) (~0) - SectionHeader.PointerToRawData < SectionHeader.SizeOfRawData) {\r
0054ce56
ED
391 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
392 return RETURN_UNSUPPORTED;\r
28186d45
ED
393 }\r
394\r
395 //\r
396 // Base on the ImageRead function to check the section data field.\r
397 // Read the last byte to make sure the data is in the image region.\r
398 //\r
399 Size = 1;\r
3acb1985 400 ReadSize = Size;\r
28186d45
ED
401 Status = ImageContext->ImageRead (\r
402 ImageContext->Handle,\r
403 SectionHeader.PointerToRawData + SectionHeader.SizeOfRawData - 1,\r
404 &Size,\r
405 &BufferData\r
406 );\r
3acb1985 407 if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
0054ce56
ED
408 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
409 if (Size != ReadSize) {\r
410 Status = RETURN_UNSUPPORTED;\r
411 }\r
28186d45
ED
412 return Status;\r
413 }\r
414 }\r
415\r
416 //\r
417 // Check next section.\r
418 //\r
419 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
420 }\r
421\r
d071fb19 422 return RETURN_SUCCESS;\r
423}\r
424\r
425\r
426/**\r
427 Retrieves information about a PE/COFF image.\r
428\r
3ecdcd11
LG
429 Computes the PeCoffHeaderOffset, IsTeImage, ImageType, ImageAddress, ImageSize, \r
430 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and \r
431 DebugDirectoryEntryRva fields of the ImageContext structure. \r
432 If ImageContext is NULL, then return RETURN_INVALID_PARAMETER. \r
433 If the PE/COFF image accessed through the ImageRead service in the ImageContext \r
434 structure is not a supported PE/COFF image type, then return RETURN_UNSUPPORTED. \r
435 If any errors occur while computing the fields of ImageContext, \r
436 then the error status is returned in the ImageError field of ImageContext. \r
437 If the image is a TE image, then SectionAlignment is set to 0.\r
122e2191 438 The ImageRead and Handle fields of ImageContext structure must be valid prior \r
439 to invoking this service.\r
d071fb19 440\r
dc204d5a
JY
441 Caution: This function may receive untrusted input.\r
442 PE/COFF image is external input, so this routine will \r
443 also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader, \r
28186d45
ED
444 SizeOfHeader, Section Data Region and Security Data Region be in PE image range. \r
445\r
2fc59a00 446 @param ImageContext The pointer to the image context structure that describes the PE/COFF\r
d071fb19 447 image that needs to be examined by this function.\r
448\r
449 @retval RETURN_SUCCESS The information on the PE/COFF image was collected.\r
450 @retval RETURN_INVALID_PARAMETER ImageContext is NULL.\r
451 @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.\r
452\r
453**/\r
454RETURN_STATUS\r
455EFIAPI\r
456PeCoffLoaderGetImageInfo (\r
efb23117 457 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
d071fb19 458 )\r
459{\r
460 RETURN_STATUS Status;\r
461 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;\r
462 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
463 EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;\r
464 UINTN Size;\r
3acb1985 465 UINTN ReadSize;\r
d071fb19 466 UINTN Index;\r
467 UINTN DebugDirectoryEntryRva;\r
468 UINTN DebugDirectoryEntryFileOffset;\r
469 UINTN SectionHeaderOffset;\r
470 EFI_IMAGE_SECTION_HEADER SectionHeader;\r
471 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;\r
472 UINT32 NumberOfRvaAndSizes;\r
473 UINT16 Magic;\r
474\r
2bfb6009 475 if (ImageContext == NULL) {\r
d071fb19 476 return RETURN_INVALID_PARAMETER;\r
477 }\r
478 //\r
479 // Assume success\r
480 //\r
481 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
482\r
483 Hdr.Union = &HdrData;\r
484 Status = PeCoffLoaderGetPeHeader (ImageContext, Hdr);\r
485 if (RETURN_ERROR (Status)) {\r
486 return Status;\r
487 }\r
488\r
489 Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);\r
490\r
491 //\r
492 // Retrieve the base address of the image\r
493 //\r
494 if (!(ImageContext->IsTeImage)) {\r
495 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
496 //\r
497 // Use PE32 offset\r
498 //\r
499 ImageContext->ImageAddress = Hdr.Pe32->OptionalHeader.ImageBase;\r
500 } else {\r
501 //\r
502 // Use PE32+ offset\r
503 //\r
504 ImageContext->ImageAddress = Hdr.Pe32Plus->OptionalHeader.ImageBase;\r
505 }\r
506 } else {\r
507 ImageContext->ImageAddress = (PHYSICAL_ADDRESS)(Hdr.Te->ImageBase + Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));\r
508 }\r
509\r
510 //\r
511 // Initialize the alternate destination address to 0 indicating that it\r
512 // should not be used.\r
513 //\r
514 ImageContext->DestinationAddress = 0;\r
515\r
516 //\r
1a82ed3d 517 // Initialize the debug codeview pointer.\r
d071fb19 518 //\r
1a82ed3d
LG
519 ImageContext->DebugDirectoryEntryRva = 0;\r
520 ImageContext->CodeView = NULL;\r
521 ImageContext->PdbPointer = NULL;\r
d071fb19 522\r
523 //\r
524 // Three cases with regards to relocations:\r
525 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable\r
526 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable\r
527 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but\r
528 // has no base relocs to apply\r
529 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.\r
530 //\r
531 // Look at the file header to determine if relocations have been stripped, and\r
58380e9c 532 // save this information in the image context for later use.\r
d071fb19 533 //\r
534 if ((!(ImageContext->IsTeImage)) && ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {\r
535 ImageContext->RelocationsStripped = TRUE;\r
9626a87e
LG
536 } else if ((ImageContext->IsTeImage) && (Hdr.Te->DataDirectory[0].Size == 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) {\r
537 ImageContext->RelocationsStripped = TRUE;\r
d071fb19 538 } else {\r
539 ImageContext->RelocationsStripped = FALSE;\r
540 }\r
6beb225a
LG
541 \r
542 //\r
543 // TE Image Relocation Data Directory Entry size is non-zero, but the Relocation Data Directory Virtual Address is zero.\r
544 // This case is not a valid TE image. \r
545 //\r
546 if ((ImageContext->IsTeImage) && (Hdr.Te->DataDirectory[0].Size != 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) {\r
0054ce56
ED
547 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
548 return RETURN_UNSUPPORTED;\r
6beb225a 549 }\r
d071fb19 550\r
551 if (!(ImageContext->IsTeImage)) {\r
552 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
553 //\r
554 // Use PE32 offset\r
555 //\r
556 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
557 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
558 } else {\r
559 //\r
560 // Use PE32+ offset\r
561 //\r
562 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
563 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
564 }\r
565\r
566 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
567\r
568 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
569\r
570 //\r
571 // Determine the file offset of the debug directory... This means we walk\r
572 // the sections to find which section contains the RVA of the debug\r
573 // directory\r
574 //\r
575 DebugDirectoryEntryFileOffset = 0;\r
576\r
577 SectionHeaderOffset = (UINTN)(\r
578 ImageContext->PeCoffHeaderOffset +\r
579 sizeof (UINT32) +\r
580 sizeof (EFI_IMAGE_FILE_HEADER) +\r
581 Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
582 );\r
583\r
584 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
585 //\r
586 // Read section header from file\r
587 //\r
588 Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
3acb1985 589 ReadSize = Size;\r
d071fb19 590 Status = ImageContext->ImageRead (\r
591 ImageContext->Handle,\r
592 SectionHeaderOffset,\r
593 &Size,\r
594 &SectionHeader\r
595 );\r
3acb1985 596 if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
d071fb19 597 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
0054ce56
ED
598 if (Size != ReadSize) {\r
599 Status = RETURN_UNSUPPORTED;\r
600 }\r
d071fb19 601 return Status;\r
602 }\r
603\r
604 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
605 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
606\r
607 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;\r
608 break;\r
609 }\r
610\r
611 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
612 }\r
613\r
614 if (DebugDirectoryEntryFileOffset != 0) {\r
615 for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {\r
616 //\r
617 // Read next debug directory entry\r
618 //\r
619 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
3acb1985 620 ReadSize = Size;\r
d071fb19 621 Status = ImageContext->ImageRead (\r
622 ImageContext->Handle,\r
be30ddf7 623 DebugDirectoryEntryFileOffset + Index,\r
d071fb19 624 &Size,\r
625 &DebugEntry\r
626 );\r
3acb1985 627 if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
d071fb19 628 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
0054ce56
ED
629 if (Size != ReadSize) {\r
630 Status = RETURN_UNSUPPORTED;\r
631 }\r
d071fb19 632 return Status;\r
633 }\r
634 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
635 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);\r
636 if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {\r
637 ImageContext->ImageSize += DebugEntry.SizeOfData;\r
638 }\r
639\r
640 return RETURN_SUCCESS;\r
641 }\r
642 }\r
643 }\r
644 }\r
645 } else {\r
646\r
647 DebugDirectoryEntry = &Hdr.Te->DataDirectory[1];\r
648 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
649 SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));\r
650\r
651 DebugDirectoryEntryFileOffset = 0;\r
652\r
653 for (Index = 0; Index < Hdr.Te->NumberOfSections;) {\r
654 //\r
655 // Read section header from file\r
656 //\r
657 Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
3acb1985 658 ReadSize = Size;\r
d071fb19 659 Status = ImageContext->ImageRead (\r
660 ImageContext->Handle,\r
661 SectionHeaderOffset,\r
662 &Size,\r
663 &SectionHeader\r
664 );\r
3acb1985 665 if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
d071fb19 666 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
0054ce56
ED
667 if (Size != ReadSize) {\r
668 Status = RETURN_UNSUPPORTED;\r
669 }\r
d071fb19 670 return Status;\r
671 }\r
672\r
673 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
674 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
675 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -\r
676 SectionHeader.VirtualAddress +\r
677 SectionHeader.PointerToRawData +\r
678 sizeof (EFI_TE_IMAGE_HEADER) -\r
679 Hdr.Te->StrippedSize;\r
680\r
681 //\r
682 // File offset of the debug directory was found, if this is not the last\r
683 // section, then skip to the last section for calculating the image size.\r
684 //\r
685 if (Index < (UINTN) Hdr.Te->NumberOfSections - 1) {\r
686 SectionHeaderOffset += (Hdr.Te->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);\r
687 Index = Hdr.Te->NumberOfSections - 1;\r
688 continue;\r
689 }\r
690 }\r
691\r
692 //\r
693 // In Te image header there is not a field to describe the ImageSize.\r
694 // Actually, the ImageSize equals the RVA plus the VirtualSize of\r
695 // the last section mapped into memory (Must be rounded up to\r
b4500f6e 696 // a multiple of Section Alignment). Per the PE/COFF specification, the\r
d071fb19 697 // section headers in the Section Table must appear in order of the RVA\r
698 // values for the corresponding sections. So the ImageSize can be determined\r
699 // by the RVA and the VirtualSize of the last section header in the\r
2bfb6009 700 // Section Table. \r
d071fb19 701 //\r
702 if ((++Index) == (UINTN)Hdr.Te->NumberOfSections) {\r
2bfb6009 703 ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize);\r
d071fb19 704 }\r
705\r
706 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
707 }\r
708\r
709 if (DebugDirectoryEntryFileOffset != 0) {\r
710 for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {\r
711 //\r
712 // Read next debug directory entry\r
713 //\r
714 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
3acb1985 715 ReadSize = Size;\r
d071fb19 716 Status = ImageContext->ImageRead (\r
717 ImageContext->Handle,\r
be30ddf7 718 DebugDirectoryEntryFileOffset + Index,\r
d071fb19 719 &Size,\r
720 &DebugEntry\r
721 );\r
3acb1985 722 if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
d071fb19 723 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
0054ce56
ED
724 if (Size != ReadSize) {\r
725 Status = RETURN_UNSUPPORTED;\r
726 }\r
d071fb19 727 return Status;\r
728 }\r
729\r
730 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
731 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);\r
732 return RETURN_SUCCESS;\r
733 }\r
734 }\r
735 }\r
736 }\r
737\r
738 return RETURN_SUCCESS;\r
739}\r
740\r
741\r
742/**\r
743 Converts an image address to the loaded address.\r
744\r
745 @param ImageContext The context of the image being loaded.\r
9833a9bb 746 @param Address The relative virtual address to be converted to the loaded address.\r
d071fb19 747\r
748 @return The converted address or NULL if the address can not be converted.\r
749\r
750**/\r
751VOID *\r
752PeCoffLoaderImageAddress (\r
753 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
754 IN UINTN Address\r
755 )\r
756{\r
757 //\r
9833a9bb 758 // Make sure that Address and ImageSize is correct for the loaded image.\r
d071fb19 759 //\r
760 if (Address >= ImageContext->ImageSize) {\r
761 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
762 return NULL;\r
763 }\r
764\r
765 return (CHAR8 *)((UINTN) ImageContext->ImageAddress + Address);\r
766}\r
767\r
768/**\r
769 Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().\r
770\r
771 If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of\r
772 ImageContext as the relocation base address. Otherwise, use the DestinationAddress field\r
773 of ImageContext as the relocation base address. The caller must allocate the relocation\r
774 fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.\r
efb23117 775 \r
776 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress, \r
777 ImageSize, DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, \r
778 DebugDirectoryEntryRva, EntryPoint, FixupDataSize, CodeView, PdbPointer, and FixupData of \r
779 the ImageContext structure must be valid prior to invoking this service.\r
780 \r
d071fb19 781 If ImageContext is NULL, then ASSERT().\r
782\r
8d579453 783 Note that if the platform does not maintain coherency between the instruction cache(s) and the data\r
784 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations\r
785 prior to transferring control to a PE/COFF image that is loaded using this library.\r
786\r
2fc59a00 787 @param ImageContext The pointer to the image context structure that describes the PE/COFF\r
d071fb19 788 image that is being relocated.\r
789\r
790 @retval RETURN_SUCCESS The PE/COFF image was relocated.\r
791 Extended status information is in the ImageError field of ImageContext.\r
792 @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image.\r
793 Extended status information is in the ImageError field of ImageContext.\r
794 @retval RETURN_UNSUPPORTED A relocation record type is not supported.\r
795 Extended status information is in the ImageError field of ImageContext.\r
796\r
797**/\r
798RETURN_STATUS\r
799EFIAPI\r
800PeCoffLoaderRelocateImage (\r
801 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
802 )\r
803{\r
804 RETURN_STATUS Status;\r
805 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
806 EFI_IMAGE_DATA_DIRECTORY *RelocDir;\r
807 UINT64 Adjust;\r
808 EFI_IMAGE_BASE_RELOCATION *RelocBase;\r
809 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;\r
810 UINT16 *Reloc;\r
811 UINT16 *RelocEnd;\r
812 CHAR8 *Fixup;\r
813 CHAR8 *FixupBase;\r
1fa524e9 814 UINT16 *Fixup16;\r
815 UINT32 *Fixup32;\r
816 UINT64 *Fixup64;\r
d071fb19 817 CHAR8 *FixupData;\r
818 PHYSICAL_ADDRESS BaseAddress;\r
819 UINT32 NumberOfRvaAndSizes;\r
820 UINT16 Magic;\r
821\r
822 ASSERT (ImageContext != NULL);\r
823\r
824 //\r
825 // Assume success\r
826 //\r
827 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
828\r
829 //\r
830 // If there are no relocation entries, then we are done\r
831 //\r
832 if (ImageContext->RelocationsStripped) {\r
b4500f6e 833 // Applies additional environment specific actions to relocate fixups \r
834 // to a PE/COFF image if needed\r
01a54966 835 PeCoffLoaderRelocateImageExtraAction (ImageContext); \r
d071fb19 836 return RETURN_SUCCESS;\r
837 }\r
838\r
839 //\r
840 // If the destination address is not 0, use that rather than the\r
841 // image address as the relocation target.\r
842 //\r
843 if (ImageContext->DestinationAddress != 0) {\r
844 BaseAddress = ImageContext->DestinationAddress;\r
d071fb19 845 } else {\r
19bee90c 846 BaseAddress = ImageContext->ImageAddress;\r
d071fb19 847 }\r
848\r
849 if (!(ImageContext->IsTeImage)) {\r
850 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);\r
851\r
852 Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);\r
853\r
854 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
855 //\r
856 // Use PE32 offset\r
857 //\r
858 Adjust = (UINT64)BaseAddress - Hdr.Pe32->OptionalHeader.ImageBase;\r
2816e216 859 if (Adjust != 0) {\r
860 Hdr.Pe32->OptionalHeader.ImageBase = (UINT32)BaseAddress;\r
861 }\r
d071fb19 862\r
863 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
864 RelocDir = &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
865 } else {\r
866 //\r
867 // Use PE32+ offset\r
868 //\r
869 Adjust = (UINT64) BaseAddress - Hdr.Pe32Plus->OptionalHeader.ImageBase;\r
2816e216 870 if (Adjust != 0) {\r
871 Hdr.Pe32Plus->OptionalHeader.ImageBase = (UINT64)BaseAddress;\r
872 }\r
d071fb19 873\r
874 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
875 RelocDir = &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
876 }\r
877\r
878 //\r
879 // Find the relocation block\r
880 // Per the PE/COFF spec, you can't assume that a given data directory\r
881 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
882 // the optional header to verify a desired directory entry is there.\r
883 //\r
884\r
9833a9bb 885 if ((NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) && (RelocDir->Size > 0)) {\r
d071fb19 886 RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);\r
887 RelocBaseEnd = PeCoffLoaderImageAddress (\r
888 ImageContext,\r
889 RelocDir->VirtualAddress + RelocDir->Size - 1\r
890 );\r
9833a9bb
LG
891 if (RelocBase == NULL || RelocBaseEnd == NULL) {\r
892 return RETURN_LOAD_ERROR;\r
893 }\r
d071fb19 894 } else {\r
895 //\r
896 // Set base and end to bypass processing below.\r
897 //\r
9833a9bb 898 RelocBase = RelocBaseEnd = NULL;\r
d071fb19 899 }\r
900 } else {\r
901 Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);\r
19bee90c 902 Adjust = (UINT64) (BaseAddress - Hdr.Te->StrippedSize + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->ImageBase);\r
2816e216 903 if (Adjust != 0) {\r
904 Hdr.Te->ImageBase = (UINT64) (BaseAddress - Hdr.Te->StrippedSize + sizeof (EFI_TE_IMAGE_HEADER));\r
905 }\r
d071fb19 906\r
907 //\r
908 // Find the relocation block\r
909 //\r
910 RelocDir = &Hdr.Te->DataDirectory[0];\r
9833a9bb
LG
911 if (RelocDir->Size > 0) {\r
912 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(\r
913 ImageContext->ImageAddress +\r
914 RelocDir->VirtualAddress +\r
915 sizeof(EFI_TE_IMAGE_HEADER) -\r
916 Hdr.Te->StrippedSize\r
917 );\r
918 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);\r
919 } else {\r
920 //\r
921 // Set base and end to bypass processing below.\r
922 //\r
923 RelocBase = RelocBaseEnd = NULL; \r
924 }\r
d071fb19 925 }\r
926\r
927 //\r
01e1171e 928 // If Adjust is not zero, then apply fix ups to the image\r
d071fb19 929 //\r
01e1171e 930 if (Adjust != 0) {\r
9833a9bb 931 //\r
01e1171e 932 // Run the relocation information and apply the fixups\r
9833a9bb 933 //\r
01e1171e 934 FixupData = ImageContext->FixupData;\r
935 while (RelocBase < RelocBaseEnd) {\r
9833a9bb 936\r
01e1171e 937 Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r
938 RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);\r
939 \r
940 //\r
941 // Make sure RelocEnd is in the Image range.\r
942 //\r
943 if ((CHAR8 *) RelocEnd < (CHAR8 *)((UINTN) ImageContext->ImageAddress) ||\r
944 (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress + (UINTN)ImageContext->ImageSize)) {\r
945 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
9833a9bb
LG
946 return RETURN_LOAD_ERROR;\r
947 }\r
d071fb19 948\r
01e1171e 949 if (!(ImageContext->IsTeImage)) {\r
950 FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);\r
951 if (FixupBase == NULL) {\r
952 return RETURN_LOAD_ERROR;\r
d071fb19 953 }\r
01e1171e 954 } else {\r
955 FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +\r
956 RelocBase->VirtualAddress +\r
957 sizeof(EFI_TE_IMAGE_HEADER) -\r
958 Hdr.Te->StrippedSize\r
959 );\r
960 } \r
961\r
962 //\r
963 // Run this relocation record\r
964 //\r
965 while (Reloc < RelocEnd) {\r
966\r
967 Fixup = FixupBase + (*Reloc & 0xFFF);\r
968 switch ((*Reloc) >> 12) {\r
969 case EFI_IMAGE_REL_BASED_ABSOLUTE:\r
970 break;\r
971\r
972 case EFI_IMAGE_REL_BASED_HIGH:\r
973 Fixup16 = (UINT16 *) Fixup;\r
974 *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));\r
975 if (FixupData != NULL) {\r
976 *(UINT16 *) FixupData = *Fixup16;\r
977 FixupData = FixupData + sizeof (UINT16);\r
978 }\r
979 break;\r
980\r
981 case EFI_IMAGE_REL_BASED_LOW:\r
982 Fixup16 = (UINT16 *) Fixup;\r
983 *Fixup16 = (UINT16) (*Fixup16 + (UINT16) Adjust);\r
984 if (FixupData != NULL) {\r
985 *(UINT16 *) FixupData = *Fixup16;\r
986 FixupData = FixupData + sizeof (UINT16);\r
987 }\r
988 break;\r
989\r
990 case EFI_IMAGE_REL_BASED_HIGHLOW:\r
991 Fixup32 = (UINT32 *) Fixup;\r
992 *Fixup32 = *Fixup32 + (UINT32) Adjust;\r
993 if (FixupData != NULL) {\r
994 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));\r
995 *(UINT32 *)FixupData = *Fixup32;\r
996 FixupData = FixupData + sizeof (UINT32);\r
997 }\r
998 break;\r
999\r
1000 case EFI_IMAGE_REL_BASED_DIR64:\r
1001 Fixup64 = (UINT64 *) Fixup;\r
1002 *Fixup64 = *Fixup64 + (UINT64) Adjust;\r
1003 if (FixupData != NULL) {\r
1004 FixupData = ALIGN_POINTER (FixupData, sizeof(UINT64));\r
1005 *(UINT64 *)(FixupData) = *Fixup64;\r
1006 FixupData = FixupData + sizeof(UINT64);\r
1007 }\r
1008 break;\r
1009\r
1010 default:\r
1011 //\r
1012 // The common code does not handle some of the stranger IPF relocations\r
1013 // PeCoffLoaderRelocateImageEx () adds support for these complex fixups\r
1014 // on IPF and is a No-Op on other architectures.\r
1015 //\r
1016 Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);\r
1017 if (RETURN_ERROR (Status)) {\r
1018 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
1019 return Status;\r
1020 }\r
d071fb19 1021 }\r
d071fb19 1022\r
d071fb19 1023 //\r
01e1171e 1024 // Next relocation record\r
d071fb19 1025 //\r
01e1171e 1026 Reloc += 1;\r
d071fb19 1027 }\r
1028\r
1029 //\r
01e1171e 1030 // Next reloc block\r
d071fb19 1031 //\r
01e1171e 1032 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;\r
d071fb19 1033 }\r
1034\r
1035 //\r
01e1171e 1036 // Adjust the EntryPoint to match the linked-to address\r
d071fb19 1037 //\r
01e1171e 1038 if (ImageContext->DestinationAddress != 0) {\r
1039 ImageContext->EntryPoint -= (UINT64) ImageContext->ImageAddress;\r
1040 ImageContext->EntryPoint += (UINT64) ImageContext->DestinationAddress;\r
1041 }\r
19bee90c 1042 }\r
27b2d249 1043 \r
1044 // Applies additional environment specific actions to relocate fixups \r
1045 // to a PE/COFF image if needed\r
1046 PeCoffLoaderRelocateImageExtraAction (ImageContext);\r
1047 \r
d071fb19 1048 return RETURN_SUCCESS;\r
1049}\r
1050\r
1051/**\r
1052 Loads a PE/COFF image into memory.\r
1053\r
1054 Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer\r
1055 specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate\r
1056 the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.\r
b4500f6e 1057 The EntryPoint, FixupDataSize, CodeView, PdbPointer and HiiResourceData fields of ImageContext are computed.\r
efb23117 1058 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress, ImageSize, \r
1059 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva \r
1060 fields of the ImageContext structure must be valid prior to invoking this service.\r
1061 \r
d071fb19 1062 If ImageContext is NULL, then ASSERT().\r
1063\r
8d579453 1064 Note that if the platform does not maintain coherency between the instruction cache(s) and the data\r
1065 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations\r
1066 prior to transferring control to a PE/COFF image that is loaded using this library.\r
1067\r
2fc59a00 1068 @param ImageContext The pointer to the image context structure that describes the PE/COFF\r
d071fb19 1069 image that is being loaded.\r
1070\r
1071 @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by\r
1072 the ImageAddress and ImageSize fields of ImageContext.\r
1073 Extended status information is in the ImageError field of ImageContext.\r
1074 @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.\r
1075 Extended status information is in the ImageError field of ImageContext.\r
1076 @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.\r
1077 Extended status information is in the ImageError field of ImageContext.\r
1078 @retval RETURN_INVALID_PARAMETER The image address is invalid.\r
1079 Extended status information is in the ImageError field of ImageContext.\r
1080\r
1081**/\r
1082RETURN_STATUS\r
1083EFIAPI\r
1084PeCoffLoaderLoadImage (\r
1085 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
1086 )\r
1087{\r
1088 RETURN_STATUS Status;\r
1089 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
1090 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;\r
1091 EFI_IMAGE_SECTION_HEADER *FirstSection;\r
1092 EFI_IMAGE_SECTION_HEADER *Section;\r
1093 UINTN NumberOfSections;\r
1094 UINTN Index;\r
1095 CHAR8 *Base;\r
1096 CHAR8 *End;\r
d071fb19 1097 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
1098 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
1099 UINTN Size;\r
1100 UINT32 TempDebugEntryRva;\r
1101 UINT32 NumberOfRvaAndSizes;\r
1102 UINT16 Magic;\r
b4500f6e 1103 EFI_IMAGE_RESOURCE_DIRECTORY *ResourceDirectory;\r
1104 EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceDirectoryEntry;\r
1105 EFI_IMAGE_RESOURCE_DIRECTORY_STRING *ResourceDirectoryString;\r
1106 EFI_IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry;\r
bab427db 1107 CHAR16 *String;\r
b4500f6e 1108\r
d071fb19 1109\r
1110 ASSERT (ImageContext != NULL);\r
1111\r
1112 //\r
1113 // Assume success\r
1114 //\r
1115 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
1116\r
1117 //\r
58380e9c 1118 // Copy the provided context information into our local version, get what we\r
d071fb19 1119 // can from the original image, and then use that to make sure everything\r
1120 // is legit.\r
1121 //\r
1122 CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));\r
1123\r
1124 Status = PeCoffLoaderGetImageInfo (&CheckContext);\r
1125 if (RETURN_ERROR (Status)) {\r
1126 return Status;\r
1127 }\r
1128\r
1129 //\r
1130 // Make sure there is enough allocated space for the image being loaded\r
1131 //\r
1132 if (ImageContext->ImageSize < CheckContext.ImageSize) {\r
1133 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;\r
1134 return RETURN_BUFFER_TOO_SMALL;\r
1135 }\r
1136 if (ImageContext->ImageAddress == 0) {\r
1137 //\r
1138 // Image cannot be loaded into 0 address.\r
1139 //\r
1140 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
1141 return RETURN_INVALID_PARAMETER;\r
1142 }\r
1143 //\r
1144 // If there's no relocations, then make sure it's not a runtime driver,\r
1145 // and that it's being loaded at the linked address.\r
1146 //\r
1147 if (CheckContext.RelocationsStripped) {\r
1148 //\r
1149 // If the image does not contain relocations and it is a runtime driver\r
1150 // then return an error.\r
1151 //\r
1152 if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {\r
1153 ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;\r
1154 return RETURN_LOAD_ERROR;\r
1155 }\r
1156 //\r
1157 // If the image does not contain relocations, and the requested load address\r
1158 // is not the linked address, then return an error.\r
1159 //\r
1160 if (CheckContext.ImageAddress != ImageContext->ImageAddress) {\r
1161 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
1162 return RETURN_INVALID_PARAMETER;\r
1163 }\r
1164 }\r
1165 //\r
1166 // Make sure the allocated space has the proper section alignment\r
1167 //\r
1168 if (!(ImageContext->IsTeImage)) {\r
1169 if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {\r
1170 ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;\r
1171 return RETURN_INVALID_PARAMETER;\r
1172 }\r
1173 }\r
1174 //\r
1175 // Read the entire PE/COFF or TE header into memory\r
1176 //\r
1177 if (!(ImageContext->IsTeImage)) {\r
1178 Status = ImageContext->ImageRead (\r
1179 ImageContext->Handle,\r
1180 0,\r
1181 &ImageContext->SizeOfHeaders,\r
1182 (VOID *) (UINTN) ImageContext->ImageAddress\r
1183 );\r
1184\r
1185 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);\r
1186\r
1187 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
1188 (UINTN)ImageContext->ImageAddress +\r
1189 ImageContext->PeCoffHeaderOffset +\r
1190 sizeof(UINT32) +\r
1191 sizeof(EFI_IMAGE_FILE_HEADER) +\r
1192 Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
1193 );\r
1194 NumberOfSections = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections);\r
1195 } else {\r
1196 Status = ImageContext->ImageRead (\r
1197 ImageContext->Handle,\r
1198 0,\r
1199 &ImageContext->SizeOfHeaders,\r
1200 (void *)(UINTN)ImageContext->ImageAddress\r
1201 );\r
1202\r
1203 Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);\r
1204\r
1205 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
1206 (UINTN)ImageContext->ImageAddress +\r
1207 sizeof(EFI_TE_IMAGE_HEADER)\r
1208 );\r
1209 NumberOfSections = (UINTN) (Hdr.Te->NumberOfSections);\r
1210\r
1211 }\r
1212\r
1213 if (RETURN_ERROR (Status)) {\r
1214 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
1215 return RETURN_LOAD_ERROR;\r
1216 }\r
1217\r
1218 //\r
1219 // Load each section of the image\r
1220 //\r
1221 Section = FirstSection;\r
f8ffa6d7 1222 for (Index = 0; Index < NumberOfSections; Index++) {\r
5cfafa07 1223 //\r
1224 // Read the section\r
1225 //\r
1226 Size = (UINTN) Section->Misc.VirtualSize;\r
1227 if ((Size == 0) || (Size > Section->SizeOfRawData)) {\r
1228 Size = (UINTN) Section->SizeOfRawData;\r
1229 }\r
1230\r
d071fb19 1231 //\r
1232 // Compute sections address\r
1233 //\r
1234 Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);\r
1235 End = PeCoffLoaderImageAddress (\r
1236 ImageContext,\r
1237 Section->VirtualAddress + Section->Misc.VirtualSize - 1\r
1238 );\r
d071fb19 1239\r
d071fb19 1240 //\r
5cfafa07 1241 // If the size of the section is non-zero and the base address or end address resolved to 0, then fail.\r
d071fb19 1242 //\r
5cfafa07 1243 if ((Size > 0) && ((Base == NULL) || (End == NULL))) {\r
d071fb19 1244 ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;\r
1245 return RETURN_LOAD_ERROR;\r
1246 }\r
1247\r
9833a9bb
LG
1248 if (ImageContext->IsTeImage) {\r
1249 Base = (CHAR8 *)((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);\r
1250 End = (CHAR8 *)((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);\r
1251 }\r
9833a9bb 1252\r
2bfb6009 1253 if (Section->SizeOfRawData > 0) {\r
d071fb19 1254 if (!(ImageContext->IsTeImage)) {\r
1255 Status = ImageContext->ImageRead (\r
1256 ImageContext->Handle,\r
1257 Section->PointerToRawData,\r
1258 &Size,\r
1259 Base\r
1260 );\r
1261 } else {\r
1262 Status = ImageContext->ImageRead (\r
1263 ImageContext->Handle,\r
1264 Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize,\r
1265 &Size,\r
1266 Base\r
1267 );\r
1268 }\r
1269\r
1270 if (RETURN_ERROR (Status)) {\r
1271 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
1272 return Status;\r
1273 }\r
1274 }\r
1275\r
1276 //\r
b4500f6e 1277 // If raw size is less then virtual size, zero fill the remaining\r
d071fb19 1278 //\r
1279\r
1280 if (Size < Section->Misc.VirtualSize) {\r
1281 ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);\r
1282 }\r
1283\r
1284 //\r
1285 // Next Section\r
1286 //\r
1287 Section += 1;\r
1288 }\r
1289\r
1290 //\r
1291 // Get image's entry point\r
1292 //\r
1293 Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);\r
1294 if (!(ImageContext->IsTeImage)) {\r
1295 //\r
1296 // Sizes of AddressOfEntryPoint are different so we need to do this safely\r
1297 //\r
1298 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1299 //\r
1300 // Use PE32 offset\r
1301 //\r
1302 ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (\r
1303 ImageContext,\r
1304 (UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint\r
1305 );\r
1306 } else {\r
1307 //\r
1308 // Use PE32+ offset\r
1309 //\r
1310 ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (\r
1311 ImageContext,\r
1312 (UINTN)Hdr.Pe32Plus->OptionalHeader.AddressOfEntryPoint\r
1313 );\r
1314 }\r
1315 } else {\r
1316 ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (\r
1317 (UINTN)ImageContext->ImageAddress +\r
1318 (UINTN)Hdr.Te->AddressOfEntryPoint +\r
1319 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -\r
1320 (UINTN)Hdr.Te->StrippedSize\r
1321 );\r
1322 }\r
1323\r
1324 //\r
1325 // Determine the size of the fixup data\r
1326 //\r
1327 // Per the PE/COFF spec, you can't assume that a given data directory\r
1328 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
1329 // the optional header to verify a desired directory entry is there.\r
1330 //\r
1331 if (!(ImageContext->IsTeImage)) {\r
1332 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1333 //\r
1334 // Use PE32 offset\r
1335 //\r
1336 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
1337 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
1338 } else {\r
1339 //\r
1340 // Use PE32+ offset\r
1341 //\r
1342 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
1343 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
1344 }\r
1345\r
1346 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
1347 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
1348 } else {\r
1349 ImageContext->FixupDataSize = 0;\r
1350 }\r
1351 } else {\r
1352 DirectoryEntry = &Hdr.Te->DataDirectory[0];\r
1353 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
1354 }\r
1355 //\r
1356 // Consumer must allocate a buffer for the relocation fixup log.\r
1357 // Only used for runtime drivers.\r
1358 //\r
1359 ImageContext->FixupData = NULL;\r
1360\r
1361 //\r
58380e9c 1362 // Load the Codeview information if present\r
d071fb19 1363 //\r
1364 if (ImageContext->DebugDirectoryEntryRva != 0) {\r
1365 if (!(ImageContext->IsTeImage)) {\r
1366 DebugEntry = PeCoffLoaderImageAddress (\r
1367 ImageContext,\r
1368 ImageContext->DebugDirectoryEntryRva\r
1369 );\r
1370 } else {\r
1371 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(\r
1372 ImageContext->ImageAddress +\r
1373 ImageContext->DebugDirectoryEntryRva +\r
1374 sizeof(EFI_TE_IMAGE_HEADER) -\r
1375 Hdr.Te->StrippedSize\r
1376 );\r
1377 }\r
1378\r
1379 if (DebugEntry != NULL) {\r
1380 TempDebugEntryRva = DebugEntry->RVA;\r
1381 if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {\r
1382 Section--;\r
1383 if ((UINTN)Section->SizeOfRawData < Section->Misc.VirtualSize) {\r
1384 TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;\r
1385 } else {\r
1386 TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;\r
1387 }\r
1388 }\r
1389\r
1390 if (TempDebugEntryRva != 0) {\r
1391 if (!(ImageContext->IsTeImage)) {\r
1392 ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);\r
1393 } else {\r
1394 ImageContext->CodeView = (VOID *)(\r
1395 (UINTN)ImageContext->ImageAddress +\r
1396 (UINTN)TempDebugEntryRva +\r
1397 (UINTN)sizeof (EFI_TE_IMAGE_HEADER) -\r
1398 (UINTN) Hdr.Te->StrippedSize\r
1399 );\r
1400 }\r
1401\r
1402 if (ImageContext->CodeView == NULL) {\r
1403 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
1404 return RETURN_LOAD_ERROR;\r
1405 }\r
1406\r
1407 if (DebugEntry->RVA == 0) {\r
1408 Size = DebugEntry->SizeOfData;\r
1409 if (!(ImageContext->IsTeImage)) {\r
1410 Status = ImageContext->ImageRead (\r
1411 ImageContext->Handle,\r
1412 DebugEntry->FileOffset,\r
1413 &Size,\r
1414 ImageContext->CodeView\r
1415 );\r
1416 } else {\r
1417 Status = ImageContext->ImageRead (\r
1418 ImageContext->Handle,\r
1419 DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize,\r
1420 &Size,\r
1421 ImageContext->CodeView\r
1422 );\r
1423 //\r
1424 // Should we apply fix up to this field according to the size difference between PE and TE?\r
1425 // Because now we maintain TE header fields unfixed, this field will also remain as they are\r
1426 // in original PE image.\r
1427 //\r
1428 }\r
1429\r
1430 if (RETURN_ERROR (Status)) {\r
1431 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
1432 return RETURN_LOAD_ERROR;\r
1433 }\r
1434\r
1435 DebugEntry->RVA = TempDebugEntryRva;\r
1436 }\r
1437\r
1438 switch (*(UINT32 *) ImageContext->CodeView) {\r
1439 case CODEVIEW_SIGNATURE_NB10:\r
1440 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);\r
1441 break;\r
1442\r
1443 case CODEVIEW_SIGNATURE_RSDS:\r
1444 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
1445 break;\r
1446\r
ebd04fc2 1447 case CODEVIEW_SIGNATURE_MTOC:\r
9101c2e8 1448 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);\r
ebd04fc2 1449 break;\r
1450\r
d071fb19 1451 default:\r
1452 break;\r
1453 }\r
1454 }\r
1455 }\r
1456 }\r
1457\r
b4500f6e 1458 //\r
1459 // Get Image's HII resource section\r
1460 //\r
1461 ImageContext->HiiResourceData = 0;\r
1462 if (!(ImageContext->IsTeImage)) {\r
1463 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1464 //\r
1465 // Use PE32 offset\r
1466 //\r
1467 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];\r
1468 } else {\r
1469 //\r
1470 // Use PE32+ offset\r
1471 //\r
1472 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];\r
1473 }\r
1474\r
1475 if (DirectoryEntry->Size != 0) {\r
1476 Base = PeCoffLoaderImageAddress (ImageContext, DirectoryEntry->VirtualAddress);\r
50cd68df 1477 if (Base != NULL) {\r
1478 ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) Base;\r
1479 ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);\r
1480\r
1481 for (Index = 0; Index < ResourceDirectory->NumberOfNamedEntries; Index++) {\r
1482 if (ResourceDirectoryEntry->u1.s.NameIsString) {\r
60893cc3
ED
1483 //\r
1484 // Check the ResourceDirectoryEntry->u1.s.NameOffset before use it.\r
1485 //\r
1486 if (ResourceDirectoryEntry->u1.s.NameOffset >= DirectoryEntry->Size) {\r
1487 continue;\r
1488 }\r
50cd68df 1489 ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (Base + ResourceDirectoryEntry->u1.s.NameOffset);\r
bab427db 1490 String = &ResourceDirectoryString->String[0];\r
50cd68df 1491\r
1492 if (ResourceDirectoryString->Length == 3 &&\r
bab427db 1493 String[0] == L'H' &&\r
1494 String[1] == L'I' &&\r
1495 String[2] == L'I') {\r
b4500f6e 1496 //\r
50cd68df 1497 // Resource Type "HII" found\r
b4500f6e 1498 //\r
b4500f6e 1499 if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {\r
1500 //\r
50cd68df 1501 // Move to next level - resource Name\r
b4500f6e 1502 //\r
1503 ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);\r
1504 ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);\r
50cd68df 1505\r
1506 if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {\r
1507 //\r
1508 // Move to next level - resource Language\r
1509 //\r
1510 ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);\r
1511 ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);\r
1512 }\r
b4500f6e 1513 }\r
b4500f6e 1514\r
50cd68df 1515 //\r
1516 // Now it ought to be resource Data\r
1517 //\r
1518 if (!ResourceDirectoryEntry->u2.s.DataIsDirectory) {\r
1519 ResourceDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *) (Base + ResourceDirectoryEntry->u2.OffsetToData);\r
1520 ImageContext->HiiResourceData = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (ImageContext, ResourceDataEntry->OffsetToData);\r
1521 break;\r
1522 }\r
b4500f6e 1523 }\r
1524 }\r
50cd68df 1525 ResourceDirectoryEntry++;\r
b4500f6e 1526 }\r
b4500f6e 1527 }\r
1528 }\r
1529 }\r
1530 \r
d071fb19 1531 return Status;\r
1532}\r
1533\r
1534\r
1535/**\r
1536 Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI\r
efb23117 1537 runtime. \r
1538 \r
9833a9bb
LG
1539 This function reapplies relocation fixups to the PE/COFF image specified by ImageBase \r
1540 and ImageSize so the image will execute correctly when the PE/COFF image is mapped \r
1541 to the address specified by VirtualImageBase. RelocationData must be identical \r
1542 to the FiuxupData buffer from the PE_COFF_LOADER_IMAGE_CONTEXT structure \r
1543 after this PE/COFF image was relocated with PeCoffLoaderRelocateImage().\r
d071fb19 1544\r
8d579453 1545 Note that if the platform does not maintain coherency between the instruction cache(s) and the data\r
1546 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations\r
1547 prior to transferring control to a PE/COFF image that is loaded using this library.\r
1548\r
2fc59a00 1549 @param ImageBase The base address of a PE/COFF image that has been loaded \r
efb23117 1550 and relocated into system memory.\r
1551 @param VirtImageBase The request virtual address that the PE/COFF image is to\r
1552 be fixed up for.\r
1553 @param ImageSize The size, in bytes, of the PE/COFF image.\r
1554 @param RelocationData A pointer to the relocation data that was collected when the PE/COFF \r
1555 image was relocated using PeCoffLoaderRelocateImage().\r
1556 \r
d071fb19 1557**/\r
1558VOID\r
1559EFIAPI\r
1560PeCoffLoaderRelocateImageForRuntime (\r
1561 IN PHYSICAL_ADDRESS ImageBase,\r
1562 IN PHYSICAL_ADDRESS VirtImageBase,\r
1563 IN UINTN ImageSize,\r
1564 IN VOID *RelocationData\r
1565 )\r
1566{\r
1567 CHAR8 *OldBase;\r
1568 CHAR8 *NewBase;\r
1569 EFI_IMAGE_DOS_HEADER *DosHdr;\r
1570 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
1571 UINT32 NumberOfRvaAndSizes;\r
1572 EFI_IMAGE_DATA_DIRECTORY *DataDirectory;\r
1573 EFI_IMAGE_DATA_DIRECTORY *RelocDir;\r
1574 EFI_IMAGE_BASE_RELOCATION *RelocBase;\r
1575 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;\r
1576 UINT16 *Reloc;\r
1577 UINT16 *RelocEnd;\r
1578 CHAR8 *Fixup;\r
1579 CHAR8 *FixupBase;\r
1fa524e9 1580 UINT16 *Fixup16;\r
1581 UINT32 *Fixup32;\r
1582 UINT64 *Fixup64;\r
d071fb19 1583 CHAR8 *FixupData;\r
1584 UINTN Adjust;\r
1585 RETURN_STATUS Status;\r
1586 UINT16 Magic;\r
1587\r
1588 OldBase = (CHAR8 *)((UINTN)ImageBase);\r
1589 NewBase = (CHAR8 *)((UINTN)VirtImageBase);\r
1590 Adjust = (UINTN) NewBase - (UINTN) OldBase;\r
1591\r
1592 //\r
1593 // Find the image's relocate dir info\r
1594 //\r
1595 DosHdr = (EFI_IMAGE_DOS_HEADER *)OldBase;\r
1596 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
1597 //\r
1598 // Valid DOS header so get address of PE header\r
1599 //\r
1600 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(((CHAR8 *)DosHdr) + DosHdr->e_lfanew);\r
1601 } else {\r
1602 //\r
1603 // No Dos header so assume image starts with PE header.\r
1604 //\r
1605 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)OldBase;\r
1606 }\r
1607\r
1608 if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
1609 //\r
1610 // Not a valid PE image so Exit\r
1611 //\r
1612 return ;\r
1613 }\r
1614\r
1615 Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);\r
1616\r
1617 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1618 //\r
1619 // Use PE32 offset\r
1620 //\r
1621 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
1622 DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[0]);\r
1623 } else {\r
1624 //\r
1625 // Use PE32+ offset\r
1626 //\r
1627 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
1628 DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[0]);\r
1629 }\r
1630\r
1631 //\r
1632 // Find the relocation block\r
1633 //\r
1634 // Per the PE/COFF spec, you can't assume that a given data directory\r
1635 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
1636 // the optional header to verify a desired directory entry is there.\r
1637 //\r
1638 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
1639 RelocDir = DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;\r
1640 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress);\r
1641 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress + RelocDir->Size);\r
1642 } else {\r
1643 //\r
2bfb6009 1644 // Cannot find relocations, cannot continue to relocate the image, ASSERT for this invalid image.\r
d071fb19 1645 //\r
1646 ASSERT (FALSE);\r
1647 return ;\r
1648 }\r
2bfb6009
LG
1649 \r
1650 //\r
1651 // ASSERT for the invalid image when RelocBase and RelocBaseEnd are both NULL.\r
1652 //\r
d071fb19 1653 ASSERT (RelocBase != NULL && RelocBaseEnd != NULL);\r
1654\r
1655 //\r
1656 // Run the whole relocation block. And re-fixup data that has not been\r
1657 // modified. The FixupData is used to see if the image has been modified\r
1658 // since it was relocated. This is so data sections that have been updated\r
1659 // by code will not be fixed up, since that would set them back to\r
1660 // defaults.\r
1661 //\r
1662 FixupData = RelocationData;\r
1663 while (RelocBase < RelocBaseEnd) {\r
60893cc3
ED
1664 //\r
1665 // Add check for RelocBase->SizeOfBlock field.\r
1666 //\r
1667 if ((RelocBase->SizeOfBlock == 0) || (RelocBase->SizeOfBlock > RelocDir->Size)) {\r
1668 //\r
1669 // Data invalid, cannot continue to relocate the image, just return.\r
1670 //\r
1671 return;\r
1672 }\r
d071fb19 1673\r
1674 Reloc = (UINT16 *) ((UINT8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r
1675 RelocEnd = (UINT16 *) ((UINT8 *) RelocBase + RelocBase->SizeOfBlock);\r
1676 FixupBase = (CHAR8 *) ((UINTN)ImageBase) + RelocBase->VirtualAddress;\r
1677\r
1678 //\r
1679 // Run this relocation record\r
1680 //\r
1681 while (Reloc < RelocEnd) {\r
1682\r
1683 Fixup = FixupBase + (*Reloc & 0xFFF);\r
1684 switch ((*Reloc) >> 12) {\r
1685\r
1686 case EFI_IMAGE_REL_BASED_ABSOLUTE:\r
1687 break;\r
1688\r
1689 case EFI_IMAGE_REL_BASED_HIGH:\r
1fa524e9 1690 Fixup16 = (UINT16 *) Fixup;\r
1691 if (*(UINT16 *) FixupData == *Fixup16) {\r
1692 *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));\r
d071fb19 1693 }\r
1694\r
1695 FixupData = FixupData + sizeof (UINT16);\r
1696 break;\r
1697\r
1698 case EFI_IMAGE_REL_BASED_LOW:\r
1fa524e9 1699 Fixup16 = (UINT16 *) Fixup;\r
1700 if (*(UINT16 *) FixupData == *Fixup16) {\r
1701 *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) Adjust & 0xffff));\r
d071fb19 1702 }\r
1703\r
1704 FixupData = FixupData + sizeof (UINT16);\r
1705 break;\r
1706\r
1707 case EFI_IMAGE_REL_BASED_HIGHLOW:\r
1fa524e9 1708 Fixup32 = (UINT32 *) Fixup;\r
d071fb19 1709 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));\r
1fa524e9 1710 if (*(UINT32 *) FixupData == *Fixup32) {\r
1711 *Fixup32 = *Fixup32 + (UINT32) Adjust;\r
d071fb19 1712 }\r
1713\r
1714 FixupData = FixupData + sizeof (UINT32);\r
1715 break;\r
1716\r
1717 case EFI_IMAGE_REL_BASED_DIR64:\r
1fa524e9 1718 Fixup64 = (UINT64 *)Fixup;\r
d071fb19 1719 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));\r
1fa524e9 1720 if (*(UINT64 *) FixupData == *Fixup64) {\r
1721 *Fixup64 = *Fixup64 + (UINT64)Adjust;\r
d071fb19 1722 }\r
1723\r
1724 FixupData = FixupData + sizeof (UINT64);\r
1725 break;\r
1726\r
1727 case EFI_IMAGE_REL_BASED_HIGHADJ:\r
1728 //\r
2bfb6009 1729 // Not valid Relocation type for UEFI image, ASSERT\r
d071fb19 1730 //\r
1731 ASSERT (FALSE);\r
1732 break;\r
1733\r
1734 default:\r
1735 //\r
1736 // Only Itanium requires ConvertPeImage_Ex\r
1737 //\r
1738 Status = PeHotRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);\r
1739 if (RETURN_ERROR (Status)) {\r
1740 return ;\r
1741 }\r
1742 }\r
1743 //\r
1744 // Next relocation record\r
1745 //\r
1746 Reloc += 1;\r
1747 }\r
1748 //\r
1749 // next reloc block\r
1750 //\r
1751 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;\r
1752 }\r
1753}\r
1754\r
1755\r
1756/**\r
657073df 1757 Reads contents of a PE/COFF image from a buffer in system memory.\r
1758 \r
1759 This is the default implementation of a PE_COFF_LOADER_READ_FILE function \r
1760 that assumes FileHandle pointer to the beginning of a PE/COFF image. \r
1761 This function reads contents of the PE/COFF image that starts at the system memory \r
1762 address specified by FileHandle. The read operation copies ReadSize bytes from the \r
1763 PE/COFF image starting at byte offset FileOffset into the buffer specified by Buffer. \r
1764 The size of the buffer actually read is returned in ReadSize.\r
1765 \r
158e788f
ED
1766 The caller must make sure the FileOffset and ReadSize within the file scope.\r
1767\r
657073df 1768 If FileHandle is NULL, then ASSERT().\r
1769 If ReadSize is NULL, then ASSERT().\r
1770 If Buffer is NULL, then ASSERT().\r
d071fb19 1771\r
2fc59a00 1772 @param FileHandle The pointer to base of the input stream\r
657073df 1773 @param FileOffset Offset into the PE/COFF image to begin the read operation.\r
1774 @param ReadSize On input, the size in bytes of the requested read operation. \r
1775 On output, the number of bytes actually read.\r
1776 @param Buffer Output buffer that contains the data read from the PE/COFF image.\r
d071fb19 1777\r
657073df 1778 @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into \r
d071fb19 1779 the buffer.\r
1780**/\r
1781RETURN_STATUS\r
1782EFIAPI\r
1783PeCoffLoaderImageReadFromMemory (\r
1784 IN VOID *FileHandle,\r
1785 IN UINTN FileOffset,\r
1786 IN OUT UINTN *ReadSize,\r
1787 OUT VOID *Buffer\r
1788 )\r
1789{\r
657073df 1790 ASSERT (ReadSize != NULL);\r
1791 ASSERT (FileHandle != NULL);\r
1792 ASSERT (Buffer != NULL);\r
1793\r
d071fb19 1794 CopyMem (Buffer, ((UINT8 *)FileHandle) + FileOffset, *ReadSize);\r
1795 return RETURN_SUCCESS;\r
1796}\r
1797\r
3d7b0992
LG
1798/**\r
1799 Unloads a loaded PE/COFF image from memory and releases its taken resource.\r
efb23117 1800 Releases any environment specific resources that were allocated when the image \r
1801 specified by ImageContext was loaded using PeCoffLoaderLoadImage(). \r
1802 \r
3d7b0992
LG
1803 For NT32 emulator, the PE/COFF image loaded by system needs to release.\r
1804 For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded, \r
1805 this function can simply return RETURN_SUCCESS.\r
efb23117 1806 \r
1807 If ImageContext is NULL, then ASSERT().\r
1808 \r
2fc59a00 1809 @param ImageContext The pointer to the image context structure that describes the PE/COFF\r
3d7b0992
LG
1810 image to be unloaded.\r
1811\r
1812 @retval RETURN_SUCCESS The PE/COFF image was unloaded successfully.\r
1813**/\r
1814RETURN_STATUS\r
1815EFIAPI\r
1816PeCoffLoaderUnloadImage (\r
0465a73e 1817 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
3d7b0992
LG
1818 )\r
1819{\r
b4500f6e 1820 //\r
27b2d249 1821 // Applies additional environment specific actions to unload a \r
1822 // PE/COFF image if needed\r
b4500f6e 1823 //\r
27b2d249 1824 PeCoffLoaderUnloadImageExtraAction (ImageContext);\r
3d7b0992
LG
1825 return RETURN_SUCCESS;\r
1826}\r