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