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