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