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