]> git.proxmox.com Git - mirror_edk2.git/blame - EdkCompatibilityPkg/Foundation/Library/Pei/PeiLib/PeCoffLoader.c
EHCI Controllers with a CapLen of 0 are ignored.
[mirror_edk2.git] / EdkCompatibilityPkg / Foundation / Library / Pei / PeiLib / PeCoffLoader.c
CommitLineData
3eb9473e 1/*++\r
2\r
4ac4deb7 3Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR>\r
4ea9375a 4This program and the accompanying materials \r
3eb9473e 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
97f201c4 73 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
3eb9473e 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
c7f33ca4 437 ImageContext->ImageAddress = (EFI_PHYSICAL_ADDRESS)(Hdr.Te->ImageBase + Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));\r
3eb9473e 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
4ac4deb7 788 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC && RelocDir->Size > 0) {\r
3eb9473e 789 RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);\r
790 RelocBaseEnd = PeCoffLoaderImageAddress (\r
791 ImageContext,\r
792 RelocDir->VirtualAddress + RelocDir->Size - 1\r
793 );\r
4ac4deb7
LG
794 if ((RelocBase == NULL) || (RelocBaseEnd == NULL)) {\r
795 //\r
796 // If the base start or end address resolved to 0, then fail.\r
797 //\r
798 return EFI_LOAD_ERROR;\r
799 }\r
3eb9473e 800 } else {\r
801 //\r
802 // Set base and end to bypass processing below.\r
803 //\r
804 RelocBase = RelocBaseEnd = 0;\r
805 }\r
806 } else {\r
807 Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);\r
c7f33ca4 808 Adjust = (UINT64) (BaseAddress - Hdr.Te->StrippedSize + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->ImageBase);\r
809 Hdr.Te->ImageBase = (UINT64) (BaseAddress - Hdr.Te->StrippedSize + sizeof (EFI_TE_IMAGE_HEADER));\r
3eb9473e 810\r
811 //\r
812 // Find the relocation block\r
813 //\r
814 RelocDir = &Hdr.Te->DataDirectory[0];\r
4ac4deb7
LG
815 if (RelocDir->Size > 0) {\r
816 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(\r
817 ImageContext->ImageAddress +\r
818 RelocDir->VirtualAddress +\r
819 sizeof(EFI_TE_IMAGE_HEADER) -\r
820 Hdr.Te->StrippedSize\r
821 );\r
822 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);\r
823 } else {\r
824 //\r
825 // Set base and end to bypass processing below.\r
826 //\r
827 RelocBase = NULL;\r
828 RelocBaseEnd = NULL;\r
829 }\r
3eb9473e 830 }\r
831 \r
832 //\r
833 // Run the relocation information and apply the fixups\r
834 //\r
835 FixupData = ImageContext->FixupData;\r
836 while (RelocBase < RelocBaseEnd) {\r
837\r
838 Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r
839 RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);\r
840 if (!(ImageContext->IsTeImage)) {\r
841 FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);\r
4ac4deb7
LG
842\r
843 if (FixupBase == NULL) {\r
844 //\r
845 // If the FixupBase address resolved to 0, then fail.\r
846 //\r
847 return EFI_LOAD_ERROR;\r
848 }\r
3eb9473e 849 } else {\r
850 FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +\r
851 RelocBase->VirtualAddress +\r
852 sizeof(EFI_TE_IMAGE_HEADER) - \r
853 Hdr.Te->StrippedSize\r
854 );\r
855 }\r
856\r
857 if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||\r
858 (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress + \r
859 (UINTN)ImageContext->ImageSize)) {\r
860 ImageContext->ImageError = EFI_IMAGE_ERROR_FAILED_RELOCATION;\r
861 return EFI_LOAD_ERROR;\r
862 }\r
863\r
864 //\r
865 // Run this relocation record\r
866 //\r
867 while (Reloc < RelocEnd) {\r
868\r
869 Fixup = FixupBase + (*Reloc & 0xFFF);\r
870 switch ((*Reloc) >> 12) {\r
871 case EFI_IMAGE_REL_BASED_ABSOLUTE:\r
872 break;\r
873\r
874 case EFI_IMAGE_REL_BASED_HIGH:\r
875 F16 = (UINT16 *) Fixup;\r
876 *F16 = (UINT16) (*F16 + (UINT16)(((UINT32)Adjust) >> 16));\r
877 if (FixupData != NULL) {\r
878 *(UINT16 *) FixupData = *F16;\r
879 FixupData = FixupData + sizeof (UINT16);\r
880 }\r
881 break;\r
882\r
883 case EFI_IMAGE_REL_BASED_LOW:\r
884 F16 = (UINT16 *) Fixup;\r
885 *F16 = (UINT16) (*F16 + (UINT16) Adjust);\r
886 if (FixupData != NULL) {\r
887 *(UINT16 *) FixupData = *F16;\r
888 FixupData = FixupData + sizeof (UINT16);\r
889 }\r
890 break;\r
891\r
892 case EFI_IMAGE_REL_BASED_HIGHLOW:\r
893 F32 = (UINT32 *) Fixup;\r
894 *F32 = *F32 + (UINT32) Adjust;\r
895 if (FixupData != NULL) {\r
896 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));\r
897 *(UINT32 *) FixupData = *F32;\r
898 FixupData = FixupData + sizeof (UINT32);\r
899 }\r
900 break;\r
901\r
902 case EFI_IMAGE_REL_BASED_DIR64:\r
903 //\r
904 // For X64 and IPF\r
905 //\r
906 F64 = (UINT64 *) Fixup;\r
907 *F64 = *F64 + (UINT64) Adjust;\r
908 if (FixupData != NULL) {\r
909 FixupData = ALIGN_POINTER (FixupData, sizeof(UINT64));\r
910 *(UINT64 *)(FixupData) = *F64;\r
911 FixupData = FixupData + sizeof(UINT64);\r
912 }\r
913 break;\r
914\r
915 case EFI_IMAGE_REL_BASED_HIGHADJ:\r
916 //\r
917 // Return the same EFI_UNSUPPORTED return code as\r
918 // PeCoffLoaderRelocateImageEx() returns if it does not recognize\r
919 // the relocation type.\r
920 //\r
921 ImageContext->ImageError = EFI_IMAGE_ERROR_FAILED_RELOCATION;\r
922 return EFI_UNSUPPORTED;\r
923\r
924 default:\r
925 //\r
926 // The common code does not handle some of the stranger IPF relocations\r
927 // PeCoffLoaderRelocateImageEx () addes support for these complex fixups\r
928 // on IPF and is a No-Op on other archtiectures.\r
929 //\r
930 Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);\r
931 if (EFI_ERROR (Status)) {\r
932 ImageContext->ImageError = EFI_IMAGE_ERROR_FAILED_RELOCATION;\r
933 return Status;\r
934 }\r
935 }\r
936\r
937 //\r
938 // Next relocation record\r
939 //\r
940 Reloc += 1;\r
941 }\r
942\r
943 //\r
944 // Next reloc block\r
945 //\r
946 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;\r
947 }\r
948\r
949#ifdef EFI_NT_EMULATOR\r
950 DllEntryPoint = NULL;\r
951 ImageContext->ModHandle = NULL;\r
952 //\r
953 // Load the DLL if it's not an EBC image.\r
954 //\r
955 if ((ImageContext->PdbPointer != NULL) && \r
956 (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) {\r
957 Status = mPeCoffLoaderWinNtLoadAsDll->Entry (\r
958 ImageContext->PdbPointer,\r
959 &DllEntryPoint,\r
960 &ModHandle\r
961 );\r
962\r
963 if (!EFI_ERROR (Status) && DllEntryPoint != NULL) {\r
964 ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;\r
965 ImageContext->ModHandle = ModHandle;\r
966 }\r
967 }\r
968#endif\r
969\r
970 return EFI_SUCCESS;\r
971}\r
972\r
973EFI_STATUS\r
974EFIAPI\r
975PeCoffLoaderLoadImage (\r
976 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
977 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
978 )\r
979/*++\r
980\r
981Routine Description:\r
982\r
983 Loads a PE/COFF image into memory\r
984\r
985Arguments:\r
986\r
987 This - Calling context\r
988\r
989 ImageContext - Contains information on image to load into memory\r
990\r
991Returns:\r
992\r
993 EFI_SUCCESS if the PE/COFF image was loaded\r
994 EFI_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer\r
995 EFI_LOAD_ERROR if the image is a runtime driver with no relocations\r
996 EFI_INVALID_PARAMETER if the image address is invalid\r
997\r
998--*/\r
999{\r
1000 EFI_STATUS Status;\r
1001 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
1002 EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;\r
1003 EFI_IMAGE_SECTION_HEADER *FirstSection;\r
1004 EFI_IMAGE_SECTION_HEADER *Section;\r
1005 UINTN NumberOfSections;\r
1006 UINTN Index;\r
1007 CHAR8 *Base;\r
1008 CHAR8 *End;\r
1009 CHAR8 *MaxEnd;\r
1010 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
1011 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
1012 UINTN Size;\r
1013 UINT32 TempDebugEntryRva;\r
1014 UINT32 NumberOfRvaAndSizes;\r
1015 UINT16 Magic;\r
1016\r
1017 if (NULL == ImageContext) {\r
1018 return EFI_INVALID_PARAMETER;\r
1019 }\r
1020\r
1021 //\r
1022 // Assume success\r
1023 //\r
1024 ImageContext->ImageError = EFI_IMAGE_ERROR_SUCCESS;\r
1025\r
1026 //\r
1027 // Copy the provided context info into our local version, get what we\r
1028 // can from the original image, and then use that to make sure everything\r
1029 // is legit.\r
1030 //\r
1031 CopyMem (&CheckContext, ImageContext, sizeof (EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT));\r
1032\r
1033 Status = PeCoffLoaderGetImageInfo (This, &CheckContext);\r
1034 if (EFI_ERROR (Status)) {\r
1035 return Status;\r
1036 }\r
1037\r
1038 //\r
1039 // Make sure there is enough allocated space for the image being loaded\r
1040 //\r
1041 if (ImageContext->ImageSize < CheckContext.ImageSize) {\r
1042 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_IMAGE_SIZE;\r
1043 return EFI_BUFFER_TOO_SMALL;\r
1044 }\r
1045 if (ImageContext->ImageAddress == 0) {\r
1046 //\r
1047 // Image cannot be loaded into 0 address.\r
1048 //\r
1049 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
1050 return EFI_INVALID_PARAMETER;\r
1051 }\r
1052 //\r
1053 // If there's no relocations, then make sure it's not a runtime driver,\r
1054 // and that it's being loaded at the linked address.\r
1055 //\r
1056 if (CheckContext.RelocationsStripped) {\r
1057 //\r
1058 // If the image does not contain relocations and it is a runtime driver\r
1059 // then return an error.\r
1060 //\r
1061 if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {\r
1062 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_SUBSYSTEM;\r
1063 return EFI_LOAD_ERROR;\r
1064 }\r
1065 //\r
1066 // If the image does not contain relocations, and the requested load address\r
1067 // is not the linked address, then return an error.\r
1068 //\r
1069 if (CheckContext.ImageAddress != ImageContext->ImageAddress) {\r
1070 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
1071 return EFI_INVALID_PARAMETER;\r
1072 }\r
1073 }\r
1074 //\r
1075 // Make sure the allocated space has the proper section alignment\r
1076 //\r
1077 if (!(ImageContext->IsTeImage)) {\r
1078 if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {\r
1079 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;\r
1080 return EFI_INVALID_PARAMETER;\r
1081 }\r
1082 }\r
1083 //\r
1084 // Read the entire PE/COFF or TE header into memory\r
1085 //\r
1086 if (!(ImageContext->IsTeImage)) {\r
1087 Status = ImageContext->ImageRead (\r
1088 ImageContext->Handle,\r
1089 0,\r
1090 &ImageContext->SizeOfHeaders,\r
1091 (VOID *) (UINTN) ImageContext->ImageAddress\r
1092 );\r
1093\r
1094 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);\r
1095\r
1096 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
1097 (UINTN)ImageContext->ImageAddress +\r
1098 ImageContext->PeCoffHeaderOffset +\r
1099 sizeof(UINT32) + \r
1100 sizeof(EFI_IMAGE_FILE_HEADER) + \r
1101 Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
1102 );\r
1103 NumberOfSections = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections);\r
1104 } else {\r
1105 Status = ImageContext->ImageRead (\r
1106 ImageContext->Handle,\r
1107 0,\r
1108 &ImageContext->SizeOfHeaders,\r
1109 (VOID *)(UINTN)ImageContext->ImageAddress\r
1110 );\r
1111\r
1112 Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);\r
1113\r
1114 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
1115 (UINTN)ImageContext->ImageAddress +\r
1116 sizeof(EFI_TE_IMAGE_HEADER)\r
1117 );\r
1118 NumberOfSections = (UINTN) (Hdr.Te->NumberOfSections);\r
1119\r
1120 }\r
1121\r
1122 if (EFI_ERROR (Status)) {\r
1123 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
1124 return EFI_LOAD_ERROR;\r
1125 }\r
1126\r
1127 //\r
1128 // Load each section of the image\r
1129 //\r
1130 Section = FirstSection;\r
1131 for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {\r
1132\r
1133 //\r
1134 // Compute sections address\r
1135 //\r
1136 Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);\r
1137 End = PeCoffLoaderImageAddress (\r
1138 ImageContext,\r
1139 Section->VirtualAddress + Section->Misc.VirtualSize - 1\r
1140 );\r
1141 if (ImageContext->IsTeImage) {\r
1142 Base = (CHAR8 *)((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);\r
1143 End = (CHAR8 *)((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);\r
1144 }\r
1145\r
1146 if (End > MaxEnd) {\r
1147 MaxEnd = End;\r
1148 }\r
1149 //\r
1150 // If the base start or end address resolved to 0, then fail.\r
1151 //\r
1152 if ((Base == NULL) || (End == NULL)) {\r
1153 ImageContext->ImageError = EFI_IMAGE_ERROR_SECTION_NOT_LOADED;\r
1154 return EFI_LOAD_ERROR;\r
1155 }\r
1156\r
1157 //\r
1158 // Read the section\r
1159 //\r
1160 Size = (UINTN) Section->Misc.VirtualSize;\r
1161 if ((Size == 0) || (Size > Section->SizeOfRawData)) {\r
1162 Size = (UINTN) Section->SizeOfRawData;\r
1163 }\r
1164\r
1165 if (Section->SizeOfRawData) {\r
1166 if (!(ImageContext->IsTeImage)) {\r
1167 Status = ImageContext->ImageRead (\r
1168 ImageContext->Handle,\r
1169 Section->PointerToRawData,\r
1170 &Size,\r
1171 Base\r
1172 );\r
1173 } else {\r
1174 Status = ImageContext->ImageRead (\r
1175 ImageContext->Handle,\r
1176 Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize,\r
1177 &Size,\r
1178 Base\r
1179 );\r
1180 }\r
1181\r
1182 if (EFI_ERROR (Status)) {\r
1183 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
1184 return Status;\r
1185 }\r
1186 }\r
1187\r
1188 //\r
1189 // If raw size is less then virt size, zero fill the remaining\r
1190 //\r
1191\r
1192 if (Size < Section->Misc.VirtualSize) {\r
1193 ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);\r
1194 }\r
1195\r
1196 //\r
1197 // Next Section\r
1198 //\r
1199 Section += 1;\r
1200 }\r
1201\r
1202 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
1203\r
1204 //\r
1205 // Get image's entry point\r
1206 //\r
1207 if (!(ImageContext->IsTeImage)) {\r
1208\r
1209 //\r
1210 // NOTE: We use Machine to identify PE32/PE32+, instead of Magic.\r
1211 // It is for backward-compatibility consideration, because\r
1212 // some system will generate PE32+ image with PE32 Magic.\r
1213 //\r
1214 if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {\r
1215 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
1216 } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {\r
1217 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
1218 } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) {\r
1219 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
1220 } else {\r
1221 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
1222 }\r
1223\r
1224 //\r
1225 // Sizes of AddressOfEntryPoint are different so we need to do this safely\r
1226 //\r
1227 ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (\r
1228 ImageContext,\r
1229 (UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint\r
1230 );\r
1231\r
1232 } else {\r
1233 ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (\r
1234 (UINTN)ImageContext->ImageAddress +\r
1235 (UINTN)Hdr.Te->AddressOfEntryPoint +\r
1236 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -\r
1237 (UINTN)Hdr.Te->StrippedSize\r
1238 );\r
1239 }\r
1240\r
1241 //\r
1242 // Determine the size of the fixup data\r
1243 //\r
1244 // Per the PE/COFF spec, you can't assume that a given data directory\r
1245 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
1246 // the optional header to verify a desired directory entry is there.\r
1247 //\r
1248 if (!(ImageContext->IsTeImage)) {\r
1249 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1250 //\r
1251 // Use PE32 offset\r
1252 //\r
1253 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
1254 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
1255 } else {\r
1256 //\r
1257 // Use PE32+ offset\r
1258 //\r
1259 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
1260 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
1261 }\r
1262 \r
1263 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
1264 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
1265 } else {\r
1266 ImageContext->FixupDataSize = 0;\r
1267 }\r
1268 } else {\r
1269 DirectoryEntry = &Hdr.Te->DataDirectory[0];\r
1270 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
1271 }\r
1272 //\r
1273 // Consumer must allocate a buffer for the relocation fixup log.\r
1274 // Only used for runtime drivers.\r
1275 //\r
1276 ImageContext->FixupData = NULL;\r
1277\r
1278 //\r
1279 // Load the Codeview info if present\r
1280 //\r
1281 if (ImageContext->DebugDirectoryEntryRva != 0) {\r
1282 if (!(ImageContext->IsTeImage)) {\r
1283 DebugEntry = PeCoffLoaderImageAddress (\r
1284 ImageContext,\r
1285 ImageContext->DebugDirectoryEntryRva\r
1286 );\r
1287 } else {\r
1288 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(\r
1289 ImageContext->ImageAddress +\r
1290 ImageContext->DebugDirectoryEntryRva +\r
1291 sizeof(EFI_TE_IMAGE_HEADER) -\r
1292 Hdr.Te->StrippedSize\r
1293 );\r
1294 }\r
1295\r
1296 if (DebugEntry != NULL) {\r
1297 TempDebugEntryRva = DebugEntry->RVA;\r
1298 if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {\r
1299 Section--;\r
1300 if ((UINTN)Section->SizeOfRawData < Section->Misc.VirtualSize) {\r
1301 TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;\r
1302 } else {\r
1303 TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;\r
1304 }\r
1305 }\r
1306\r
1307 if (TempDebugEntryRva != 0) {\r
1308 if (!(ImageContext->IsTeImage)) {\r
1309 ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);\r
1310 } else {\r
1311 ImageContext->CodeView = (VOID *)(\r
1312 (UINTN)ImageContext->ImageAddress +\r
1313 (UINTN)TempDebugEntryRva +\r
1314 (UINTN)sizeof (EFI_TE_IMAGE_HEADER) -\r
1315 (UINTN) Hdr.Te->StrippedSize\r
1316 );\r
1317 }\r
1318\r
1319 if (ImageContext->CodeView == NULL) {\r
1320 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
1321 return EFI_LOAD_ERROR;\r
1322 }\r
1323\r
1324 if (DebugEntry->RVA == 0) {\r
1325 Size = DebugEntry->SizeOfData;\r
1326 if (!(ImageContext->IsTeImage)) {\r
1327 Status = ImageContext->ImageRead (\r
1328 ImageContext->Handle,\r
1329 DebugEntry->FileOffset,\r
1330 &Size,\r
1331 ImageContext->CodeView\r
1332 );\r
1333 } else {\r
1334 Status = ImageContext->ImageRead (\r
1335 ImageContext->Handle,\r
1336 DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize,\r
1337 &Size,\r
1338 ImageContext->CodeView\r
1339 );\r
1340 //\r
1341 // Should we apply fix up to this field according to the size difference between PE and TE?\r
1342 // Because now we maintain TE header fields unfixed, this field will also remain as they are\r
1343 // in original PE image.\r
1344 //\r
1345 }\r
1346\r
1347 if (EFI_ERROR (Status)) {\r
1348 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
1349 return EFI_LOAD_ERROR;\r
1350 }\r
1351\r
1352 DebugEntry->RVA = TempDebugEntryRva;\r
1353 }\r
1354\r
1355 switch (*(UINT32 *) ImageContext->CodeView) {\r
1356 case CODEVIEW_SIGNATURE_NB10:\r
1357 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);\r
1358 break;\r
1359\r
1360 case CODEVIEW_SIGNATURE_RSDS:\r
1361 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
1362 break;\r
1363\r
1364 default:\r
1365 break;\r
1366 }\r
1367 }\r
1368 }\r
1369 }\r
1370\r
1371#if defined (EFI_DEBUG_ITP_BREAK) && !defined (_CONSOLE)\r
1372 AsmEfiSetBreakSupport ((UINTN)(ImageContext->ImageAddress));\r
1373#endif\r
1374\r
1375 return Status;\r
1376}\r
1377\r
1378EFI_STATUS\r
1379EFIAPI\r
1380PeCoffLoaderUnloadImage (\r
97f201c4 1381 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
3eb9473e 1382 )\r
1383/*++\r
1384\r
1385Routine Description:\r
1386\r
1387 Unload a PE/COFF image from memory\r
1388\r
1389Arguments:\r
1390\r
1391 ImageContext - Contains information on image to load into memory\r
1392\r
1393Returns:\r
1394\r
1395 EFI_SUCCESS \r
1396\r
1397--*/\r
1398{\r
1399#ifdef EFI_NT_EMULATOR\r
1400 //\r
1401 // Calling Win32 API free library\r
1402 //\r
1403 mPeCoffLoaderWinNtLoadAsDll->FreeLibrary (ImageContext->ModHandle);\r
1404\r
1405#endif\r
1406\r
1407 return EFI_SUCCESS;\r
1408}\r