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