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