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