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