]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/FMMT/Rebase.c
BaseTools/FMMT: Add a tool FMMT
[mirror_edk2.git] / BaseTools / Source / C / FMMT / Rebase.c
CommitLineData
080981d7
SZ
1/** @file\r
2\r
3 Library to rebase PE image.\r
4\r
5Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
6SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8**/\r
9\r
10#include "Rebase.h"\r
11#include <stdio.h>\r
12#include <stdlib.h>\r
13#ifdef __GNUC__\r
14#include <unistd.h>\r
15#else\r
16#include <io.h>\r
17#include <direct.h>\r
18#endif\r
19#include <PeCoffLib.h>\r
20#include <CommonLib.h>\r
21#include <IndustryStandard/PeImage.h>\r
22#include <FvLib.h>\r
23#include "EfiUtilityMsgs.h"\r
24\r
25static\r
26EFI_STATUS\r
27FfsRebaseImageRead(\r
28IN VOID *FileHandle,\r
29IN UINTN FileOffset,\r
30IN OUT UINT32 *ReadSize,\r
31OUT VOID *Buffer\r
32);\r
33\r
34EFI_STATUS\r
35RebaseFfs(\r
36IN OUT UINT64 BaseAddress,\r
37IN CHAR8 *FileName,\r
38IN OUT EFI_FFS_FILE_HEADER *FfsFile,\r
39IN UINTN XipOffset\r
40)\r
41/*++\r
42\r
43Routine Description:\r
44\r
45This function determines if a file is XIP and should be rebased. It will\r
46rebase any PE32 sections found in the file using the base address.\r
47\r
48Arguments:\r
49\r
50FvInfo A pointer to FV_INFO struture.\r
51FileName Ffs File PathName\r
52FfsFile A pointer to Ffs file image.\r
53XipOffset The offset address to use for rebasing the XIP file image.\r
54\r
55Returns:\r
56\r
57EFI_SUCCESS The image was properly rebased.\r
58EFI_INVALID_PARAMETER An input parameter is invalid.\r
59EFI_ABORTED An error occurred while rebasing the input file image.\r
60EFI_OUT_OF_RESOURCES Could not allocate a required resource.\r
61EFI_NOT_FOUND No compressed sections could be found.\r
62\r
63--*/\r
64{\r
65 EFI_STATUS Status;\r
66 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
67 PE_COFF_LOADER_IMAGE_CONTEXT OrigImageContext;\r
68 EFI_PHYSICAL_ADDRESS XipBase;\r
69 EFI_PHYSICAL_ADDRESS NewPe32BaseAddress;\r
70 UINTN Index;\r
71 EFI_FILE_SECTION_POINTER CurrentPe32Section;\r
72 EFI_FFS_FILE_STATE SavedState;\r
73 EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;\r
74 EFI_TE_IMAGE_HEADER *TEImageHeader;\r
75 UINT8 *MemoryImagePointer;\r
76 EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
77 CHAR8 PeFileName[MAX_LONG_FILE_PATH];\r
78 CHAR8 *Cptr;\r
79 FILE *PeFile;\r
80 UINT8 *PeFileBuffer;\r
81 UINT32 PeFileSize;\r
82 CHAR8 *PdbPointer;\r
83 UINT32 FfsHeaderSize;\r
84 UINT32 CurSecHdrSize;\r
85 CHAR8 *LongFilePathName;\r
86\r
87 Index = 0;\r
88 MemoryImagePointer = NULL;\r
89 TEImageHeader = NULL;\r
90 ImgHdr = NULL;\r
91 SectionHeader = NULL;\r
92 Cptr = NULL;\r
93 PeFile = NULL;\r
94 PeFileBuffer = NULL;\r
95\r
96 //\r
97 // Don't need to relocate image when BaseAddress is zero and no ForceRebase Flag specified.\r
98 //\r
99 if (BaseAddress == 0) {\r
100 return EFI_SUCCESS;\r
101 }\r
102\r
103 XipBase = BaseAddress + XipOffset;\r
104\r
105 //\r
106 // We only process files potentially containing PE32 sections.\r
107 //\r
108 switch (FfsFile->Type) {\r
109 case EFI_FV_FILETYPE_SECURITY_CORE:\r
110 case EFI_FV_FILETYPE_PEI_CORE:\r
111 case EFI_FV_FILETYPE_PEIM:\r
112 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
113 case EFI_FV_FILETYPE_DRIVER:\r
114 case EFI_FV_FILETYPE_DXE_CORE:\r
115 break;\r
116 case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:\r
117 //\r
118 // Rebase the inside FvImage.\r
119 //\r
120 GetChildFvFromFfs (BaseAddress, FfsFile, XipOffset);\r
121\r
122 //\r
123 // Search PE/TE section in FV sectin.\r
124 //\r
125 break;\r
126 default:\r
127 return EFI_SUCCESS;\r
128 }\r
129\r
130 FfsHeaderSize = GetFfsHeaderLength(FfsFile);\r
131 //\r
132 // Rebase each PE32 section\r
133 //\r
134 Status = EFI_SUCCESS;\r
135 for (Index = 1;; Index++) {\r
136 //\r
137 // Init Value\r
138 //\r
139 NewPe32BaseAddress = 0;\r
140\r
141 //\r
142 // Find Pe Image\r
143 //\r
144 Status = GetSectionByType(FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);\r
145 if (EFI_ERROR(Status)) {\r
146 break;\r
147 }\r
148 CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader);\r
149\r
150 //\r
151 // Initialize context\r
152 //\r
153 memset(&ImageContext, 0, sizeof (ImageContext));\r
154 ImageContext.Handle = (VOID *)((UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize);\r
155 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)FfsRebaseImageRead;\r
156 Status = PeCoffLoaderGetImageInfo(&ImageContext);\r
157 if (EFI_ERROR(Status)) {\r
158 Error(NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int)Status);\r
159 return Status;\r
160 }\r
161\r
162 //if ((ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) ||\r
163 // (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64)) {\r
164 // mArm = TRUE;\r
165 //}\r
166\r
167 //\r
168 // Keep Image Context for PE image in FV\r
169 //\r
170 memcpy(&OrigImageContext, &ImageContext, sizeof (ImageContext));\r
171\r
172 //\r
173 // Get File PdbPointer\r
174 //\r
175 PdbPointer = PeCoffLoaderGetPdbPointer(ImageContext.Handle);\r
176 if (PdbPointer == NULL) {\r
177 PdbPointer = FileName;\r
178 }\r
179\r
180 //\r
181 // Get PeHeader pointer\r
182 //\r
183 ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize + ImageContext.PeCoffHeaderOffset);\r
184\r
185 //\r
186 // Calculate the PE32 base address, based on file type\r
187 //\r
188 switch (FfsFile->Type) {\r
189 case EFI_FV_FILETYPE_SECURITY_CORE:\r
190 case EFI_FV_FILETYPE_PEI_CORE:\r
191 case EFI_FV_FILETYPE_PEIM:\r
192 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
193 //\r
194 // Check if section-alignment and file-alignment match or not\r
195 //\r
196 if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {\r
197 //\r
198 // Xip module has the same section alignment and file alignment.\r
199 //\r
200 Error(NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);\r
201 return EFI_ABORTED;\r
202 }\r
203 //\r
204 // PeImage has no reloc section. It will try to get reloc data from the original EFI image.\r
205 //\r
206 if (ImageContext.RelocationsStripped) {\r
207 //\r
208 // Construct the original efi file Name\r
209 //\r
210 if (strlen (FileName) > MAX_LONG_FILE_PATH - 1) {\r
211 Error(NULL, 0, 3000, "Invalid", "The file name for %s is too long.", FileName);\r
212 return EFI_ABORTED;\r
213 }\r
214 strncpy(PeFileName, FileName, MAX_LONG_FILE_PATH - 1);\r
215 PeFileName[MAX_LONG_FILE_PATH - 1] = 0;\r
216 Cptr = PeFileName + strlen(PeFileName);\r
217 while (*Cptr != '.') {\r
218 Cptr--;\r
219 }\r
220 if (*Cptr != '.') {\r
221 Error(NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
222 return EFI_ABORTED;\r
223 }\r
224 else {\r
225 *(Cptr + 1) = 'e';\r
226 *(Cptr + 2) = 'f';\r
227 *(Cptr + 3) = 'i';\r
228 *(Cptr + 4) = '\0';\r
229 }\r
230 LongFilePathName = LongFilePath(PeFileName);\r
231 if (LongFilePathName == NULL) {\r
232 Error(NULL, 0, 3000, "Invalid", "Fail to get long file path for file %s.", FileName);\r
233 return EFI_ABORTED;\r
234 }\r
235 PeFile = fopen(LongFilePathName, "rb");\r
236 if (PeFile == NULL) {\r
237 Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);\r
238 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
239 //return EFI_ABORTED;\r
240 break;\r
241 }\r
242 //\r
243 // Get the file size\r
244 //\r
245 PeFileSize = _filelength(fileno(PeFile));\r
246 PeFileBuffer = (UINT8 *)malloc(PeFileSize);\r
247 if (PeFileBuffer == NULL) {\r
248 Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
249 fclose(PeFile);\r
250 return EFI_OUT_OF_RESOURCES;\r
251 }\r
252 //\r
253 // Read Pe File\r
254 //\r
255 fread(PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);\r
256 //\r
257 // close file\r
258 //\r
259 fclose(PeFile);\r
260 //\r
261 // Handle pointer to the original efi image.\r
262 //\r
263 ImageContext.Handle = PeFileBuffer;\r
264 Status = PeCoffLoaderGetImageInfo(&ImageContext);\r
265 if (EFI_ERROR(Status)) {\r
266 Error(NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int)Status);\r
267 return Status;\r
268 }\r
269 ImageContext.RelocationsStripped = FALSE;\r
270 }\r
271\r
272 NewPe32BaseAddress = XipBase + (UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile;\r
273 break;\r
274\r
275 case EFI_FV_FILETYPE_DRIVER:\r
276 case EFI_FV_FILETYPE_DXE_CORE:\r
277 //\r
278 // Check if section-alignment and file-alignment match or not\r
279 //\r
280 if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {\r
281 //\r
282 // Xip module has the same section alignment and file alignment.\r
283 //\r
284 Error(NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);\r
285 return EFI_ABORTED;\r
286 }\r
287 NewPe32BaseAddress = XipBase + (UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile;\r
288 break;\r
289\r
290 default:\r
291 //\r
292 // Not supported file type\r
293 //\r
294 return EFI_SUCCESS;\r
295 }\r
296\r
297 //\r
298 // Relocation doesn't exist\r
299 //\r
300 if (ImageContext.RelocationsStripped) {\r
301 Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);\r
302 continue;\r
303 }\r
304\r
305 //\r
306 // Relocation exist and rebase\r
307 //\r
308 //\r
309 // Load and Relocate Image Data\r
310 //\r
311 MemoryImagePointer = (UINT8 *)malloc((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);\r
312 if (MemoryImagePointer == NULL) {\r
313 Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
314 return EFI_OUT_OF_RESOURCES;\r
315 }\r
316 memset((VOID *)MemoryImagePointer, 0, (UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);\r
317 ImageContext.ImageAddress = ((UINTN)MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN)ImageContext.SectionAlignment - 1));\r
318\r
319 Status = PeCoffLoaderLoadImage(&ImageContext);\r
320 if (EFI_ERROR(Status)) {\r
321 Error(NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);\r
322 free((VOID *)MemoryImagePointer);\r
323 return Status;\r
324 }\r
325\r
326 ImageContext.DestinationAddress = NewPe32BaseAddress;\r
327 Status = PeCoffLoaderRelocateImage(&ImageContext);\r
328 if (EFI_ERROR(Status)) {\r
329 Error(NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName);\r
330 free((VOID *)MemoryImagePointer);\r
331 return Status;\r
332 }\r
333\r
334 //\r
335 // Copy Relocated data to raw image file.\r
336 //\r
337 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(\r
338 (UINTN)ImgHdr +\r
339 sizeof (UINT32)+\r
340 sizeof (EFI_IMAGE_FILE_HEADER)+\r
341 ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader\r
342 );\r
343\r
344 for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
345 CopyMem(\r
346 (UINT8 *)CurrentPe32Section.Pe32Section + CurSecHdrSize + SectionHeader->PointerToRawData,\r
347 (VOID*)(UINTN)(ImageContext.ImageAddress + SectionHeader->VirtualAddress),\r
348 SectionHeader->SizeOfRawData\r
349 );\r
350 }\r
351\r
352 free((VOID *)MemoryImagePointer);\r
353 MemoryImagePointer = NULL;\r
354 if (PeFileBuffer != NULL) {\r
355 free(PeFileBuffer);\r
356 PeFileBuffer = NULL;\r
357 }\r
358\r
359 //\r
360 // Update Image Base Address\r
361 //\r
362 if (ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
363 ImgHdr->Pe32.OptionalHeader.ImageBase = (UINT32)NewPe32BaseAddress;\r
364 }\r
365 else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
366 ImgHdr->Pe32Plus.OptionalHeader.ImageBase = NewPe32BaseAddress;\r
367 }\r
368 else {\r
369 Error(NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",\r
370 ImgHdr->Pe32.OptionalHeader.Magic,\r
371 FileName\r
372 );\r
373 return EFI_ABORTED;\r
374 }\r
375\r
376 //\r
377 // Now update file checksum\r
378 //\r
379 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
380 SavedState = FfsFile->State;\r
381 FfsFile->IntegrityCheck.Checksum.File = 0;\r
382 FfsFile->State = 0;\r
383 FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8(\r
384 (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize),\r
385 GetFfsFileLength(FfsFile) - FfsHeaderSize\r
386 );\r
387 FfsFile->State = SavedState;\r
388 }\r
389\r
390 }\r
391\r
392 if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&\r
393 FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&\r
394 FfsFile->Type != EFI_FV_FILETYPE_PEIM &&\r
395 FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER &&\r
396 FfsFile->Type != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE\r
397 ) {\r
398 //\r
399 // Only Peim code may have a TE section\r
400 //\r
401 return EFI_SUCCESS;\r
402 }\r
403\r
404 //\r
405 // Now process TE sections\r
406 //\r
407 for (Index = 1;; Index++) {\r
408 NewPe32BaseAddress = 0;\r
409\r
410 //\r
411 // Find Te Image\r
412 //\r
413 Status = GetSectionByType(FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);\r
414 if (EFI_ERROR(Status)) {\r
415 break;\r
416 }\r
417\r
418 CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader);\r
419\r
420 //\r
421 // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off\r
422 // by GenTEImage\r
423 //\r
424 TEImageHeader = (EFI_TE_IMAGE_HEADER *)((UINT8 *)CurrentPe32Section.Pe32Section + CurSecHdrSize);\r
425\r
426 //\r
427 // Initialize context, load image info.\r
428 //\r
429 memset(&ImageContext, 0, sizeof (ImageContext));\r
430 ImageContext.Handle = (VOID *)TEImageHeader;\r
431 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)FfsRebaseImageRead;\r
432 Status = PeCoffLoaderGetImageInfo(&ImageContext);\r
433 if (EFI_ERROR(Status)) {\r
434 Error(NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int)Status);\r
435 return Status;\r
436 }\r
437\r
438 //if ((ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) ||\r
439 // (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64)) {\r
440 // mArm = TRUE;\r
441 //}\r
442\r
443 //\r
444 // Keep Image Context for TE image in FV\r
445 //\r
446 memcpy(&OrigImageContext, &ImageContext, sizeof (ImageContext));\r
447\r
448 //\r
449 // Get File PdbPointer\r
450 //\r
451 PdbPointer = PeCoffLoaderGetPdbPointer(ImageContext.Handle);\r
452 if (PdbPointer == NULL) {\r
453 PdbPointer = FileName;\r
454 }\r
455 //\r
456 // Set new rebased address.\r
457 //\r
458 NewPe32BaseAddress = XipBase + (UINTN)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \\r
459 - TEImageHeader->StrippedSize - (UINTN)FfsFile;\r
460\r
461 //\r
462 // if reloc is stripped, try to get the original efi image to get reloc info.\r
463 //\r
464 if (ImageContext.RelocationsStripped) {\r
465 //\r
466 // Construct the original efi file name\r
467 //\r
468 if (strlen (FileName) > MAX_LONG_FILE_PATH - 1) {\r
469 Error(NULL, 0, 3000, "Invalid", "The file name for %s is too long.", FileName);\r
470 return EFI_ABORTED;\r
471 }\r
472 strncpy(PeFileName, FileName, MAX_LONG_FILE_PATH - 1);\r
473 PeFileName[MAX_LONG_FILE_PATH - 1] = 0;\r
474 Cptr = PeFileName + strlen(PeFileName);\r
475 while (*Cptr != '.') {\r
476 Cptr--;\r
477 }\r
478\r
479 if (*Cptr != '.') {\r
480 Error(NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
481 return EFI_ABORTED;\r
482 }\r
483 else {\r
484 *(Cptr + 1) = 'e';\r
485 *(Cptr + 2) = 'f';\r
486 *(Cptr + 3) = 'i';\r
487 *(Cptr + 4) = '\0';\r
488 }\r
489\r
490 LongFilePathName = LongFilePath(PeFileName);\r
491 if (LongFilePathName == NULL) {\r
492 Error(NULL, 0, 3000, "Invalid", "Fail to get long file path for file %s.", FileName);\r
493 return EFI_ABORTED;\r
494 }\r
495 PeFile = fopen(LongFilePathName, "rb");\r
496 if (PeFile == NULL) {\r
497 Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);\r
498 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
499 //return EFI_ABORTED;\r
500 }\r
501 else {\r
502 //\r
503 // Get the file size\r
504 //\r
505 PeFileSize = _filelength(fileno(PeFile));\r
506 PeFileBuffer = (UINT8 *)malloc(PeFileSize);\r
507 if (PeFileBuffer == NULL) {\r
508 Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
509 fclose(PeFile);\r
510 return EFI_OUT_OF_RESOURCES;\r
511 }\r
512 //\r
513 // Read Pe File\r
514 //\r
515 fread(PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);\r
516 //\r
517 // close file\r
518 //\r
519 fclose(PeFile);\r
520 //\r
521 // Append reloc section into TeImage\r
522 //\r
523 ImageContext.Handle = PeFileBuffer;\r
524 Status = PeCoffLoaderGetImageInfo(&ImageContext);\r
525 if (EFI_ERROR(Status)) {\r
526 Error(NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int)Status);\r
527 return Status;\r
528 }\r
529 ImageContext.RelocationsStripped = FALSE;\r
530 }\r
531 }\r
532 //\r
533 // Relocation doesn't exist\r
534 //\r
535 if (ImageContext.RelocationsStripped) {\r
536 Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);\r
537 continue;\r
538 }\r
539\r
540 //\r
541 // Relocation exist and rebase\r
542 //\r
543 //\r
544 // Load and Relocate Image Data\r
545 //\r
546 MemoryImagePointer = (UINT8 *)malloc((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);\r
547 if (MemoryImagePointer == NULL) {\r
548 Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
549 return EFI_OUT_OF_RESOURCES;\r
550 }\r
551 memset((VOID *)MemoryImagePointer, 0, (UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);\r
552 ImageContext.ImageAddress = ((UINTN)MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN)ImageContext.SectionAlignment - 1));\r
553\r
554 Status = PeCoffLoaderLoadImage(&ImageContext);\r
555 if (EFI_ERROR(Status)) {\r
556 Error(NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);\r
557 free((VOID *)MemoryImagePointer);\r
558 return Status;\r
559 }\r
560 //\r
561 // Reloacate TeImage\r
562 //\r
563 ImageContext.DestinationAddress = NewPe32BaseAddress;\r
564 Status = PeCoffLoaderRelocateImage(&ImageContext);\r
565 if (EFI_ERROR(Status)) {\r
566 Error(NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName);\r
567 free((VOID *)MemoryImagePointer);\r
568 return Status;\r
569 }\r
570\r
571 //\r
572 // Copy the relocated image into raw image file.\r
573 //\r
574 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(TEImageHeader + 1);\r
575 for (Index = 0; Index < TEImageHeader->NumberOfSections; Index++, SectionHeader++) {\r
576 if (!ImageContext.IsTeImage) {\r
577 CopyMem(\r
578 (UINT8 *)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,\r
579 (VOID*)(UINTN)(ImageContext.ImageAddress + SectionHeader->VirtualAddress),\r
580 SectionHeader->SizeOfRawData\r
581 );\r
582 }\r
583 else {\r
584 CopyMem(\r
585 (UINT8 *)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,\r
586 (VOID*)(UINTN)(ImageContext.ImageAddress + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHeader->StrippedSize + SectionHeader->VirtualAddress),\r
587 SectionHeader->SizeOfRawData\r
588 );\r
589 }\r
590 }\r
591\r
592 //\r
593 // Free the allocated memory resource\r
594 //\r
595 free((VOID *)MemoryImagePointer);\r
596 MemoryImagePointer = NULL;\r
597 if (PeFileBuffer != NULL) {\r
598 free(PeFileBuffer);\r
599 PeFileBuffer = NULL;\r
600 }\r
601\r
602 //\r
603 // Update Image Base Address\r
604 //\r
605 TEImageHeader->ImageBase = NewPe32BaseAddress;\r
606\r
607 //\r
608 // Now update file checksum\r
609 //\r
610 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
611 SavedState = FfsFile->State;\r
612 FfsFile->IntegrityCheck.Checksum.File = 0;\r
613 FfsFile->State = 0;\r
614 FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8(\r
615 (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize),\r
616 GetFfsFileLength(FfsFile) - FfsHeaderSize\r
617 );\r
618 FfsFile->State = SavedState;\r
619 }\r
620 }\r
621\r
622 return EFI_SUCCESS;\r
623}\r
624\r
625EFI_STATUS\r
626FfsRebaseImageRead(\r
627IN VOID *FileHandle,\r
628IN UINTN FileOffset,\r
629IN OUT UINT32 *ReadSize,\r
630OUT VOID *Buffer\r
631)\r
632/*++\r
633\r
634Routine Description:\r
635\r
636Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
637\r
638Arguments:\r
639\r
640FileHandle - The handle to the PE/COFF file\r
641\r
642FileOffset - The offset, in bytes, into the file to read\r
643\r
644ReadSize - The number of bytes to read from the file starting at FileOffset\r
645\r
646Buffer - A pointer to the buffer to read the data into.\r
647\r
648Returns:\r
649\r
650EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
651\r
652--*/\r
653{\r
654 CHAR8 *Destination8;\r
655 CHAR8 *Source8;\r
656 UINT32 Length;\r
657\r
658 Destination8 = Buffer;\r
659 Source8 = (CHAR8 *)((UINTN)FileHandle + FileOffset);\r
660 Length = *ReadSize;\r
661 while (Length--) {\r
662 *(Destination8++) = *(Source8++);\r
663 }\r
664\r
665 return EFI_SUCCESS;\r
666}\r
667\r
668EFI_STATUS\r
669GetChildFvFromFfs (\r
670 IN UINT64 BaseAddress,\r
671 IN EFI_FFS_FILE_HEADER *FfsFile,\r
672 IN UINTN XipOffset\r
673 )\r
674/*++\r
675\r
676Routine Description:\r
677\r
678 This function gets all child FvImages in the input FfsFile, and records\r
679 their base address to the parent image.\r
680\r
681Arguments:\r
682 FvInfo A pointer to FV_INFO struture.\r
683 FfsFile A pointer to Ffs file image that may contain FvImage.\r
684 XipOffset The offset address to the parent FvImage base.\r
685\r
686Returns:\r
687\r
688 EFI_SUCCESS Base address of child Fv image is recorded.\r
689--*/\r
690{\r
691 EFI_STATUS Status;\r
692 UINTN Index;\r
693 EFI_FILE_SECTION_POINTER SubFvSection;\r
694 EFI_FIRMWARE_VOLUME_HEADER *SubFvImageHeader;\r
695 EFI_PHYSICAL_ADDRESS SubFvBaseAddress;\r
696 EFI_FIRMWARE_VOLUME_HEADER *OrigFvHeader;\r
697 UINT32 OrigFvLength;\r
698 EFI_PHYSICAL_ADDRESS OrigFvBaseAddress;\r
699 EFI_FFS_FILE_HEADER *CurrentFile;\r
700\r
701 //\r
702 // Initialize FV library, saving previous values\r
703 //\r
704 OrigFvHeader = NULL;\r
705 GetFvHeader (&OrigFvHeader, &OrigFvLength);\r
706 OrigFvBaseAddress = BaseAddress;\r
707 for (Index = 1;; Index++) {\r
708 //\r
709 // Find FV section\r
710 //\r
711 Status = GetSectionByType (FfsFile, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, Index, &SubFvSection);\r
712 if (EFI_ERROR (Status)) {\r
713 break;\r
714 }\r
715 SubFvImageHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) SubFvSection.FVImageSection + GetSectionHeaderLength(SubFvSection.FVImageSection));\r
716\r
717 //\r
718 // Rebase on Flash\r
719 //\r
720 SubFvBaseAddress = OrigFvBaseAddress + (UINTN) SubFvImageHeader - (UINTN) FfsFile + XipOffset;\r
721 //mFvBaseAddress[mFvBaseAddressNumber ++ ] = SubFvBaseAddress;\r
722 BaseAddress = SubFvBaseAddress;\r
723 InitializeFvLib(SubFvImageHeader, (UINT32) SubFvImageHeader->FvLength);\r
724\r
725 Status = GetNextFile (NULL, &CurrentFile);\r
726 if (EFI_ERROR (Status)) {\r
727 Error (NULL, 0, 0003, "error parsing FV image", "FFS file can't be found");\r
728 continue;\r
729 }\r
730 while (CurrentFile) {\r
731 RebaseFfs (BaseAddress, "", CurrentFile, (UINTN) CurrentFile - (UINTN) SubFvImageHeader);\r
732 Status = GetNextFile (CurrentFile, &CurrentFile);\r
733 if (EFI_ERROR (Status)) {\r
734 break;\r
735 }\r
736 }\r
737 }\r
738\r
739 BaseAddress = OrigFvBaseAddress;\r
740 if (OrigFvHeader != NULL) {\r
741 InitializeFvLib(OrigFvHeader, OrigFvLength);\r
742 }\r
743\r
744 return EFI_SUCCESS;\r
745}\r
746\r
747EFI_STATUS\r
748GetPe32Info (\r
749 IN UINT8 *Pe32,\r
750 OUT UINT32 *EntryPoint,\r
751 OUT UINT32 *BaseOfCode,\r
752 OUT UINT16 *MachineType\r
753 )\r
754/*++\r
755\r
756Routine Description:\r
757\r
758 Retrieves the PE32 entry point offset and machine type from PE image or TeImage.\r
759 See EfiImage.h for machine types. The entry point offset is from the beginning\r
760 of the PE32 buffer passed in.\r
761\r
762Arguments:\r
763\r
764 Pe32 Beginning of the PE32.\r
765 EntryPoint Offset from the beginning of the PE32 to the image entry point.\r
766 BaseOfCode Base address of code.\r
767 MachineType Magic number for the machine type.\r
768\r
769Returns:\r
770\r
771 EFI_SUCCESS Function completed successfully.\r
772 EFI_ABORTED Error encountered.\r
773 EFI_INVALID_PARAMETER A required parameter was NULL.\r
774 EFI_UNSUPPORTED The operation is unsupported.\r
775\r
776--*/\r
777{\r
778 EFI_IMAGE_DOS_HEADER *DosHeader;\r
779 EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;\r
780 EFI_TE_IMAGE_HEADER *TeHeader;\r
781\r
782 //\r
783 // Verify input parameters\r
784 //\r
785 if (Pe32 == NULL) {\r
786 return EFI_INVALID_PARAMETER;\r
787 }\r
788\r
789 //\r
790 // First check whether it is one TE Image.\r
791 //\r
792 TeHeader = (EFI_TE_IMAGE_HEADER *) Pe32;\r
793 if (TeHeader->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
794 //\r
795 // By TeImage Header to get output\r
796 //\r
797 *EntryPoint = TeHeader->AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;\r
798 *BaseOfCode = TeHeader->BaseOfCode + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;\r
799 *MachineType = TeHeader->Machine;\r
800 } else {\r
801\r
802 //\r
803 // Then check whether\r
804 // First is the DOS header\r
805 //\r
806 DosHeader = (EFI_IMAGE_DOS_HEADER *) Pe32;\r
807\r
808 //\r
809 // Verify DOS header is expected\r
810 //\r
811 if (DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
812 Error (NULL, 0, 3000, "Invalid", "Unknown magic number in the DOS header, 0x%04X.", DosHeader->e_magic);\r
813 return EFI_UNSUPPORTED;\r
814 }\r
815 //\r
816 // Immediately following is the NT header.\r
817 //\r
818 ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN) Pe32 + DosHeader->e_lfanew);\r
819\r
820 //\r
821 // Verify NT header is expected\r
822 //\r
823 if (ImgHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {\r
824 Error (NULL, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", (unsigned) ImgHdr->Pe32.Signature);\r
825 return EFI_UNSUPPORTED;\r
826 }\r
827 //\r
828 // Get output\r
829 //\r
830 *EntryPoint = ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint;\r
831 *BaseOfCode = ImgHdr->Pe32.OptionalHeader.BaseOfCode;\r
832 *MachineType = ImgHdr->Pe32.FileHeader.Machine;\r
833 }\r
834\r
835 //\r
836 // Verify machine type is supported\r
837 //\r
838 if ((*MachineType != EFI_IMAGE_MACHINE_IA32) && (*MachineType != EFI_IMAGE_MACHINE_X64) && (*MachineType != EFI_IMAGE_MACHINE_EBC) &&\r
839 (*MachineType != EFI_IMAGE_MACHINE_ARMT) && (*MachineType != EFI_IMAGE_MACHINE_AARCH64)) {\r
840 Error (NULL, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");\r
841 return EFI_UNSUPPORTED;\r
842 }\r
843\r
844 return EFI_SUCCESS;\r
845}\r
846\r