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