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