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