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