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