(1) Using EfiCompress in place of TianoCompress as EFI_STANDARD_COMPRESSION type...
[mirror_edk2.git] / EdkModulePkg / Library / EdkPeCoffLoaderX64Lib / EdkPeCoffLoaderX64.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, 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 EdkPeCoffLoaderX64.c\r
15\r
16Abstract:\r
17\r
18 Wrap the Base PE/COFF loader with the PE COFF Protocol\r
19\r
20\r
21--*/\r
22\r
23#define IMAGE_64_MACHINE_TYPE_SUPPORTED(Machine) \\r
24 ((Machine) == EFI_IMAGE_MACHINE_IA32 || \\r
25 (Machine) == EFI_IMAGE_MACHINE_X64 || \\r
26 (Machine) == EFI_IMAGE_MACHINE_EBC)\r
27\r
28STATIC\r
29EFI_STATUS\r
30PeCoffLoader64GetPeHeader (\r
31 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
32 OUT EFI_IMAGE_NT_HEADERS64 *PeHdr\r
33 );\r
34\r
35STATIC\r
36EFI_STATUS\r
37PeCoffLoader64CheckImageType (\r
38 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
39 IN EFI_IMAGE_NT_HEADERS64 *PeHdr\r
40 );\r
41\r
42STATIC\r
43VOID *\r
44PeCoffLoader64ImageAddress (\r
45 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
46 IN UINTN Address\r
47 );\r
48\r
49EFI_STATUS\r
50EFIAPI\r
51PeCoffLoader64GetImageInfo (\r
52 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
53 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
54 );\r
55\r
56EFI_STATUS\r
57EFIAPI\r
58PeCoffLoader64RelocateImage (\r
59 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
60 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
61 );\r
62\r
63EFI_STATUS\r
64EFIAPI\r
65PeCoffLoader64LoadImage (\r
66 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
67 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
68 );\r
69\r
70EFI_STATUS\r
71EFIAPI\r
72PeCoffLoader64UnloadImage (\r
73 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
74 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
75 );\r
76\r
77EFI_STATUS\r
78PeCoffLoader64RelocateImageEx (\r
79 IN UINT16 *Reloc,\r
80 IN OUT CHAR8 *Fixup, \r
81 IN OUT CHAR8 **FixupData,\r
82 IN UINT64 Adjust\r
83 );\r
84\r
85EFI_PEI_PE_COFF_LOADER_PROTOCOL mPeCoffLoaderX64 = {\r
86 PeCoffLoader64GetImageInfo,\r
87 PeCoffLoader64LoadImage,\r
88 PeCoffLoader64RelocateImage,\r
89 PeCoffLoader64UnloadImage\r
90};\r
91\r
92STATIC\r
93EFI_STATUS\r
94PeCoffLoader64GetPeHeader (\r
95 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
96 OUT EFI_IMAGE_NT_HEADERS64 *PeHdr\r
97 )\r
98/*++\r
99\r
100Routine Description:\r
101 Retrieves the PE Header from a PE/COFF image\r
102\r
103Arguments:\r
104 ImageContext - The context of the image being loaded\r
105 PeHdr - The buffer in which to return the PE header\r
106\r
107Returns:\r
108 EFI_SUCCESS if the PE Header is read, \r
109 Otherwise, the error status from reading the PE/COFF image using the ImageRead function.\r
110\r
111--*/\r
112{\r
113 EFI_STATUS Status;\r
114 EFI_IMAGE_DOS_HEADER DosHdr;\r
115 UINTN Size;\r
116 \r
117 //\r
118 // Read the DOS image headers\r
119 //\r
120 Size = sizeof (EFI_IMAGE_DOS_HEADER);\r
121 Status = ImageContext->ImageRead (\r
122 ImageContext->Handle, \r
123 0,\r
124 &Size, \r
125 &DosHdr\r
126 );\r
127 if (EFI_ERROR (Status)) {\r
128 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
129 return Status;\r
130 }\r
131\r
132 ImageContext->PeCoffHeaderOffset = 0;\r
133 if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
134 //\r
135 // DOS image header is present, so read the PE header after the DOS image header\r
136 //\r
137 ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;\r
138 } \r
139\r
140 //\r
141 // Read the PE/COFF Header\r
142 //\r
143 Size = sizeof (EFI_IMAGE_NT_HEADERS64);\r
144 Status = ImageContext->ImageRead (\r
145 ImageContext->Handle, \r
146 ImageContext->PeCoffHeaderOffset, \r
147 &Size, \r
148 PeHdr\r
149 );\r
150 if (EFI_ERROR (Status)) {\r
151 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
152 return Status;\r
153 }\r
154\r
155 return EFI_SUCCESS;\r
156}\r
157\r
158static\r
159EFI_STATUS\r
160PeCoffLoader64CheckImageType (\r
161 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
162 IN EFI_IMAGE_NT_HEADERS64 *PeHdr\r
163 )\r
164/*++\r
165\r
166Routine Description:\r
167 Checks the PE header of a PE/COFF image to determine if it supported\r
168\r
169Arguments:\r
170 ImageContext - The context of the image being loaded\r
171 PeHdr - The buffer in which to return the PE header\r
172\r
173Returns:\r
174 EFI_SUCCESS if the PE/COFF image is supported\r
175 EFI_UNSUPPORTED of the PE/COFF image is not supported.\r
176\r
177--*/\r
178{\r
179 //\r
180 // Check the PE/COFF Header SIgnature\r
181 //\r
182 if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
183 ImageContext->ImageError = IMAGE_ERROR_INVALID_PE_HEADER_SIGNATURE;\r
184 return EFI_UNSUPPORTED;\r
185 }\r
186\r
187 //\r
188 // See if the machine type is supported. We support a native machine type (IA-32/Itanium-based)\r
189 // and the machine type for the Virtual Machine.\r
190 //\r
191 ImageContext->Machine = PeHdr->FileHeader.Machine;\r
192 if (!(IMAGE_64_MACHINE_TYPE_SUPPORTED (ImageContext->Machine))) {\r
193 ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;\r
194 return EFI_UNSUPPORTED;\r
195 }\r
196\r
197 //\r
198 // See if the image type is supported. We support EFI Applications, \r
199 // EFI Boot Service Drivers, and EFI Runtime Drivers.\r
200 //\r
201 ImageContext->ImageType = PeHdr->OptionalHeader.Subsystem;\r
202 switch (ImageContext->ImageType) {\r
203\r
204 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:\r
205 ImageContext->ImageCodeMemoryType = EfiLoaderCode;\r
206 ImageContext->ImageDataMemoryType = EfiLoaderData;\r
207 break;\r
208 \r
209 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:\r
210 ImageContext->ImageCodeMemoryType = EfiBootServicesCode;\r
211 ImageContext->ImageDataMemoryType = EfiBootServicesData;\r
212 break;\r
213 \r
214 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:\r
215 case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:\r
216 ImageContext->ImageCodeMemoryType = EfiRuntimeServicesCode;\r
217 ImageContext->ImageDataMemoryType = EfiRuntimeServicesData;\r
218 break;\r
219 \r
220 default:\r
221 ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;\r
222 return EFI_UNSUPPORTED;\r
223 }\r
224\r
225 return EFI_SUCCESS;\r
226}\r
227\r
228EFI_STATUS\r
229EFIAPI\r
230PeCoffLoader64GetImageInfo (\r
231 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
232 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
233 )\r
234/*++\r
235\r
236Routine Description:\r
237 Retrieves information on a PE/COFF image\r
238\r
239Arguments:\r
240 ImageContext - The context of the image being loaded\r
241 PeHdr - The buffer in which to return the PE header\r
242\r
243Returns:\r
244 EFI_SUCCESS if the information on the PE/COFF image was collected.\r
245 EFI_UNSUPPORTED of the PE/COFF image is not supported.\r
246 Otherwise, the error status from reading the PE/COFF image using the \r
247 ImageContext->ImageRead() function\r
248\r
249--*/\r
250{\r
251 EFI_STATUS Status;\r
252 EFI_IMAGE_NT_HEADERS64 PeHdr;\r
253 EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;\r
254 UINTN Size;\r
255 UINTN Index;\r
256 UINTN DebugDirectoryEntryRva;\r
257 UINTN DebugDirectoryEntryFileOffset;\r
258 UINTN SectionHeaderOffset;\r
259 EFI_IMAGE_SECTION_HEADER SectionHeader;\r
260 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;\r
261\r
262 if (NULL == ImageContext) {\r
263 return EFI_INVALID_PARAMETER;\r
264 }\r
265\r
266 //\r
267 // Assume success\r
268 //\r
269 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
270 \r
271 Status = PeCoffLoader64GetPeHeader (ImageContext, &PeHdr);\r
272 if (EFI_ERROR (Status)) {\r
273 return Status;\r
274 }\r
275\r
276 //\r
277 // Verify machine type\r
278 //\r
279 Status = PeCoffLoader64CheckImageType (ImageContext, &PeHdr);\r
280 if (EFI_ERROR(Status)) {\r
281 return Status;\r
282 }\r
283\r
284 //\r
285 // Retrieve the base address of the image\r
286 //\r
287 ImageContext->ImageAddress = PeHdr.OptionalHeader.ImageBase;\r
288 \r
289 //\r
290 // Initialize the alternate destination address to 0 indicating that it \r
291 // should not be used.\r
292 //\r
293 ImageContext->DestinationAddress = 0;\r
294\r
295 //\r
296 // Initialize the codeview pointer.\r
297 //\r
298 ImageContext->CodeView = NULL;\r
299 ImageContext->PdbPointer = NULL;\r
300 \r
301 //\r
302 // Three cases with regards to relocations:\r
303 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable\r
304 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable\r
305 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but\r
306 // has no base relocs to apply\r
307 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.\r
308 //\r
309 // Look at the file header to determine if relocations have been stripped, and\r
310 // save this info in the image context for later use.\r
311 //\r
312 if (PeHdr.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) {\r
313 ImageContext->RelocationsStripped = TRUE;\r
314 } else {\r
315 ImageContext->RelocationsStripped = FALSE;\r
316 }\r
317\r
318 ImageContext->ImageSize = (UINT64)PeHdr.OptionalHeader.SizeOfImage;\r
319 ImageContext->SectionAlignment = PeHdr.OptionalHeader.SectionAlignment;\r
320 ImageContext->SizeOfHeaders = PeHdr.OptionalHeader.SizeOfHeaders; \r
321\r
322 //\r
323 // Modify ImageSize to contain .PDB file name if required and initialize\r
324 // PdbRVA field...\r
325 //\r
326\r
327 if (PeHdr.OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
328 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)\r
329 &(PeHdr.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
330\r
331 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
332\r
333 //\r
334 // Determine the file offset of the debug directory... This means we walk\r
335 // the sections to find which section contains the RVA of the debug\r
336 // directory\r
337 //\r
338 \r
339 DebugDirectoryEntryFileOffset = 0;\r
340 \r
341 SectionHeaderOffset = (UINTN) (\r
342 ImageContext->PeCoffHeaderOffset +\r
343 sizeof (UINT32) + \r
344 sizeof (EFI_IMAGE_FILE_HEADER) + \r
345 PeHdr.FileHeader.SizeOfOptionalHeader\r
346 );\r
347 \r
348 for (Index = 0; Index < PeHdr.FileHeader.NumberOfSections; Index += 1) {\r
349 //\r
350 // Read section header from file\r
351 //\r
352 Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
353 Status = ImageContext->ImageRead (\r
354 ImageContext->Handle, \r
355 SectionHeaderOffset, \r
356 &Size, \r
357 &SectionHeader\r
358 );\r
359 if (EFI_ERROR (Status)) {\r
360 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
361 return Status;\r
362 }\r
363 \r
364 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
365 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
366 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;\r
367 break;\r
368 }\r
369 \r
370 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
371 }\r
372 \r
373 if (DebugDirectoryEntryFileOffset != 0) {\r
374 for (Index = 0; Index < DebugDirectoryEntry->Size; Index++) {\r
375 //\r
376 // Read next debug directory entry\r
377 //\r
378 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
379 Status = ImageContext->ImageRead (\r
380 ImageContext->Handle, \r
381 DebugDirectoryEntryFileOffset, \r
382 &Size, \r
383 &DebugEntry\r
384 );\r
385 if (EFI_ERROR (Status)) {\r
386 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
387 return Status;\r
388 }\r
389 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
390 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));\r
391 if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {\r
392 ImageContext->ImageSize += DebugEntry.SizeOfData;\r
393 }\r
394 return EFI_SUCCESS;\r
395 }\r
396 }\r
397 }\r
398 }\r
399 return EFI_SUCCESS;\r
400}\r
401\r
402static\r
403VOID *\r
404PeCoffLoader64ImageAddress (\r
405 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
406 IN UINTN Address\r
407 )\r
408/*++\r
409\r
410Routine Description:\r
411 Converts an image address to the loaded address\r
412\r
413Arguments:\r
414 ImageContext - The context of the image being loaded\r
415 Address - The address to be converted to the loaded address\r
416\r
417Returns:\r
418 NULL if the address can not be converted, otherwise, the converted address\r
419\r
420--*/\r
421{\r
422 if (Address >= ImageContext->ImageSize) {\r
423 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
424 return NULL;\r
425 }\r
426 return (CHAR8 *)((UINTN)ImageContext->ImageAddress + Address);\r
427}\r
428\r
429EFI_STATUS\r
430EFIAPI\r
431PeCoffLoader64RelocateImage (\r
432 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
433 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
434 )\r
435/*++\r
436\r
437Routine Description:\r
438 Relocates a PE/COFF image in memory\r
439\r
440Arguments:\r
441 ImageContext - Contains information on the loaded image to relocate\r
442\r
443Returns:\r
444 EFI_SUCCESS if the PE/COFF image was relocated\r
445 EFI_LOAD_ERROR if the image is not a valid PE/COFF image\r
446\r
447--*/\r
448{\r
449 EFI_STATUS Status;\r
450 EFI_IMAGE_NT_HEADERS64 *PeHdr;\r
451 EFI_IMAGE_DATA_DIRECTORY *RelocDir;\r
452 IN UINT64 Adjust;\r
453 EFI_IMAGE_BASE_RELOCATION *RelocBase;\r
454 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;\r
455 UINT16 *Reloc;\r
456 UINT16 *RelocEnd;\r
457 CHAR8 *Fixup;\r
458 CHAR8 *FixupBase;\r
459 UINT16 *F16;\r
460 UINT32 *F32;\r
461 CHAR8 *FixupData;\r
462 EFI_PHYSICAL_ADDRESS BaseAddress;\r
463\r
464\r
465 //\r
466 // Assume success\r
467 //\r
468 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
469\r
470 //\r
471 // If there are no relocation entries, then we are done\r
472 //\r
473 if (ImageContext->RelocationsStripped) {\r
474 return EFI_SUCCESS;\r
475 }\r
476\r
477 //\r
478 // If the destination address is not 0, use that rather than the\r
479 // image address as the relocation target.\r
480 //\r
481 if (ImageContext->DestinationAddress) {\r
482 BaseAddress = ImageContext->DestinationAddress;\r
483 } else {\r
484 BaseAddress = ImageContext->ImageAddress;\r
485 }\r
486 PeHdr = (EFI_IMAGE_NT_HEADERS64 *)((UINTN)ImageContext->ImageAddress + \r
487 ImageContext->PeCoffHeaderOffset);\r
488 Adjust = (UINT64) BaseAddress - PeHdr->OptionalHeader.ImageBase;\r
489\r
490 PeHdr->OptionalHeader.ImageBase = (UINTN) BaseAddress;\r
491\r
492 //\r
493 // Find the relocation block\r
494 //\r
495 // Per the PE/COFF spec, you can't assume that a given data directory \r
496 // is present in the image. You have to check the NumberOfRvaAndSizes in \r
497 // the optional header to verify a desired directory entry is there.\r
498 //\r
499 if (PeHdr->OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
500 RelocDir = &PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
501 RelocBase = PeCoffLoader64ImageAddress (ImageContext, RelocDir->VirtualAddress);\r
502 RelocBaseEnd = PeCoffLoader64ImageAddress ( \r
503 ImageContext, \r
504 RelocDir->VirtualAddress + RelocDir->Size - 1\r
505 );\r
506} else {\r
507 //\r
508 // Set base and end to bypass processing below.\r
509 //\r
510 RelocBase = RelocBaseEnd = 0;\r
511 }\r
512 //\r
513 // Run the relocation information and apply the fixups\r
514 //\r
515 FixupData = ImageContext->FixupData;\r
516 while (RelocBase < RelocBaseEnd) {\r
517 \r
518 Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof(EFI_IMAGE_BASE_RELOCATION));\r
519 RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);\r
520 FixupBase = PeCoffLoader64ImageAddress (ImageContext, RelocBase->VirtualAddress);\r
521 if ((CHAR8 *) RelocEnd < (CHAR8 *)((UINTN)ImageContext->ImageAddress) || \r
522 (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress + \r
523 (UINTN)ImageContext->ImageSize)) {\r
524 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
525 return EFI_LOAD_ERROR;\r
526 }\r
527\r
528 //\r
529 // Run this relocation record\r
530 //\r
531 while (Reloc < RelocEnd) {\r
532\r
533 Fixup = FixupBase + (*Reloc & 0xFFF);\r
534 switch ((*Reloc) >> 12) {\r
535 case EFI_IMAGE_REL_BASED_ABSOLUTE:\r
536 break;\r
537 case EFI_IMAGE_REL_BASED_HIGH:\r
538 F16 = (UINT16 *) Fixup;\r
9c7790d2 539 *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16)));\r
878ddf1f 540 if (FixupData != NULL) {\r
541 *(UINT16 *) FixupData = *F16;\r
542 FixupData = FixupData + sizeof(UINT16);\r
543 }\r
544 break;\r
545 case EFI_IMAGE_REL_BASED_LOW:\r
546 F16 = (UINT16 *) Fixup;\r
547 *F16 = (UINT16)(*F16 + (UINT16) Adjust);\r
548 if (FixupData != NULL) {\r
549 *(UINT16 *) FixupData = *F16;\r
550 FixupData = FixupData + sizeof(UINT16);\r
551 }\r
552 break;\r
553 case EFI_IMAGE_REL_BASED_HIGHLOW:\r
554 F32 = (UINT32 *) Fixup;\r
555 *F32 = *F32 + (UINT32) Adjust;\r
556 if (FixupData != NULL) {\r
557 FixupData = ALIGN_POINTER(FixupData, sizeof(UINT32));\r
558 *(UINT32 *) FixupData = *F32;\r
559 FixupData = FixupData + sizeof(UINT32);\r
560 }\r
561 break;\r
562 case EFI_IMAGE_REL_BASED_HIGHADJ:\r
563 // Return the same EFI_UNSUPPORTED return code as \r
564 // PeCoffLoader64RelocateImageEx() returns if it does not recognize\r
565 // the relocation type.\r
566 //\r
567 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
568 return EFI_UNSUPPORTED;\r
569 default:\r
570 Status = PeCoffLoader64RelocateImageEx (Reloc, Fixup, &FixupData, Adjust);\r
571 if (EFI_ERROR (Status)) {\r
572 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
573 return Status;\r
574 }\r
575 }\r
576\r
577 //\r
578 // Next relocation record\r
579 //\r
580 Reloc += 1;\r
581 }\r
582\r
583 //\r
584 // Next reloc block\r
585 //\r
586 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;\r
587 }\r
588\r
589 return EFI_SUCCESS;\r
590}\r
591\r
592\r
593EFI_STATUS\r
594PeCoffLoader64RelocateImageEx (\r
595 IN UINT16 *Reloc,\r
596 IN OUT CHAR8 *Fixup, \r
597 IN OUT CHAR8 **FixupData,\r
598 IN UINT64 Adjust\r
599 )\r
600/*++\r
601\r
602Routine Description:\r
603 Performs an IA-32 specific relocation fixup\r
604\r
605Arguments:\r
606 Reloc - Pointer to the relocation record\r
607 Fixup - Pointer to the address to fix up\r
608 FixupData - Pointer to a buffer to log the fixups\r
609 Adjust - The offset to adjust the fixup\r
610\r
611Returns:\r
612 None\r
613\r
614--*/\r
615{\r
616 UINT64 *F64;\r
617\r
618 switch ((*Reloc) >> 12) {\r
619\r
620 case EFI_IMAGE_REL_BASED_DIR64:\r
621 F64 = (UINT64 *) Fixup;\r
622 *F64 = *F64 + (UINT64) Adjust;\r
623 if (*FixupData != NULL) {\r
624 *FixupData = ALIGN_POINTER(*FixupData, sizeof(UINT64));\r
625 *(UINT64 *)(*FixupData) = *F64;\r
626 *FixupData = *FixupData + sizeof(UINT64);\r
627 }\r
628 break;\r
629\r
630 default:\r
631 return EFI_UNSUPPORTED;\r
632 }\r
633\r
634 return EFI_SUCCESS;\r
635}\r
636\r
637\r
638\r
639EFI_STATUS\r
640EFIAPI\r
641PeCoffLoader64LoadImage (\r
642 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
643 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
644 )\r
645/*++\r
646\r
647Routine Description:\r
648 Loads a PE/COFF image into memory\r
649\r
650Arguments:\r
651 ImageContext - Contains information on image to load into memory\r
652\r
653Returns:\r
654 EFI_SUCCESS if the PE/COFF image was loaded\r
655 EFI_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer\r
656 EFI_LOAD_ERROR if the image is a runtime driver with no relocations\r
657 EFI_INVALID_PARAMETER if the image address is invalid\r
658\r
659--*/\r
660{\r
661 EFI_STATUS Status;\r
662 EFI_IMAGE_NT_HEADERS64 *PeHdr;\r
663 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;\r
664 EFI_IMAGE_SECTION_HEADER *FirstSection;\r
665 EFI_IMAGE_SECTION_HEADER *Section;\r
666 UINTN Index;\r
667 CHAR8 *Base;\r
668 CHAR8 *End;\r
669 CHAR8 *MaxEnd;\r
670 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
671 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
672 UINTN Size;\r
673 UINT32 TempDebugEntryRva;\r
674\r
675 //\r
676 // Assume success\r
677 //\r
678 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
679\r
680 //\r
681 // Copy the provided context info into our local version, get what we\r
682 // can from the original image, and then use that to make sure everything\r
683 // is legit.\r
684 //\r
685 CopyMem (\r
686 &CheckContext, \r
687 ImageContext, \r
688 sizeof (PE_COFF_LOADER_IMAGE_CONTEXT)\r
689 );\r
690 \r
691 Status = PeCoffLoader64GetImageInfo (\r
692 This,\r
693 &CheckContext \r
694 );\r
695 if (EFI_ERROR (Status)) {\r
696 return Status;\r
697 }\r
698\r
699 //\r
700 // Make sure there is enough allocated space for the image being loaded\r
701 //\r
702 if (ImageContext->ImageSize < CheckContext.ImageSize) {\r
703 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;\r
704 return EFI_BUFFER_TOO_SMALL;\r
705 }\r
706\r
707 //\r
708 // If there's no relocations, then make sure it's not a runtime driver,\r
709 // and that it's being loaded at the linked address.\r
710 //\r
711 if (CheckContext.RelocationsStripped == TRUE) {\r
712 //\r
713 // If the image does not contain relocations and it is a runtime driver \r
714 // then return an error.\r
715 //\r
716 if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {\r
717 ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;\r
718 return EFI_LOAD_ERROR;\r
719 }\r
720 //\r
721 // If the image does not contain relocations, and the requested load address \r
722 // is not the linked address, then return an error.\r
723 //\r
724 if (CheckContext.ImageAddress != ImageContext->ImageAddress) {\r
725 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
726 return EFI_INVALID_PARAMETER;\r
727 }\r
728 }\r
729\r
730 //\r
731 // Make sure the allocated space has the proper section alignment\r
732 //\r
733 if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {\r
734 ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;\r
735 return EFI_INVALID_PARAMETER;\r
736 }\r
737\r
738 //\r
739 // Read the entire PE/COFF header into memory\r
740 //\r
741 Status = ImageContext->ImageRead (\r
742 ImageContext->Handle, \r
743 0, \r
744 &ImageContext->SizeOfHeaders, \r
745 (VOID *)(UINTN)ImageContext->ImageAddress\r
746 );\r
747 if (EFI_ERROR(Status)) {\r
748 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
749 return EFI_LOAD_ERROR;\r
750 }\r
751\r
752 PeHdr = (EFI_IMAGE_NT_HEADERS64 *)\r
753 ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);\r
754\r
755 //\r
756 // Load each section of the image\r
757 //\r
758 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
759 (UINTN)ImageContext->ImageAddress +\r
760 ImageContext->PeCoffHeaderOffset +\r
761 sizeof(UINT32) + \r
762 sizeof(EFI_IMAGE_FILE_HEADER) + \r
763 PeHdr->FileHeader.SizeOfOptionalHeader\r
764 );\r
765\r
766 Section = FirstSection;\r
767 for ( Index=0, MaxEnd = NULL; \r
768 Index < PeHdr->FileHeader.NumberOfSections; \r
769 Index += 1) {\r
770\r
771 //\r
772 // Compute sections address\r
773 //\r
774 Base = PeCoffLoader64ImageAddress (ImageContext, Section->VirtualAddress);\r
775 End = PeCoffLoader64ImageAddress (\r
776 ImageContext, \r
777 Section->VirtualAddress + Section->Misc.VirtualSize - 1);\r
778 if (End > MaxEnd) {\r
779 MaxEnd = End;\r
780 }\r
781 //\r
782 // If the base start or end address resolved to 0, then fail.\r
783 //\r
784 if (!Base || !End) {\r
785 ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;\r
786 return EFI_LOAD_ERROR;\r
787 }\r
788\r
789 //\r
790 // Read the section, we can resume the length of PE image can't \r
791 // exceed the max 32bit integer\r
792 //\r
793 Size = (UINTN) Section->Misc.VirtualSize;\r
794 if ((Size == 0) || (Size > Section->SizeOfRawData)) {\r
795 Size = (UINTN) Section->SizeOfRawData;\r
796 }\r
797 if (Section->SizeOfRawData) {\r
798 Status = ImageContext->ImageRead (\r
799 ImageContext->Handle, \r
800 Section->PointerToRawData, \r
801 &Size, \r
802 Base);\r
803 if (EFI_ERROR(Status)) {\r
804 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
805 return Status;\r
806 }\r
807 }\r
808\r
809 //\r
810 // If raw size is less then virt size, zero fill the remaining\r
811 //\r
812\r
813 if (Size < Section->Misc.VirtualSize) {\r
814 ZeroMem (Base + Size, Section->Misc.VirtualSize - (UINTN)Size);\r
815 }\r
816\r
817 //\r
818 // Next Section\r
819 //\r
820 Section += 1;\r
821 }\r
822\r
823 //\r
824 // Get image's entry point\r
825 //\r
826 ImageContext->EntryPoint = \r
827 (EFI_PHYSICAL_ADDRESS) (UINTN) PeCoffLoader64ImageAddress (\r
828 ImageContext, \r
829 PeHdr->OptionalHeader.AddressOfEntryPoint\r
830 );\r
831\r
832 //\r
833 // Determine the size of the fixup data\r
834 //\r
835 // Per the PE/COFF spec, you can't assume that a given data directory \r
836 // is present in the image. You have to check the NumberOfRvaAndSizes in \r
837 // the optional header to verify a desired directory entry is there.\r
838 //\r
839 if (PeHdr->OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
840 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)\r
841 &PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
842 ImageContext->FixupDataSize = \r
843 DirectoryEntry->Size / sizeof(UINT16) * sizeof(UINTN);\r
844 } else {\r
845 ImageContext->FixupDataSize = 0;\r
846 }\r
847 //\r
848 // Consumer must allocate a buffer for the relocation fixup log.\r
849 // Only used for runtime drivers.\r
850 //\r
851 ImageContext->FixupData = NULL;\r
852\r
853 //\r
854 // Load the Codeview info if present\r
855 //\r
856 if (ImageContext->DebugDirectoryEntryRva != 0) {\r
857 DebugEntry = PeCoffLoader64ImageAddress (\r
858 ImageContext, \r
859 ImageContext->DebugDirectoryEntryRva\r
860 );\r
861 if (DebugEntry != NULL) {\r
862 TempDebugEntryRva = DebugEntry->RVA;\r
863 if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {\r
864 Section--;\r
865 if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) {\r
866 TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;\r
867 } else {\r
868 TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;\r
869 }\r
870 }\r
871 if (TempDebugEntryRva != 0) {\r
872 ImageContext->CodeView = PeCoffLoader64ImageAddress (ImageContext, TempDebugEntryRva);\r
873 if (ImageContext->CodeView == NULL) {\r
874 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
875 return EFI_LOAD_ERROR;\r
876 }\r
877\r
878 if (DebugEntry->RVA == 0) {\r
879 Size = (UINTN) DebugEntry->SizeOfData;\r
880 Status = ImageContext->ImageRead (\r
881 ImageContext->Handle, \r
882 DebugEntry->FileOffset,\r
883 &Size, \r
884 ImageContext->CodeView\r
885 );\r
886 if (EFI_ERROR(Status)) {\r
887 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
888 return EFI_LOAD_ERROR;\r
889 }\r
890 DebugEntry->RVA = TempDebugEntryRva;\r
891 }\r
892\r
893 switch (* (UINT32 *) ImageContext->CodeView) {\r
894 case CODEVIEW_SIGNATURE_NB10:\r
895 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);\r
896 break;\r
897 case CODEVIEW_SIGNATURE_RSDS:\r
898 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
899 break;\r
900 default:\r
901 break;\r
902 }\r
903 }\r
904 }\r
905 }\r
906 \r
907 return Status;\r
908}\r
909\r
910EFI_STATUS\r
911EFIAPI\r
912PeCoffLoader64UnloadImage (\r
913 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
914 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
915 )\r
916/*++\r
917\r
918Routine Description:\r
919 Unload of images is not supported\r
920\r
921Arguments:\r
922 ImageContext - The image to unload\r
923\r
924Returns:\r
925 EFI_SUCCESS\r
926\r
927--*/\r
928{\r
929 return EFI_SUCCESS;\r
930}\r
931\r
932EFI_PEI_PE_COFF_LOADER_PROTOCOL *\r
933EFIAPI\r
934GetPeCoffLoaderX64Protocol (\r
935 )\r
936{\r
937 return &mPeCoffLoaderX64;\r
938}\r
939\r
940\r