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