]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdePkg/Library/BasePeCoffLib/BasePeCoff.c
Validate some fields in PE image to make sure not access violation for later code.
[mirror_edk2.git] / MdePkg / Library / BasePeCoffLib / BasePeCoff.c
... / ...
CommitLineData
1/** @file\r
2 Base PE/COFF loader supports loading any PE32/PE32+ or TE image, but\r
3 only supports relocating IA32, x64, IPF, and EBC images.\r
4\r
5 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
6 Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
7 This program and the accompanying materials\r
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
10 http://opensource.org/licenses/bsd-license.php.\r
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
15**/\r
16\r
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
39 if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
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
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
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
71 UINT32 SectionHeaderOffset;\r
72 UINT32 Index;\r
73 CHAR8 BufferData;\r
74 EFI_IMAGE_SECTION_HEADER SectionHeader;\r
75\r
76 //\r
77 // Read the DOS image header to check for its existence\r
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
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
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
125 //\r
126 // For TeImage, SectionAlignment is undefined to be set to Zero\r
127 // ImageSize can be calculated.\r
128 //\r
129 ImageContext->ImageSize = 0;\r
130 ImageContext->SectionAlignment = 0;\r
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
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
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
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
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
304 // unsupported. This library can support lots of types of images\r
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
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
360 return RETURN_SUCCESS;\r
361}\r
362\r
363\r
364/**\r
365 Retrieves information about a PE/COFF image.\r
366\r
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
376 The ImageRead and Handle fields of ImageContext structure must be valid prior \r
377 to invoking this service.\r
378\r
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
382 @param ImageContext The pointer to the image context structure that describes the PE/COFF\r
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
393 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
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
410 if (ImageContext == NULL) {\r
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
452 // Initialize the debug codeview pointer.\r
453 //\r
454 ImageContext->DebugDirectoryEntryRva = 0;\r
455 ImageContext->CodeView = NULL;\r
456 ImageContext->PdbPointer = NULL;\r
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
467 // save this information in the image context for later use.\r
468 //\r
469 if ((!(ImageContext->IsTeImage)) && ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {\r
470 ImageContext->RelocationsStripped = TRUE;\r
471 } else if ((ImageContext->IsTeImage) && (Hdr.Te->DataDirectory[0].Size == 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) {\r
472 ImageContext->RelocationsStripped = TRUE;\r
473 } else {\r
474 ImageContext->RelocationsStripped = FALSE;\r
475 }\r
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
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
552 DebugDirectoryEntryFileOffset + Index,\r
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
618 // a multiple of Section Alignment). Per the PE/COFF specification, the\r
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
622 // Section Table. \r
623 //\r
624 if ((++Index) == (UINTN)Hdr.Te->NumberOfSections) {\r
625 ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize);\r
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
639 DebugDirectoryEntryFileOffset + Index,\r
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
664 @param Address The relative virtual address to be converted to the loaded address.\r
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
676 // Make sure that Address and ImageSize is correct for the loaded image.\r
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
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
699 If ImageContext is NULL, then ASSERT().\r
700\r
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
705 @param ImageContext The pointer to the image context structure that describes the PE/COFF\r
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
732 UINT16 *Fixup16;\r
733 UINT32 *Fixup32;\r
734 UINT64 *Fixup64;\r
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
751 // Applies additional environment specific actions to relocate fixups \r
752 // to a PE/COFF image if needed\r
753 PeCoffLoaderRelocateImageExtraAction (ImageContext); \r
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
763 } else {\r
764 BaseAddress = ImageContext->ImageAddress;\r
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
777 if (Adjust != 0) {\r
778 Hdr.Pe32->OptionalHeader.ImageBase = (UINT32)BaseAddress;\r
779 }\r
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
788 if (Adjust != 0) {\r
789 Hdr.Pe32Plus->OptionalHeader.ImageBase = (UINT64)BaseAddress;\r
790 }\r
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
803 if ((NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) && (RelocDir->Size > 0)) {\r
804 RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);\r
805 RelocBaseEnd = PeCoffLoaderImageAddress (\r
806 ImageContext,\r
807 RelocDir->VirtualAddress + RelocDir->Size - 1\r
808 );\r
809 if (RelocBase == NULL || RelocBaseEnd == NULL) {\r
810 return RETURN_LOAD_ERROR;\r
811 }\r
812 } else {\r
813 //\r
814 // Set base and end to bypass processing below.\r
815 //\r
816 RelocBase = RelocBaseEnd = NULL;\r
817 }\r
818 } else {\r
819 Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);\r
820 Adjust = (UINT64) (BaseAddress - Hdr.Te->StrippedSize + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->ImageBase);\r
821 if (Adjust != 0) {\r
822 Hdr.Te->ImageBase = (UINT64) (BaseAddress - Hdr.Te->StrippedSize + sizeof (EFI_TE_IMAGE_HEADER));\r
823 }\r
824\r
825 //\r
826 // Find the relocation block\r
827 //\r
828 RelocDir = &Hdr.Te->DataDirectory[0];\r
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
843 }\r
844\r
845 //\r
846 // If Adjust is not zero, then apply fix ups to the image\r
847 //\r
848 if (Adjust != 0) {\r
849 //\r
850 // Run the relocation information and apply the fixups\r
851 //\r
852 FixupData = ImageContext->FixupData;\r
853 while (RelocBase < RelocBaseEnd) {\r
854\r
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
864 return RETURN_LOAD_ERROR;\r
865 }\r
866\r
867 if (!(ImageContext->IsTeImage)) {\r
868 FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);\r
869 if (FixupBase == NULL) {\r
870 return RETURN_LOAD_ERROR;\r
871 }\r
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
939 }\r
940\r
941 //\r
942 // Next relocation record\r
943 //\r
944 Reloc += 1;\r
945 }\r
946\r
947 //\r
948 // Next reloc block\r
949 //\r
950 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;\r
951 }\r
952\r
953 //\r
954 // Adjust the EntryPoint to match the linked-to address\r
955 //\r
956 if (ImageContext->DestinationAddress != 0) {\r
957 ImageContext->EntryPoint -= (UINT64) ImageContext->ImageAddress;\r
958 ImageContext->EntryPoint += (UINT64) ImageContext->DestinationAddress;\r
959 }\r
960 }\r
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
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
975 The EntryPoint, FixupDataSize, CodeView, PdbPointer and HiiResourceData fields of ImageContext are computed.\r
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
980 If ImageContext is NULL, then ASSERT().\r
981\r
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
986 @param ImageContext The pointer to the image context structure that describes the PE/COFF\r
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
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
1026 CHAR16 *String;\r
1027\r
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
1037 // Copy the provided context information into our local version, get what we\r
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
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
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
1158\r
1159 //\r
1160 // If the size of the section is non-zero and the base address or end address resolved to 0, then fail.\r
1161 //\r
1162 if ((Size > 0) && ((Base == NULL) || (End == NULL))) {\r
1163 ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;\r
1164 return RETURN_LOAD_ERROR;\r
1165 }\r
1166\r
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
1176 if (Section->SizeOfRawData > 0) {\r
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
1200 // If raw size is less then virtual size, zero fill the remaining\r
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
1285 // Load the Codeview information if present\r
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
1370 case CODEVIEW_SIGNATURE_MTOC:\r
1371 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);\r
1372 break;\r
1373\r
1374 default:\r
1375 break;\r
1376 }\r
1377 }\r
1378 }\r
1379 }\r
1380\r
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
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
1407 String = &ResourceDirectoryString->String[0];\r
1408\r
1409 if (ResourceDirectoryString->Length == 3 &&\r
1410 String[0] == L'H' &&\r
1411 String[1] == L'I' &&\r
1412 String[2] == L'I') {\r
1413 //\r
1414 // Resource Type "HII" found\r
1415 //\r
1416 if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {\r
1417 //\r
1418 // Move to next level - resource Name\r
1419 //\r
1420 ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);\r
1421 ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);\r
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
1430 }\r
1431\r
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
1440 }\r
1441 }\r
1442 ResourceDirectoryEntry++;\r
1443 }\r
1444 }\r
1445 }\r
1446 }\r
1447 \r
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
1454 runtime. \r
1455 \r
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
1461\r
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
1466 @param ImageBase The base address of a PE/COFF image that has been loaded \r
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
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
1497 UINT16 *Fixup16;\r
1498 UINT32 *Fixup32;\r
1499 UINT64 *Fixup64;\r
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
1561 // Cannot find relocations, cannot continue to relocate the image, ASSERT for this invalid image.\r
1562 //\r
1563 ASSERT (FALSE);\r
1564 return ;\r
1565 }\r
1566 \r
1567 //\r
1568 // ASSERT for the invalid image when RelocBase and RelocBaseEnd are both NULL.\r
1569 //\r
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
1598 Fixup16 = (UINT16 *) Fixup;\r
1599 if (*(UINT16 *) FixupData == *Fixup16) {\r
1600 *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));\r
1601 }\r
1602\r
1603 FixupData = FixupData + sizeof (UINT16);\r
1604 break;\r
1605\r
1606 case EFI_IMAGE_REL_BASED_LOW:\r
1607 Fixup16 = (UINT16 *) Fixup;\r
1608 if (*(UINT16 *) FixupData == *Fixup16) {\r
1609 *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) Adjust & 0xffff));\r
1610 }\r
1611\r
1612 FixupData = FixupData + sizeof (UINT16);\r
1613 break;\r
1614\r
1615 case EFI_IMAGE_REL_BASED_HIGHLOW:\r
1616 Fixup32 = (UINT32 *) Fixup;\r
1617 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));\r
1618 if (*(UINT32 *) FixupData == *Fixup32) {\r
1619 *Fixup32 = *Fixup32 + (UINT32) Adjust;\r
1620 }\r
1621\r
1622 FixupData = FixupData + sizeof (UINT32);\r
1623 break;\r
1624\r
1625 case EFI_IMAGE_REL_BASED_DIR64:\r
1626 Fixup64 = (UINT64 *)Fixup;\r
1627 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));\r
1628 if (*(UINT64 *) FixupData == *Fixup64) {\r
1629 *Fixup64 = *Fixup64 + (UINT64)Adjust;\r
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
1637 // Not valid Relocation type for UEFI image, ASSERT\r
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
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
1677\r
1678 @param FileHandle The pointer to base of the input stream\r
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
1683\r
1684 @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into \r
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
1696 ASSERT (ReadSize != NULL);\r
1697 ASSERT (FileHandle != NULL);\r
1698 ASSERT (Buffer != NULL);\r
1699\r
1700 CopyMem (Buffer, ((UINT8 *)FileHandle) + FileOffset, *ReadSize);\r
1701 return RETURN_SUCCESS;\r
1702}\r
1703\r
1704/**\r
1705 Unloads a loaded PE/COFF image from memory and releases its taken resource.\r
1706 Releases any environment specific resources that were allocated when the image \r
1707 specified by ImageContext was loaded using PeCoffLoaderLoadImage(). \r
1708 \r
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
1712 \r
1713 If ImageContext is NULL, then ASSERT().\r
1714 \r
1715 @param ImageContext The pointer to the image context structure that describes the PE/COFF\r
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
1723 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
1724 )\r
1725{\r
1726 //\r
1727 // Applies additional environment specific actions to unload a \r
1728 // PE/COFF image if needed\r
1729 //\r
1730 PeCoffLoaderUnloadImageExtraAction (ImageContext);\r
1731 return RETURN_SUCCESS;\r
1732}\r