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