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