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