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