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