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