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