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