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