]> git.proxmox.com Git - mirror_edk2.git/blame - EdkCompatibilityPkg/Foundation/Library/Pei/PeiLib/PeCoffLoader.c
Add in the 1st version of ECP.
[mirror_edk2.git] / EdkCompatibilityPkg / Foundation / Library / Pei / PeiLib / PeCoffLoader.c
CommitLineData
3eb9473e 1/*++\r
2\r
3Copyright (c) 2005 - 2007, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 PeCoffLoader.c\r
15\r
16Abstract:\r
17\r
18 Tiano PE/COFF loader \r
19\r
20Revision History\r
21\r
22--*/\r
23\r
24#include "Tiano.h"\r
25#include "Pei.h"\r
26#include "PeiLib.h"\r
27#include "PeCoffLoaderEx.h"\r
28\r
29#ifdef EFI_NT_EMULATOR\r
30#include "peilib.h"\r
31#include "EfiHobLib.h"\r
32#include EFI_PPI_DEFINITION (NtLoadAsDll)\r
33#endif\r
34\r
35STATIC\r
36EFI_STATUS\r
37PeCoffLoaderGetPeHeader (\r
38 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
39 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr\r
40 );\r
41\r
42STATIC\r
43VOID*\r
44PeCoffLoaderImageAddress (\r
45 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
46 IN UINTN Address\r
47 );\r
48\r
49EFI_STATUS\r
50EFIAPI\r
51PeCoffLoaderGetImageInfo (\r
52 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
53 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
54 );\r
55\r
56EFI_STATUS\r
57EFIAPI\r
58PeCoffLoaderRelocateImage (\r
59 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
60 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
61 );\r
62\r
63EFI_STATUS\r
64EFIAPI\r
65PeCoffLoaderLoadImage (\r
66 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
67 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
68 );\r
69\r
70EFI_STATUS\r
71EFIAPI\r
72PeCoffLoaderUnloadImage (\r
73 IN EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
74 );\r
75\r
76#if defined (EFI_DEBUG_ITP_BREAK) && !defined (_CONSOLE)\r
77VOID\r
78AsmEfiSetBreakSupport (\r
79 IN UINTN LoadAddr\r
80 );\r
81#endif\r
82\r
83EFI_PEI_PE_COFF_LOADER_PROTOCOL mPeCoffLoader = {\r
84 PeCoffLoaderGetImageInfo,\r
85 PeCoffLoaderLoadImage,\r
86 PeCoffLoaderRelocateImage,\r
87 PeCoffLoaderUnloadImage\r
88};\r
89\r
90#ifdef EFI_NT_EMULATOR\r
91EFI_NT_LOAD_AS_DLL_PPI *mPeCoffLoaderWinNtLoadAsDll = NULL;\r
92#endif\r
93\r
94EFI_STATUS\r
95InstallEfiPeiPeCoffLoader (\r
96 IN EFI_PEI_SERVICES **PeiServices,\r
97 IN OUT EFI_PEI_PE_COFF_LOADER_PROTOCOL **This,\r
98 IN EFI_PEI_PPI_DESCRIPTOR *ThisPpi\r
99 )\r
100/*++\r
101\r
102Routine Description:\r
103\r
104 Install PE/COFF loader PPI\r
105 \r
106Arguments:\r
107\r
108 PeiServices - General purpose services available to every PEIM\r
109\r
110 This - Pointer to get Pei PE coff loader protocol as output\r
111 \r
112 ThisPpi - Passed in as EFI_NT_LOAD_AS_DLL_PPI on NT_EMULATOR platform\r
113\r
114Returns:\r
115\r
116 EFI_SUCCESS\r
117\r
118--*/\r
119{\r
120 EFI_STATUS Status;\r
121\r
122 Status = EFI_SUCCESS;\r
123\r
124#ifdef EFI_NT_EMULATOR\r
125 //\r
126 // For use by PEI Core and Modules\r
127 //\r
128 if (NULL != PeiServices) {\r
129 Status = (**PeiServices).LocatePpi (\r
130 PeiServices,\r
131 &gEfiNtLoadAsDllPpiGuid,\r
132 0,\r
133 NULL,\r
134 &mPeCoffLoaderWinNtLoadAsDll\r
135 );\r
136 } else {\r
137 //\r
138 // Now in SecMain or ERM usage, bind appropriately\r
139 //\r
140 PEI_ASSERT (PeiServices, (NULL != ThisPpi));\r
141\r
142 mPeCoffLoaderWinNtLoadAsDll = (EFI_NT_LOAD_AS_DLL_PPI *) ThisPpi;\r
143 PEI_ASSERT (PeiServices, (NULL != mPeCoffLoaderWinNtLoadAsDll));\r
144 }\r
145#endif\r
146\r
147 if (NULL != This) {\r
148 *This = &mPeCoffLoader;\r
149 }\r
150\r
151 return Status;\r
152}\r
153\r
154STATIC\r
155EFI_STATUS\r
156PeCoffLoaderGetPeHeader (\r
157 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
158 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr\r
159 )\r
160/*++\r
161\r
162Routine Description:\r
163\r
164 Retrieves the PE or TE Header from a PE/COFF or TE image\r
165\r
166Arguments:\r
167\r
168 ImageContext - The context of the image being loaded\r
169\r
170 PeHdr - The buffer in which to return the PE32, PE32+, or TE header\r
171\r
172Returns:\r
173\r
174 EFI_SUCCESS if the PE or TE Header is read, \r
175 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.\r
176\r
177--*/\r
178{\r
179 EFI_STATUS Status;\r
180 EFI_IMAGE_DOS_HEADER DosHdr;\r
181 UINTN Size;\r
182 UINT16 Magic;\r
183\r
184 //\r
185 // Read the DOS image header to check for it's existance\r
186 //\r
187 Size = sizeof (EFI_IMAGE_DOS_HEADER);\r
188 Status = ImageContext->ImageRead (\r
189 ImageContext->Handle,\r
190 0,\r
191 &Size,\r
192 &DosHdr\r
193 );\r
194 if (EFI_ERROR (Status)) {\r
195 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
196 return Status;\r
197 }\r
198\r
199 ImageContext->PeCoffHeaderOffset = 0;\r
200 if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
201 //\r
202 // DOS image header is present, so read the PE header after the DOS image \r
203 // header\r
204 //\r
205 ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;\r
206 }\r
207\r
208 //\r
209 // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much \r
210 // data, but that should not hurt anythine. Hdr.Pe32->OptionalHeader.Magic\r
211 // determins if this is a PE32 or PE32+ image. The magic is in the same \r
212 // location in both images.\r
213 //\r
214 Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);\r
215 Status = ImageContext->ImageRead (\r
216 ImageContext->Handle,\r
217 ImageContext->PeCoffHeaderOffset,\r
218 &Size,\r
219 Hdr.Pe32\r
220 );\r
221 if (EFI_ERROR (Status)) {\r
222 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
223 return Status;\r
224 }\r
225\r
226 //\r
227 // Use Signature to figure out if we understand the image format\r
228 //\r
229 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
230 ImageContext->IsTeImage = TRUE;\r
231 ImageContext->Machine = Hdr.Te->Machine;\r
232 ImageContext->ImageType = (UINT16)(Hdr.Te->Subsystem);\r
233 ImageContext->ImageSize = 0;\r
234 ImageContext->SectionAlignment = 4096;\r
235 ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;\r
236\r
237 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
238 ImageContext->IsTeImage = FALSE;\r
239 ImageContext->Machine = Hdr.Pe32->FileHeader.Machine;\r
240 \r
241 //\r
242 // NOTE: We use Machine to identify PE32/PE32+, instead of Magic.\r
243 // It is for backward-compatibility consideration, because\r
244 // some system will generate PE32+ image with PE32 Magic.\r
245 //\r
246 if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {\r
247 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
248 } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {\r
249 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
250 } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) {\r
251 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
252 } else {\r
253 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
254 }\r
255\r
256 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ||\r
257 Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
258 //\r
259 // PE32 and PE32+ have the same offset for these fields.\r
260 // We use PE32 for both PE32 and PE32+ headers here.\r
261 //\r
262 ImageContext->ImageType = Hdr.Pe32->OptionalHeader.Subsystem;\r
263 ImageContext->ImageSize = (UINT64)Hdr.Pe32->OptionalHeader.SizeOfImage;\r
264 ImageContext->SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;\r
265 ImageContext->SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;\r
266\r
267 } else {\r
268 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_MACHINE_TYPE;\r
269 return EFI_UNSUPPORTED; \r
270 }\r
271 } else {\r
272 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_MACHINE_TYPE;\r
273 return EFI_UNSUPPORTED;\r
274 }\r
275\r
276 if (!PeCoffLoaderImageFormatSupported (ImageContext->Machine)) {\r
277 //\r
278 // If the PE/COFF loader does not support the image type return\r
279 // unsupported. This library can suport lots of types of images\r
280 // this does not mean the user of this library can call the entry\r
281 // point of the image. \r
282 //\r
283 return EFI_UNSUPPORTED;\r
284 }\r
285\r
286 return EFI_SUCCESS;\r
287}\r
288\r
289STATIC\r
290EFI_STATUS\r
291PeCoffLoaderCheckImageType (\r
292 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
293 )\r
294/*++\r
295\r
296Routine Description:\r
297\r
298 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported\r
299\r
300Arguments:\r
301\r
302 ImageContext - The context of the image being loaded\r
303\r
304Returns:\r
305\r
306 EFI_SUCCESS if the PE/COFF or TE image is supported\r
307 EFI_UNSUPPORTED of the PE/COFF or TE image is not supported.\r
308\r
309--*/\r
310{\r
311 switch (ImageContext->ImageType) {\r
312\r
313 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:\r
314 ImageContext->ImageCodeMemoryType = EfiLoaderCode;\r
315 ImageContext->ImageDataMemoryType = EfiLoaderData;\r
316 break;\r
317\r
318 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:\r
319 ImageContext->ImageCodeMemoryType = EfiBootServicesCode;\r
320 ImageContext->ImageDataMemoryType = EfiBootServicesData;\r
321 break;\r
322\r
323 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:\r
324 case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:\r
325 ImageContext->ImageCodeMemoryType = EfiRuntimeServicesCode;\r
326 ImageContext->ImageDataMemoryType = EfiRuntimeServicesData;\r
327 break;\r
328\r
329 default:\r
330 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_SUBSYSTEM;\r
331 return EFI_UNSUPPORTED;\r
332 }\r
333\r
334 return EFI_SUCCESS;\r
335}\r
336\r
337EFI_STATUS\r
338EFIAPI\r
339PeCoffLoaderGetImageInfo (\r
340 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
341 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
342 )\r
343/*++\r
344\r
345Routine Description:\r
346\r
347 Retrieves information on a PE/COFF image\r
348\r
349Arguments:\r
350\r
351 This - Calling context\r
352\r
353 ImageContext - The context of the image being loaded\r
354\r
355Returns:\r
356\r
357 EFI_SUCCESS if the information on the PE/COFF image was collected.\r
358 EFI_UNSUPPORTED of the PE/COFF image is not supported.\r
359 Otherwise, the error status from reading the PE/COFF image using the \r
360 ImageContext->ImageRead() function\r
361\r
362 EFI_INVALID_PARAMETER - ImageContext is NULL.\r
363\r
364--*/\r
365{\r
366 EFI_STATUS Status;\r
367 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;\r
368 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
369 EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;\r
370 UINTN Size;\r
371 UINTN Index;\r
372 UINTN DebugDirectoryEntryRva;\r
373 UINTN DebugDirectoryEntryFileOffset;\r
374 UINTN SectionHeaderOffset;\r
375 EFI_IMAGE_SECTION_HEADER SectionHeader;\r
376 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;\r
377 UINT32 NumberOfRvaAndSizes;\r
378 UINT16 Magic;\r
379\r
380 if (NULL == ImageContext) {\r
381 return EFI_INVALID_PARAMETER;\r
382 }\r
383\r
384 //\r
385 // Assume success\r
386 //\r
387 ImageContext->ImageError = EFI_IMAGE_ERROR_SUCCESS;\r
388\r
389 Hdr.Union = &HdrData;\r
390 Status = PeCoffLoaderGetPeHeader (ImageContext, Hdr);\r
391 if (EFI_ERROR (Status)) {\r
392 return Status;\r
393 }\r
394\r
395 //\r
396 // Verify machine type\r
397 //\r
398 Status = PeCoffLoaderCheckImageType (ImageContext);\r
399 if (EFI_ERROR (Status)) {\r
400 return Status;\r
401 }\r
402\r
403 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
404\r
405 //\r
406 // Retrieve the base address of the image\r
407 //\r
408 if (!(ImageContext->IsTeImage)) {\r
409 \r
410 //\r
411 // NOTE: We use Machine to identify PE32/PE32+, instead of Magic.\r
412 // It is for backward-compatibility consideration, because\r
413 // some system will generate PE32+ image with PE32 Magic.\r
414 //\r
415 if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {\r
416 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
417 } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {\r
418 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
419 } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) {\r
420 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
421 } else {\r
422 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
423 }\r
424\r
425 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
426 //\r
427 // Use PE32 offset\r
428 //\r
429 ImageContext->ImageAddress = Hdr.Pe32->OptionalHeader.ImageBase;\r
430 } else {\r
431 //\r
432 // Use PE32+ offset\r
433 //\r
434 ImageContext->ImageAddress = Hdr.Pe32Plus->OptionalHeader.ImageBase;\r
435 }\r
436 } else {\r
437 ImageContext->ImageAddress = (EFI_PHYSICAL_ADDRESS)(Hdr.Te->ImageBase);\r
438 }\r
439\r
440 //\r
441 // Initialize the alternate destination address to 0 indicating that it\r
442 // should not be used.\r
443 //\r
444 ImageContext->DestinationAddress = 0;\r
445\r
446 //\r
447 // Initialize the codeview pointer.\r
448 //\r
449 ImageContext->CodeView = NULL;\r
450 ImageContext->PdbPointer = NULL;\r
451\r
452 //\r
453 // Three cases with regards to relocations:\r
454 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable\r
455 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable\r
456 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but\r
457 // has no base relocs to apply\r
458 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.\r
459 //\r
460 // Look at the file header to determine if relocations have been stripped, and\r
461 // save this info in the image context for later use.\r
462 //\r
463 if ((!(ImageContext->IsTeImage)) && ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {\r
464 ImageContext->RelocationsStripped = TRUE;\r
465 } else {\r
466 ImageContext->RelocationsStripped = FALSE;\r
467 }\r
468\r
469 if (!(ImageContext->IsTeImage)) {\r
470 //\r
471 // Use PE32 to access fields that have same offset in PE32 and PE32+\r
472 //\r
473 ImageContext->ImageSize = (UINT64) Hdr.Pe32->OptionalHeader.SizeOfImage;\r
474 ImageContext->SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;\r
475 ImageContext->SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;\r
476 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
477 // \r
478 // Use PE32 offset\r
479 //\r
480 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
481 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
482 } else {\r
483 // \r
484 // Use PE32+ offset\r
485 //\r
486 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
487 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
488 } \r
489 \r
490 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
491\r
492 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
493\r
494 //\r
495 // Determine the file offset of the debug directory... This means we walk\r
496 // the sections to find which section contains the RVA of the debug\r
497 // directory\r
498 //\r
499 DebugDirectoryEntryFileOffset = 0;\r
500\r
501 SectionHeaderOffset = (UINTN)(\r
502 ImageContext->PeCoffHeaderOffset +\r
503 sizeof (UINT32) + \r
504 sizeof (EFI_IMAGE_FILE_HEADER) + \r
505 Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
506 );\r
507\r
508 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
509 //\r
510 // Read section header from file\r
511 //\r
512 Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
513 Status = ImageContext->ImageRead (\r
514 ImageContext->Handle,\r
515 SectionHeaderOffset,\r
516 &Size,\r
517 &SectionHeader\r
518 );\r
519 if (EFI_ERROR (Status)) {\r
520 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
521 return Status;\r
522 }\r
523\r
524 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
525 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
526\r
527 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;\r
528 break;\r
529 }\r
530\r
531 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
532 }\r
533\r
534 if (DebugDirectoryEntryFileOffset != 0) {\r
535 for (Index = 0; Index < DebugDirectoryEntry->Size; Index++) {\r
536 //\r
537 // Read next debug directory entry\r
538 //\r
539 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
540 Status = ImageContext->ImageRead (\r
541 ImageContext->Handle,\r
542 DebugDirectoryEntryFileOffset,\r
543 &Size,\r
544 &DebugEntry\r
545 );\r
546 if (EFI_ERROR (Status)) {\r
547 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
548 return Status;\r
549 }\r
550\r
551 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
552 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));\r
553 if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {\r
554 ImageContext->ImageSize += DebugEntry.SizeOfData;\r
555 }\r
556\r
557 return EFI_SUCCESS;\r
558 }\r
559 }\r
560 }\r
561 }\r
562 } else {\r
563 //\r
564 // Because Te image only extracts base relocations and debug directory entries from\r
565 // Pe image and in Te image header there is not a field to describe the imagesize,\r
566 // we use the largest VirtualAddress plus Size in each directory entry to describe the imagesize\r
567 //\r
568 ImageContext->ImageSize = (UINT64) (Hdr.Te->DataDirectory[0].VirtualAddress + Hdr.Te->DataDirectory[0].Size);\r
569 ImageContext->SectionAlignment = 4096;\r
570 ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN) Hdr.Te->BaseOfCode - (UINTN) Hdr.Te->StrippedSize;\r
571\r
572 DebugDirectoryEntry = &Hdr.Te->DataDirectory[1];\r
573 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
574 SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));\r
575\r
576 DebugDirectoryEntryFileOffset = 0;\r
577\r
578 for (Index = 0; Index < Hdr.Te->NumberOfSections; Index++) {\r
579 //\r
580 // Read section header from file\r
581 //\r
582 Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
583 Status = ImageContext->ImageRead (\r
584 ImageContext->Handle,\r
585 SectionHeaderOffset,\r
586 &Size,\r
587 &SectionHeader\r
588 );\r
589 if (EFI_ERROR (Status)) {\r
590 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
591 return Status;\r
592 }\r
593\r
594 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
595 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
596 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -\r
597 SectionHeader.VirtualAddress +\r
598 SectionHeader.PointerToRawData +\r
599 sizeof (EFI_TE_IMAGE_HEADER) -\r
600 Hdr.Te->StrippedSize;\r
601 break;\r
602 }\r
603\r
604 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
605 }\r
606\r
607 if (DebugDirectoryEntryFileOffset != 0) {\r
608 for (Index = 0; Index < DebugDirectoryEntry->Size; Index++) {\r
609 //\r
610 // Read next debug directory entry\r
611 //\r
612 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
613 Status = ImageContext->ImageRead (\r
614 ImageContext->Handle,\r
615 DebugDirectoryEntryFileOffset,\r
616 &Size,\r
617 &DebugEntry\r
618 );\r
619 if (EFI_ERROR (Status)) {\r
620 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
621 return Status;\r
622 }\r
623\r
624 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
625 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));\r
626 return EFI_SUCCESS;\r
627 }\r
628 }\r
629 }\r
630 }\r
631\r
632 return EFI_SUCCESS;\r
633}\r
634\r
635STATIC\r
636VOID *\r
637PeCoffLoaderImageAddress (\r
638 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
639 IN UINTN Address\r
640 )\r
641/*++\r
642\r
643Routine Description:\r
644\r
645 Converts an image address to the loaded address\r
646\r
647Arguments:\r
648\r
649 ImageContext - The context of the image being loaded\r
650\r
651 Address - The address to be converted to the loaded address\r
652\r
653Returns:\r
654\r
655 NULL if the address can not be converted, otherwise, the converted address\r
656\r
657--*/\r
658{\r
659 if (Address >= ImageContext->ImageSize) {\r
660 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
661 return NULL;\r
662 }\r
663\r
664 return (CHAR8 *) ((UINTN) ImageContext->ImageAddress + Address);\r
665}\r
666\r
667EFI_STATUS\r
668EFIAPI\r
669PeCoffLoaderRelocateImage (\r
670 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
671 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
672 )\r
673/*++\r
674\r
675Routine Description:\r
676\r
677 Relocates a PE/COFF image in memory\r
678\r
679Arguments:\r
680\r
681 This - Calling context\r
682\r
683 ImageContext - Contains information on the loaded image to relocate\r
684\r
685Returns:\r
686\r
687 EFI_SUCCESS if the PE/COFF image was relocated\r
688 EFI_LOAD_ERROR if the image is not a valid PE/COFF image\r
689 EFI_UNSUPPORTED not support\r
690\r
691--*/\r
692{\r
693 EFI_STATUS Status;\r
694 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
695 EFI_IMAGE_DATA_DIRECTORY *RelocDir;\r
696 UINT64 Adjust;\r
697 EFI_IMAGE_BASE_RELOCATION *RelocBase;\r
698 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;\r
699 UINT16 *Reloc;\r
700 UINT16 *RelocEnd;\r
701 CHAR8 *Fixup;\r
702 CHAR8 *FixupBase;\r
703 UINT16 *F16;\r
704 UINT32 *F32; \r
705 UINT64 *F64;\r
706 CHAR8 *FixupData;\r
707 EFI_PHYSICAL_ADDRESS BaseAddress;\r
708 UINT32 NumberOfRvaAndSizes;\r
709 UINT16 Magic;\r
710#ifdef EFI_NT_EMULATOR\r
711 VOID *DllEntryPoint;\r
712 VOID *ModHandle;\r
713\r
714 ModHandle = NULL;\r
715#endif\r
716\r
717 if (NULL == ImageContext) {\r
718 return EFI_INVALID_PARAMETER;\r
719 }\r
720\r
721 //\r
722 // Assume success\r
723 //\r
724 ImageContext->ImageError = EFI_IMAGE_ERROR_SUCCESS;\r
725\r
726 //\r
727 // If there are no relocation entries, then we are done\r
728 //\r
729 if (ImageContext->RelocationsStripped) {\r
730 return EFI_SUCCESS;\r
731 }\r
732\r
733 //\r
734 // If the destination address is not 0, use that rather than the\r
735 // image address as the relocation target.\r
736 //\r
737 if (ImageContext->DestinationAddress != 0) {\r
738 BaseAddress = ImageContext->DestinationAddress;\r
739 } else {\r
740 BaseAddress = ImageContext->ImageAddress;\r
741 }\r
742\r
743 if (!(ImageContext->IsTeImage)) {\r
744 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);\r
745 \r
746 //\r
747 // NOTE: We use Machine to identify PE32/PE32+, instead of Magic.\r
748 // It is for backward-compatibility consideration, because\r
749 // some system will generate PE32+ image with PE32 Magic.\r
750 //\r
751 if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {\r
752 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
753 } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {\r
754 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
755 } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) {\r
756 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
757 } else {\r
758 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
759 }\r
760\r
761 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
762 //\r
763 // Use PE32 offset\r
764 //\r
765 Adjust = (UINT64)BaseAddress - Hdr.Pe32->OptionalHeader.ImageBase;\r
766 Hdr.Pe32->OptionalHeader.ImageBase = (UINT32)BaseAddress;\r
767 \r
768 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
769 RelocDir = &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
770 } else {\r
771 //\r
772 // Use PE32+ offset\r
773 //\r
774 Adjust = (UINT64) BaseAddress - Hdr.Pe32Plus->OptionalHeader.ImageBase;\r
775 Hdr.Pe32Plus->OptionalHeader.ImageBase = (UINT64)BaseAddress;\r
776\r
777 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
778 RelocDir = &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
779 }\r
780\r
781 //\r
782 // Find the relocation block\r
783 // Per the PE/COFF spec, you can't assume that a given data directory\r
784 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
785 // the optional header to verify a desired directory entry is there.\r
786 //\r
787\r
788 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
789 RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);\r
790 RelocBaseEnd = PeCoffLoaderImageAddress (\r
791 ImageContext,\r
792 RelocDir->VirtualAddress + RelocDir->Size - 1\r
793 );\r
794 } else {\r
795 //\r
796 // Set base and end to bypass processing below.\r
797 //\r
798 RelocBase = RelocBaseEnd = 0;\r
799 }\r
800 } else {\r
801 Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);\r
802 Adjust = (UINT64) (BaseAddress - Hdr.Te->ImageBase);\r
803 Hdr.Te->ImageBase = (UINT64) (BaseAddress);\r
804\r
805 //\r
806 // Find the relocation block\r
807 //\r
808 RelocDir = &Hdr.Te->DataDirectory[0];\r
809 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(\r
810 ImageContext->ImageAddress + \r
811 RelocDir->VirtualAddress +\r
812 sizeof(EFI_TE_IMAGE_HEADER) - \r
813 Hdr.Te->StrippedSize\r
814 );\r
815 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);\r
816 }\r
817 \r
818 //\r
819 // Run the relocation information and apply the fixups\r
820 //\r
821 FixupData = ImageContext->FixupData;\r
822 while (RelocBase < RelocBaseEnd) {\r
823\r
824 Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r
825 RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);\r
826 if (!(ImageContext->IsTeImage)) {\r
827 FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);\r
828 } else {\r
829 FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +\r
830 RelocBase->VirtualAddress +\r
831 sizeof(EFI_TE_IMAGE_HEADER) - \r
832 Hdr.Te->StrippedSize\r
833 );\r
834 }\r
835\r
836 if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||\r
837 (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress + \r
838 (UINTN)ImageContext->ImageSize)) {\r
839 ImageContext->ImageError = EFI_IMAGE_ERROR_FAILED_RELOCATION;\r
840 return EFI_LOAD_ERROR;\r
841 }\r
842\r
843 //\r
844 // Run this relocation record\r
845 //\r
846 while (Reloc < RelocEnd) {\r
847\r
848 Fixup = FixupBase + (*Reloc & 0xFFF);\r
849 switch ((*Reloc) >> 12) {\r
850 case EFI_IMAGE_REL_BASED_ABSOLUTE:\r
851 break;\r
852\r
853 case EFI_IMAGE_REL_BASED_HIGH:\r
854 F16 = (UINT16 *) Fixup;\r
855 *F16 = (UINT16) (*F16 + (UINT16)(((UINT32)Adjust) >> 16));\r
856 if (FixupData != NULL) {\r
857 *(UINT16 *) FixupData = *F16;\r
858 FixupData = FixupData + sizeof (UINT16);\r
859 }\r
860 break;\r
861\r
862 case EFI_IMAGE_REL_BASED_LOW:\r
863 F16 = (UINT16 *) Fixup;\r
864 *F16 = (UINT16) (*F16 + (UINT16) Adjust);\r
865 if (FixupData != NULL) {\r
866 *(UINT16 *) FixupData = *F16;\r
867 FixupData = FixupData + sizeof (UINT16);\r
868 }\r
869 break;\r
870\r
871 case EFI_IMAGE_REL_BASED_HIGHLOW:\r
872 F32 = (UINT32 *) Fixup;\r
873 *F32 = *F32 + (UINT32) Adjust;\r
874 if (FixupData != NULL) {\r
875 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));\r
876 *(UINT32 *) FixupData = *F32;\r
877 FixupData = FixupData + sizeof (UINT32);\r
878 }\r
879 break;\r
880\r
881 case EFI_IMAGE_REL_BASED_DIR64:\r
882 //\r
883 // For X64 and IPF\r
884 //\r
885 F64 = (UINT64 *) Fixup;\r
886 *F64 = *F64 + (UINT64) Adjust;\r
887 if (FixupData != NULL) {\r
888 FixupData = ALIGN_POINTER (FixupData, sizeof(UINT64));\r
889 *(UINT64 *)(FixupData) = *F64;\r
890 FixupData = FixupData + sizeof(UINT64);\r
891 }\r
892 break;\r
893\r
894 case EFI_IMAGE_REL_BASED_HIGHADJ:\r
895 //\r
896 // Return the same EFI_UNSUPPORTED return code as\r
897 // PeCoffLoaderRelocateImageEx() returns if it does not recognize\r
898 // the relocation type.\r
899 //\r
900 ImageContext->ImageError = EFI_IMAGE_ERROR_FAILED_RELOCATION;\r
901 return EFI_UNSUPPORTED;\r
902\r
903 default:\r
904 //\r
905 // The common code does not handle some of the stranger IPF relocations\r
906 // PeCoffLoaderRelocateImageEx () addes support for these complex fixups\r
907 // on IPF and is a No-Op on other archtiectures.\r
908 //\r
909 Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);\r
910 if (EFI_ERROR (Status)) {\r
911 ImageContext->ImageError = EFI_IMAGE_ERROR_FAILED_RELOCATION;\r
912 return Status;\r
913 }\r
914 }\r
915\r
916 //\r
917 // Next relocation record\r
918 //\r
919 Reloc += 1;\r
920 }\r
921\r
922 //\r
923 // Next reloc block\r
924 //\r
925 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;\r
926 }\r
927\r
928#ifdef EFI_NT_EMULATOR\r
929 DllEntryPoint = NULL;\r
930 ImageContext->ModHandle = NULL;\r
931 //\r
932 // Load the DLL if it's not an EBC image.\r
933 //\r
934 if ((ImageContext->PdbPointer != NULL) && \r
935 (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) {\r
936 Status = mPeCoffLoaderWinNtLoadAsDll->Entry (\r
937 ImageContext->PdbPointer,\r
938 &DllEntryPoint,\r
939 &ModHandle\r
940 );\r
941\r
942 if (!EFI_ERROR (Status) && DllEntryPoint != NULL) {\r
943 ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;\r
944 ImageContext->ModHandle = ModHandle;\r
945 }\r
946 }\r
947#endif\r
948\r
949 return EFI_SUCCESS;\r
950}\r
951\r
952EFI_STATUS\r
953EFIAPI\r
954PeCoffLoaderLoadImage (\r
955 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
956 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
957 )\r
958/*++\r
959\r
960Routine Description:\r
961\r
962 Loads a PE/COFF image into memory\r
963\r
964Arguments:\r
965\r
966 This - Calling context\r
967\r
968 ImageContext - Contains information on image to load into memory\r
969\r
970Returns:\r
971\r
972 EFI_SUCCESS if the PE/COFF image was loaded\r
973 EFI_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer\r
974 EFI_LOAD_ERROR if the image is a runtime driver with no relocations\r
975 EFI_INVALID_PARAMETER if the image address is invalid\r
976\r
977--*/\r
978{\r
979 EFI_STATUS Status;\r
980 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
981 EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;\r
982 EFI_IMAGE_SECTION_HEADER *FirstSection;\r
983 EFI_IMAGE_SECTION_HEADER *Section;\r
984 UINTN NumberOfSections;\r
985 UINTN Index;\r
986 CHAR8 *Base;\r
987 CHAR8 *End;\r
988 CHAR8 *MaxEnd;\r
989 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
990 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
991 UINTN Size;\r
992 UINT32 TempDebugEntryRva;\r
993 UINT32 NumberOfRvaAndSizes;\r
994 UINT16 Magic;\r
995\r
996 if (NULL == ImageContext) {\r
997 return EFI_INVALID_PARAMETER;\r
998 }\r
999\r
1000 //\r
1001 // Assume success\r
1002 //\r
1003 ImageContext->ImageError = EFI_IMAGE_ERROR_SUCCESS;\r
1004\r
1005 //\r
1006 // Copy the provided context info into our local version, get what we\r
1007 // can from the original image, and then use that to make sure everything\r
1008 // is legit.\r
1009 //\r
1010 CopyMem (&CheckContext, ImageContext, sizeof (EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT));\r
1011\r
1012 Status = PeCoffLoaderGetImageInfo (This, &CheckContext);\r
1013 if (EFI_ERROR (Status)) {\r
1014 return Status;\r
1015 }\r
1016\r
1017 //\r
1018 // Make sure there is enough allocated space for the image being loaded\r
1019 //\r
1020 if (ImageContext->ImageSize < CheckContext.ImageSize) {\r
1021 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_IMAGE_SIZE;\r
1022 return EFI_BUFFER_TOO_SMALL;\r
1023 }\r
1024 if (ImageContext->ImageAddress == 0) {\r
1025 //\r
1026 // Image cannot be loaded into 0 address.\r
1027 //\r
1028 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
1029 return EFI_INVALID_PARAMETER;\r
1030 }\r
1031 //\r
1032 // If there's no relocations, then make sure it's not a runtime driver,\r
1033 // and that it's being loaded at the linked address.\r
1034 //\r
1035 if (CheckContext.RelocationsStripped) {\r
1036 //\r
1037 // If the image does not contain relocations and it is a runtime driver\r
1038 // then return an error.\r
1039 //\r
1040 if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {\r
1041 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_SUBSYSTEM;\r
1042 return EFI_LOAD_ERROR;\r
1043 }\r
1044 //\r
1045 // If the image does not contain relocations, and the requested load address\r
1046 // is not the linked address, then return an error.\r
1047 //\r
1048 if (CheckContext.ImageAddress != ImageContext->ImageAddress) {\r
1049 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
1050 return EFI_INVALID_PARAMETER;\r
1051 }\r
1052 }\r
1053 //\r
1054 // Make sure the allocated space has the proper section alignment\r
1055 //\r
1056 if (!(ImageContext->IsTeImage)) {\r
1057 if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {\r
1058 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;\r
1059 return EFI_INVALID_PARAMETER;\r
1060 }\r
1061 }\r
1062 //\r
1063 // Read the entire PE/COFF or TE header into memory\r
1064 //\r
1065 if (!(ImageContext->IsTeImage)) {\r
1066 Status = ImageContext->ImageRead (\r
1067 ImageContext->Handle,\r
1068 0,\r
1069 &ImageContext->SizeOfHeaders,\r
1070 (VOID *) (UINTN) ImageContext->ImageAddress\r
1071 );\r
1072\r
1073 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);\r
1074\r
1075 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
1076 (UINTN)ImageContext->ImageAddress +\r
1077 ImageContext->PeCoffHeaderOffset +\r
1078 sizeof(UINT32) + \r
1079 sizeof(EFI_IMAGE_FILE_HEADER) + \r
1080 Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
1081 );\r
1082 NumberOfSections = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections);\r
1083 } else {\r
1084 Status = ImageContext->ImageRead (\r
1085 ImageContext->Handle,\r
1086 0,\r
1087 &ImageContext->SizeOfHeaders,\r
1088 (VOID *)(UINTN)ImageContext->ImageAddress\r
1089 );\r
1090\r
1091 Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);\r
1092\r
1093 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
1094 (UINTN)ImageContext->ImageAddress +\r
1095 sizeof(EFI_TE_IMAGE_HEADER)\r
1096 );\r
1097 NumberOfSections = (UINTN) (Hdr.Te->NumberOfSections);\r
1098\r
1099 }\r
1100\r
1101 if (EFI_ERROR (Status)) {\r
1102 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
1103 return EFI_LOAD_ERROR;\r
1104 }\r
1105\r
1106 //\r
1107 // Load each section of the image\r
1108 //\r
1109 Section = FirstSection;\r
1110 for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {\r
1111\r
1112 //\r
1113 // Compute sections address\r
1114 //\r
1115 Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);\r
1116 End = PeCoffLoaderImageAddress (\r
1117 ImageContext,\r
1118 Section->VirtualAddress + Section->Misc.VirtualSize - 1\r
1119 );\r
1120 if (ImageContext->IsTeImage) {\r
1121 Base = (CHAR8 *)((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);\r
1122 End = (CHAR8 *)((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);\r
1123 }\r
1124\r
1125 if (End > MaxEnd) {\r
1126 MaxEnd = End;\r
1127 }\r
1128 //\r
1129 // If the base start or end address resolved to 0, then fail.\r
1130 //\r
1131 if ((Base == NULL) || (End == NULL)) {\r
1132 ImageContext->ImageError = EFI_IMAGE_ERROR_SECTION_NOT_LOADED;\r
1133 return EFI_LOAD_ERROR;\r
1134 }\r
1135\r
1136 //\r
1137 // Read the section\r
1138 //\r
1139 Size = (UINTN) Section->Misc.VirtualSize;\r
1140 if ((Size == 0) || (Size > Section->SizeOfRawData)) {\r
1141 Size = (UINTN) Section->SizeOfRawData;\r
1142 }\r
1143\r
1144 if (Section->SizeOfRawData) {\r
1145 if (!(ImageContext->IsTeImage)) {\r
1146 Status = ImageContext->ImageRead (\r
1147 ImageContext->Handle,\r
1148 Section->PointerToRawData,\r
1149 &Size,\r
1150 Base\r
1151 );\r
1152 } else {\r
1153 Status = ImageContext->ImageRead (\r
1154 ImageContext->Handle,\r
1155 Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize,\r
1156 &Size,\r
1157 Base\r
1158 );\r
1159 }\r
1160\r
1161 if (EFI_ERROR (Status)) {\r
1162 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
1163 return Status;\r
1164 }\r
1165 }\r
1166\r
1167 //\r
1168 // If raw size is less then virt size, zero fill the remaining\r
1169 //\r
1170\r
1171 if (Size < Section->Misc.VirtualSize) {\r
1172 ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);\r
1173 }\r
1174\r
1175 //\r
1176 // Next Section\r
1177 //\r
1178 Section += 1;\r
1179 }\r
1180\r
1181 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
1182\r
1183 //\r
1184 // Get image's entry point\r
1185 //\r
1186 if (!(ImageContext->IsTeImage)) {\r
1187\r
1188 //\r
1189 // NOTE: We use Machine to identify PE32/PE32+, instead of Magic.\r
1190 // It is for backward-compatibility consideration, because\r
1191 // some system will generate PE32+ image with PE32 Magic.\r
1192 //\r
1193 if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {\r
1194 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
1195 } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {\r
1196 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
1197 } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) {\r
1198 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
1199 } else {\r
1200 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
1201 }\r
1202\r
1203 //\r
1204 // Sizes of AddressOfEntryPoint are different so we need to do this safely\r
1205 //\r
1206 ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (\r
1207 ImageContext,\r
1208 (UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint\r
1209 );\r
1210\r
1211 } else {\r
1212 ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (\r
1213 (UINTN)ImageContext->ImageAddress +\r
1214 (UINTN)Hdr.Te->AddressOfEntryPoint +\r
1215 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -\r
1216 (UINTN)Hdr.Te->StrippedSize\r
1217 );\r
1218 }\r
1219\r
1220 //\r
1221 // Determine the size of the fixup data\r
1222 //\r
1223 // Per the PE/COFF spec, you can't assume that a given data directory\r
1224 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
1225 // the optional header to verify a desired directory entry is there.\r
1226 //\r
1227 if (!(ImageContext->IsTeImage)) {\r
1228 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1229 //\r
1230 // Use PE32 offset\r
1231 //\r
1232 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
1233 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
1234 } else {\r
1235 //\r
1236 // Use PE32+ offset\r
1237 //\r
1238 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
1239 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
1240 }\r
1241 \r
1242 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
1243 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
1244 } else {\r
1245 ImageContext->FixupDataSize = 0;\r
1246 }\r
1247 } else {\r
1248 DirectoryEntry = &Hdr.Te->DataDirectory[0];\r
1249 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
1250 }\r
1251 //\r
1252 // Consumer must allocate a buffer for the relocation fixup log.\r
1253 // Only used for runtime drivers.\r
1254 //\r
1255 ImageContext->FixupData = NULL;\r
1256\r
1257 //\r
1258 // Load the Codeview info if present\r
1259 //\r
1260 if (ImageContext->DebugDirectoryEntryRva != 0) {\r
1261 if (!(ImageContext->IsTeImage)) {\r
1262 DebugEntry = PeCoffLoaderImageAddress (\r
1263 ImageContext,\r
1264 ImageContext->DebugDirectoryEntryRva\r
1265 );\r
1266 } else {\r
1267 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(\r
1268 ImageContext->ImageAddress +\r
1269 ImageContext->DebugDirectoryEntryRva +\r
1270 sizeof(EFI_TE_IMAGE_HEADER) -\r
1271 Hdr.Te->StrippedSize\r
1272 );\r
1273 }\r
1274\r
1275 if (DebugEntry != NULL) {\r
1276 TempDebugEntryRva = DebugEntry->RVA;\r
1277 if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {\r
1278 Section--;\r
1279 if ((UINTN)Section->SizeOfRawData < Section->Misc.VirtualSize) {\r
1280 TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;\r
1281 } else {\r
1282 TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;\r
1283 }\r
1284 }\r
1285\r
1286 if (TempDebugEntryRva != 0) {\r
1287 if (!(ImageContext->IsTeImage)) {\r
1288 ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);\r
1289 } else {\r
1290 ImageContext->CodeView = (VOID *)(\r
1291 (UINTN)ImageContext->ImageAddress +\r
1292 (UINTN)TempDebugEntryRva +\r
1293 (UINTN)sizeof (EFI_TE_IMAGE_HEADER) -\r
1294 (UINTN) Hdr.Te->StrippedSize\r
1295 );\r
1296 }\r
1297\r
1298 if (ImageContext->CodeView == NULL) {\r
1299 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
1300 return EFI_LOAD_ERROR;\r
1301 }\r
1302\r
1303 if (DebugEntry->RVA == 0) {\r
1304 Size = DebugEntry->SizeOfData;\r
1305 if (!(ImageContext->IsTeImage)) {\r
1306 Status = ImageContext->ImageRead (\r
1307 ImageContext->Handle,\r
1308 DebugEntry->FileOffset,\r
1309 &Size,\r
1310 ImageContext->CodeView\r
1311 );\r
1312 } else {\r
1313 Status = ImageContext->ImageRead (\r
1314 ImageContext->Handle,\r
1315 DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize,\r
1316 &Size,\r
1317 ImageContext->CodeView\r
1318 );\r
1319 //\r
1320 // Should we apply fix up to this field according to the size difference between PE and TE?\r
1321 // Because now we maintain TE header fields unfixed, this field will also remain as they are\r
1322 // in original PE image.\r
1323 //\r
1324 }\r
1325\r
1326 if (EFI_ERROR (Status)) {\r
1327 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
1328 return EFI_LOAD_ERROR;\r
1329 }\r
1330\r
1331 DebugEntry->RVA = TempDebugEntryRva;\r
1332 }\r
1333\r
1334 switch (*(UINT32 *) ImageContext->CodeView) {\r
1335 case CODEVIEW_SIGNATURE_NB10:\r
1336 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);\r
1337 break;\r
1338\r
1339 case CODEVIEW_SIGNATURE_RSDS:\r
1340 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
1341 break;\r
1342\r
1343 default:\r
1344 break;\r
1345 }\r
1346 }\r
1347 }\r
1348 }\r
1349\r
1350#if defined (EFI_DEBUG_ITP_BREAK) && !defined (_CONSOLE)\r
1351 AsmEfiSetBreakSupport ((UINTN)(ImageContext->ImageAddress));\r
1352#endif\r
1353\r
1354 return Status;\r
1355}\r
1356\r
1357EFI_STATUS\r
1358EFIAPI\r
1359PeCoffLoaderUnloadImage (\r
1360 IN EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
1361 )\r
1362/*++\r
1363\r
1364Routine Description:\r
1365\r
1366 Unload a PE/COFF image from memory\r
1367\r
1368Arguments:\r
1369\r
1370 ImageContext - Contains information on image to load into memory\r
1371\r
1372Returns:\r
1373\r
1374 EFI_SUCCESS \r
1375\r
1376--*/\r
1377{\r
1378#ifdef EFI_NT_EMULATOR\r
1379 //\r
1380 // Calling Win32 API free library\r
1381 //\r
1382 mPeCoffLoaderWinNtLoadAsDll->FreeLibrary (ImageContext->ModHandle);\r
1383\r
1384#endif\r
1385\r
1386 return EFI_SUCCESS;\r
1387}\r