]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/BasePeCoffLib/BasePeCoff.c
MdePkg: Clean up source files
[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 - 2018, 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) {
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
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 = ImageContext->PeCoffHeaderOffset +
707 sizeof (UINT32) +
708 sizeof (EFI_IMAGE_FILE_HEADER) +
709 Hdr.Pe32->FileHeader.SizeOfOptionalHeader;
710
711 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
712 //
713 // Read section header from file
714 //
715 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
716 ReadSize = Size;
717 Status = ImageContext->ImageRead (
718 ImageContext->Handle,
719 SectionHeaderOffset,
720 &Size,
721 &SectionHeader
722 );
723 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
724 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
725 if (Size != ReadSize) {
726 Status = RETURN_UNSUPPORTED;
727 }
728 return Status;
729 }
730
731 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
732 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
733
734 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;
735 break;
736 }
737
738 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
739 }
740
741 if (DebugDirectoryEntryFileOffset != 0) {
742 for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
743 //
744 // Read next debug directory entry
745 //
746 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
747 ReadSize = Size;
748 Status = ImageContext->ImageRead (
749 ImageContext->Handle,
750 DebugDirectoryEntryFileOffset + Index,
751 &Size,
752 &DebugEntry
753 );
754 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
755 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
756 if (Size != ReadSize) {
757 Status = RETURN_UNSUPPORTED;
758 }
759 return Status;
760 }
761
762 //
763 // From PeCoff spec, when DebugEntry.RVA == 0 means this debug info will not load into memory.
764 // Here we will always load EFI_IMAGE_DEBUG_TYPE_CODEVIEW type debug info. so need adjust the
765 // ImageContext->ImageSize when DebugEntry.RVA == 0.
766 //
767 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
768 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
769 if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {
770 ImageContext->ImageSize += DebugEntry.SizeOfData;
771 }
772
773 return RETURN_SUCCESS;
774 }
775 }
776 }
777 }
778 } else {
779
780 DebugDirectoryEntry = &Hdr.Te->DataDirectory[1];
781 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
782 SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));
783
784 DebugDirectoryEntryFileOffset = 0;
785
786 for (Index = 0; Index < Hdr.Te->NumberOfSections;) {
787 //
788 // Read section header from file
789 //
790 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
791 ReadSize = Size;
792 Status = ImageContext->ImageRead (
793 ImageContext->Handle,
794 SectionHeaderOffset,
795 &Size,
796 &SectionHeader
797 );
798 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
799 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
800 if (Size != ReadSize) {
801 Status = RETURN_UNSUPPORTED;
802 }
803 return Status;
804 }
805
806 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
807 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
808 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -
809 SectionHeader.VirtualAddress +
810 SectionHeader.PointerToRawData -
811 TeStrippedOffset;
812
813 //
814 // File offset of the debug directory was found, if this is not the last
815 // section, then skip to the last section for calculating the image size.
816 //
817 if (Index < (UINTN) Hdr.Te->NumberOfSections - 1) {
818 SectionHeaderOffset += (Hdr.Te->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);
819 Index = Hdr.Te->NumberOfSections - 1;
820 continue;
821 }
822 }
823
824 //
825 // In Te image header there is not a field to describe the ImageSize.
826 // Actually, the ImageSize equals the RVA plus the VirtualSize of
827 // the last section mapped into memory (Must be rounded up to
828 // a multiple of Section Alignment). Per the PE/COFF specification, the
829 // section headers in the Section Table must appear in order of the RVA
830 // values for the corresponding sections. So the ImageSize can be determined
831 // by the RVA and the VirtualSize of the last section header in the
832 // Section Table.
833 //
834 if ((++Index) == (UINTN)Hdr.Te->NumberOfSections) {
835 ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) - TeStrippedOffset;
836 }
837
838 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
839 }
840
841 if (DebugDirectoryEntryFileOffset != 0) {
842 for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
843 //
844 // Read next debug directory entry
845 //
846 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
847 ReadSize = Size;
848 Status = ImageContext->ImageRead (
849 ImageContext->Handle,
850 DebugDirectoryEntryFileOffset + Index,
851 &Size,
852 &DebugEntry
853 );
854 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
855 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
856 if (Size != ReadSize) {
857 Status = RETURN_UNSUPPORTED;
858 }
859 return Status;
860 }
861
862 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
863 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
864 return RETURN_SUCCESS;
865 }
866 }
867 }
868 }
869
870 return RETURN_SUCCESS;
871 }
872
873
874 /**
875 Converts an image address to the loaded address.
876
877 @param ImageContext The context of the image being loaded.
878 @param Address The address to be converted to the loaded address.
879 @param TeStrippedOffset Stripped offset for TE image.
880
881 @return The converted address or NULL if the address can not be converted.
882
883 **/
884 VOID *
885 PeCoffLoaderImageAddress (
886 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
887 IN UINTN Address,
888 IN UINTN TeStrippedOffset
889 )
890 {
891 //
892 // Make sure that Address and ImageSize is correct for the loaded image.
893 //
894 if (Address >= ImageContext->ImageSize + TeStrippedOffset) {
895 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
896 return NULL;
897 }
898
899 return (CHAR8 *)((UINTN) ImageContext->ImageAddress + Address - TeStrippedOffset);
900 }
901
902 /**
903 Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().
904
905 If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of
906 ImageContext as the relocation base address. Otherwise, use the DestinationAddress field
907 of ImageContext as the relocation base address. The caller must allocate the relocation
908 fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.
909
910 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress,
911 ImageSize, DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders,
912 DebugDirectoryEntryRva, EntryPoint, FixupDataSize, CodeView, PdbPointer, and FixupData of
913 the ImageContext structure must be valid prior to invoking this service.
914
915 If ImageContext is NULL, then ASSERT().
916
917 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
918 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
919 prior to transferring control to a PE/COFF image that is loaded using this library.
920
921 @param ImageContext The pointer to the image context structure that describes the PE/COFF
922 image that is being relocated.
923
924 @retval RETURN_SUCCESS The PE/COFF image was relocated.
925 Extended status information is in the ImageError field of ImageContext.
926 @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image.
927 Extended status information is in the ImageError field of ImageContext.
928 @retval RETURN_UNSUPPORTED A relocation record type is not supported.
929 Extended status information is in the ImageError field of ImageContext.
930
931 **/
932 RETURN_STATUS
933 EFIAPI
934 PeCoffLoaderRelocateImage (
935 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
936 )
937 {
938 RETURN_STATUS Status;
939 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
940 EFI_IMAGE_DATA_DIRECTORY *RelocDir;
941 UINT64 Adjust;
942 EFI_IMAGE_BASE_RELOCATION *RelocBaseOrg;
943 EFI_IMAGE_BASE_RELOCATION *RelocBase;
944 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
945 UINT16 *Reloc;
946 UINT16 *RelocEnd;
947 CHAR8 *Fixup;
948 CHAR8 *FixupBase;
949 UINT16 *Fixup16;
950 UINT32 *Fixup32;
951 UINT64 *Fixup64;
952 CHAR8 *FixupData;
953 PHYSICAL_ADDRESS BaseAddress;
954 UINT32 NumberOfRvaAndSizes;
955 UINT16 Magic;
956 UINT32 TeStrippedOffset;
957
958 ASSERT (ImageContext != NULL);
959
960 //
961 // Assume success
962 //
963 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
964
965 //
966 // If there are no relocation entries, then we are done
967 //
968 if (ImageContext->RelocationsStripped) {
969 // Applies additional environment specific actions to relocate fixups
970 // to a PE/COFF image if needed
971 PeCoffLoaderRelocateImageExtraAction (ImageContext);
972 return RETURN_SUCCESS;
973 }
974
975 //
976 // If the destination address is not 0, use that rather than the
977 // image address as the relocation target.
978 //
979 if (ImageContext->DestinationAddress != 0) {
980 BaseAddress = ImageContext->DestinationAddress;
981 } else {
982 BaseAddress = ImageContext->ImageAddress;
983 }
984
985 if (!(ImageContext->IsTeImage)) {
986 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
987 TeStrippedOffset = 0;
988 Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
989
990 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
991 //
992 // Use PE32 offset
993 //
994 Adjust = (UINT64)BaseAddress - Hdr.Pe32->OptionalHeader.ImageBase;
995 if (Adjust != 0) {
996 Hdr.Pe32->OptionalHeader.ImageBase = (UINT32)BaseAddress;
997 }
998
999 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1000 RelocDir = &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1001 } else {
1002 //
1003 // Use PE32+ offset
1004 //
1005 Adjust = (UINT64) BaseAddress - Hdr.Pe32Plus->OptionalHeader.ImageBase;
1006 if (Adjust != 0) {
1007 Hdr.Pe32Plus->OptionalHeader.ImageBase = (UINT64)BaseAddress;
1008 }
1009
1010 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1011 RelocDir = &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1012 }
1013
1014 //
1015 // Find the relocation block
1016 // Per the PE/COFF spec, you can't assume that a given data directory
1017 // is present in the image. You have to check the NumberOfRvaAndSizes in
1018 // the optional header to verify a desired directory entry is there.
1019 //
1020 if ((NumberOfRvaAndSizes < EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC)) {
1021 RelocDir = NULL;
1022 }
1023 } else {
1024 Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
1025 TeStrippedOffset = (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
1026 Adjust = (UINT64) (BaseAddress - (Hdr.Te->ImageBase + TeStrippedOffset));
1027 if (Adjust != 0) {
1028 Hdr.Te->ImageBase = (UINT64) (BaseAddress - TeStrippedOffset);
1029 }
1030
1031 //
1032 // Find the relocation block
1033 //
1034 RelocDir = &Hdr.Te->DataDirectory[0];
1035 }
1036
1037 if ((RelocDir != NULL) && (RelocDir->Size > 0)) {
1038 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress, TeStrippedOffset);
1039 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) PeCoffLoaderImageAddress (ImageContext,
1040 RelocDir->VirtualAddress + RelocDir->Size - 1,
1041 TeStrippedOffset
1042 );
1043 if (RelocBase == NULL || RelocBaseEnd == NULL || RelocBaseEnd < RelocBase) {
1044 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1045 return RETURN_LOAD_ERROR;
1046 }
1047 } else {
1048 //
1049 // Set base and end to bypass processing below.
1050 //
1051 RelocBase = RelocBaseEnd = NULL;
1052 }
1053 RelocBaseOrg = RelocBase;
1054
1055 //
1056 // If Adjust is not zero, then apply fix ups to the image
1057 //
1058 if (Adjust != 0) {
1059 //
1060 // Run the relocation information and apply the fixups
1061 //
1062 FixupData = ImageContext->FixupData;
1063 while (RelocBase < RelocBaseEnd) {
1064
1065 Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
1066 //
1067 // Add check for RelocBase->SizeOfBlock field.
1068 //
1069 if (RelocBase->SizeOfBlock == 0) {
1070 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1071 return RETURN_LOAD_ERROR;
1072 }
1073 if ((UINTN)RelocBase > MAX_ADDRESS - RelocBase->SizeOfBlock) {
1074 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1075 return RETURN_LOAD_ERROR;
1076 }
1077
1078 RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);
1079 if ((UINTN)RelocEnd > (UINTN)RelocBaseOrg + RelocDir->Size) {
1080 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1081 return RETURN_LOAD_ERROR;
1082 }
1083 FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress, TeStrippedOffset);
1084 if (FixupBase == NULL) {
1085 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1086 return RETURN_LOAD_ERROR;
1087 }
1088
1089 //
1090 // Run this relocation record
1091 //
1092 while (Reloc < RelocEnd) {
1093 Fixup = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress + (*Reloc & 0xFFF), TeStrippedOffset);
1094 if (Fixup == NULL) {
1095 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1096 return RETURN_LOAD_ERROR;
1097 }
1098 switch ((*Reloc) >> 12) {
1099 case EFI_IMAGE_REL_BASED_ABSOLUTE:
1100 break;
1101
1102 case EFI_IMAGE_REL_BASED_HIGH:
1103 Fixup16 = (UINT16 *) Fixup;
1104 *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));
1105 if (FixupData != NULL) {
1106 *(UINT16 *) FixupData = *Fixup16;
1107 FixupData = FixupData + sizeof (UINT16);
1108 }
1109 break;
1110
1111 case EFI_IMAGE_REL_BASED_LOW:
1112 Fixup16 = (UINT16 *) Fixup;
1113 *Fixup16 = (UINT16) (*Fixup16 + (UINT16) Adjust);
1114 if (FixupData != NULL) {
1115 *(UINT16 *) FixupData = *Fixup16;
1116 FixupData = FixupData + sizeof (UINT16);
1117 }
1118 break;
1119
1120 case EFI_IMAGE_REL_BASED_HIGHLOW:
1121 Fixup32 = (UINT32 *) Fixup;
1122 *Fixup32 = *Fixup32 + (UINT32) Adjust;
1123 if (FixupData != NULL) {
1124 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
1125 *(UINT32 *)FixupData = *Fixup32;
1126 FixupData = FixupData + sizeof (UINT32);
1127 }
1128 break;
1129
1130 case EFI_IMAGE_REL_BASED_DIR64:
1131 Fixup64 = (UINT64 *) Fixup;
1132 *Fixup64 = *Fixup64 + (UINT64) Adjust;
1133 if (FixupData != NULL) {
1134 FixupData = ALIGN_POINTER (FixupData, sizeof(UINT64));
1135 *(UINT64 *)(FixupData) = *Fixup64;
1136 FixupData = FixupData + sizeof(UINT64);
1137 }
1138 break;
1139
1140 default:
1141 //
1142 // The common code does not handle some of the stranger IPF relocations
1143 // PeCoffLoaderRelocateImageEx () adds support for these complex fixups
1144 // on IPF and is a No-Op on other architectures.
1145 //
1146 Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
1147 if (RETURN_ERROR (Status)) {
1148 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1149 return Status;
1150 }
1151 }
1152
1153 //
1154 // Next relocation record
1155 //
1156 Reloc += 1;
1157 }
1158
1159 //
1160 // Next reloc block
1161 //
1162 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
1163 }
1164 ASSERT ((UINTN)FixupData <= (UINTN)ImageContext->FixupData + ImageContext->FixupDataSize);
1165
1166 //
1167 // Adjust the EntryPoint to match the linked-to address
1168 //
1169 if (ImageContext->DestinationAddress != 0) {
1170 ImageContext->EntryPoint -= (UINT64) ImageContext->ImageAddress;
1171 ImageContext->EntryPoint += (UINT64) ImageContext->DestinationAddress;
1172 }
1173 }
1174
1175 // Applies additional environment specific actions to relocate fixups
1176 // to a PE/COFF image if needed
1177 PeCoffLoaderRelocateImageExtraAction (ImageContext);
1178
1179 return RETURN_SUCCESS;
1180 }
1181
1182 /**
1183 Loads a PE/COFF image into memory.
1184
1185 Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer
1186 specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate
1187 the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.
1188 The EntryPoint, FixupDataSize, CodeView, PdbPointer and HiiResourceData fields of ImageContext are computed.
1189 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress, ImageSize,
1190 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva
1191 fields of the ImageContext structure must be valid prior to invoking this service.
1192
1193 If ImageContext is NULL, then ASSERT().
1194
1195 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1196 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1197 prior to transferring control to a PE/COFF image that is loaded using this library.
1198
1199 @param ImageContext The pointer to the image context structure that describes the PE/COFF
1200 image that is being loaded.
1201
1202 @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by
1203 the ImageAddress and ImageSize fields of ImageContext.
1204 Extended status information is in the ImageError field of ImageContext.
1205 @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.
1206 Extended status information is in the ImageError field of ImageContext.
1207 @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.
1208 Extended status information is in the ImageError field of ImageContext.
1209 @retval RETURN_INVALID_PARAMETER The image address is invalid.
1210 Extended status information is in the ImageError field of ImageContext.
1211
1212 **/
1213 RETURN_STATUS
1214 EFIAPI
1215 PeCoffLoaderLoadImage (
1216 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1217 )
1218 {
1219 RETURN_STATUS Status;
1220 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1221 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;
1222 EFI_IMAGE_SECTION_HEADER *FirstSection;
1223 EFI_IMAGE_SECTION_HEADER *Section;
1224 UINTN NumberOfSections;
1225 UINTN Index;
1226 CHAR8 *Base;
1227 CHAR8 *End;
1228 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
1229 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
1230 UINTN Size;
1231 UINT32 TempDebugEntryRva;
1232 UINT32 NumberOfRvaAndSizes;
1233 UINT16 Magic;
1234 EFI_IMAGE_RESOURCE_DIRECTORY *ResourceDirectory;
1235 EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceDirectoryEntry;
1236 EFI_IMAGE_RESOURCE_DIRECTORY_STRING *ResourceDirectoryString;
1237 EFI_IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry;
1238 CHAR16 *String;
1239 UINT32 Offset;
1240 UINT32 TeStrippedOffset;
1241
1242 ASSERT (ImageContext != NULL);
1243
1244 //
1245 // Assume success
1246 //
1247 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
1248
1249 //
1250 // Copy the provided context information into our local version, get what we
1251 // can from the original image, and then use that to make sure everything
1252 // is legit.
1253 //
1254 CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
1255
1256 Status = PeCoffLoaderGetImageInfo (&CheckContext);
1257 if (RETURN_ERROR (Status)) {
1258 return Status;
1259 }
1260
1261 //
1262 // Make sure there is enough allocated space for the image being loaded
1263 //
1264 if (ImageContext->ImageSize < CheckContext.ImageSize) {
1265 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;
1266 return RETURN_BUFFER_TOO_SMALL;
1267 }
1268 if (ImageContext->ImageAddress == 0) {
1269 //
1270 // Image cannot be loaded into 0 address.
1271 //
1272 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
1273 return RETURN_INVALID_PARAMETER;
1274 }
1275 //
1276 // If there's no relocations, then make sure it's not a runtime driver,
1277 // and that it's being loaded at the linked address.
1278 //
1279 if (CheckContext.RelocationsStripped) {
1280 //
1281 // If the image does not contain relocations and it is a runtime driver
1282 // then return an error.
1283 //
1284 if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
1285 ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
1286 return RETURN_LOAD_ERROR;
1287 }
1288 //
1289 // If the image does not contain relocations, and the requested load address
1290 // is not the linked address, then return an error.
1291 //
1292 if (CheckContext.ImageAddress != ImageContext->ImageAddress) {
1293 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
1294 return RETURN_INVALID_PARAMETER;
1295 }
1296 }
1297 //
1298 // Make sure the allocated space has the proper section alignment
1299 //
1300 if (!(ImageContext->IsTeImage)) {
1301 if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {
1302 ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;
1303 return RETURN_INVALID_PARAMETER;
1304 }
1305 }
1306 //
1307 // Read the entire PE/COFF or TE header into memory
1308 //
1309 if (!(ImageContext->IsTeImage)) {
1310 Status = ImageContext->ImageRead (
1311 ImageContext->Handle,
1312 0,
1313 &ImageContext->SizeOfHeaders,
1314 (VOID *) (UINTN) ImageContext->ImageAddress
1315 );
1316
1317 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
1318
1319 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
1320 (UINTN)ImageContext->ImageAddress +
1321 ImageContext->PeCoffHeaderOffset +
1322 sizeof(UINT32) +
1323 sizeof(EFI_IMAGE_FILE_HEADER) +
1324 Hdr.Pe32->FileHeader.SizeOfOptionalHeader
1325 );
1326 NumberOfSections = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections);
1327 TeStrippedOffset = 0;
1328 } else {
1329 Status = ImageContext->ImageRead (
1330 ImageContext->Handle,
1331 0,
1332 &ImageContext->SizeOfHeaders,
1333 (void *)(UINTN)ImageContext->ImageAddress
1334 );
1335
1336 Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
1337 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
1338 (UINTN)ImageContext->ImageAddress +
1339 sizeof(EFI_TE_IMAGE_HEADER)
1340 );
1341 NumberOfSections = (UINTN) (Hdr.Te->NumberOfSections);
1342 TeStrippedOffset = (UINT32) Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
1343 }
1344
1345 if (RETURN_ERROR (Status)) {
1346 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1347 return RETURN_LOAD_ERROR;
1348 }
1349
1350 //
1351 // Load each section of the image
1352 //
1353 Section = FirstSection;
1354 for (Index = 0; Index < NumberOfSections; Index++) {
1355 //
1356 // Read the section
1357 //
1358 Size = (UINTN) Section->Misc.VirtualSize;
1359 if ((Size == 0) || (Size > Section->SizeOfRawData)) {
1360 Size = (UINTN) Section->SizeOfRawData;
1361 }
1362
1363 //
1364 // Compute sections address
1365 //
1366 Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress, TeStrippedOffset);
1367 End = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress + Section->Misc.VirtualSize - 1, TeStrippedOffset);
1368
1369 //
1370 // If the size of the section is non-zero and the base address or end address resolved to 0, then fail.
1371 //
1372 if ((Size > 0) && ((Base == NULL) || (End == NULL))) {
1373 ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;
1374 return RETURN_LOAD_ERROR;
1375 }
1376
1377 if (Section->SizeOfRawData > 0) {
1378 Status = ImageContext->ImageRead (
1379 ImageContext->Handle,
1380 Section->PointerToRawData - TeStrippedOffset,
1381 &Size,
1382 Base
1383 );
1384 if (RETURN_ERROR (Status)) {
1385 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1386 return Status;
1387 }
1388 }
1389
1390 //
1391 // If raw size is less then virtual size, zero fill the remaining
1392 //
1393
1394 if (Size < Section->Misc.VirtualSize) {
1395 ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);
1396 }
1397
1398 //
1399 // Next Section
1400 //
1401 Section += 1;
1402 }
1403
1404 //
1405 // Get image's entry point
1406 //
1407 Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
1408 if (!(ImageContext->IsTeImage)) {
1409 //
1410 // Sizes of AddressOfEntryPoint are different so we need to do this safely
1411 //
1412 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1413 //
1414 // Use PE32 offset
1415 //
1416 ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
1417 ImageContext,
1418 (UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint,
1419 0
1420 );
1421 } else {
1422 //
1423 // Use PE32+ offset
1424 //
1425 ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
1426 ImageContext,
1427 (UINTN)Hdr.Pe32Plus->OptionalHeader.AddressOfEntryPoint,
1428 0
1429 );
1430 }
1431 } else {
1432 ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
1433 ImageContext,
1434 (UINTN)Hdr.Te->AddressOfEntryPoint,
1435 TeStrippedOffset
1436 );
1437 }
1438
1439 //
1440 // Determine the size of the fixup data
1441 //
1442 // Per the PE/COFF spec, you can't assume that a given data directory
1443 // is present in the image. You have to check the NumberOfRvaAndSizes in
1444 // the optional header to verify a desired directory entry is there.
1445 //
1446 if (!(ImageContext->IsTeImage)) {
1447 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1448 //
1449 // Use PE32 offset
1450 //
1451 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1452 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1453 } else {
1454 //
1455 // Use PE32+ offset
1456 //
1457 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1458 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1459 }
1460
1461 //
1462 // Must use UINT64 here, because there might a case that 32bit loader to load 64bit image.
1463 //
1464 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1465 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINT64);
1466 } else {
1467 ImageContext->FixupDataSize = 0;
1468 }
1469 } else {
1470 DirectoryEntry = &Hdr.Te->DataDirectory[0];
1471 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINT64);
1472 }
1473 //
1474 // Consumer must allocate a buffer for the relocation fixup log.
1475 // Only used for runtime drivers.
1476 //
1477 ImageContext->FixupData = NULL;
1478
1479 //
1480 // Load the Codeview information if present
1481 //
1482 if (ImageContext->DebugDirectoryEntryRva != 0) {
1483 DebugEntry = PeCoffLoaderImageAddress (
1484 ImageContext,
1485 ImageContext->DebugDirectoryEntryRva,
1486 TeStrippedOffset
1487 );
1488 if (DebugEntry == NULL) {
1489 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1490 return RETURN_LOAD_ERROR;
1491 }
1492
1493 TempDebugEntryRva = DebugEntry->RVA;
1494 if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {
1495 Section--;
1496 if ((UINTN)Section->SizeOfRawData < Section->Misc.VirtualSize) {
1497 TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;
1498 } else {
1499 TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;
1500 }
1501 }
1502
1503 if (TempDebugEntryRva != 0) {
1504 ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva, TeStrippedOffset);
1505 if (ImageContext->CodeView == NULL) {
1506 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1507 return RETURN_LOAD_ERROR;
1508 }
1509
1510 if (DebugEntry->RVA == 0) {
1511 Size = DebugEntry->SizeOfData;
1512 Status = ImageContext->ImageRead (
1513 ImageContext->Handle,
1514 DebugEntry->FileOffset - TeStrippedOffset,
1515 &Size,
1516 ImageContext->CodeView
1517 );
1518 //
1519 // Should we apply fix up to this field according to the size difference between PE and TE?
1520 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1521 // in original PE image.
1522 //
1523
1524 if (RETURN_ERROR (Status)) {
1525 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1526 return RETURN_LOAD_ERROR;
1527 }
1528
1529 DebugEntry->RVA = TempDebugEntryRva;
1530 }
1531
1532 switch (*(UINT32 *) ImageContext->CodeView) {
1533 case CODEVIEW_SIGNATURE_NB10:
1534 if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)) {
1535 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1536 return RETURN_UNSUPPORTED;
1537 }
1538 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
1539 break;
1540
1541 case CODEVIEW_SIGNATURE_RSDS:
1542 if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY)) {
1543 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1544 return RETURN_UNSUPPORTED;
1545 }
1546 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
1547 break;
1548
1549 case CODEVIEW_SIGNATURE_MTOC:
1550 if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY)) {
1551 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1552 return RETURN_UNSUPPORTED;
1553 }
1554 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);
1555 break;
1556
1557 default:
1558 break;
1559 }
1560 }
1561 }
1562
1563 //
1564 // Get Image's HII resource section
1565 //
1566 ImageContext->HiiResourceData = 0;
1567 if (!(ImageContext->IsTeImage)) {
1568 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1569 //
1570 // Use PE32 offset
1571 //
1572 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1573 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
1574 } else {
1575 //
1576 // Use PE32+ offset
1577 //
1578 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1579 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
1580 }
1581
1582 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE && DirectoryEntry->Size != 0) {
1583 Base = PeCoffLoaderImageAddress (ImageContext, DirectoryEntry->VirtualAddress, 0);
1584 if (Base != NULL) {
1585 ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) Base;
1586 Offset = sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) *
1587 (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
1588 if (Offset > DirectoryEntry->Size) {
1589 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1590 return RETURN_UNSUPPORTED;
1591 }
1592 ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);
1593
1594 for (Index = 0; Index < ResourceDirectory->NumberOfNamedEntries; Index++) {
1595 if (ResourceDirectoryEntry->u1.s.NameIsString) {
1596 //
1597 // Check the ResourceDirectoryEntry->u1.s.NameOffset before use it.
1598 //
1599 if (ResourceDirectoryEntry->u1.s.NameOffset >= DirectoryEntry->Size) {
1600 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1601 return RETURN_UNSUPPORTED;
1602 }
1603 ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (Base + ResourceDirectoryEntry->u1.s.NameOffset);
1604 String = &ResourceDirectoryString->String[0];
1605
1606 if (ResourceDirectoryString->Length == 3 &&
1607 String[0] == L'H' &&
1608 String[1] == L'I' &&
1609 String[2] == L'I') {
1610 //
1611 // Resource Type "HII" found
1612 //
1613 if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
1614 //
1615 // Move to next level - resource Name
1616 //
1617 if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {
1618 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1619 return RETURN_UNSUPPORTED;
1620 }
1621 ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);
1622 Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) +
1623 sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
1624 if (Offset > DirectoryEntry->Size) {
1625 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1626 return RETURN_UNSUPPORTED;
1627 }
1628 ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);
1629
1630 if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
1631 //
1632 // Move to next level - resource Language
1633 //
1634 if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {
1635 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1636 return RETURN_UNSUPPORTED;
1637 }
1638 ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);
1639 Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) +
1640 sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
1641 if (Offset > DirectoryEntry->Size) {
1642 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1643 return RETURN_UNSUPPORTED;
1644 }
1645 ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);
1646 }
1647 }
1648
1649 //
1650 // Now it ought to be resource Data
1651 //
1652 if (!ResourceDirectoryEntry->u2.s.DataIsDirectory) {
1653 if (ResourceDirectoryEntry->u2.OffsetToData >= DirectoryEntry->Size) {
1654 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1655 return RETURN_UNSUPPORTED;
1656 }
1657 ResourceDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *) (Base + ResourceDirectoryEntry->u2.OffsetToData);
1658 ImageContext->HiiResourceData = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (ImageContext, ResourceDataEntry->OffsetToData, 0);
1659 break;
1660 }
1661 }
1662 }
1663 ResourceDirectoryEntry++;
1664 }
1665 }
1666 }
1667 }
1668
1669 return Status;
1670 }
1671
1672
1673 /**
1674 Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI
1675 runtime.
1676
1677 This function reapplies relocation fixups to the PE/COFF image specified by ImageBase
1678 and ImageSize so the image will execute correctly when the PE/COFF image is mapped
1679 to the address specified by VirtualImageBase. RelocationData must be identical
1680 to the FiuxupData buffer from the PE_COFF_LOADER_IMAGE_CONTEXT structure
1681 after this PE/COFF image was relocated with PeCoffLoaderRelocateImage().
1682
1683 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1684 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1685 prior to transferring control to a PE/COFF image that is loaded using this library.
1686
1687 @param ImageBase The base address of a PE/COFF image that has been loaded
1688 and relocated into system memory.
1689 @param VirtImageBase The request virtual address that the PE/COFF image is to
1690 be fixed up for.
1691 @param ImageSize The size, in bytes, of the PE/COFF image.
1692 @param RelocationData A pointer to the relocation data that was collected when the PE/COFF
1693 image was relocated using PeCoffLoaderRelocateImage().
1694
1695 **/
1696 VOID
1697 EFIAPI
1698 PeCoffLoaderRelocateImageForRuntime (
1699 IN PHYSICAL_ADDRESS ImageBase,
1700 IN PHYSICAL_ADDRESS VirtImageBase,
1701 IN UINTN ImageSize,
1702 IN VOID *RelocationData
1703 )
1704 {
1705 CHAR8 *OldBase;
1706 CHAR8 *NewBase;
1707 EFI_IMAGE_DOS_HEADER *DosHdr;
1708 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1709 UINT32 NumberOfRvaAndSizes;
1710 EFI_IMAGE_DATA_DIRECTORY *DataDirectory;
1711 EFI_IMAGE_DATA_DIRECTORY *RelocDir;
1712 EFI_IMAGE_BASE_RELOCATION *RelocBase;
1713 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
1714 UINT16 *Reloc;
1715 UINT16 *RelocEnd;
1716 CHAR8 *Fixup;
1717 CHAR8 *FixupBase;
1718 UINT16 *Fixup16;
1719 UINT32 *Fixup32;
1720 UINT64 *Fixup64;
1721 CHAR8 *FixupData;
1722 UINTN Adjust;
1723 RETURN_STATUS Status;
1724 UINT16 Magic;
1725
1726 OldBase = (CHAR8 *)((UINTN)ImageBase);
1727 NewBase = (CHAR8 *)((UINTN)VirtImageBase);
1728 Adjust = (UINTN) NewBase - (UINTN) OldBase;
1729
1730 //
1731 // Find the image's relocate dir info
1732 //
1733 DosHdr = (EFI_IMAGE_DOS_HEADER *)OldBase;
1734 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
1735 //
1736 // Valid DOS header so get address of PE header
1737 //
1738 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(((CHAR8 *)DosHdr) + DosHdr->e_lfanew);
1739 } else {
1740 //
1741 // No Dos header so assume image starts with PE header.
1742 //
1743 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)OldBase;
1744 }
1745
1746 if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
1747 //
1748 // Not a valid PE image so Exit
1749 //
1750 return ;
1751 }
1752
1753 Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
1754
1755 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1756 //
1757 // Use PE32 offset
1758 //
1759 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1760 DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[0]);
1761 } else {
1762 //
1763 // Use PE32+ offset
1764 //
1765 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1766 DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[0]);
1767 }
1768
1769 //
1770 // Find the relocation block
1771 //
1772 // Per the PE/COFF spec, you can't assume that a given data directory
1773 // is present in the image. You have to check the NumberOfRvaAndSizes in
1774 // the optional header to verify a desired directory entry is there.
1775 //
1776 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1777 RelocDir = DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;
1778 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress);
1779 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress + RelocDir->Size);
1780 } else {
1781 //
1782 // Cannot find relocations, cannot continue to relocate the image, ASSERT for this invalid image.
1783 //
1784 ASSERT (FALSE);
1785 return ;
1786 }
1787
1788 //
1789 // ASSERT for the invalid image when RelocBase and RelocBaseEnd are both NULL.
1790 //
1791 ASSERT (RelocBase != NULL && RelocBaseEnd != NULL);
1792
1793 //
1794 // Run the whole relocation block. And re-fixup data that has not been
1795 // modified. The FixupData is used to see if the image has been modified
1796 // since it was relocated. This is so data sections that have been updated
1797 // by code will not be fixed up, since that would set them back to
1798 // defaults.
1799 //
1800 FixupData = RelocationData;
1801 while (RelocBase < RelocBaseEnd) {
1802 //
1803 // Add check for RelocBase->SizeOfBlock field.
1804 //
1805 if ((RelocBase->SizeOfBlock == 0) || (RelocBase->SizeOfBlock > RelocDir->Size)) {
1806 //
1807 // Data invalid, cannot continue to relocate the image, just return.
1808 //
1809 return;
1810 }
1811
1812 Reloc = (UINT16 *) ((UINT8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
1813 RelocEnd = (UINT16 *) ((UINT8 *) RelocBase + RelocBase->SizeOfBlock);
1814 FixupBase = (CHAR8 *) ((UINTN)ImageBase) + RelocBase->VirtualAddress;
1815
1816 //
1817 // Run this relocation record
1818 //
1819 while (Reloc < RelocEnd) {
1820
1821 Fixup = FixupBase + (*Reloc & 0xFFF);
1822 switch ((*Reloc) >> 12) {
1823
1824 case EFI_IMAGE_REL_BASED_ABSOLUTE:
1825 break;
1826
1827 case EFI_IMAGE_REL_BASED_HIGH:
1828 Fixup16 = (UINT16 *) Fixup;
1829 if (*(UINT16 *) FixupData == *Fixup16) {
1830 *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));
1831 }
1832
1833 FixupData = FixupData + sizeof (UINT16);
1834 break;
1835
1836 case EFI_IMAGE_REL_BASED_LOW:
1837 Fixup16 = (UINT16 *) Fixup;
1838 if (*(UINT16 *) FixupData == *Fixup16) {
1839 *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) Adjust & 0xffff));
1840 }
1841
1842 FixupData = FixupData + sizeof (UINT16);
1843 break;
1844
1845 case EFI_IMAGE_REL_BASED_HIGHLOW:
1846 Fixup32 = (UINT32 *) Fixup;
1847 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
1848 if (*(UINT32 *) FixupData == *Fixup32) {
1849 *Fixup32 = *Fixup32 + (UINT32) Adjust;
1850 }
1851
1852 FixupData = FixupData + sizeof (UINT32);
1853 break;
1854
1855 case EFI_IMAGE_REL_BASED_DIR64:
1856 Fixup64 = (UINT64 *)Fixup;
1857 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));
1858 if (*(UINT64 *) FixupData == *Fixup64) {
1859 *Fixup64 = *Fixup64 + (UINT64)Adjust;
1860 }
1861
1862 FixupData = FixupData + sizeof (UINT64);
1863 break;
1864
1865 default:
1866 //
1867 // Only Itanium requires ConvertPeImage_Ex
1868 //
1869 Status = PeHotRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
1870 if (RETURN_ERROR (Status)) {
1871 return ;
1872 }
1873 }
1874 //
1875 // Next relocation record
1876 //
1877 Reloc += 1;
1878 }
1879 //
1880 // next reloc block
1881 //
1882 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
1883 }
1884 }
1885
1886
1887 /**
1888 Reads contents of a PE/COFF image from a buffer in system memory.
1889
1890 This is the default implementation of a PE_COFF_LOADER_READ_FILE function
1891 that assumes FileHandle pointer to the beginning of a PE/COFF image.
1892 This function reads contents of the PE/COFF image that starts at the system memory
1893 address specified by FileHandle. The read operation copies ReadSize bytes from the
1894 PE/COFF image starting at byte offset FileOffset into the buffer specified by Buffer.
1895 The size of the buffer actually read is returned in ReadSize.
1896
1897 The caller must make sure the FileOffset and ReadSize within the file scope.
1898
1899 If FileHandle is NULL, then ASSERT().
1900 If ReadSize is NULL, then ASSERT().
1901 If Buffer is NULL, then ASSERT().
1902
1903 @param FileHandle The pointer to base of the input stream
1904 @param FileOffset Offset into the PE/COFF image to begin the read operation.
1905 @param ReadSize On input, the size in bytes of the requested read operation.
1906 On output, the number of bytes actually read.
1907 @param Buffer Output buffer that contains the data read from the PE/COFF image.
1908
1909 @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into
1910 the buffer.
1911 **/
1912 RETURN_STATUS
1913 EFIAPI
1914 PeCoffLoaderImageReadFromMemory (
1915 IN VOID *FileHandle,
1916 IN UINTN FileOffset,
1917 IN OUT UINTN *ReadSize,
1918 OUT VOID *Buffer
1919 )
1920 {
1921 ASSERT (ReadSize != NULL);
1922 ASSERT (FileHandle != NULL);
1923 ASSERT (Buffer != NULL);
1924
1925 CopyMem (Buffer, ((UINT8 *)FileHandle) + FileOffset, *ReadSize);
1926 return RETURN_SUCCESS;
1927 }
1928
1929 /**
1930 Unloads a loaded PE/COFF image from memory and releases its taken resource.
1931 Releases any environment specific resources that were allocated when the image
1932 specified by ImageContext was loaded using PeCoffLoaderLoadImage().
1933
1934 For NT32 emulator, the PE/COFF image loaded by system needs to release.
1935 For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded,
1936 this function can simply return RETURN_SUCCESS.
1937
1938 If ImageContext is NULL, then ASSERT().
1939
1940 @param ImageContext The pointer to the image context structure that describes the PE/COFF
1941 image to be unloaded.
1942
1943 @retval RETURN_SUCCESS The PE/COFF image was unloaded successfully.
1944 **/
1945 RETURN_STATUS
1946 EFIAPI
1947 PeCoffLoaderUnloadImage (
1948 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1949 )
1950 {
1951 //
1952 // Applies additional environment specific actions to unload a
1953 // PE/COFF image if needed
1954 //
1955 PeCoffLoaderUnloadImageExtraAction (ImageContext);
1956 return RETURN_SUCCESS;
1957 }