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