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