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