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