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