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