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