]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/GenFv/GenFvInternalLib.c
d17a2ff1a8f3c030f92445c0b5c3e671aa4cda7c
[mirror_edk2.git] / BaseTools / Source / C / GenFv / GenFvInternalLib.c
1 /** @file
2
3 Copyright (c) 2004 - 2009, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 GenFvInternalLib.c
15
16 Abstract:
17
18 This file contains the internal functions required to generate a Firmware Volume.
19
20 **/
21
22 //
23 // Include files
24 //
25 #ifdef __GNUC__
26 #include <uuid/uuid.h>
27 #include <sys/stat.h>
28 #endif
29 #include <string.h>
30 #ifndef __GNUC__
31 #include <io.h>
32 #endif
33 #include <assert.h>
34
35 #include "GenFvInternalLib.h"
36 #include "FvLib.h"
37 #include "PeCoffLib.h"
38 #include "WinNtInclude.h"
39
40 BOOLEAN mArm = FALSE;
41 STATIC UINT32 MaxFfsAlignment = 0;
42
43 EFI_GUID mEfiFirmwareVolumeTopFileGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;
44 EFI_GUID mFileGuidArray [MAX_NUMBER_OF_FILES_IN_FV];
45 EFI_GUID mZeroGuid = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
46 EFI_GUID mDefaultCapsuleGuid = {0x3B6686BD, 0x0D76, 0x4030, { 0xB7, 0x0E, 0xB5, 0x51, 0x9E, 0x2F, 0xC5, 0xA0 }};
47
48 CHAR8 *mFvbAttributeName[] = {
49 EFI_FVB2_READ_DISABLED_CAP_STRING,
50 EFI_FVB2_READ_ENABLED_CAP_STRING,
51 EFI_FVB2_READ_STATUS_STRING,
52 EFI_FVB2_WRITE_DISABLED_CAP_STRING,
53 EFI_FVB2_WRITE_ENABLED_CAP_STRING,
54 EFI_FVB2_WRITE_STATUS_STRING,
55 EFI_FVB2_LOCK_CAP_STRING,
56 EFI_FVB2_LOCK_STATUS_STRING,
57 NULL,
58 EFI_FVB2_STICKY_WRITE_STRING,
59 EFI_FVB2_MEMORY_MAPPED_STRING,
60 EFI_FVB2_ERASE_POLARITY_STRING,
61 EFI_FVB2_READ_LOCK_CAP_STRING,
62 EFI_FVB2_READ_LOCK_STATUS_STRING,
63 EFI_FVB2_WRITE_LOCK_CAP_STRING,
64 EFI_FVB2_WRITE_LOCK_STATUS_STRING
65 };
66
67 CHAR8 *mFvbAlignmentName[] = {
68 EFI_FVB2_ALIGNMENT_1_STRING,
69 EFI_FVB2_ALIGNMENT_2_STRING,
70 EFI_FVB2_ALIGNMENT_4_STRING,
71 EFI_FVB2_ALIGNMENT_8_STRING,
72 EFI_FVB2_ALIGNMENT_16_STRING,
73 EFI_FVB2_ALIGNMENT_32_STRING,
74 EFI_FVB2_ALIGNMENT_64_STRING,
75 EFI_FVB2_ALIGNMENT_128_STRING,
76 EFI_FVB2_ALIGNMENT_256_STRING,
77 EFI_FVB2_ALIGNMENT_512_STRING,
78 EFI_FVB2_ALIGNMENT_1K_STRING,
79 EFI_FVB2_ALIGNMENT_2K_STRING,
80 EFI_FVB2_ALIGNMENT_4K_STRING,
81 EFI_FVB2_ALIGNMENT_8K_STRING,
82 EFI_FVB2_ALIGNMENT_16K_STRING,
83 EFI_FVB2_ALIGNMENT_32K_STRING,
84 EFI_FVB2_ALIGNMENT_64K_STRING,
85 EFI_FVB2_ALIGNMENT_128K_STRING,
86 EFI_FVB2_ALIGNMENT_256K_STRING,
87 EFI_FVB2_ALIGNMNET_512K_STRING,
88 EFI_FVB2_ALIGNMENT_1M_STRING,
89 EFI_FVB2_ALIGNMENT_2M_STRING,
90 EFI_FVB2_ALIGNMENT_4M_STRING,
91 EFI_FVB2_ALIGNMENT_8M_STRING,
92 EFI_FVB2_ALIGNMENT_16M_STRING,
93 EFI_FVB2_ALIGNMENT_32M_STRING,
94 EFI_FVB2_ALIGNMENT_64M_STRING,
95 EFI_FVB2_ALIGNMENT_128M_STRING,
96 EFI_FVB2_ALIGNMENT_256M_STRING,
97 EFI_FVB2_ALIGNMENT_512M_STRING,
98 EFI_FVB2_ALIGNMENT_1G_STRING,
99 EFI_FVB2_ALIGNMENT_2G_STRING
100 };
101
102 //
103 // This data array will be located at the base of the Firmware Volume Header (FVH)
104 // in the boot block. It must not exceed 14 bytes of code. The last 2 bytes
105 // will be used to keep the FVH checksum consistent.
106 // This code will be run in response to a starutp IPI for HT-enabled systems.
107 //
108 #define SIZEOF_STARTUP_DATA_ARRAY 0x10
109
110 UINT8 m128kRecoveryStartupApDataArray[SIZEOF_STARTUP_DATA_ARRAY] = {
111 //
112 // EA D0 FF 00 F0 ; far jmp F000:FFD0
113 // 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes
114 // 0, 0 ; Checksum Padding
115 //
116 0xEA,
117 0xD0,
118 0xFF,
119 0x0,
120 0xF0,
121 0x00,
122 0x00,
123 0x00,
124 0x00,
125 0x00,
126 0x00,
127 0x00,
128 0x00,
129 0x00,
130 0x00,
131 0x00
132 };
133
134 UINT8 m64kRecoveryStartupApDataArray[SIZEOF_STARTUP_DATA_ARRAY] = {
135 //
136 // EB CE ; jmp short ($-0x30)
137 // ; (from offset 0x0 to offset 0xFFD0)
138 // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes
139 // 0, 0 ; Checksum Padding
140 //
141 0xEB,
142 0xCE,
143 0x00,
144 0x00,
145 0x00,
146 0x00,
147 0x00,
148 0x00,
149 0x00,
150 0x00,
151 0x00,
152 0x00,
153 0x00,
154 0x00,
155 0x00,
156 0x00
157 };
158
159 FV_INFO mFvDataInfo;
160 CAP_INFO mCapDataInfo;
161
162 EFI_STATUS
163 ParseFvInf (
164 IN MEMORY_FILE *InfFile,
165 OUT FV_INFO *FvInfo
166 )
167 /*++
168
169 Routine Description:
170
171 This function parses a FV.INF file and copies info into a FV_INFO structure.
172
173 Arguments:
174
175 InfFile Memory file image.
176 FvInfo Information read from INF file.
177
178 Returns:
179
180 EFI_SUCCESS INF file information successfully retrieved.
181 EFI_ABORTED INF file has an invalid format.
182 EFI_NOT_FOUND A required string was not found in the INF file.
183 --*/
184 {
185 CHAR8 Value[_MAX_PATH];
186 UINT64 Value64;
187 UINTN Index;
188 UINTN Number;
189 EFI_STATUS Status;
190 EFI_GUID GuidValue;
191
192 //
193 // Read the FV base address
194 //
195 if (!mFvDataInfo.BaseAddressSet) {
196 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_BASE_ADDRESS_STRING, 0, Value);
197 if (Status == EFI_SUCCESS) {
198 //
199 // Get the base address
200 //
201 Status = AsciiStringToUint64 (Value, FALSE, &Value64);
202 if (EFI_ERROR (Status)) {
203 Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_BASE_ADDRESS_STRING, Value);
204 return EFI_ABORTED;
205 }
206 DebugMsg (NULL, 0, 9, "rebase address", "%s = %s", EFI_FV_BASE_ADDRESS_STRING, Value);
207
208 FvInfo->BaseAddress = Value64;
209 }
210 }
211
212 //
213 // Read the FV File System Guid
214 //
215 if (!FvInfo->FvFileSystemGuidSet) {
216 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_FILESYSTEMGUID_STRING, 0, Value);
217 if (Status == EFI_SUCCESS) {
218 //
219 // Get the guid value
220 //
221 Status = StringToGuid (Value, &GuidValue);
222 if (EFI_ERROR (Status)) {
223 Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_FILESYSTEMGUID_STRING, Value);
224 return EFI_ABORTED;
225 }
226 memcpy (&FvInfo->FvFileSystemGuid, &GuidValue, sizeof (EFI_GUID));
227 FvInfo->FvFileSystemGuidSet = TRUE;
228 }
229 }
230
231 //
232 // Read the FV Extension Header File Name
233 //
234 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FV_EXT_HEADER_FILE_NAME, 0, Value);
235 if (Status == EFI_SUCCESS) {
236 strcpy (FvInfo->FvExtHeaderFile, Value);
237 }
238
239 //
240 // Read the FV file name
241 //
242 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_FILE_NAME_STRING, 0, Value);
243 if (Status == EFI_SUCCESS) {
244 //
245 // copy the file name
246 //
247 strcpy (FvInfo->FvName, Value);
248 }
249
250 //
251 // Read Fv Attribute
252 //
253 for (Index = 0; Index < sizeof (mFvbAttributeName)/sizeof (CHAR8 *); Index ++) {
254 if ((mFvbAttributeName [Index] != NULL) && \
255 (FindToken (InfFile, ATTRIBUTES_SECTION_STRING, mFvbAttributeName [Index], 0, Value) == EFI_SUCCESS)) {
256 if ((strcmp (Value, TRUE_STRING) == 0) || (strcmp (Value, ONE_STRING) == 0)) {
257 FvInfo->FvAttributes |= 1 << Index;
258 } else if ((strcmp (Value, FALSE_STRING) != 0) && (strcmp (Value, ZERO_STRING) != 0)) {
259 Error (NULL, 0, 2000, "Invalid parameter", "%s expected %s | %s", mFvbAttributeName [Index], TRUE_STRING, FALSE_STRING);
260 return EFI_ABORTED;
261 }
262 }
263 }
264
265 //
266 // Read Fv Alignment
267 //
268 for (Index = 0; Index < sizeof (mFvbAlignmentName)/sizeof (CHAR8 *); Index ++) {
269 if (FindToken (InfFile, ATTRIBUTES_SECTION_STRING, mFvbAlignmentName [Index], 0, Value) == EFI_SUCCESS) {
270 if (strcmp (Value, TRUE_STRING) == 0) {
271 FvInfo->FvAttributes |= Index << 16;
272 DebugMsg (NULL, 0, 9, "FV file alignment", "Align = %s", mFvbAlignmentName [Index]);
273 break;
274 }
275 }
276 }
277
278 //
279 // Read block maps
280 //
281 for (Index = 0; Index < MAX_NUMBER_OF_FV_BLOCKS; Index++) {
282 if (FvInfo->FvBlocks[Index].Length == 0) {
283 //
284 // Read block size
285 //
286 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_BLOCK_SIZE_STRING, Index, Value);
287
288 if (Status == EFI_SUCCESS) {
289 //
290 // Update the size of block
291 //
292 Status = AsciiStringToUint64 (Value, FALSE, &Value64);
293 if (EFI_ERROR (Status)) {
294 Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_BLOCK_SIZE_STRING, Value);
295 return EFI_ABORTED;
296 }
297
298 FvInfo->FvBlocks[Index].Length = (UINT32) Value64;
299 DebugMsg (NULL, 0, 9, "FV Block Size", "%s = %s", EFI_BLOCK_SIZE_STRING, Value);
300 } else {
301 //
302 // If there is no blocks size, but there is the number of block, then we have a mismatched pair
303 // and should return an error.
304 //
305 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_NUM_BLOCKS_STRING, Index, Value);
306 if (!EFI_ERROR (Status)) {
307 Error (NULL, 0, 2000, "Invalid parameter", "both %s and %s must be specified.", EFI_NUM_BLOCKS_STRING, EFI_BLOCK_SIZE_STRING);
308 return EFI_ABORTED;
309 } else {
310 //
311 // We are done
312 //
313 break;
314 }
315 }
316
317 //
318 // Read blocks number
319 //
320 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_NUM_BLOCKS_STRING, Index, Value);
321
322 if (Status == EFI_SUCCESS) {
323 //
324 // Update the number of blocks
325 //
326 Status = AsciiStringToUint64 (Value, FALSE, &Value64);
327 if (EFI_ERROR (Status)) {
328 Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_NUM_BLOCKS_STRING, Value);
329 return EFI_ABORTED;
330 }
331
332 FvInfo->FvBlocks[Index].NumBlocks = (UINT32) Value64;
333 DebugMsg (NULL, 0, 9, "FV Block Number", "%s = %s", EFI_NUM_BLOCKS_STRING, Value);
334 }
335 }
336 }
337
338 if (Index == 0) {
339 Error (NULL, 0, 2001, "Missing required argument", "block size.");
340 return EFI_ABORTED;
341 }
342
343 //
344 // Read files
345 //
346 Number = 0;
347 for (Number = 0; Number < MAX_NUMBER_OF_FILES_IN_FV; Number ++) {
348 if (FvInfo->FvFiles[Number][0] == '\0') {
349 break;
350 }
351 }
352
353 for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_FV; Index++) {
354 //
355 // Read the FFS file list
356 //
357 Status = FindToken (InfFile, FILES_SECTION_STRING, EFI_FILE_NAME_STRING, Index, Value);
358
359 if (Status == EFI_SUCCESS) {
360 //
361 // Add the file
362 //
363 strcpy (FvInfo->FvFiles[Number + Index], Value);
364 DebugMsg (NULL, 0, 9, "FV component file", "the %uth name is %s", (unsigned) Index, Value);
365 } else {
366 break;
367 }
368 }
369
370 if ((Index + Number) == 0) {
371 Warning (NULL, 0, 0, "FV components are not specified.", NULL);
372 }
373
374 return EFI_SUCCESS;
375 }
376
377 VOID
378 UpdateFfsFileState (
379 IN EFI_FFS_FILE_HEADER *FfsFile,
380 IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader
381 )
382 /*++
383
384 Routine Description:
385
386 This function changes the FFS file attributes based on the erase polarity
387 of the FV. Update the reserved bits of State to EFI_FVB2_ERASE_POLARITY.
388
389 Arguments:
390
391 FfsFile File header.
392 FvHeader FV header.
393
394 Returns:
395
396 None
397
398 --*/
399 {
400 if (FvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
401 FfsFile->State = (UINT8)~(FfsFile->State);
402 // FfsFile->State |= ~(UINT8) EFI_FILE_ALL_STATE_BITS;
403 }
404 }
405
406 EFI_STATUS
407 ReadFfsAlignment (
408 IN EFI_FFS_FILE_HEADER *FfsFile,
409 IN OUT UINT32 *Alignment
410 )
411 /*++
412
413 Routine Description:
414
415 This function determines the alignment of the FFS input file from the file
416 attributes.
417
418 Arguments:
419
420 FfsFile FFS file to parse
421 Alignment The minimum required alignment offset of the FFS file
422
423 Returns:
424
425 EFI_SUCCESS The function completed successfully.
426 EFI_INVALID_PARAMETER One of the input parameters was invalid.
427 EFI_ABORTED An error occurred.
428
429 --*/
430 {
431 //
432 // Verify input parameters.
433 //
434 if (FfsFile == NULL || Alignment == NULL) {
435 return EFI_INVALID_PARAMETER;
436 }
437
438 switch ((FfsFile->Attributes >> 3) & 0x07) {
439
440 case 0:
441 //
442 // 8 byte alignment, mini alignment requirement for FFS file.
443 //
444 *Alignment = 3;
445 break;
446
447 case 1:
448 //
449 // 16 byte alignment
450 //
451 *Alignment = 4;
452 break;
453
454 case 2:
455 //
456 // 128 byte alignment
457 //
458 *Alignment = 7;
459 break;
460
461 case 3:
462 //
463 // 512 byte alignment
464 //
465 *Alignment = 9;
466 break;
467
468 case 4:
469 //
470 // 1K byte alignment
471 //
472 *Alignment = 10;
473 break;
474
475 case 5:
476 //
477 // 4K byte alignment
478 //
479 *Alignment = 12;
480 break;
481
482 case 6:
483 //
484 // 32K byte alignment
485 //
486 *Alignment = 15;
487 break;
488
489 case 7:
490 //
491 // 64K byte alignment
492 //
493 *Alignment = 16;
494 break;
495
496 default:
497 break;
498 }
499
500 return EFI_SUCCESS;
501 }
502
503 EFI_STATUS
504 AddPadFile (
505 IN OUT MEMORY_FILE *FvImage,
506 IN UINT32 DataAlignment,
507 IN VOID *FvEnd,
508 IN EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHeader
509 )
510 /*++
511
512 Routine Description:
513
514 This function adds a pad file to the FV image if it required to align the
515 data of the next file.
516
517 Arguments:
518
519 FvImage The memory image of the FV to add it to.
520 The current offset must be valid.
521 DataAlignment The data alignment of the next FFS file.
522 FvEnd End of the empty data in FvImage.
523 ExtHeader PI FvExtHeader Optional
524
525 Returns:
526
527 EFI_SUCCESS The function completed successfully.
528 EFI_INVALID_PARAMETER One of the input parameters was invalid.
529 EFI_OUT_OF_RESOURCES Insufficient resources exist in the FV to complete
530 the pad file add.
531
532 --*/
533 {
534 EFI_FFS_FILE_HEADER *PadFile;
535 UINTN PadFileSize;
536
537 //
538 // Verify input parameters.
539 //
540 if (FvImage == NULL) {
541 return EFI_INVALID_PARAMETER;
542 }
543
544 //
545 // Check if a pad file is necessary
546 //
547 if ((ExtHeader == NULL) && (((UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + sizeof (EFI_FFS_FILE_HEADER)) % DataAlignment == 0)) {
548 return EFI_SUCCESS;
549 }
550
551 //
552 // Calculate the pad file size
553 //
554 //
555 // This is the earliest possible valid offset (current plus pad file header
556 // plus the next file header)
557 //
558 PadFileSize = (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + (sizeof (EFI_FFS_FILE_HEADER) * 2);
559
560 //
561 // Add whatever it takes to get to the next aligned address
562 //
563 while ((PadFileSize % DataAlignment) != 0) {
564 PadFileSize++;
565 }
566 //
567 // Subtract the next file header size
568 //
569 PadFileSize -= sizeof (EFI_FFS_FILE_HEADER);
570
571 //
572 // Subtract the starting offset to get size
573 //
574 PadFileSize -= (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage;
575
576 //
577 // Append extension header size
578 //
579 if (ExtHeader != NULL) {
580 PadFileSize = PadFileSize + ExtHeader->ExtHeaderSize;
581 }
582
583 //
584 // Verify that we have enough space for the file header
585 //
586 if (((UINTN) FvImage->CurrentFilePointer + PadFileSize) > (UINTN) FvEnd) {
587 return EFI_OUT_OF_RESOURCES;
588 }
589
590 //
591 // Write pad file header
592 //
593 PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer;
594
595 //
596 // Write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
597 //
598 PadFile->Type = EFI_FV_FILETYPE_FFS_PAD;
599 PadFile->Attributes = 0;
600
601 //
602 // Write pad file size (calculated size minus next file header size)
603 //
604 PadFile->Size[0] = (UINT8) (PadFileSize & 0xFF);
605 PadFile->Size[1] = (UINT8) ((PadFileSize >> 8) & 0xFF);
606 PadFile->Size[2] = (UINT8) ((PadFileSize >> 16) & 0xFF);
607
608 //
609 // Fill in checksums and state, they must be 0 for checksumming.
610 //
611 PadFile->IntegrityCheck.Checksum.Header = 0;
612 PadFile->IntegrityCheck.Checksum.File = 0;
613 PadFile->State = 0;
614 PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, sizeof (EFI_FFS_FILE_HEADER));
615 PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
616
617 PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
618 UpdateFfsFileState (
619 (EFI_FFS_FILE_HEADER *) PadFile,
620 (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage
621 );
622
623 //
624 // Update the current FV pointer
625 //
626 FvImage->CurrentFilePointer += PadFileSize;
627
628 if (ExtHeader != NULL) {
629 //
630 // Copy Fv Extension Header and Set Fv Extension header offset
631 //
632 memcpy (PadFile + 1, ExtHeader, ExtHeader->ExtHeaderSize);
633 ((EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage)->ExtHeaderOffset = (UINT16) ((UINTN) (PadFile + 1) - (UINTN) FvImage->FileImage);
634 //
635 // Make next file start at QWord Boundry
636 //
637 while (((UINTN) FvImage->CurrentFilePointer & (EFI_FFS_FILE_HEADER_ALIGNMENT - 1)) != 0) {
638 FvImage->CurrentFilePointer++;
639 }
640 }
641
642 return EFI_SUCCESS;
643 }
644
645 BOOLEAN
646 IsVtfFile (
647 IN EFI_FFS_FILE_HEADER *FileBuffer
648 )
649 /*++
650
651 Routine Description:
652
653 This function checks the header to validate if it is a VTF file
654
655 Arguments:
656
657 FileBuffer Buffer in which content of a file has been read.
658
659 Returns:
660
661 TRUE If this is a VTF file
662 FALSE If this is not a VTF file
663
664 --*/
665 {
666 if (!memcmp (&FileBuffer->Name, &mEfiFirmwareVolumeTopFileGuid, sizeof (EFI_GUID))) {
667 return TRUE;
668 } else {
669 return FALSE;
670 }
671 }
672
673 EFI_STATUS
674 WriteMapFile (
675 IN OUT FILE *FvMapFile,
676 IN CHAR8 *FileName,
677 IN EFI_GUID *FileGuidPtr,
678 IN EFI_PHYSICAL_ADDRESS ImageBaseAddress,
679 IN PE_COFF_LOADER_IMAGE_CONTEXT *pImageContext
680 )
681 /*++
682
683 Routine Description:
684
685 This function gets the basic debug information (entrypoint, baseaddress, .text, .data section base address)
686 from PE/COFF image and abstracts Pe Map file information and add them into FvMap file for Debug.
687
688 Arguments:
689
690 FvMapFile A pointer to FvMap File
691 FileName Ffs File PathName
692 FileGuidPtr Guid Value of Ffs file
693 ImageBaseAddress PeImage Base Address.
694 pImageContext Image Context Information.
695
696 Returns:
697
698 EFI_SUCCESS Added required map information.
699
700 --*/
701 {
702 CHAR8 PeMapFileName [_MAX_PATH];
703 CHAR8 *Cptr, *Cptr2;
704 CHAR8 FileGuidName [MAX_LINE_LEN];
705 FILE *PeMapFile;
706 CHAR8 Line [MAX_LINE_LEN];
707 CHAR8 KeyWord [MAX_LINE_LEN];
708 CHAR8 FunctionName [MAX_LINE_LEN];
709 EFI_PHYSICAL_ADDRESS FunctionAddress;
710 UINT32 FunctionType;
711 CHAR8 FunctionTypeName [MAX_LINE_LEN];
712 UINT32 Index;
713 UINT32 AddressOfEntryPoint;
714 UINT32 Offset;
715 EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
716 EFI_TE_IMAGE_HEADER *TEImageHeader;
717 EFI_IMAGE_SECTION_HEADER *SectionHeader;
718 unsigned long long TempLongAddress;
719 //
720 // Init local variable
721 //
722 FunctionType = 0;
723 //
724 // Print FileGuid to string buffer.
725 //
726 PrintGuidToBuffer (FileGuidPtr, (UINT8 *)FileGuidName, MAX_LINE_LEN, TRUE);
727
728 //
729 // Construct Map file Name
730 //
731 strcpy (PeMapFileName, FileName);
732
733 //
734 // Change '\\' to '/', unified path format.
735 //
736 Cptr = PeMapFileName;
737 while (*Cptr != '\0') {
738 if (*Cptr == '\\') {
739 *Cptr = FILE_SEP_CHAR;
740 }
741 Cptr ++;
742 }
743
744 //
745 // Get Map file
746 //
747 Cptr = PeMapFileName + strlen (PeMapFileName);
748 while ((*Cptr != '.') && (Cptr >= PeMapFileName)) {
749 Cptr --;
750 }
751 if (Cptr < PeMapFileName) {
752 return EFI_NOT_FOUND;
753 } else {
754 *(Cptr + 1) = 'm';
755 *(Cptr + 2) = 'a';
756 *(Cptr + 3) = 'p';
757 *(Cptr + 4) = '\0';
758 }
759
760 //
761 // Get module Name
762 //
763 Cptr2 = Cptr;
764 while ((*Cptr != FILE_SEP_CHAR) && (Cptr >= PeMapFileName)) {
765 Cptr --;
766 }
767 *Cptr2 = '\0';
768 strcpy (KeyWord, Cptr + 1);
769 *Cptr2 = '.';
770
771 //
772 // AddressOfEntryPoint and Offset in Image
773 //
774 if (!pImageContext->IsTeImage) {
775 ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) pImageContext->Handle + pImageContext->PeCoffHeaderOffset);
776 AddressOfEntryPoint = ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
777 Offset = 0;
778 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (
779 (UINT8 *) ImgHdr +
780 sizeof (UINT32) +
781 sizeof (EFI_IMAGE_FILE_HEADER) +
782 ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
783 );
784 Index = ImgHdr->Pe32.FileHeader.NumberOfSections;
785 } else {
786 TEImageHeader = (EFI_TE_IMAGE_HEADER *) pImageContext->Handle;
787 AddressOfEntryPoint = TEImageHeader->AddressOfEntryPoint;
788 Offset = TEImageHeader->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
789 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TEImageHeader + 1);
790 Index = TEImageHeader->NumberOfSections;
791 }
792
793 //
794 // module information output
795 //
796 if (ImageBaseAddress == 0) {
797 fprintf (FvMapFile, "%s (dummy) (", KeyWord);
798 fprintf (FvMapFile, "BaseAddress=%08llx, ", (unsigned long long) ImageBaseAddress);
799 } else {
800 fprintf (FvMapFile, "%s (", KeyWord);
801 fprintf (FvMapFile, "BaseAddress=%08llx, ", (unsigned long long) (ImageBaseAddress + Offset));
802 }
803 fprintf (FvMapFile, "EntryPoint=%08llx, ", (unsigned long long) (ImageBaseAddress + AddressOfEntryPoint));
804 fprintf (FvMapFile, "GUID=%s", FileGuidName);
805 fprintf (FvMapFile, ")\n");
806
807 for (; Index > 0; Index --, SectionHeader ++) {
808 if (stricmp ((CHAR8 *)SectionHeader->Name, ".text") == 0) {
809 fprintf (FvMapFile, ".textbaseaddress=%08llx ", (unsigned long long) (ImageBaseAddress + SectionHeader->VirtualAddress));
810 } else if (stricmp ((CHAR8 *)SectionHeader->Name, ".data") == 0) {
811 fprintf (FvMapFile, ".databaseaddress=%08llx ", (unsigned long long) (ImageBaseAddress + SectionHeader->VirtualAddress));
812 }
813 }
814 fprintf (FvMapFile, "\n\n");
815
816 //
817 // Open PeMapFile
818 //
819 PeMapFile = fopen (PeMapFileName, "r");
820 if (PeMapFile == NULL) {
821 // fprintf (stdout, "can't open %s file to reading\n", PeMapFileName);
822 return EFI_ABORTED;
823 }
824 VerboseMsg ("The map file is %s", PeMapFileName);
825
826 //
827 // Output Functions information into Fv Map file
828 //
829 while (fgets (Line, MAX_LINE_LEN, PeMapFile) != NULL) {
830 //
831 // Skip blank line
832 //
833 if (Line[0] == 0x0a) {
834 FunctionType = 0;
835 continue;
836 }
837 //
838 // By Address and Static keyword
839 //
840 if (FunctionType == 0) {
841 sscanf (Line, "%s", KeyWord);
842 if (stricmp (KeyWord, "Address") == 0) {
843 //
844 // function list
845 //
846 FunctionType = 1;
847 fgets (Line, MAX_LINE_LEN, PeMapFile);
848 } else if (stricmp (KeyWord, "Static") == 0) {
849 //
850 // static function list
851 //
852 FunctionType = 2;
853 fgets (Line, MAX_LINE_LEN, PeMapFile);
854 }
855 continue;
856 }
857 //
858 // Printf Function Information
859 //
860 if (FunctionType == 1) {
861 sscanf (Line, "%s %s %llx %s", KeyWord, FunctionName, &TempLongAddress, FunctionTypeName);
862 FunctionAddress = (UINT64) TempLongAddress;
863 if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) {
864 fprintf (FvMapFile, " %016llx ", (unsigned long long) (ImageBaseAddress + FunctionAddress));
865 fprintf (FvMapFile, "(%08llx) F ", (unsigned long long) (FunctionAddress - Offset));
866 fprintf (FvMapFile, "%s\n", FunctionName);
867 } else {
868 fprintf (FvMapFile, " %016llx ", (unsigned long long) (ImageBaseAddress + FunctionAddress));
869 fprintf (FvMapFile, "(%08llx) ", (unsigned long long) (FunctionAddress - Offset));
870 fprintf (FvMapFile, "%s\n", FunctionName);
871 }
872 } else if (FunctionType == 2) {
873 sscanf (Line, "%s %s %llx %s", KeyWord, FunctionName, &TempLongAddress, FunctionTypeName);
874 FunctionAddress = (UINT64) TempLongAddress;
875 if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) {
876 fprintf (FvMapFile, " %016llx ", (unsigned long long) (ImageBaseAddress + FunctionAddress));
877 fprintf (FvMapFile, "(%08llx) FS ", (unsigned long long) (FunctionAddress - Offset));
878 fprintf (FvMapFile, "%s\n", FunctionName);
879 } else {
880 fprintf (FvMapFile, " %016llx ", (unsigned long long) (ImageBaseAddress + FunctionAddress));
881 fprintf (FvMapFile, "(%08llx) ", (unsigned long long) (FunctionAddress - Offset));
882 fprintf (FvMapFile, "%s\n", FunctionName);
883 }
884 }
885 }
886 //
887 // Close PeMap file
888 //
889 fprintf (FvMapFile, "\n\n");
890 fclose (PeMapFile);
891
892 return EFI_SUCCESS;
893 }
894
895 EFI_STATUS
896 AddFile (
897 IN OUT MEMORY_FILE *FvImage,
898 IN FV_INFO *FvInfo,
899 IN UINTN Index,
900 IN OUT EFI_FFS_FILE_HEADER **VtfFileImage,
901 IN FILE *FvMapFile
902 )
903 /*++
904
905 Routine Description:
906
907 This function adds a file to the FV image. The file will pad to the
908 appropriate alignment if required.
909
910 Arguments:
911
912 FvImage The memory image of the FV to add it to. The current offset
913 must be valid.
914 FvInfo Pointer to information about the FV.
915 Index The file in the FvInfo file list to add.
916 VtfFileImage A pointer to the VTF file within the FvImage. If this is equal
917 to the end of the FvImage then no VTF previously found.
918 FvMapFile Pointer to FvMap File
919
920 Returns:
921
922 EFI_SUCCESS The function completed successfully.
923 EFI_INVALID_PARAMETER One of the input parameters was invalid.
924 EFI_ABORTED An error occurred.
925 EFI_OUT_OF_RESOURCES Insufficient resources exist to complete the add.
926
927 --*/
928 {
929 FILE *NewFile;
930 UINTN FileSize;
931 UINT8 *FileBuffer;
932 UINTN NumBytesRead;
933 UINT32 CurrentFileAlignment;
934 EFI_STATUS Status;
935 UINTN Index1;
936
937 Index1 = 0;
938 //
939 // Verify input parameters.
940 //
941 if (FvImage == NULL || FvInfo == NULL || FvInfo->FvFiles[Index][0] == 0 || VtfFileImage == NULL) {
942 return EFI_INVALID_PARAMETER;
943 }
944
945 //
946 // Read the file to add
947 //
948 NewFile = fopen (FvInfo->FvFiles[Index], "rb");
949
950 if (NewFile == NULL) {
951 Error (NULL, 0, 0001, "Error opening file", FvInfo->FvFiles[Index]);
952 return EFI_ABORTED;
953 }
954
955 //
956 // Get the file size
957 //
958 FileSize = _filelength (fileno (NewFile));
959
960 //
961 // Read the file into a buffer
962 //
963 FileBuffer = malloc (FileSize);
964 if (FileBuffer == NULL) {
965 Error (NULL, 0, 4001, "Resouce", "memory cannot be allocated!");
966 return EFI_OUT_OF_RESOURCES;
967 }
968
969 NumBytesRead = fread (FileBuffer, sizeof (UINT8), FileSize, NewFile);
970
971 //
972 // Done with the file, from this point on we will just use the buffer read.
973 //
974 fclose (NewFile);
975
976 //
977 // Verify read successful
978 //
979 if (NumBytesRead != sizeof (UINT8) * FileSize) {
980 free (FileBuffer);
981 Error (NULL, 0, 0004, "Error reading file", FvInfo->FvFiles[Index]);
982 return EFI_ABORTED;
983 }
984
985 //
986 // For None PI Ffs file, directly add them into FvImage.
987 //
988 if (!FvInfo->IsPiFvImage) {
989 memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize);
990 if (FvInfo->SizeofFvFiles[Index] > FileSize) {
991 FvImage->CurrentFilePointer += FvInfo->SizeofFvFiles[Index];
992 } else {
993 FvImage->CurrentFilePointer += FileSize;
994 }
995 goto Done;
996 }
997
998 //
999 // Verify Ffs file
1000 //
1001 Status = VerifyFfsFile ((EFI_FFS_FILE_HEADER *)FileBuffer);
1002 if (EFI_ERROR (Status)) {
1003 free (FileBuffer);
1004 Error (NULL, 0, 3000, "Invalid", "%s is a FFS file.", FvInfo->FvFiles[Index]);
1005 return EFI_INVALID_PARAMETER;
1006 }
1007
1008 //
1009 // Verify space exists to add the file
1010 //
1011 if (FileSize > (UINTN) ((UINTN) *VtfFileImage - (UINTN) FvImage->CurrentFilePointer)) {
1012 free (FileBuffer);
1013 Error (NULL, 0, 4002, "Resource", "FV space is full, not enough room to add file %s.", FvInfo->FvFiles[Index]);
1014 return EFI_OUT_OF_RESOURCES;
1015 }
1016
1017 //
1018 // Verify the input file is the duplicated file in this Fv image
1019 //
1020 for (Index1 = 0; Index1 < Index; Index1 ++) {
1021 if (CompareGuid ((EFI_GUID *) FileBuffer, &mFileGuidArray [Index1]) == 0) {
1022 Error (NULL, 0, 2000, "Invalid parameter", "the %dth file and %uth file have the same file GUID.", (unsigned) Index1 + 1, (unsigned) Index + 1);
1023 PrintGuid ((EFI_GUID *) FileBuffer);
1024 return EFI_INVALID_PARAMETER;
1025 }
1026 }
1027 CopyMem (&mFileGuidArray [Index], FileBuffer, sizeof (EFI_GUID));
1028
1029 //
1030 // Update the file state based on polarity of the FV.
1031 //
1032 UpdateFfsFileState (
1033 (EFI_FFS_FILE_HEADER *) FileBuffer,
1034 (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage
1035 );
1036
1037 //
1038 // Check if alignment is required
1039 //
1040 ReadFfsAlignment ((EFI_FFS_FILE_HEADER *) FileBuffer, &CurrentFileAlignment);
1041
1042 //
1043 // Find the largest alignment of all the FFS files in the FV
1044 //
1045 if (CurrentFileAlignment > MaxFfsAlignment) {
1046 MaxFfsAlignment = CurrentFileAlignment;
1047 }
1048 //
1049 // If we have a VTF file, add it at the top.
1050 //
1051 if (IsVtfFile ((EFI_FFS_FILE_HEADER *) FileBuffer)) {
1052 if ((UINTN) *VtfFileImage == (UINTN) FvImage->Eof) {
1053 //
1054 // No previous VTF, add this one.
1055 //
1056 *VtfFileImage = (EFI_FFS_FILE_HEADER *) (UINTN) ((UINTN) FvImage->FileImage + FvInfo->Size - FileSize);
1057 //
1058 // Sanity check. The file MUST align appropriately
1059 //
1060 if (((UINTN) *VtfFileImage + sizeof (EFI_FFS_FILE_HEADER) - (UINTN) FvImage->FileImage) % (1 << CurrentFileAlignment)) {
1061 Error (NULL, 0, 3000, "Invalid", "VTF file cannot be aligned on a %u-byte boundary.", (unsigned) (1 << CurrentFileAlignment));
1062 free (FileBuffer);
1063 return EFI_ABORTED;
1064 }
1065 //
1066 // Rebase the PE or TE image in FileBuffer of FFS file for XIP
1067 // Rebase for the debug genfvmap tool
1068 //
1069 FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) *VtfFileImage - (UINTN) FvImage->FileImage, FvMapFile);
1070 //
1071 // copy VTF File
1072 //
1073 memcpy (*VtfFileImage, FileBuffer, FileSize);
1074 free (FileBuffer);
1075 DebugMsg (NULL, 0, 9, "Add VTF FFS file in FV image", NULL);
1076 return EFI_SUCCESS;
1077 } else {
1078 //
1079 // Already found a VTF file.
1080 //
1081 Error (NULL, 0, 3000, "Invalid", "multiple VTF files are not permitted within a single FV.");
1082 free (FileBuffer);
1083 return EFI_ABORTED;
1084 }
1085 }
1086
1087 //
1088 // Add pad file if necessary
1089 //
1090 Status = AddPadFile (FvImage, 1 << CurrentFileAlignment, *VtfFileImage, NULL);
1091 if (EFI_ERROR (Status)) {
1092 Error (NULL, 0, 4002, "Resource", "FV space is full, could not add pad file for data alignment property.");
1093 free (FileBuffer);
1094 return EFI_ABORTED;
1095 }
1096 //
1097 // Add file
1098 //
1099 if ((UINTN) (FvImage->CurrentFilePointer + FileSize) <= (UINTN) (*VtfFileImage)) {
1100 //
1101 // Rebase the PE or TE image in FileBuffer of FFS file for XIP.
1102 // Rebase Bs and Rt drivers for the debug genfvmap tool.
1103 //
1104 FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage, FvMapFile);
1105 //
1106 // Copy the file
1107 //
1108 memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize);
1109 FvImage->CurrentFilePointer += FileSize;
1110 } else {
1111 Error (NULL, 0, 4002, "Resource", "FV space is full, cannot add file %s.", FvInfo->FvFiles[Index]);
1112 free (FileBuffer);
1113 return EFI_ABORTED;
1114 }
1115 //
1116 // Make next file start at QWord Boundry
1117 //
1118 while (((UINTN) FvImage->CurrentFilePointer & (EFI_FFS_FILE_HEADER_ALIGNMENT - 1)) != 0) {
1119 FvImage->CurrentFilePointer++;
1120 }
1121
1122 Done:
1123 //
1124 // Free allocated memory.
1125 //
1126 free (FileBuffer);
1127
1128 return EFI_SUCCESS;
1129 }
1130
1131 EFI_STATUS
1132 PadFvImage (
1133 IN MEMORY_FILE *FvImage,
1134 IN EFI_FFS_FILE_HEADER *VtfFileImage
1135 )
1136 /*++
1137
1138 Routine Description:
1139
1140 This function places a pad file between the last file in the FV and the VTF
1141 file if the VTF file exists.
1142
1143 Arguments:
1144
1145 FvImage Memory file for the FV memory image
1146 VtfFileImage The address of the VTF file. If this is the end of the FV
1147 image, no VTF exists and no pad file is needed.
1148
1149 Returns:
1150
1151 EFI_SUCCESS Completed successfully.
1152 EFI_INVALID_PARAMETER One of the input parameters was NULL.
1153
1154 --*/
1155 {
1156 EFI_FFS_FILE_HEADER *PadFile;
1157 UINTN FileSize;
1158
1159 //
1160 // If there is no VTF or the VTF naturally follows the previous file without a
1161 // pad file, then there's nothing to do
1162 //
1163 if ((UINTN) VtfFileImage == (UINTN) FvImage->Eof || \
1164 ((UINTN) VtfFileImage == (UINTN) FvImage->CurrentFilePointer)) {
1165 return EFI_SUCCESS;
1166 }
1167
1168 if ((UINTN) VtfFileImage < (UINTN) FvImage->CurrentFilePointer) {
1169 return EFI_INVALID_PARAMETER;
1170 }
1171
1172 //
1173 // Pad file starts at beginning of free space
1174 //
1175 PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer;
1176
1177 //
1178 // write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
1179 //
1180 PadFile->Type = EFI_FV_FILETYPE_FFS_PAD;
1181 PadFile->Attributes = 0;
1182
1183 //
1184 // FileSize includes the EFI_FFS_FILE_HEADER
1185 //
1186 FileSize = (UINTN) VtfFileImage - (UINTN) FvImage->CurrentFilePointer;
1187 PadFile->Size[0] = (UINT8) (FileSize & 0x000000FF);
1188 PadFile->Size[1] = (UINT8) ((FileSize & 0x0000FF00) >> 8);
1189 PadFile->Size[2] = (UINT8) ((FileSize & 0x00FF0000) >> 16);
1190
1191 //
1192 // Fill in checksums and state, must be zero during checksum calculation.
1193 //
1194 PadFile->IntegrityCheck.Checksum.Header = 0;
1195 PadFile->IntegrityCheck.Checksum.File = 0;
1196 PadFile->State = 0;
1197 PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, sizeof (EFI_FFS_FILE_HEADER));
1198 PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
1199
1200 PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
1201
1202 UpdateFfsFileState (
1203 (EFI_FFS_FILE_HEADER *) PadFile,
1204 (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage
1205 );
1206 //
1207 // Update the current FV pointer
1208 //
1209 FvImage->CurrentFilePointer = FvImage->Eof;
1210
1211 return EFI_SUCCESS;
1212 }
1213
1214 EFI_STATUS
1215 UpdateResetVector (
1216 IN MEMORY_FILE *FvImage,
1217 IN FV_INFO *FvInfo,
1218 IN EFI_FFS_FILE_HEADER *VtfFile
1219 )
1220 /*++
1221
1222 Routine Description:
1223
1224 This parses the FV looking for the PEI core and then plugs the address into
1225 the SALE_ENTRY point of the BSF/VTF for IPF and does BUGBUG TBD action to
1226 complete an IA32 Bootstrap FV.
1227
1228 Arguments:
1229
1230 FvImage Memory file for the FV memory image
1231 FvInfo Information read from INF file.
1232 VtfFile Pointer to the VTF file in the FV image.
1233
1234 Returns:
1235
1236 EFI_SUCCESS Function Completed successfully.
1237 EFI_ABORTED Error encountered.
1238 EFI_INVALID_PARAMETER A required parameter was NULL.
1239 EFI_NOT_FOUND PEI Core file not found.
1240
1241 --*/
1242 {
1243 EFI_FFS_FILE_HEADER *PeiCoreFile;
1244 EFI_FFS_FILE_HEADER *SecCoreFile;
1245 EFI_STATUS Status;
1246 EFI_FILE_SECTION_POINTER Pe32Section;
1247 UINT32 EntryPoint;
1248 UINT32 BaseOfCode;
1249 UINT16 MachineType;
1250 EFI_PHYSICAL_ADDRESS PeiCorePhysicalAddress;
1251 EFI_PHYSICAL_ADDRESS SecCorePhysicalAddress;
1252 EFI_PHYSICAL_ADDRESS *SecCoreEntryAddressPtr;
1253 INT32 Ia32SecEntryOffset;
1254 UINT32 *Ia32ResetAddressPtr;
1255 UINT8 *BytePointer;
1256 UINT8 *BytePointer2;
1257 UINT16 *WordPointer;
1258 UINT16 CheckSum;
1259 UINT32 IpiVector;
1260 UINTN Index;
1261 EFI_FFS_FILE_STATE SavedState;
1262 UINT64 FitAddress;
1263 FIT_TABLE *FitTablePtr;
1264 BOOLEAN Vtf0Detected;
1265
1266 //
1267 // Verify input parameters
1268 //
1269 if (FvImage == NULL || FvInfo == NULL || VtfFile == NULL) {
1270 return EFI_INVALID_PARAMETER;
1271 }
1272 //
1273 // Initialize FV library
1274 //
1275 InitializeFvLib (FvImage->FileImage, FvInfo->Size);
1276
1277 //
1278 // Verify VTF file
1279 //
1280 Status = VerifyFfsFile (VtfFile);
1281 if (EFI_ERROR (Status)) {
1282 return EFI_INVALID_PARAMETER;
1283 }
1284
1285 if (
1286 (((UINTN)FvImage->Eof - (UINTN)FvImage->FileImage) >=
1287 IA32_X64_VTF_SIGNATURE_OFFSET) &&
1288 (*(UINT32 *)(VOID*)((UINTN) FvImage->Eof -
1289 IA32_X64_VTF_SIGNATURE_OFFSET) ==
1290 IA32_X64_VTF0_SIGNATURE)
1291 ) {
1292 Vtf0Detected = TRUE;
1293 } else {
1294 Vtf0Detected = FALSE;
1295 }
1296
1297 //
1298 // Find the Sec Core
1299 //
1300 Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile);
1301 if (EFI_ERROR (Status) || SecCoreFile == NULL) {
1302 if (Vtf0Detected) {
1303 //
1304 // If the SEC core file is not found, but the VTF-0 signature
1305 // is found, we'll treat it as a VTF-0 'Volume Top File'.
1306 // This means no modifications are required to the VTF.
1307 //
1308 return EFI_SUCCESS;
1309 }
1310
1311 Error (NULL, 0, 3000, "Invalid", "could not find the SEC core file in the FV.");
1312 return EFI_ABORTED;
1313 }
1314 //
1315 // Sec Core found, now find PE32 section
1316 //
1317 Status = GetSectionByType (SecCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);
1318 if (Status == EFI_NOT_FOUND) {
1319 Status = GetSectionByType (SecCoreFile, EFI_SECTION_TE, 1, &Pe32Section);
1320 }
1321
1322 if (EFI_ERROR (Status)) {
1323 Error (NULL, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");
1324 return EFI_ABORTED;
1325 }
1326
1327 Status = GetPe32Info (
1328 (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),
1329 &EntryPoint,
1330 &BaseOfCode,
1331 &MachineType
1332 );
1333
1334 if (EFI_ERROR (Status)) {
1335 Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");
1336 return EFI_ABORTED;
1337 }
1338
1339 if (
1340 Vtf0Detected &&
1341 (MachineType == EFI_IMAGE_MACHINE_IA32 ||
1342 MachineType == EFI_IMAGE_MACHINE_X64)
1343 ) {
1344 //
1345 // If the SEC core code is IA32 or X64 and the VTF-0 signature
1346 // is found, we'll treat it as a VTF-0 'Volume Top File'.
1347 // This means no modifications are required to the VTF.
1348 //
1349 return EFI_SUCCESS;
1350 }
1351
1352 //
1353 // Physical address is FV base + offset of PE32 + offset of the entry point
1354 //
1355 SecCorePhysicalAddress = FvInfo->BaseAddress;
1356 SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;
1357 SecCorePhysicalAddress += EntryPoint;
1358 DebugMsg (NULL, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress);
1359
1360 //
1361 // Find the PEI Core
1362 //
1363 Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);
1364 if (EFI_ERROR (Status) || PeiCoreFile == NULL) {
1365 Error (NULL, 0, 3000, "Invalid", "could not find the PEI core in the FV.");
1366 return EFI_ABORTED;
1367 }
1368 //
1369 // PEI Core found, now find PE32 or TE section
1370 //
1371 Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);
1372 if (Status == EFI_NOT_FOUND) {
1373 Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);
1374 }
1375
1376 if (EFI_ERROR (Status)) {
1377 Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file.");
1378 return EFI_ABORTED;
1379 }
1380
1381 Status = GetPe32Info (
1382 (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),
1383 &EntryPoint,
1384 &BaseOfCode,
1385 &MachineType
1386 );
1387
1388 if (EFI_ERROR (Status)) {
1389 Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core.");
1390 return EFI_ABORTED;
1391 }
1392 //
1393 // Physical address is FV base + offset of PE32 + offset of the entry point
1394 //
1395 PeiCorePhysicalAddress = FvInfo->BaseAddress;
1396 PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;
1397 PeiCorePhysicalAddress += EntryPoint;
1398 DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress);
1399
1400 if (MachineType == EFI_IMAGE_MACHINE_IA64) {
1401 //
1402 // Update PEI_CORE address
1403 //
1404 //
1405 // Set the uncached attribute bit in the physical address
1406 //
1407 PeiCorePhysicalAddress |= 0x8000000000000000ULL;
1408
1409 //
1410 // Check if address is aligned on a 16 byte boundary
1411 //
1412 if (PeiCorePhysicalAddress & 0xF) {
1413 Error (NULL, 0, 3000, "Invalid",
1414 "PEI_CORE entry point is not aligned on a 16 byte boundary, address specified is %llXh.",
1415 (unsigned long long) PeiCorePhysicalAddress
1416 );
1417 return EFI_ABORTED;
1418 }
1419 //
1420 // First Get the FIT table address
1421 //
1422 FitAddress = (*(UINT64 *) (FvImage->Eof - IPF_FIT_ADDRESS_OFFSET)) & 0xFFFFFFFF;
1423
1424 FitTablePtr = (FIT_TABLE *) (FvImage->FileImage + (FitAddress - FvInfo->BaseAddress));
1425
1426 Status = UpdatePeiCoreEntryInFit (FitTablePtr, PeiCorePhysicalAddress);
1427
1428 if (!EFI_ERROR (Status)) {
1429 UpdateFitCheckSum (FitTablePtr);
1430 }
1431
1432 //
1433 // Update SEC_CORE address
1434 //
1435 //
1436 // Set the uncached attribute bit in the physical address
1437 //
1438 SecCorePhysicalAddress |= 0x8000000000000000ULL;
1439 //
1440 // Check if address is aligned on a 16 byte boundary
1441 //
1442 if (SecCorePhysicalAddress & 0xF) {
1443 Error (NULL, 0, 3000, "Invalid",
1444 "SALE_ENTRY entry point is not aligned on a 16 byte boundary, address specified is %llXh.",
1445 (unsigned long long) SecCorePhysicalAddress
1446 );
1447 return EFI_ABORTED;
1448 }
1449 //
1450 // Update the address
1451 //
1452 SecCoreEntryAddressPtr = (EFI_PHYSICAL_ADDRESS *) ((UINTN) FvImage->Eof - IPF_SALE_ENTRY_ADDRESS_OFFSET);
1453 *SecCoreEntryAddressPtr = SecCorePhysicalAddress;
1454
1455 } else if (MachineType == EFI_IMAGE_MACHINE_IA32 || MachineType == EFI_IMAGE_MACHINE_X64) {
1456 //
1457 // Get the location to update
1458 //
1459 Ia32ResetAddressPtr = (UINT32 *) ((UINTN) FvImage->Eof - IA32_PEI_CORE_ENTRY_OFFSET);
1460
1461 //
1462 // Write lower 32 bits of physical address for Pei Core entry
1463 //
1464 *Ia32ResetAddressPtr = (UINT32) PeiCorePhysicalAddress;
1465
1466 //
1467 // Write SecCore Entry point relative address into the jmp instruction in reset vector.
1468 //
1469 Ia32ResetAddressPtr = (UINT32 *) ((UINTN) FvImage->Eof - IA32_SEC_CORE_ENTRY_OFFSET);
1470
1471 Ia32SecEntryOffset = (INT32) (SecCorePhysicalAddress - (FV_IMAGES_TOP_ADDRESS - IA32_SEC_CORE_ENTRY_OFFSET + 2));
1472 if (Ia32SecEntryOffset <= -65536) {
1473 Error (NULL, 0, 3000, "Invalid", "The SEC EXE file size is too large, it must be less than 64K.");
1474 return STATUS_ERROR;
1475 }
1476
1477 *(UINT16 *) Ia32ResetAddressPtr = (UINT16) Ia32SecEntryOffset;
1478
1479 //
1480 // Update the BFV base address
1481 //
1482 Ia32ResetAddressPtr = (UINT32 *) ((UINTN) FvImage->Eof - 4);
1483 *Ia32ResetAddressPtr = (UINT32) (FvInfo->BaseAddress);
1484 DebugMsg (NULL, 0, 9, "update BFV base address in the top FV image", "BFV base address = 0x%llX.", (unsigned long long) FvInfo->BaseAddress);
1485
1486 //
1487 // Update the Startup AP in the FVH header block ZeroVector region.
1488 //
1489 BytePointer = (UINT8 *) ((UINTN) FvImage->FileImage);
1490 if (FvInfo->Size <= 0x10000) {
1491 BytePointer2 = m64kRecoveryStartupApDataArray;
1492 } else if (FvInfo->Size <= 0x20000) {
1493 BytePointer2 = m128kRecoveryStartupApDataArray;
1494 } else {
1495 BytePointer2 = m128kRecoveryStartupApDataArray;
1496 //
1497 // Find the position to place Ap reset vector, the offset
1498 // between the position and the end of Fvrecovery.fv file
1499 // should not exceed 128kB to prevent Ap reset vector from
1500 // outside legacy E and F segment
1501 //
1502 Status = FindApResetVectorPosition (FvImage, &BytePointer);
1503 if (EFI_ERROR (Status)) {
1504 Error (NULL, 0, 3000, "Invalid", "Cannot find the appropriate location in FvImage to add Ap reset vector!");
1505 return EFI_ABORTED;
1506 }
1507 }
1508
1509 for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY; Index++) {
1510 BytePointer[Index] = BytePointer2[Index];
1511 }
1512 //
1513 // Calculate the checksum
1514 //
1515 CheckSum = 0x0000;
1516 WordPointer = (UINT16 *) (BytePointer);
1517 for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY / 2; Index++) {
1518 CheckSum = (UINT16) (CheckSum + ((UINT16) *WordPointer));
1519 WordPointer++;
1520 }
1521 //
1522 // Update the checksum field
1523 //
1524 WordPointer = (UINT16 *) (BytePointer + SIZEOF_STARTUP_DATA_ARRAY - 2);
1525 *WordPointer = (UINT16) (0x10000 - (UINT32) CheckSum);
1526
1527 //
1528 // IpiVector at the 4k aligned address in the top 2 blocks in the PEI FV.
1529 //
1530 IpiVector = (UINT32) (FV_IMAGES_TOP_ADDRESS - ((UINTN) FvImage->Eof - (UINTN) BytePointer));
1531 DebugMsg (NULL, 0, 9, "Startup AP Vector address", "IpiVector at 0x%X", (unsigned) IpiVector);
1532 if ((IpiVector & 0xFFF) != 0) {
1533 Error (NULL, 0, 3000, "Invalid", "Startup AP Vector address are not 4K aligned, because the FV size is not 4K aligned");
1534 return EFI_ABORTED;
1535 }
1536 IpiVector = IpiVector >> 12;
1537 IpiVector = IpiVector & 0xFF;
1538
1539 //
1540 // Write IPI Vector at Offset FvrecoveryFileSize - 8
1541 //
1542 Ia32ResetAddressPtr = (UINT32 *) ((UINTN) FvImage->Eof - 8);
1543 *Ia32ResetAddressPtr = IpiVector;
1544 } else if (MachineType == EFI_IMAGE_MACHINE_ARMT) {
1545 //
1546 // Since the ARM reset vector is in the FV Header you really don't need a
1547 // Volume Top File, but if you have one for some reason don't crash...
1548 //
1549 } else {
1550 Error (NULL, 0, 3000, "Invalid", "machine type=0x%X in PEI core.", MachineType);
1551 return EFI_ABORTED;
1552 }
1553
1554 //
1555 // Now update file checksum
1556 //
1557 SavedState = VtfFile->State;
1558 VtfFile->IntegrityCheck.Checksum.File = 0;
1559 VtfFile->State = 0;
1560 if (VtfFile->Attributes & FFS_ATTRIB_CHECKSUM) {
1561 VtfFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (
1562 (UINT8 *) (VtfFile + 1),
1563 GetLength (VtfFile->Size) - sizeof (EFI_FFS_FILE_HEADER)
1564 );
1565 } else {
1566 VtfFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
1567 }
1568
1569 VtfFile->State = SavedState;
1570
1571 return EFI_SUCCESS;
1572 }
1573
1574
1575 EFI_STATUS
1576 UpdateArmResetVectorIfNeeded (
1577 IN MEMORY_FILE *FvImage,
1578 IN FV_INFO *FvInfo
1579 )
1580 /*++
1581
1582 Routine Description:
1583 This parses the FV looking for SEC and patches that address into the
1584 beginning of the FV header.
1585
1586 For ARM the reset vector is at 0x00000000 or 0xFFFF0000.
1587 This would commonly map to the first entry in the ROM.
1588 ARM Exceptions:
1589 Reset +0
1590 Undefined +4
1591 SWI +8
1592 Prefetch Abort +12
1593 Data Abort +16
1594 IRQ +20
1595 FIQ +24
1596
1597 We support two schemes on ARM.
1598 1) Beginning of the FV is the reset vector
1599 2) Reset vector is data bytes FDF file and that code branches to reset vector
1600 in the beginning of the FV (fixed size offset).
1601
1602
1603 Need to have the jump for the reset vector at location zero.
1604 We also need to store the address or PEI (if it exists).
1605 We stub out a return from interrupt in case the debugger
1606 is using SWI.
1607 The optional entry to the common exception handler is
1608 to support full featured exception handling from ROM and is currently
1609 not support by this tool.
1610
1611 Arguments:
1612 FvImage Memory file for the FV memory image
1613 FvInfo Information read from INF file.
1614
1615 Returns:
1616
1617 EFI_SUCCESS Function Completed successfully.
1618 EFI_ABORTED Error encountered.
1619 EFI_INVALID_PARAMETER A required parameter was NULL.
1620 EFI_NOT_FOUND PEI Core file not found.
1621
1622 --*/
1623 {
1624 EFI_FFS_FILE_HEADER *PeiCoreFile;
1625 EFI_FFS_FILE_HEADER *SecCoreFile;
1626 EFI_STATUS Status;
1627 EFI_FILE_SECTION_POINTER Pe32Section;
1628 UINT32 EntryPoint;
1629 UINT32 BaseOfCode;
1630 UINT16 MachineType;
1631 EFI_PHYSICAL_ADDRESS PeiCorePhysicalAddress;
1632 EFI_PHYSICAL_ADDRESS SecCorePhysicalAddress;
1633 INT32 ResetVector[4]; // 0 - is branch relative to SEC entry point
1634 // 1 - PEI Entry Point
1635 // 2 - movs pc,lr for a SWI handler
1636 // 3 - Place holder for Common Exception Handler
1637
1638 //
1639 // Verify input parameters
1640 //
1641 if (FvImage == NULL || FvInfo == NULL) {
1642 return EFI_INVALID_PARAMETER;
1643 }
1644 //
1645 // Initialize FV library
1646 //
1647 InitializeFvLib (FvImage->FileImage, FvInfo->Size);
1648
1649 //
1650 // Find the Sec Core
1651 //
1652 Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile);
1653 if (EFI_ERROR (Status) || SecCoreFile == NULL) {
1654 //
1655 // Maybe hardware does SEC job and we only have PEI Core?
1656 //
1657
1658 //
1659 // Find the PEI Core. It may not exist if SEC loads DXE core directly
1660 //
1661 PeiCorePhysicalAddress = 0;
1662 Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);
1663 if (!EFI_ERROR (Status) && PeiCoreFile != NULL) {
1664 //
1665 // PEI Core found, now find PE32 or TE section
1666 //
1667 Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);
1668 if (Status == EFI_NOT_FOUND) {
1669 Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);
1670 }
1671
1672 if (EFI_ERROR (Status)) {
1673 Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");
1674 return EFI_ABORTED;
1675 }
1676
1677 Status = GetPe32Info (
1678 (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),
1679 &EntryPoint,
1680 &BaseOfCode,
1681 &MachineType
1682 );
1683
1684 if (EFI_ERROR (Status)) {
1685 Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");
1686 return EFI_ABORTED;
1687 }
1688 //
1689 // Physical address is FV base + offset of PE32 + offset of the entry point
1690 //
1691 PeiCorePhysicalAddress = FvInfo->BaseAddress;
1692 PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;
1693 PeiCorePhysicalAddress += EntryPoint;
1694 DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress);
1695
1696 if (MachineType == EFI_IMAGE_MACHINE_ARMT) {
1697 memset (ResetVector, 0, sizeof (ResetVector));
1698 // Address of PEI Core, if we have one
1699 ResetVector[1] = (UINT32)PeiCorePhysicalAddress;
1700 }
1701
1702 //
1703 // Copy to the beginning of the FV
1704 //
1705 memcpy ((UINT8 *) ((UINTN) FvImage->FileImage), ResetVector, sizeof (ResetVector));
1706
1707 }
1708
1709 return EFI_SUCCESS;
1710 }
1711
1712 //
1713 // Sec Core found, now find PE32 section
1714 //
1715 Status = GetSectionByType (SecCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);
1716 if (Status == EFI_NOT_FOUND) {
1717 Status = GetSectionByType (SecCoreFile, EFI_SECTION_TE, 1, &Pe32Section);
1718 }
1719
1720 if (EFI_ERROR (Status)) {
1721 Error (NULL, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");
1722 return EFI_ABORTED;
1723 }
1724
1725 Status = GetPe32Info (
1726 (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),
1727 &EntryPoint,
1728 &BaseOfCode,
1729 &MachineType
1730 );
1731 if (EFI_ERROR (Status)) {
1732 Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");
1733 return EFI_ABORTED;
1734 }
1735
1736 if (MachineType != EFI_IMAGE_MACHINE_ARMT) {
1737 //
1738 // If SEC is not ARM we have nothing to do
1739 //
1740 return EFI_SUCCESS;
1741 }
1742
1743 //
1744 // Physical address is FV base + offset of PE32 + offset of the entry point
1745 //
1746 SecCorePhysicalAddress = FvInfo->BaseAddress;
1747 SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;
1748 SecCorePhysicalAddress += EntryPoint;
1749 DebugMsg (NULL, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress);
1750
1751 //
1752 // Find the PEI Core. It may not exist if SEC loads DXE core directly
1753 //
1754 PeiCorePhysicalAddress = 0;
1755 Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);
1756 if (!EFI_ERROR (Status) && PeiCoreFile != NULL) {
1757 //
1758 // PEI Core found, now find PE32 or TE section
1759 //
1760 Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);
1761 if (Status == EFI_NOT_FOUND) {
1762 Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);
1763 }
1764
1765 if (EFI_ERROR (Status)) {
1766 Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");
1767 return EFI_ABORTED;
1768 }
1769
1770 Status = GetPe32Info (
1771 (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),
1772 &EntryPoint,
1773 &BaseOfCode,
1774 &MachineType
1775 );
1776
1777 if (EFI_ERROR (Status)) {
1778 Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");
1779 return EFI_ABORTED;
1780 }
1781 //
1782 // Physical address is FV base + offset of PE32 + offset of the entry point
1783 //
1784 PeiCorePhysicalAddress = FvInfo->BaseAddress;
1785 PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;
1786 PeiCorePhysicalAddress += EntryPoint;
1787 DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress);
1788 }
1789
1790
1791 // B SecEntryPoint - signed_immed_24 part +/-32MB offset
1792 // on ARM, the PC is always 8 ahead, so we're not really jumping from the base address, but from base address + 8
1793 ResetVector[0] = (INT32)(SecCorePhysicalAddress - FvInfo->BaseAddress - 8) >> 2;
1794
1795 if (ResetVector[0] > 0x00FFFFFF) {
1796 Error (NULL, 0, 3000, "Invalid", "SEC Entry point must be within 32MB of the start of the FV");
1797 return EFI_ABORTED;
1798 }
1799
1800 // Add opcode for an uncondional branch with no link. AKA B SecEntryPoint
1801 ResetVector[0] |= 0xEA000000;
1802
1803
1804 // Address of PEI Core, if we have one
1805 ResetVector[1] = (UINT32)PeiCorePhysicalAddress;
1806
1807 // SWI handler movs pc,lr. Just in case a debugger uses SWI
1808 ResetVector[2] = 0xE1B0F07E;
1809
1810 // Place holder to support a common interrupt handler from ROM.
1811 // Currently not suppprted. For this to be used the reset vector would not be in this FV
1812 // and the exception vectors would be hard coded in the ROM and just through this address
1813 // to find a common handler in the a module in the FV.
1814 ResetVector[3] = 0;
1815
1816 //
1817 // Copy to the beginning of the FV
1818 //
1819 memcpy ((UINT8 *) ((UINTN) FvImage->FileImage), ResetVector, sizeof (ResetVector));
1820
1821 DebugMsg (NULL, 0, 9, "Update Reset vector in FV Header", NULL);
1822
1823 return EFI_SUCCESS;
1824 }
1825
1826 EFI_STATUS
1827 GetPe32Info (
1828 IN UINT8 *Pe32,
1829 OUT UINT32 *EntryPoint,
1830 OUT UINT32 *BaseOfCode,
1831 OUT UINT16 *MachineType
1832 )
1833 /*++
1834
1835 Routine Description:
1836
1837 Retrieves the PE32 entry point offset and machine type from PE image or TeImage.
1838 See EfiImage.h for machine types. The entry point offset is from the beginning
1839 of the PE32 buffer passed in.
1840
1841 Arguments:
1842
1843 Pe32 Beginning of the PE32.
1844 EntryPoint Offset from the beginning of the PE32 to the image entry point.
1845 BaseOfCode Base address of code.
1846 MachineType Magic number for the machine type.
1847
1848 Returns:
1849
1850 EFI_SUCCESS Function completed successfully.
1851 EFI_ABORTED Error encountered.
1852 EFI_INVALID_PARAMETER A required parameter was NULL.
1853 EFI_UNSUPPORTED The operation is unsupported.
1854
1855 --*/
1856 {
1857 EFI_IMAGE_DOS_HEADER *DosHeader;
1858 EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
1859 EFI_TE_IMAGE_HEADER *TeHeader;
1860
1861 //
1862 // Verify input parameters
1863 //
1864 if (Pe32 == NULL) {
1865 return EFI_INVALID_PARAMETER;
1866 }
1867
1868 //
1869 // First check whether it is one TE Image.
1870 //
1871 TeHeader = (EFI_TE_IMAGE_HEADER *) Pe32;
1872 if (TeHeader->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
1873 //
1874 // By TeImage Header to get output
1875 //
1876 *EntryPoint = TeHeader->AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;
1877 *BaseOfCode = TeHeader->BaseOfCode + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;
1878 *MachineType = TeHeader->Machine;
1879 } else {
1880
1881 //
1882 // Then check whether
1883 // First is the DOS header
1884 //
1885 DosHeader = (EFI_IMAGE_DOS_HEADER *) Pe32;
1886
1887 //
1888 // Verify DOS header is expected
1889 //
1890 if (DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
1891 Error (NULL, 0, 3000, "Invalid", "Unknown magic number in the DOS header, 0x%04X.", DosHeader->e_magic);
1892 return EFI_UNSUPPORTED;
1893 }
1894 //
1895 // Immediately following is the NT header.
1896 //
1897 ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN) Pe32 + DosHeader->e_lfanew);
1898
1899 //
1900 // Verify NT header is expected
1901 //
1902 if (ImgHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
1903 Error (NULL, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", (unsigned) ImgHdr->Pe32.Signature);
1904 return EFI_UNSUPPORTED;
1905 }
1906 //
1907 // Get output
1908 //
1909 *EntryPoint = ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
1910 *BaseOfCode = ImgHdr->Pe32.OptionalHeader.BaseOfCode;
1911 *MachineType = ImgHdr->Pe32.FileHeader.Machine;
1912 }
1913
1914 //
1915 // Verify machine type is supported
1916 //
1917 if (*MachineType != EFI_IMAGE_MACHINE_IA32 && *MachineType != EFI_IMAGE_MACHINE_IA64 && *MachineType != EFI_IMAGE_MACHINE_X64 && *MachineType != EFI_IMAGE_MACHINE_EBC &&
1918 *MachineType != EFI_IMAGE_MACHINE_ARMT) {
1919 Error (NULL, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");
1920 return EFI_UNSUPPORTED;
1921 }
1922
1923 return EFI_SUCCESS;
1924 }
1925
1926 EFI_STATUS
1927 GenerateFvImage (
1928 IN CHAR8 *InfFileImage,
1929 IN UINTN InfFileSize,
1930 IN CHAR8 *FvFileName,
1931 IN CHAR8 *MapFileName
1932 )
1933 /*++
1934
1935 Routine Description:
1936
1937 This is the main function which will be called from application.
1938
1939 Arguments:
1940
1941 InfFileImage Buffer containing the INF file contents.
1942 InfFileSize Size of the contents of the InfFileImage buffer.
1943 FvFileName Requested name for the FV file.
1944 MapFileName Fv map file to log fv driver information.
1945
1946 Returns:
1947
1948 EFI_SUCCESS Function completed successfully.
1949 EFI_OUT_OF_RESOURCES Could not allocate required resources.
1950 EFI_ABORTED Error encountered.
1951 EFI_INVALID_PARAMETER A required parameter was NULL.
1952
1953 --*/
1954 {
1955 EFI_STATUS Status;
1956 MEMORY_FILE InfMemoryFile;
1957 MEMORY_FILE FvImageMemoryFile;
1958 UINTN Index;
1959 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
1960 EFI_FFS_FILE_HEADER *VtfFileImage;
1961 UINT8 *FvBufferHeader; // to make sure fvimage header 8 type alignment.
1962 UINT8 *FvImage;
1963 UINTN FvImageSize;
1964 FILE *FvFile;
1965 CHAR8 FvMapName [_MAX_PATH];
1966 FILE *FvMapFile;
1967 EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
1968 FILE *FvExtHeaderFile;
1969 UINTN FileSize;
1970
1971 FvBufferHeader = NULL;
1972 FvFile = NULL;
1973 FvMapFile = NULL;
1974
1975 if (InfFileImage != NULL) {
1976 //
1977 // Initialize file structures
1978 //
1979 InfMemoryFile.FileImage = InfFileImage;
1980 InfMemoryFile.CurrentFilePointer = InfFileImage;
1981 InfMemoryFile.Eof = InfFileImage + InfFileSize;
1982
1983 //
1984 // Parse the FV inf file for header information
1985 //
1986 Status = ParseFvInf (&InfMemoryFile, &mFvDataInfo);
1987 if (EFI_ERROR (Status)) {
1988 Error (NULL, 0, 0003, "Error parsing file", "the input FV INF file.");
1989 return Status;
1990 }
1991 }
1992
1993 //
1994 // Update the file name return values
1995 //
1996 if (FvFileName == NULL && mFvDataInfo.FvName[0] != '\0') {
1997 FvFileName = mFvDataInfo.FvName;
1998 }
1999
2000 if (FvFileName == NULL) {
2001 Error (NULL, 0, 1001, "Missing option", "Output file name");
2002 return EFI_ABORTED;
2003 }
2004
2005 if (mFvDataInfo.FvBlocks[0].Length == 0) {
2006 Error (NULL, 0, 1001, "Missing required argument", "Block Size");
2007 return EFI_ABORTED;
2008 }
2009
2010 //
2011 // Debug message Fv File System Guid
2012 //
2013 if (mFvDataInfo.FvFileSystemGuidSet) {
2014 DebugMsg (NULL, 0, 9, "FV File System Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
2015 (unsigned) mFvDataInfo.FvFileSystemGuid.Data1,
2016 mFvDataInfo.FvFileSystemGuid.Data2,
2017 mFvDataInfo.FvFileSystemGuid.Data3,
2018 mFvDataInfo.FvFileSystemGuid.Data4[0],
2019 mFvDataInfo.FvFileSystemGuid.Data4[1],
2020 mFvDataInfo.FvFileSystemGuid.Data4[2],
2021 mFvDataInfo.FvFileSystemGuid.Data4[3],
2022 mFvDataInfo.FvFileSystemGuid.Data4[4],
2023 mFvDataInfo.FvFileSystemGuid.Data4[5],
2024 mFvDataInfo.FvFileSystemGuid.Data4[6],
2025 mFvDataInfo.FvFileSystemGuid.Data4[7]);
2026 }
2027
2028 //
2029 // Add PI FV extension header
2030 //
2031 FvExtHeader = NULL;
2032 FvExtHeaderFile = NULL;
2033 if (mFvDataInfo.FvExtHeaderFile[0] != 0) {
2034 //
2035 // Open the FV Extension Header file
2036 //
2037 FvExtHeaderFile = fopen (mFvDataInfo.FvExtHeaderFile, "rb");
2038
2039 //
2040 // Get the file size
2041 //
2042 FileSize = _filelength (fileno (FvExtHeaderFile));
2043
2044 //
2045 // Allocate a buffer for the FV Extension Header
2046 //
2047 FvExtHeader = malloc(FileSize);
2048 if (FvExtHeader == NULL) {
2049 fclose (FvExtHeaderFile);
2050 return EFI_OUT_OF_RESOURCES;
2051 }
2052
2053 //
2054 // Read the FV Extension Header
2055 //
2056 fread (FvExtHeader, sizeof (UINT8), FileSize, FvExtHeaderFile);
2057 fclose (FvExtHeaderFile);
2058
2059 //
2060 // See if there is an override for the FV Name GUID
2061 //
2062 if (mFvDataInfo.FvNameGuidSet) {
2063 memcpy (&FvExtHeader->FvName, &mFvDataInfo.FvNameGuid, sizeof (EFI_GUID));
2064 }
2065 memcpy (&mFvDataInfo.FvNameGuid, &FvExtHeader->FvName, sizeof (EFI_GUID));
2066 mFvDataInfo.FvNameGuidSet = TRUE;
2067 } else if (mFvDataInfo.FvNameGuidSet) {
2068 //
2069 // Allocate a buffer for the FV Extension Header
2070 //
2071 FvExtHeader = malloc(sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER));
2072 if (FvExtHeader == NULL) {
2073 return EFI_OUT_OF_RESOURCES;
2074 }
2075 memcpy (&FvExtHeader->FvName, &mFvDataInfo.FvNameGuid, sizeof (EFI_GUID));
2076 FvExtHeader->ExtHeaderSize = sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER);
2077 }
2078
2079 //
2080 // Debug message Fv Name Guid
2081 //
2082 if (mFvDataInfo.FvNameGuidSet) {
2083 DebugMsg (NULL, 0, 9, "FV Name Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
2084 (unsigned) mFvDataInfo.FvNameGuid.Data1,
2085 mFvDataInfo.FvNameGuid.Data2,
2086 mFvDataInfo.FvNameGuid.Data3,
2087 mFvDataInfo.FvNameGuid.Data4[0],
2088 mFvDataInfo.FvNameGuid.Data4[1],
2089 mFvDataInfo.FvNameGuid.Data4[2],
2090 mFvDataInfo.FvNameGuid.Data4[3],
2091 mFvDataInfo.FvNameGuid.Data4[4],
2092 mFvDataInfo.FvNameGuid.Data4[5],
2093 mFvDataInfo.FvNameGuid.Data4[6],
2094 mFvDataInfo.FvNameGuid.Data4[7]);
2095 }
2096
2097 if (CompareGuid (&mFvDataInfo.FvFileSystemGuid, &mEfiFirmwareFileSystem2Guid) == 0) {
2098 mFvDataInfo.IsPiFvImage = TRUE;
2099 }
2100
2101 //
2102 // FvMap file to log the function address of all modules in one Fvimage
2103 //
2104 if (MapFileName != NULL) {
2105 strcpy (FvMapName, MapFileName);
2106 } else {
2107 strcpy (FvMapName, FvFileName);
2108 strcat (FvMapName, ".map");
2109 }
2110 VerboseMsg ("FV Map file name is %s", FvMapName);
2111
2112 //
2113 // Calculate the FV size and Update Fv Size based on the actual FFS files.
2114 // And Update mFvDataInfo data.
2115 //
2116 Status = CalculateFvSize (&mFvDataInfo);
2117 if (EFI_ERROR (Status)) {
2118 return Status;
2119 }
2120 VerboseMsg ("the generated FV image size is %u bytes", (unsigned) mFvDataInfo.Size);
2121
2122 //
2123 // support fv image and empty fv image
2124 //
2125 FvImageSize = mFvDataInfo.Size;
2126
2127 //
2128 // Allocate the FV, assure FvImage Header 8 byte alignment
2129 //
2130 FvBufferHeader = malloc (FvImageSize + sizeof (UINT64));
2131 if (FvBufferHeader == NULL) {
2132 return EFI_OUT_OF_RESOURCES;
2133 }
2134 FvImage = (UINT8 *) (((UINTN) FvBufferHeader + 7) & ~7);
2135
2136 //
2137 // Initialize the FV to the erase polarity
2138 //
2139 if (mFvDataInfo.FvAttributes == 0) {
2140 //
2141 // Set Default Fv Attribute
2142 //
2143 mFvDataInfo.FvAttributes = FV_DEFAULT_ATTRIBUTE;
2144 }
2145 if (mFvDataInfo.FvAttributes & EFI_FVB2_ERASE_POLARITY) {
2146 memset (FvImage, -1, FvImageSize);
2147 } else {
2148 memset (FvImage, 0, FvImageSize);
2149 }
2150
2151 //
2152 // Initialize FV header
2153 //
2154 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvImage;
2155
2156 //
2157 // Initialize the zero vector to all zeros.
2158 //
2159 memset (FvHeader->ZeroVector, 0, 16);
2160
2161 //
2162 // Copy the Fv file system GUID
2163 //
2164 memcpy (&FvHeader->FileSystemGuid, &mFvDataInfo.FvFileSystemGuid, sizeof (EFI_GUID));
2165
2166 FvHeader->FvLength = FvImageSize;
2167 FvHeader->Signature = EFI_FVH_SIGNATURE;
2168 FvHeader->Attributes = mFvDataInfo.FvAttributes;
2169 FvHeader->Revision = EFI_FVH_REVISION;
2170 FvHeader->ExtHeaderOffset = 0;
2171 FvHeader->Reserved[0] = 0;
2172
2173 //
2174 // Copy firmware block map
2175 //
2176 for (Index = 0; mFvDataInfo.FvBlocks[Index].Length != 0; Index++) {
2177 FvHeader->BlockMap[Index].NumBlocks = mFvDataInfo.FvBlocks[Index].NumBlocks;
2178 FvHeader->BlockMap[Index].Length = mFvDataInfo.FvBlocks[Index].Length;
2179 }
2180
2181 //
2182 // Add block map terminator
2183 //
2184 FvHeader->BlockMap[Index].NumBlocks = 0;
2185 FvHeader->BlockMap[Index].Length = 0;
2186
2187 //
2188 // Complete the header
2189 //
2190 FvHeader->HeaderLength = (UINT16) (((UINTN) &(FvHeader->BlockMap[Index + 1])) - (UINTN) FvImage);
2191 FvHeader->Checksum = 0;
2192 FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
2193
2194 //
2195 // If there is no FFS file, generate one empty FV
2196 //
2197 if (mFvDataInfo.FvFiles[0][0] == 0 && !mFvDataInfo.FvNameGuidSet) {
2198 goto WriteFile;
2199 }
2200
2201 //
2202 // Initialize our "file" view of the buffer
2203 //
2204 FvImageMemoryFile.FileImage = (CHAR8 *)FvImage;
2205 FvImageMemoryFile.CurrentFilePointer = (CHAR8 *)FvImage + FvHeader->HeaderLength;
2206 FvImageMemoryFile.Eof = (CHAR8 *)FvImage + FvImageSize;
2207
2208 //
2209 // Initialize the FV library.
2210 //
2211 InitializeFvLib (FvImageMemoryFile.FileImage, FvImageSize);
2212
2213 //
2214 // Initialize the VTF file address.
2215 //
2216 VtfFileImage = (EFI_FFS_FILE_HEADER *) FvImageMemoryFile.Eof;
2217
2218 //
2219 // Open FvMap file
2220 //
2221 FvMapFile = fopen (FvMapName, "w");
2222 if (FvMapFile == NULL) {
2223 Error (NULL, 0, 0001, "Error opening file", FvMapName);
2224 return EFI_ABORTED;
2225 }
2226
2227 //
2228 // record FV size information into FvMap file.
2229 //
2230 if (mFvTotalSize != 0) {
2231 fprintf (FvMapFile, EFI_FV_TOTAL_SIZE_STRING);
2232 fprintf (FvMapFile, " = 0x%x\n", (unsigned) mFvTotalSize);
2233 }
2234 if (mFvTakenSize != 0) {
2235 fprintf (FvMapFile, EFI_FV_TAKEN_SIZE_STRING);
2236 fprintf (FvMapFile, " = 0x%x\n", (unsigned) mFvTakenSize);
2237 }
2238 if (mFvTotalSize != 0 && mFvTakenSize != 0) {
2239 fprintf (FvMapFile, EFI_FV_SPACE_SIZE_STRING);
2240 fprintf (FvMapFile, " = 0x%x\n\n", (unsigned) (mFvTotalSize - mFvTakenSize));
2241 }
2242
2243 //
2244 // Add PI FV extension header
2245 //
2246 if (FvExtHeader != NULL) {
2247 //
2248 // Add FV Extended Header contents to the FV as a PAD file
2249 //
2250 AddPadFile (&FvImageMemoryFile, 4, VtfFileImage, FvExtHeader);
2251
2252 //
2253 // Fv Extension header change update Fv Header Check sum
2254 //
2255 FvHeader->Checksum = 0;
2256 FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
2257 }
2258
2259 //
2260 // Add files to FV
2261 //
2262 for (Index = 0; mFvDataInfo.FvFiles[Index][0] != 0; Index++) {
2263 //
2264 // Add the file
2265 //
2266 Status = AddFile (&FvImageMemoryFile, &mFvDataInfo, Index, &VtfFileImage, FvMapFile);
2267
2268 //
2269 // Exit if error detected while adding the file
2270 //
2271 if (EFI_ERROR (Status)) {
2272 goto Finish;
2273 }
2274 }
2275
2276 //
2277 // If there is a VTF file, some special actions need to occur.
2278 //
2279 if ((UINTN) VtfFileImage != (UINTN) FvImageMemoryFile.Eof) {
2280 //
2281 // Pad from the end of the last file to the beginning of the VTF file.
2282 // If the left space is less than sizeof (EFI_FFS_FILE_HEADER)?
2283 //
2284 Status = PadFvImage (&FvImageMemoryFile, VtfFileImage);
2285 if (EFI_ERROR (Status)) {
2286 Error (NULL, 0, 4002, "Resource", "FV space is full, cannot add pad file between the last file and the VTF file.");
2287 goto Finish;
2288 }
2289 if (!mArm) {
2290 //
2291 // Update reset vector (SALE_ENTRY for IPF)
2292 // Now for IA32 and IA64 platform, the fv which has bsf file must have the
2293 // EndAddress of 0xFFFFFFFF. Thus, only this type fv needs to update the
2294 // reset vector. If the PEI Core is found, the VTF file will probably get
2295 // corrupted by updating the entry point.
2296 //
2297 if ((mFvDataInfo.BaseAddress + mFvDataInfo.Size) == FV_IMAGES_TOP_ADDRESS) {
2298 Status = UpdateResetVector (&FvImageMemoryFile, &mFvDataInfo, VtfFileImage);
2299 if (EFI_ERROR(Status)) {
2300 Error (NULL, 0, 3000, "Invalid", "Could not update the reset vector.");
2301 goto Finish;
2302 }
2303 DebugMsg (NULL, 0, 9, "Update Reset vector in VTF file", NULL);
2304 }
2305 }
2306 }
2307
2308 if (mArm) {
2309 Status = UpdateArmResetVectorIfNeeded (&FvImageMemoryFile, &mFvDataInfo);
2310 if (EFI_ERROR (Status)) {
2311 Error (NULL, 0, 3000, "Invalid", "Could not update the reset vector.");
2312 goto Finish;
2313 }
2314
2315 //
2316 // Update Checksum for FvHeader
2317 //
2318 FvHeader->Checksum = 0;
2319 FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
2320 }
2321
2322 //
2323 // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV
2324 //
2325 if ((((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16)) < MaxFfsAlignment) {
2326 FvHeader->Attributes = ((MaxFfsAlignment << 16) | (FvHeader->Attributes & 0xFFFF));
2327 //
2328 // Update Checksum for FvHeader
2329 //
2330 FvHeader->Checksum = 0;
2331 FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
2332 }
2333
2334 WriteFile:
2335 //
2336 // Write fv file
2337 //
2338 FvFile = fopen (FvFileName, "wb");
2339 if (FvFile == NULL) {
2340 Error (NULL, 0, 0001, "Error opening file", FvFileName);
2341 Status = EFI_ABORTED;
2342 goto Finish;
2343 }
2344
2345 if (fwrite (FvImage, 1, FvImageSize, FvFile) != FvImageSize) {
2346 Error (NULL, 0, 0002, "Error writing file", FvFileName);
2347 Status = EFI_ABORTED;
2348 goto Finish;
2349 }
2350
2351 Finish:
2352 if (FvBufferHeader != NULL) {
2353 free (FvBufferHeader);
2354 }
2355
2356 if (FvExtHeader != NULL) {
2357 free (FvExtHeader);
2358 }
2359
2360 if (FvFile != NULL) {
2361 fclose (FvFile);
2362 }
2363
2364 if (FvMapFile != NULL) {
2365 fclose (FvMapFile);
2366 }
2367
2368 return Status;
2369 }
2370
2371 EFI_STATUS
2372 UpdatePeiCoreEntryInFit (
2373 IN FIT_TABLE *FitTablePtr,
2374 IN UINT64 PeiCorePhysicalAddress
2375 )
2376 /*++
2377
2378 Routine Description:
2379
2380 This function is used to update the Pei Core address in FIT, this can be used by Sec core to pass control from
2381 Sec to Pei Core
2382
2383 Arguments:
2384
2385 FitTablePtr - The pointer of FIT_TABLE.
2386 PeiCorePhysicalAddress - The address of Pei Core entry.
2387
2388 Returns:
2389
2390 EFI_SUCCESS - The PEI_CORE FIT entry was updated successfully.
2391 EFI_NOT_FOUND - Not found the PEI_CORE FIT entry.
2392
2393 --*/
2394 {
2395 FIT_TABLE *TmpFitPtr;
2396 UINTN Index;
2397 UINTN NumFitComponents;
2398
2399 TmpFitPtr = FitTablePtr;
2400 NumFitComponents = TmpFitPtr->CompSize;
2401
2402 for (Index = 0; Index < NumFitComponents; Index++) {
2403 if ((TmpFitPtr->CvAndType & FIT_TYPE_MASK) == COMP_TYPE_FIT_PEICORE) {
2404 TmpFitPtr->CompAddress = PeiCorePhysicalAddress;
2405 return EFI_SUCCESS;
2406 }
2407
2408 TmpFitPtr++;
2409 }
2410
2411 return EFI_NOT_FOUND;
2412 }
2413
2414 VOID
2415 UpdateFitCheckSum (
2416 IN FIT_TABLE *FitTablePtr
2417 )
2418 /*++
2419
2420 Routine Description:
2421
2422 This function is used to update the checksum for FIT.
2423
2424
2425 Arguments:
2426
2427 FitTablePtr - The pointer of FIT_TABLE.
2428
2429 Returns:
2430
2431 None.
2432
2433 --*/
2434 {
2435 if ((FitTablePtr->CvAndType & CHECKSUM_BIT_MASK) >> 7) {
2436 FitTablePtr->CheckSum = 0;
2437 FitTablePtr->CheckSum = CalculateChecksum8 ((UINT8 *) FitTablePtr, FitTablePtr->CompSize * 16);
2438 }
2439 }
2440
2441 EFI_STATUS
2442 CalculateFvSize (
2443 FV_INFO *FvInfoPtr
2444 )
2445 /*++
2446 Routine Description:
2447 Calculate the FV size and Update Fv Size based on the actual FFS files.
2448 And Update FvInfo data.
2449
2450 Arguments:
2451 FvInfoPtr - The pointer to FV_INFO structure.
2452
2453 Returns:
2454 EFI_ABORTED - Ffs Image Error
2455 EFI_SUCCESS - Successfully update FvSize
2456 --*/
2457 {
2458 UINTN CurrentOffset;
2459 UINTN Index;
2460 FILE *fpin;
2461 UINTN FfsFileSize;
2462 UINTN FvExtendHeaderSize;
2463 UINT32 FfsAlignment;
2464 EFI_FFS_FILE_HEADER FfsHeader;
2465 BOOLEAN VtfFileFlag;
2466 UINTN VtfFileSize;
2467
2468 FvExtendHeaderSize = 0;
2469 VtfFileSize = 0;
2470 VtfFileFlag = FALSE;
2471 fpin = NULL;
2472 Index = 0;
2473
2474 //
2475 // Compute size for easy access later
2476 //
2477 FvInfoPtr->Size = 0;
2478 for (Index = 0; FvInfoPtr->FvBlocks[Index].NumBlocks > 0 && FvInfoPtr->FvBlocks[Index].Length > 0; Index++) {
2479 FvInfoPtr->Size += FvInfoPtr->FvBlocks[Index].NumBlocks * FvInfoPtr->FvBlocks[Index].Length;
2480 }
2481
2482 //
2483 // Caculate the required sizes for all FFS files.
2484 //
2485 CurrentOffset = sizeof (EFI_FIRMWARE_VOLUME_HEADER);
2486
2487 for (Index = 1;; Index ++) {
2488 CurrentOffset += sizeof (EFI_FV_BLOCK_MAP_ENTRY);
2489 if (FvInfoPtr->FvBlocks[Index].NumBlocks == 0 || FvInfoPtr->FvBlocks[Index].Length == 0) {
2490 break;
2491 }
2492 }
2493
2494 //
2495 // Calculate PI extension header
2496 //
2497 if (mFvDataInfo.FvExtHeaderFile[0] != '\0') {
2498 fpin = fopen (mFvDataInfo.FvExtHeaderFile, "rb");
2499 if (fpin == NULL) {
2500 Error (NULL, 0, 0001, "Error opening file", mFvDataInfo.FvExtHeaderFile);
2501 return EFI_ABORTED;
2502 }
2503 FvExtendHeaderSize = _filelength (fileno (fpin));
2504 fclose (fpin);
2505 CurrentOffset += sizeof (EFI_FFS_FILE_HEADER) + FvExtendHeaderSize;
2506 CurrentOffset = (CurrentOffset + 7) & (~7);
2507 } else if (mFvDataInfo.FvNameGuidSet) {
2508 CurrentOffset += sizeof (EFI_FFS_FILE_HEADER) + sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER);
2509 CurrentOffset = (CurrentOffset + 7) & (~7);
2510 }
2511
2512 //
2513 // Accumlate every FFS file size.
2514 //
2515 for (Index = 0; FvInfoPtr->FvFiles[Index][0] != 0; Index++) {
2516 //
2517 // Open FFS file
2518 //
2519 fpin = NULL;
2520 fpin = fopen (FvInfoPtr->FvFiles[Index], "rb");
2521 if (fpin == NULL) {
2522 Error (NULL, 0, 0001, "Error opening file", FvInfoPtr->FvFiles[Index]);
2523 return EFI_ABORTED;
2524 }
2525 //
2526 // Get the file size
2527 //
2528 FfsFileSize = _filelength (fileno (fpin));
2529 //
2530 // Read Ffs File header
2531 //
2532 fread (&FfsHeader, sizeof (UINT8), sizeof (EFI_FFS_FILE_HEADER), fpin);
2533 //
2534 // close file
2535 //
2536 fclose (fpin);
2537
2538 if (FvInfoPtr->IsPiFvImage) {
2539 //
2540 // Check whether this ffs file is vtf file
2541 //
2542 if (IsVtfFile (&FfsHeader)) {
2543 if (VtfFileFlag) {
2544 //
2545 // One Fv image can't have two vtf files.
2546 //
2547 return EFI_ABORTED;
2548 }
2549 VtfFileFlag = TRUE;
2550 VtfFileSize = FfsFileSize;
2551 continue;
2552 }
2553
2554 //
2555 // Get the alignment of FFS file
2556 //
2557 ReadFfsAlignment (&FfsHeader, &FfsAlignment);
2558 FfsAlignment = 1 << FfsAlignment;
2559 //
2560 // Add Pad file
2561 //
2562 if (((CurrentOffset + sizeof (EFI_FFS_FILE_HEADER)) % FfsAlignment) != 0) {
2563 CurrentOffset = (CurrentOffset + sizeof (EFI_FFS_FILE_HEADER) * 2 + FfsAlignment - 1) & ~(FfsAlignment - 1);
2564 CurrentOffset -= sizeof (EFI_FFS_FILE_HEADER);
2565 }
2566 }
2567
2568 //
2569 // Add ffs file size
2570 //
2571 if (FvInfoPtr->SizeofFvFiles[Index] > FfsFileSize) {
2572 CurrentOffset += FvInfoPtr->SizeofFvFiles[Index];
2573 } else {
2574 CurrentOffset += FfsFileSize;
2575 }
2576
2577 //
2578 // Make next ffs file start at QWord Boundry
2579 //
2580 if (FvInfoPtr->IsPiFvImage) {
2581 CurrentOffset = (CurrentOffset + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1);
2582 }
2583 }
2584 CurrentOffset += VtfFileSize;
2585 DebugMsg (NULL, 0, 9, "FvImage size", "The caculated fv image size is 0x%x and the current set fv image size is 0x%x", (unsigned) CurrentOffset, (unsigned) FvInfoPtr->Size);
2586
2587 if (FvInfoPtr->Size == 0) {
2588 //
2589 // Update FvInfo data
2590 //
2591 FvInfoPtr->FvBlocks[0].NumBlocks = CurrentOffset / FvInfoPtr->FvBlocks[0].Length + ((CurrentOffset % FvInfoPtr->FvBlocks[0].Length)?1:0);
2592 FvInfoPtr->Size = FvInfoPtr->FvBlocks[0].NumBlocks * FvInfoPtr->FvBlocks[0].Length;
2593 FvInfoPtr->FvBlocks[1].NumBlocks = 0;
2594 FvInfoPtr->FvBlocks[1].Length = 0;
2595 } else if (FvInfoPtr->Size < CurrentOffset) {
2596 //
2597 // Not invalid
2598 //
2599 Error (NULL, 0, 3000, "Invalid", "the required fv image size 0x%x exceeds the set fv image size 0x%x", (unsigned) CurrentOffset, (unsigned) FvInfoPtr->Size);
2600 return EFI_INVALID_PARAMETER;
2601 }
2602
2603 //
2604 // Set Fv Size Information
2605 //
2606 mFvTotalSize = FvInfoPtr->Size;
2607 mFvTakenSize = CurrentOffset;
2608
2609 return EFI_SUCCESS;
2610 }
2611
2612 EFI_STATUS
2613 FfsRebaseImageRead (
2614 IN VOID *FileHandle,
2615 IN UINTN FileOffset,
2616 IN OUT UINT32 *ReadSize,
2617 OUT VOID *Buffer
2618 )
2619 /*++
2620
2621 Routine Description:
2622
2623 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
2624
2625 Arguments:
2626
2627 FileHandle - The handle to the PE/COFF file
2628
2629 FileOffset - The offset, in bytes, into the file to read
2630
2631 ReadSize - The number of bytes to read from the file starting at FileOffset
2632
2633 Buffer - A pointer to the buffer to read the data into.
2634
2635 Returns:
2636
2637 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
2638
2639 --*/
2640 {
2641 CHAR8 *Destination8;
2642 CHAR8 *Source8;
2643 UINT32 Length;
2644
2645 Destination8 = Buffer;
2646 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
2647 Length = *ReadSize;
2648 while (Length--) {
2649 *(Destination8++) = *(Source8++);
2650 }
2651
2652 return EFI_SUCCESS;
2653 }
2654
2655 EFI_STATUS
2656 FfsRebase (
2657 IN OUT FV_INFO *FvInfo,
2658 IN CHAR8 *FileName,
2659 IN OUT EFI_FFS_FILE_HEADER *FfsFile,
2660 IN UINTN XipOffset,
2661 IN FILE *FvMapFile
2662 )
2663 /*++
2664
2665 Routine Description:
2666
2667 This function determines if a file is XIP and should be rebased. It will
2668 rebase any PE32 sections found in the file using the base address.
2669
2670 Arguments:
2671
2672 FvInfo A pointer to FV_INFO struture.
2673 FileName Ffs File PathName
2674 FfsFile A pointer to Ffs file image.
2675 XipOffset The offset address to use for rebasing the XIP file image.
2676 FvMapFile FvMapFile to record the function address in one Fvimage
2677
2678 Returns:
2679
2680 EFI_SUCCESS The image was properly rebased.
2681 EFI_INVALID_PARAMETER An input parameter is invalid.
2682 EFI_ABORTED An error occurred while rebasing the input file image.
2683 EFI_OUT_OF_RESOURCES Could not allocate a required resource.
2684 EFI_NOT_FOUND No compressed sections could be found.
2685
2686 --*/
2687 {
2688 EFI_STATUS Status;
2689 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
2690 PE_COFF_LOADER_IMAGE_CONTEXT OrigImageContext;
2691 EFI_PHYSICAL_ADDRESS XipBase;
2692 EFI_PHYSICAL_ADDRESS NewPe32BaseAddress;
2693 EFI_PHYSICAL_ADDRESS *BaseToUpdate;
2694 UINTN Index;
2695 EFI_FILE_SECTION_POINTER CurrentPe32Section;
2696 EFI_FFS_FILE_STATE SavedState;
2697 EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
2698 EFI_TE_IMAGE_HEADER *TEImageHeader;
2699 UINT8 Flags;
2700 UINT8 *MemoryImagePointer;
2701 EFI_IMAGE_SECTION_HEADER *SectionHeader;
2702 CHAR8 PeFileName [_MAX_PATH];
2703 CHAR8 *Cptr;
2704 FILE *PeFile;
2705 UINT8 *PeFileBuffer;
2706 UINT32 PeFileSize;
2707 CHAR8 *PdbPointer;
2708
2709 Index = 0;
2710 MemoryImagePointer = NULL;
2711 BaseToUpdate = NULL;
2712 TEImageHeader = NULL;
2713 ImgHdr = NULL;
2714 SectionHeader = NULL;
2715 Cptr = NULL;
2716 PeFile = NULL;
2717 PeFileBuffer = NULL;
2718
2719 //
2720 // Check XipAddress, BootAddress and RuntimeAddress
2721 //
2722 Flags = 0;
2723 XipBase = 0;
2724 if (FvInfo->BaseAddress != 0) {
2725 Flags |= REBASE_XIP_FILE;
2726 XipBase = FvInfo->BaseAddress + XipOffset;
2727 }
2728 if (FvInfo->BootBaseAddress != 0) {
2729 Flags |= REBASE_BOOTTIME_FILE;
2730 }
2731 if (FvInfo->RuntimeBaseAddress != 0) {
2732 Flags |= REBASE_RUNTIME_FILE;
2733 }
2734
2735 //
2736 // Don't Rebase this FFS.
2737 // Only copy the original map file into the FvMap file
2738 // for the image that is not required to be relocated.
2739 //
2740
2741 //
2742 // We only process files potentially containing PE32 sections.
2743 //
2744 switch (FfsFile->Type) {
2745 case EFI_FV_FILETYPE_SECURITY_CORE:
2746 case EFI_FV_FILETYPE_PEI_CORE:
2747 case EFI_FV_FILETYPE_PEIM:
2748 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
2749 case EFI_FV_FILETYPE_DRIVER:
2750 case EFI_FV_FILETYPE_DXE_CORE:
2751 break;
2752 default:
2753 return EFI_SUCCESS;
2754 }
2755 //
2756 // Rebase each PE32 section
2757 //
2758 Status = EFI_SUCCESS;
2759 for (Index = 1;; Index++) {
2760 //
2761 // Init Value
2762 //
2763 NewPe32BaseAddress = 0;
2764
2765 //
2766 // Find Pe Image
2767 //
2768 Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);
2769 if (EFI_ERROR (Status)) {
2770 break;
2771 }
2772
2773 //
2774 // Initialize context
2775 //
2776 memset (&ImageContext, 0, sizeof (ImageContext));
2777 ImageContext.Handle = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION));
2778 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;
2779 Status = PeCoffLoaderGetImageInfo (&ImageContext);
2780 if (EFI_ERROR (Status)) {
2781 Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int) Status);
2782 return Status;
2783 }
2784
2785 if (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) {
2786 mArm = TRUE;
2787 }
2788
2789 //
2790 // Keep Image Context for PE image in FV
2791 //
2792 memcpy (&OrigImageContext, &ImageContext, sizeof (ImageContext));
2793
2794 //
2795 // Get File PdbPointer
2796 //
2797 PdbPointer = PeCoffLoaderGetPdbPointer (ImageContext.Handle);
2798
2799 //
2800 // Get PeHeader pointer
2801 //
2802 ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) + ImageContext.PeCoffHeaderOffset);
2803
2804 //
2805 // Calculate the PE32 base address, based on file type
2806 //
2807 switch (FfsFile->Type) {
2808 case EFI_FV_FILETYPE_SECURITY_CORE:
2809 case EFI_FV_FILETYPE_PEI_CORE:
2810 case EFI_FV_FILETYPE_PEIM:
2811 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
2812 if ((Flags & REBASE_XIP_FILE) == 0) {
2813 //
2814 // We aren't relocating XIP code, so skip it.
2815 //
2816 goto WritePeMap;
2817 }
2818
2819 //
2820 // Check if section-alignment and file-alignment match or not
2821 //
2822 if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {
2823 //
2824 // Xip module has the same section alignment and file alignment.
2825 //
2826 Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);
2827 return EFI_ABORTED;
2828 }
2829 //
2830 // PeImage has no reloc section. It will try to get reloc data from the original EFI image.
2831 //
2832 if (ImageContext.RelocationsStripped) {
2833 //
2834 // Construct the original efi file Name
2835 //
2836 strcpy (PeFileName, FileName);
2837 Cptr = PeFileName + strlen (PeFileName);
2838 while (*Cptr != '.') {
2839 Cptr --;
2840 }
2841 if (*Cptr != '.') {
2842 Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
2843 return EFI_ABORTED;
2844 } else {
2845 *(Cptr + 1) = 'e';
2846 *(Cptr + 2) = 'f';
2847 *(Cptr + 3) = 'i';
2848 *(Cptr + 4) = '\0';
2849 }
2850 PeFile = fopen (PeFileName, "rb");
2851 if (PeFile == NULL) {
2852 Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
2853 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
2854 //return EFI_ABORTED;
2855 break;
2856 }
2857 //
2858 // Get the file size
2859 //
2860 PeFileSize = _filelength (fileno (PeFile));
2861 PeFileBuffer = (UINT8 *) malloc (PeFileSize);
2862 if (PeFileBuffer == NULL) {
2863 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
2864 return EFI_OUT_OF_RESOURCES;
2865 }
2866 //
2867 // Read Pe File
2868 //
2869 fread (PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);
2870 //
2871 // close file
2872 //
2873 fclose (PeFile);
2874 //
2875 // Handle pointer to the original efi image.
2876 //
2877 ImageContext.Handle = PeFileBuffer;
2878 Status = PeCoffLoaderGetImageInfo (&ImageContext);
2879 if (EFI_ERROR (Status)) {
2880 Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int) Status);
2881 return Status;
2882 }
2883 ImageContext.RelocationsStripped = FALSE;
2884 }
2885
2886 NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) - (UINTN)FfsFile;
2887 BaseToUpdate = &XipBase;
2888 break;
2889
2890 case EFI_FV_FILETYPE_DRIVER:
2891 case EFI_FV_FILETYPE_DXE_CORE:
2892 switch (ImgHdr->Pe32.OptionalHeader.Subsystem) {
2893 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
2894 if ((Flags & REBASE_XIP_FILE) == REBASE_XIP_FILE) {
2895 //
2896 // Check if section-alignment and file-alignment match or not
2897 //
2898 if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {
2899 //
2900 // Xip module has the same section alignment and file alignment.
2901 //
2902 Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);
2903 return EFI_ABORTED;
2904 }
2905 NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) - (UINTN)FfsFile;
2906 BaseToUpdate = &XipBase;
2907 } else if ((Flags & REBASE_RUNTIME_FILE) == REBASE_RUNTIME_FILE) {
2908 //
2909 // make sure image base address at the section alignment
2910 //
2911 FvInfo->RuntimeBaseAddress = (FvInfo->RuntimeBaseAddress - ImageContext.ImageSize) & (~(ImageContext.SectionAlignment - 1));
2912 FvInfo->RuntimeBaseAddress = FvInfo->RuntimeBaseAddress & (~(EFI_PAGE_SIZE - 1));
2913 NewPe32BaseAddress = FvInfo->RuntimeBaseAddress;
2914 BaseToUpdate = &(FvInfo->RuntimeBaseAddress);
2915 } else {
2916 //
2917 // RT drivers aren't supposed to be relocated
2918 //
2919 goto WritePeMap;
2920 }
2921 break;
2922
2923 default:
2924 //
2925 // We treat all other subsystems the same as BS_DRIVER
2926 //
2927 if ((Flags & REBASE_XIP_FILE) == REBASE_XIP_FILE) {
2928 //
2929 // Check if section-alignment and file-alignment match or not
2930 //
2931 if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {
2932 //
2933 // Xip module has the same section alignment and file alignment.
2934 //
2935 Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);
2936 return EFI_ABORTED;
2937 }
2938 NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) - (UINTN)FfsFile;
2939 BaseToUpdate = &XipBase;
2940 } else if ((Flags & REBASE_BOOTTIME_FILE) == REBASE_BOOTTIME_FILE) {
2941 //
2942 // make sure image base address at the Section and Page alignment
2943 //
2944 FvInfo->BootBaseAddress = (FvInfo->BootBaseAddress - ImageContext.ImageSize) & (~(ImageContext.SectionAlignment - 1));
2945 FvInfo->BootBaseAddress = FvInfo->BootBaseAddress & (~(EFI_PAGE_SIZE - 1));
2946 NewPe32BaseAddress = FvInfo->BootBaseAddress;
2947 BaseToUpdate = &(FvInfo->BootBaseAddress);
2948 } else {
2949 //
2950 // Skip all BS_DRIVER's
2951 //
2952 goto WritePeMap;
2953 }
2954 break;
2955 }
2956 break;
2957
2958 default:
2959 //
2960 // Not supported file type
2961 //
2962 return EFI_SUCCESS;
2963 }
2964
2965 //
2966 // Relocation exist and rebase
2967 //
2968 if (!ImageContext.RelocationsStripped) {
2969 //
2970 // Load and Relocate Image Data
2971 //
2972 MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
2973 if (MemoryImagePointer == NULL) {
2974 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
2975 return EFI_OUT_OF_RESOURCES;
2976 }
2977 memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
2978 ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((INT64)ImageContext.SectionAlignment - 1));
2979
2980 Status = PeCoffLoaderLoadImage (&ImageContext);
2981 if (EFI_ERROR (Status)) {
2982 Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);
2983 free ((VOID *) MemoryImagePointer);
2984 return Status;
2985 }
2986
2987 ImageContext.DestinationAddress = NewPe32BaseAddress;
2988 Status = PeCoffLoaderRelocateImage (&ImageContext);
2989 if (EFI_ERROR (Status)) {
2990 Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName);
2991 free ((VOID *) MemoryImagePointer);
2992 return Status;
2993 }
2994
2995 //
2996 // Copy Relocated data to raw image file.
2997 //
2998 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (
2999 (UINTN) ImgHdr +
3000 sizeof (UINT32) +
3001 sizeof (EFI_IMAGE_FILE_HEADER) +
3002 ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
3003 );
3004
3005 for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {
3006 CopyMem (
3007 (UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER) + SectionHeader->PointerToRawData,
3008 (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress),
3009 SectionHeader->SizeOfRawData
3010 );
3011 }
3012
3013 free ((VOID *) MemoryImagePointer);
3014 MemoryImagePointer = NULL;
3015 if (PeFileBuffer != NULL) {
3016 free (PeFileBuffer);
3017 PeFileBuffer = NULL;
3018 }
3019 }
3020
3021 //
3022 // Update Image Base Address
3023 //
3024 if (ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
3025 ImgHdr->Pe32.OptionalHeader.ImageBase = (UINT32) NewPe32BaseAddress;
3026 } else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
3027 ImgHdr->Pe32Plus.OptionalHeader.ImageBase = NewPe32BaseAddress;
3028 } else {
3029 Error (NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",
3030 ImgHdr->Pe32.OptionalHeader.Magic,
3031 FileName
3032 );
3033 return EFI_ABORTED;
3034 }
3035
3036 //
3037 // Update BASE address by add one page size.
3038 //
3039 *BaseToUpdate -= EFI_PAGE_SIZE;
3040
3041 //
3042 // Now update file checksum
3043 //
3044 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
3045 SavedState = FfsFile->State;
3046 FfsFile->IntegrityCheck.Checksum.File = 0;
3047 FfsFile->State = 0;
3048 FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (
3049 (UINT8 *) (FfsFile + 1),
3050 GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_HEADER)
3051 );
3052 FfsFile->State = SavedState;
3053 }
3054
3055 //
3056 // Get this module function address from ModulePeMapFile and add them into FvMap file
3057 //
3058 WritePeMap:
3059 //
3060 // Default use FileName as map file path
3061 //
3062 if (PdbPointer == NULL) {
3063 PdbPointer = FileName;
3064 }
3065
3066 WriteMapFile (FvMapFile, PdbPointer, (EFI_GUID *) FfsFile, NewPe32BaseAddress, &OrigImageContext);
3067 }
3068
3069 if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&
3070 FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&
3071 FfsFile->Type != EFI_FV_FILETYPE_PEIM &&
3072 FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
3073 ) {
3074 //
3075 // Only Peim code may have a TE section
3076 //
3077 return EFI_SUCCESS;
3078 }
3079
3080 //
3081 // Now process TE sections
3082 //
3083 for (Index = 1;; Index++) {
3084 NewPe32BaseAddress = 0;
3085
3086 //
3087 // Find Te Image
3088 //
3089 Status = GetSectionByType (FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);
3090 if (EFI_ERROR (Status)) {
3091 break;
3092 }
3093
3094 //
3095 // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off
3096 // by GenTEImage
3097 //
3098 TEImageHeader = (EFI_TE_IMAGE_HEADER *) ((UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER));
3099
3100 //
3101 // Initialize context, load image info.
3102 //
3103 memset (&ImageContext, 0, sizeof (ImageContext));
3104 ImageContext.Handle = (VOID *) TEImageHeader;
3105 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;
3106 Status = PeCoffLoaderGetImageInfo (&ImageContext);
3107 if (EFI_ERROR (Status)) {
3108 Error (NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int) Status);
3109 return Status;
3110 }
3111
3112 if (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) {
3113 mArm = TRUE;
3114 }
3115
3116 //
3117 // Keep Image Context for TE image in FV
3118 //
3119 memcpy (&OrigImageContext, &ImageContext, sizeof (ImageContext));
3120
3121 //
3122 // Get File PdbPointer
3123 //
3124 PdbPointer = PeCoffLoaderGetPdbPointer (ImageContext.Handle);
3125
3126 if ((Flags & REBASE_XIP_FILE) == 0) {
3127 //
3128 // For none XIP PEIM module, their map info also are collected.
3129 //
3130 goto WriteTeMap;
3131 }
3132
3133 //
3134 // Set new rebased address.
3135 //
3136 NewPe32BaseAddress = XipBase + (UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \
3137 - TEImageHeader->StrippedSize - (UINTN) FfsFile;
3138
3139 //
3140 // if reloc is stripped, try to get the original efi image to get reloc info.
3141 //
3142 if (ImageContext.RelocationsStripped == TRUE) {
3143 //
3144 // Construct the original efi file name
3145 //
3146 strcpy (PeFileName, FileName);
3147 Cptr = PeFileName + strlen (PeFileName);
3148 while (*Cptr != '.') {
3149 Cptr --;
3150 }
3151
3152 if (*Cptr != '.') {
3153 Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3154 return EFI_ABORTED;
3155 } else {
3156 *(Cptr + 1) = 'e';
3157 *(Cptr + 2) = 'f';
3158 *(Cptr + 3) = 'i';
3159 *(Cptr + 4) = '\0';
3160 }
3161
3162 PeFile = fopen (PeFileName, "rb");
3163 if (PeFile == NULL) {
3164 Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
3165 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3166 //return EFI_ABORTED;
3167 } else {
3168 //
3169 // Get the file size
3170 //
3171 PeFileSize = _filelength (fileno (PeFile));
3172 PeFileBuffer = (UINT8 *) malloc (PeFileSize);
3173 if (PeFileBuffer == NULL) {
3174 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
3175 return EFI_OUT_OF_RESOURCES;
3176 }
3177 //
3178 // Read Pe File
3179 //
3180 fread (PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);
3181 //
3182 // close file
3183 //
3184 fclose (PeFile);
3185 //
3186 // Append reloc section into TeImage
3187 //
3188 ImageContext.Handle = PeFileBuffer;
3189 Status = PeCoffLoaderGetImageInfo (&ImageContext);
3190 if (EFI_ERROR (Status)) {
3191 Error (NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int) Status);
3192 return Status;
3193 }
3194 ImageContext.RelocationsStripped = FALSE;
3195 }
3196 }
3197
3198 //
3199 // Relocation exist and rebase
3200 //
3201 if (!ImageContext.RelocationsStripped) {
3202 //
3203 // Load and Relocate Image Data
3204 //
3205 MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
3206 if (MemoryImagePointer == NULL) {
3207 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
3208 return EFI_OUT_OF_RESOURCES;
3209 }
3210 memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
3211 ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~(ImageContext.SectionAlignment - 1));
3212
3213 Status = PeCoffLoaderLoadImage (&ImageContext);
3214 if (EFI_ERROR (Status)) {
3215 Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);
3216 free ((VOID *) MemoryImagePointer);
3217 return Status;
3218 }
3219 //
3220 // Reloacate TeImage
3221 //
3222 ImageContext.DestinationAddress = NewPe32BaseAddress;
3223 Status = PeCoffLoaderRelocateImage (&ImageContext);
3224 if (EFI_ERROR (Status)) {
3225 Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName);
3226 free ((VOID *) MemoryImagePointer);
3227 return Status;
3228 }
3229
3230 //
3231 // Copy the relocated image into raw image file.
3232 //
3233 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TEImageHeader + 1);
3234 for (Index = 0; Index < TEImageHeader->NumberOfSections; Index ++, SectionHeader ++) {
3235 if (!ImageContext.IsTeImage) {
3236 CopyMem (
3237 (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,
3238 (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress),
3239 SectionHeader->SizeOfRawData
3240 );
3241 } else {
3242 CopyMem (
3243 (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,
3244 (VOID*) (UINTN) (ImageContext.ImageAddress + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->VirtualAddress),
3245 SectionHeader->SizeOfRawData
3246 );
3247 }
3248 }
3249
3250 //
3251 // Free the allocated memory resource
3252 //
3253 free ((VOID *) MemoryImagePointer);
3254 MemoryImagePointer = NULL;
3255 if (PeFileBuffer != NULL) {
3256 free (PeFileBuffer);
3257 PeFileBuffer = NULL;
3258 }
3259 }
3260
3261 //
3262 // Update Image Base Address
3263 //
3264 TEImageHeader->ImageBase = NewPe32BaseAddress;
3265
3266 //
3267 // Now update file checksum
3268 //
3269 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
3270 SavedState = FfsFile->State;
3271 FfsFile->IntegrityCheck.Checksum.File = 0;
3272 FfsFile->State = 0;
3273 FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (
3274 (UINT8 *)(FfsFile + 1),
3275 GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_HEADER)
3276 );
3277 FfsFile->State = SavedState;
3278 }
3279 //
3280 // Get this module function address from ModulePeMapFile and add them into FvMap file
3281 //
3282 WriteTeMap:
3283 //
3284 // Default use FileName as map file path
3285 //
3286 if (PdbPointer == NULL) {
3287 PdbPointer = FileName;
3288 }
3289
3290 WriteMapFile (
3291 FvMapFile,
3292 PdbPointer,
3293 (EFI_GUID *) FfsFile,
3294 NewPe32BaseAddress,
3295 &OrigImageContext
3296 );
3297 }
3298
3299 return EFI_SUCCESS;
3300 }
3301
3302 EFI_STATUS
3303 FindApResetVectorPosition (
3304 IN MEMORY_FILE *FvImage,
3305 OUT UINT8 **Pointer
3306 )
3307 /*++
3308
3309 Routine Description:
3310
3311 Find the position in this FvImage to place Ap reset vector.
3312
3313 Arguments:
3314
3315 FvImage Memory file for the FV memory image.
3316 Pointer Pointer to pointer to position.
3317
3318 Returns:
3319
3320 EFI_NOT_FOUND - No satisfied position is found.
3321 EFI_SUCCESS - The suitable position is return.
3322
3323 --*/
3324 {
3325 EFI_FFS_FILE_HEADER *PadFile;
3326 UINT32 Index;
3327 EFI_STATUS Status;
3328 UINT8 *FixPoint;
3329 UINT32 FileLength;
3330
3331 for (Index = 1; ;Index ++) {
3332 //
3333 // Find Pad File to add ApResetVector info
3334 //
3335 Status = GetFileByType (EFI_FV_FILETYPE_FFS_PAD, Index, &PadFile);
3336 if (EFI_ERROR (Status) || (PadFile == NULL)) {
3337 //
3338 // No Pad file to be found.
3339 //
3340 break;
3341 }
3342 //
3343 // Get Pad file size.
3344 //
3345 FileLength = (*(UINT32 *)(PadFile->Size)) & 0x00FFFFFF;
3346 FileLength = (FileLength + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1);
3347 //
3348 // FixPoint must be align on 0x1000 relative to FvImage Header
3349 //
3350 FixPoint = (UINT8*) PadFile + sizeof (EFI_FFS_FILE_HEADER);
3351 FixPoint = FixPoint + 0x1000 - (((UINTN) FixPoint - (UINTN) FvImage->FileImage) & 0xFFF);
3352 //
3353 // FixPoint be larger at the last place of one fv image.
3354 //
3355 while (((UINTN) FixPoint + SIZEOF_STARTUP_DATA_ARRAY - (UINTN) PadFile) <= FileLength) {
3356 FixPoint += 0x1000;
3357 }
3358 FixPoint -= 0x1000;
3359
3360 if ((UINTN) FixPoint < ((UINTN) PadFile + sizeof (EFI_FFS_FILE_HEADER))) {
3361 //
3362 // No alignment FixPoint in this Pad File.
3363 //
3364 continue;
3365 }
3366
3367 if ((UINTN) FvImage->Eof - (UINTN)FixPoint <= 0x20000) {
3368 //
3369 // Find the position to place ApResetVector
3370 //
3371 *Pointer = FixPoint;
3372 return EFI_SUCCESS;
3373 }
3374 }
3375
3376 return EFI_NOT_FOUND;
3377 }
3378
3379 EFI_STATUS
3380 ParseCapInf (
3381 IN MEMORY_FILE *InfFile,
3382 OUT CAP_INFO *CapInfo
3383 )
3384 /*++
3385
3386 Routine Description:
3387
3388 This function parses a Cap.INF file and copies info into a CAP_INFO structure.
3389
3390 Arguments:
3391
3392 InfFile Memory file image.
3393 CapInfo Information read from INF file.
3394
3395 Returns:
3396
3397 EFI_SUCCESS INF file information successfully retrieved.
3398 EFI_ABORTED INF file has an invalid format.
3399 EFI_NOT_FOUND A required string was not found in the INF file.
3400 --*/
3401 {
3402 CHAR8 Value[_MAX_PATH];
3403 UINT64 Value64;
3404 UINTN Index, Number;
3405 EFI_STATUS Status;
3406
3407 //
3408 // Initialize Cap info
3409 //
3410 // memset (CapInfo, 0, sizeof (CAP_INFO));
3411 //
3412
3413 //
3414 // Read the Capsule Guid
3415 //
3416 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_GUID_STRING, 0, Value);
3417 if (Status == EFI_SUCCESS) {
3418 //
3419 // Get the Capsule Guid
3420 //
3421 Status = StringToGuid (Value, &CapInfo->CapGuid);
3422 if (EFI_ERROR (Status)) {
3423 Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_GUID_STRING, Value);
3424 return EFI_ABORTED;
3425 }
3426 DebugMsg (NULL, 0, 9, "Capsule Guid", "%s = %s", EFI_CAPSULE_GUID_STRING, Value);
3427 }
3428
3429 //
3430 // Read the Capsule Header Size
3431 //
3432 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_HEADER_SIZE_STRING, 0, Value);
3433 if (Status == EFI_SUCCESS) {
3434 Status = AsciiStringToUint64 (Value, FALSE, &Value64);
3435 if (EFI_ERROR (Status)) {
3436 Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING, Value);
3437 return EFI_ABORTED;
3438 }
3439 CapInfo->HeaderSize = (UINT32) Value64;
3440 DebugMsg (NULL, 0, 9, "Capsule Header size", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING, Value);
3441 }
3442
3443 //
3444 // Read the Capsule Flag
3445 //
3446 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_FLAGS_STRING, 0, Value);
3447 if (Status == EFI_SUCCESS) {
3448 if (strstr (Value, "PopulateSystemTable") != NULL) {
3449 CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE;
3450 if (strstr (Value, "InitiateReset") != NULL) {
3451 CapInfo->Flags |= CAPSULE_FLAGS_INITIATE_RESET;
3452 }
3453 } else if (strstr (Value, "PersistAcrossReset") != NULL) {
3454 CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
3455 if (strstr (Value, "InitiateReset") != NULL) {
3456 CapInfo->Flags |= CAPSULE_FLAGS_INITIATE_RESET;
3457 }
3458 } else {
3459 Error (NULL, 0, 2000, "Invalid parameter", "invalid Flag setting for %s.", EFI_CAPSULE_FLAGS_STRING);
3460 return EFI_ABORTED;
3461 }
3462 DebugMsg (NULL, 0, 9, "Capsule Flag", Value);
3463 }
3464
3465 //
3466 // Read Capsule File name
3467 //
3468 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FILE_NAME_STRING, 0, Value);
3469 if (Status == EFI_SUCCESS) {
3470 //
3471 // Get output file name
3472 //
3473 strcpy (CapInfo->CapName, Value);
3474 }
3475
3476 //
3477 // Read the Capsule FileImage
3478 //
3479 Number = 0;
3480 for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_CAP; Index++) {
3481 if (CapInfo->CapFiles[Index][0] != '\0') {
3482 continue;
3483 }
3484 //
3485 // Read the capsule file name
3486 //
3487 Status = FindToken (InfFile, FILES_SECTION_STRING, EFI_FILE_NAME_STRING, Number++, Value);
3488
3489 if (Status == EFI_SUCCESS) {
3490 //
3491 // Add the file
3492 //
3493 strcpy (CapInfo->CapFiles[Index], Value);
3494 DebugMsg (NULL, 0, 9, "Capsule component file", "the %uth file name is %s", (unsigned) Index, CapInfo->CapFiles[Index]);
3495 } else {
3496 break;
3497 }
3498 }
3499
3500 if (Index == 0) {
3501 Warning (NULL, 0, 0, "Capsule components are not specified.", NULL);
3502 }
3503
3504 return EFI_SUCCESS;
3505 }
3506
3507 EFI_STATUS
3508 GenerateCapImage (
3509 IN CHAR8 *InfFileImage,
3510 IN UINTN InfFileSize,
3511 IN CHAR8 *CapFileName
3512 )
3513 /*++
3514
3515 Routine Description:
3516
3517 This is the main function which will be called from application to create UEFI Capsule image.
3518
3519 Arguments:
3520
3521 InfFileImage Buffer containing the INF file contents.
3522 InfFileSize Size of the contents of the InfFileImage buffer.
3523 CapFileName Requested name for the Cap file.
3524
3525 Returns:
3526
3527 EFI_SUCCESS Function completed successfully.
3528 EFI_OUT_OF_RESOURCES Could not allocate required resources.
3529 EFI_ABORTED Error encountered.
3530 EFI_INVALID_PARAMETER A required parameter was NULL.
3531
3532 --*/
3533 {
3534 UINT32 CapSize;
3535 UINT8 *CapBuffer;
3536 EFI_CAPSULE_HEADER *CapsuleHeader;
3537 MEMORY_FILE InfMemoryFile;
3538 UINT32 FileSize;
3539 UINT32 Index;
3540 FILE *fpin, *fpout;
3541 EFI_STATUS Status;
3542
3543 if (InfFileImage != NULL) {
3544 //
3545 // Initialize file structures
3546 //
3547 InfMemoryFile.FileImage = InfFileImage;
3548 InfMemoryFile.CurrentFilePointer = InfFileImage;
3549 InfMemoryFile.Eof = InfFileImage + InfFileSize;
3550
3551 //
3552 // Parse the Cap inf file for header information
3553 //
3554 Status = ParseCapInf (&InfMemoryFile, &mCapDataInfo);
3555 if (Status != EFI_SUCCESS) {
3556 return Status;
3557 }
3558 }
3559
3560 if (mCapDataInfo.HeaderSize == 0) {
3561 //
3562 // make header size align 16 bytes.
3563 //
3564 mCapDataInfo.HeaderSize = sizeof (EFI_CAPSULE_HEADER);
3565 mCapDataInfo.HeaderSize = (mCapDataInfo.HeaderSize + 0xF) & ~0xF;
3566 }
3567
3568 if (mCapDataInfo.HeaderSize < sizeof (EFI_CAPSULE_HEADER)) {
3569 Error (NULL, 0, 2000, "Invalid parameter", "The specified HeaderSize cannot be less than the size of EFI_CAPSULE_HEADER.");
3570 return EFI_INVALID_PARAMETER;
3571 }
3572
3573 if (CapFileName == NULL && mCapDataInfo.CapName[0] != '\0') {
3574 CapFileName = mCapDataInfo.CapName;
3575 }
3576
3577 if (CapFileName == NULL) {
3578 Error (NULL, 0, 2001, "Missing required argument", "Output Capsule file name");
3579 return EFI_INVALID_PARAMETER;
3580 }
3581
3582 //
3583 // Set Default Capsule Guid value
3584 //
3585 if (CompareGuid (&mCapDataInfo.CapGuid, &mZeroGuid) == 0) {
3586 memcpy (&mCapDataInfo.CapGuid, &mDefaultCapsuleGuid, sizeof (EFI_GUID));
3587 }
3588 //
3589 // Calculate the size of capsule image.
3590 //
3591 Index = 0;
3592 FileSize = 0;
3593 CapSize = mCapDataInfo.HeaderSize;
3594 while (mCapDataInfo.CapFiles [Index][0] != '\0') {
3595 fpin = fopen (mCapDataInfo.CapFiles[Index], "rb");
3596 if (fpin == NULL) {
3597 Error (NULL, 0, 0001, "Error opening file", mCapDataInfo.CapFiles[Index]);
3598 return EFI_ABORTED;
3599 }
3600 FileSize = _filelength (fileno (fpin));
3601 CapSize += FileSize;
3602 fclose (fpin);
3603 Index ++;
3604 }
3605
3606 //
3607 // Allocate buffer for capsule image.
3608 //
3609 CapBuffer = (UINT8 *) malloc (CapSize);
3610 if (CapBuffer == NULL) {
3611 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated for creating the capsule.");
3612 return EFI_OUT_OF_RESOURCES;
3613 }
3614
3615 //
3616 // Initialize the capsule header to zero
3617 //
3618 memset (CapBuffer, 0, mCapDataInfo.HeaderSize);
3619
3620 //
3621 // create capsule header and get capsule body
3622 //
3623 CapsuleHeader = (EFI_CAPSULE_HEADER *) CapBuffer;
3624 memcpy (&CapsuleHeader->CapsuleGuid, &mCapDataInfo.CapGuid, sizeof (EFI_GUID));
3625 CapsuleHeader->HeaderSize = mCapDataInfo.HeaderSize;
3626 CapsuleHeader->Flags = mCapDataInfo.Flags;
3627 CapsuleHeader->CapsuleImageSize = CapSize;
3628
3629 Index = 0;
3630 FileSize = 0;
3631 CapSize = CapsuleHeader->HeaderSize;
3632 while (mCapDataInfo.CapFiles [Index][0] != '\0') {
3633 fpin = fopen (mCapDataInfo.CapFiles[Index], "rb");
3634 if (fpin == NULL) {
3635 Error (NULL, 0, 0001, "Error opening file", mCapDataInfo.CapFiles[Index]);
3636 free (CapBuffer);
3637 return EFI_ABORTED;
3638 }
3639 FileSize = _filelength (fileno (fpin));
3640 fread (CapBuffer + CapSize, 1, FileSize, fpin);
3641 fclose (fpin);
3642 Index ++;
3643 CapSize += FileSize;
3644 }
3645
3646 //
3647 // write capsule data into the output file
3648 //
3649 fpout = fopen (CapFileName, "wb");
3650 if (fpout == NULL) {
3651 Error (NULL, 0, 0001, "Error opening file", CapFileName);
3652 free (CapBuffer);
3653 return EFI_ABORTED;
3654 }
3655
3656 fwrite (CapBuffer, 1, CapSize, fpout);
3657 fclose (fpout);
3658
3659 VerboseMsg ("The size of the generated capsule image is %u bytes", (unsigned) CapSize);
3660
3661 return EFI_SUCCESS;
3662 }