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