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