]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/GenFv/GenFvInternalLib.c
BaseTools: BaseTools changes for RISC-V platform.
[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
3143 UINTN Index;\r
3144 FILE *fpin;\r
3145 UINTN FfsFileSize;\r
b303ea72 3146 UINTN FvExtendHeaderSize;\r
30fdf114 3147 UINT32 FfsAlignment;\r
e8a47801 3148 UINT32 FfsHeaderSize;\r
30fdf114 3149 EFI_FFS_FILE_HEADER FfsHeader;\r
fd171542 3150 UINTN VtfFileSize;\r
f7496d71 3151\r
b303ea72 3152 FvExtendHeaderSize = 0;\r
fd171542 3153 VtfFileSize = 0;\r
30fdf114
LG
3154 fpin = NULL;\r
3155 Index = 0;\r
3156\r
3157 //\r
3158 // Compute size for easy access later\r
3159 //\r
3160 FvInfoPtr->Size = 0;\r
3161 for (Index = 0; FvInfoPtr->FvBlocks[Index].NumBlocks > 0 && FvInfoPtr->FvBlocks[Index].Length > 0; Index++) {\r
3162 FvInfoPtr->Size += FvInfoPtr->FvBlocks[Index].NumBlocks * FvInfoPtr->FvBlocks[Index].Length;\r
3163 }\r
f7496d71 3164\r
30fdf114 3165 //\r
64957e35 3166 // Calculate the required sizes for all FFS files.\r
30fdf114
LG
3167 //\r
3168 CurrentOffset = sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
f7496d71 3169\r
30fdf114
LG
3170 for (Index = 1;; Index ++) {\r
3171 CurrentOffset += sizeof (EFI_FV_BLOCK_MAP_ENTRY);\r
3172 if (FvInfoPtr->FvBlocks[Index].NumBlocks == 0 || FvInfoPtr->FvBlocks[Index].Length == 0) {\r
3173 break;\r
3174 }\r
3175 }\r
f7496d71 3176\r
30fdf114
LG
3177 //\r
3178 // Calculate PI extension header\r
3179 //\r
b303ea72 3180 if (mFvDataInfo.FvExtHeaderFile[0] != '\0') {\r
1be2ed90 3181 fpin = fopen (LongFilePath (mFvDataInfo.FvExtHeaderFile), "rb");\r
b303ea72
LG
3182 if (fpin == NULL) {\r
3183 Error (NULL, 0, 0001, "Error opening file", mFvDataInfo.FvExtHeaderFile);\r
3184 return EFI_ABORTED;\r
3185 }\r
3186 FvExtendHeaderSize = _filelength (fileno (fpin));\r
3187 fclose (fpin);\r
e8a47801
LG
3188 if (sizeof (EFI_FFS_FILE_HEADER) + FvExtendHeaderSize >= MAX_FFS_SIZE) {\r
3189 CurrentOffset += sizeof (EFI_FFS_FILE_HEADER2) + FvExtendHeaderSize;\r
3190 mIsLargeFfs = TRUE;\r
3191 } else {\r
3192 CurrentOffset += sizeof (EFI_FFS_FILE_HEADER) + FvExtendHeaderSize;\r
3193 }\r
b303ea72
LG
3194 CurrentOffset = (CurrentOffset + 7) & (~7);\r
3195 } else if (mFvDataInfo.FvNameGuidSet) {\r
30fdf114
LG
3196 CurrentOffset += sizeof (EFI_FFS_FILE_HEADER) + sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER);\r
3197 CurrentOffset = (CurrentOffset + 7) & (~7);\r
3198 }\r
3199\r
3200 //\r
fb0b35e0 3201 // Accumulate every FFS file size.\r
30fdf114
LG
3202 //\r
3203 for (Index = 0; FvInfoPtr->FvFiles[Index][0] != 0; Index++) {\r
3204 //\r
3205 // Open FFS file\r
3206 //\r
3207 fpin = NULL;\r
1be2ed90 3208 fpin = fopen (LongFilePath (FvInfoPtr->FvFiles[Index]), "rb");\r
30fdf114
LG
3209 if (fpin == NULL) {\r
3210 Error (NULL, 0, 0001, "Error opening file", FvInfoPtr->FvFiles[Index]);\r
3211 return EFI_ABORTED;\r
3212 }\r
3213 //\r
3214 // Get the file size\r
3215 //\r
3216 FfsFileSize = _filelength (fileno (fpin));\r
e8a47801
LG
3217 if (FfsFileSize >= MAX_FFS_SIZE) {\r
3218 FfsHeaderSize = sizeof(EFI_FFS_FILE_HEADER2);\r
3219 mIsLargeFfs = TRUE;\r
3220 } else {\r
3221 FfsHeaderSize = sizeof(EFI_FFS_FILE_HEADER);\r
3222 }\r
30fdf114
LG
3223 //\r
3224 // Read Ffs File header\r
3225 //\r
3226 fread (&FfsHeader, sizeof (UINT8), sizeof (EFI_FFS_FILE_HEADER), fpin);\r
3227 //\r
3228 // close file\r
3229 //\r
3230 fclose (fpin);\r
f7496d71 3231\r
30fdf114 3232 if (FvInfoPtr->IsPiFvImage) {\r
2ff9e575
YZ
3233 //\r
3234 // Check whether this ffs file is vtf file\r
3235 //\r
3236 if (IsVtfFile (&FfsHeader)) {\r
3237 if (VtfFileFlag) {\r
3238 //\r
3239 // One Fv image can't have two vtf files.\r
3240 //\r
3241 Error (NULL, 0, 3000,"Invalid", "One Fv image can't have two vtf files.");\r
3242 return EFI_ABORTED;\r
3243 }\r
3244 VtfFileFlag = TRUE;\r
fd171542 3245 VtfFileSize = FfsFileSize;\r
3246 continue;\r
3247 }\r
3248\r
3249 //\r
f7496d71 3250 // Get the alignment of FFS file\r
fd171542 3251 //\r
3252 ReadFfsAlignment (&FfsHeader, &FfsAlignment);\r
3253 FfsAlignment = 1 << FfsAlignment;\r
3254 //\r
3255 // Add Pad file\r
3256 //\r
e8a47801
LG
3257 if (((CurrentOffset + FfsHeaderSize) % FfsAlignment) != 0) {\r
3258 //\r
3259 // Only EFI_FFS_FILE_HEADER is needed for a pad section.\r
3260 //\r
3261 CurrentOffset = (CurrentOffset + FfsHeaderSize + sizeof(EFI_FFS_FILE_HEADER) + FfsAlignment - 1) & ~(FfsAlignment - 1);\r
3262 CurrentOffset -= FfsHeaderSize;\r
fd171542 3263 }\r
f7496d71 3264 }\r
30fdf114
LG
3265\r
3266 //\r
3267 // Add ffs file size\r
3268 //\r
3269 if (FvInfoPtr->SizeofFvFiles[Index] > FfsFileSize) {\r
f7496d71 3270 CurrentOffset += FvInfoPtr->SizeofFvFiles[Index];\r
30fdf114 3271 } else {\r
f7496d71 3272 CurrentOffset += FfsFileSize;\r
30fdf114 3273 }\r
f7496d71 3274\r
30fdf114 3275 //\r
fb0b35e0 3276 // Make next ffs file start at QWord Boundary\r
30fdf114
LG
3277 //\r
3278 if (FvInfoPtr->IsPiFvImage) {\r
f7496d71 3279 CurrentOffset = (CurrentOffset + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1);\r
30fdf114
LG
3280 }\r
3281 }\r
fd171542 3282 CurrentOffset += VtfFileSize;\r
64957e35 3283 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
3284\r
3285 if (FvInfoPtr->Size == 0) {\r
30fdf114
LG
3286 //\r
3287 // Update FvInfo data\r
3288 //\r
3289 FvInfoPtr->FvBlocks[0].NumBlocks = CurrentOffset / FvInfoPtr->FvBlocks[0].Length + ((CurrentOffset % FvInfoPtr->FvBlocks[0].Length)?1:0);\r
3290 FvInfoPtr->Size = FvInfoPtr->FvBlocks[0].NumBlocks * FvInfoPtr->FvBlocks[0].Length;\r
3291 FvInfoPtr->FvBlocks[1].NumBlocks = 0;\r
3292 FvInfoPtr->FvBlocks[1].Length = 0;\r
3293 } else if (FvInfoPtr->Size < CurrentOffset) {\r
3294 //\r
3295 // Not invalid\r
3296 //\r
fd171542 3297 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
3298 return EFI_INVALID_PARAMETER;\r
3299 }\r
f7496d71 3300\r
30fdf114
LG
3301 //\r
3302 // Set Fv Size Information\r
3303 //\r
3304 mFvTotalSize = FvInfoPtr->Size;\r
3305 mFvTakenSize = CurrentOffset;\r
3306\r
3307 return EFI_SUCCESS;\r
3308}\r
3309\r
3310EFI_STATUS\r
3311FfsRebaseImageRead (\r
3312 IN VOID *FileHandle,\r
3313 IN UINTN FileOffset,\r
3314 IN OUT UINT32 *ReadSize,\r
3315 OUT VOID *Buffer\r
3316 )\r
3317/*++\r
3318\r
3319Routine Description:\r
3320\r
3321 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
3322\r
3323Arguments:\r
3324\r
3325 FileHandle - The handle to the PE/COFF file\r
3326\r
3327 FileOffset - The offset, in bytes, into the file to read\r
3328\r
3329 ReadSize - The number of bytes to read from the file starting at FileOffset\r
3330\r
3331 Buffer - A pointer to the buffer to read the data into.\r
3332\r
3333Returns:\r
3334\r
3335 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
3336\r
3337--*/\r
3338{\r
3339 CHAR8 *Destination8;\r
3340 CHAR8 *Source8;\r
3341 UINT32 Length;\r
3342\r
3343 Destination8 = Buffer;\r
3344 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
3345 Length = *ReadSize;\r
3346 while (Length--) {\r
3347 *(Destination8++) = *(Source8++);\r
3348 }\r
3349\r
3350 return EFI_SUCCESS;\r
3351}\r
3352\r
52302d4d
LG
3353EFI_STATUS\r
3354GetChildFvFromFfs (\r
f7496d71 3355 IN FV_INFO *FvInfo,\r
52302d4d
LG
3356 IN EFI_FFS_FILE_HEADER *FfsFile,\r
3357 IN UINTN XipOffset\r
3358 )\r
3359/*++\r
3360\r
3361Routine Description:\r
3362\r
3363 This function gets all child FvImages in the input FfsFile, and records\r
3364 their base address to the parent image.\r
3365\r
3366Arguments:\r
fb0b35e0 3367 FvInfo A pointer to FV_INFO structure.\r
52302d4d
LG
3368 FfsFile A pointer to Ffs file image that may contain FvImage.\r
3369 XipOffset The offset address to the parent FvImage base.\r
3370\r
3371Returns:\r
3372\r
3373 EFI_SUCCESS Base address of child Fv image is recorded.\r
3374--*/\r
3375{\r
3376 EFI_STATUS Status;\r
3377 UINTN Index;\r
3378 EFI_FILE_SECTION_POINTER SubFvSection;\r
3379 EFI_FIRMWARE_VOLUME_HEADER *SubFvImageHeader;\r
3380 EFI_PHYSICAL_ADDRESS SubFvBaseAddress;\r
eca22f36
EC
3381 EFI_FILE_SECTION_POINTER CorePe32;\r
3382 UINT16 MachineType;\r
52302d4d
LG
3383\r
3384 for (Index = 1;; Index++) {\r
3385 //\r
f7496d71 3386 // Find FV section\r
52302d4d
LG
3387 //\r
3388 Status = GetSectionByType (FfsFile, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, Index, &SubFvSection);\r
3389 if (EFI_ERROR (Status)) {\r
3390 break;\r
3391 }\r
e8a47801 3392 SubFvImageHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) SubFvSection.FVImageSection + GetSectionHeaderLength(SubFvSection.FVImageSection));\r
eca22f36
EC
3393\r
3394 //\r
3395 // See if there's an SEC core in the child FV\r
3396 Status = FindCorePeSection(SubFvImageHeader, SubFvImageHeader->FvLength, EFI_FV_FILETYPE_SECURITY_CORE, &CorePe32);\r
3397\r
3398 // if we couldn't find the SEC core, look for a PEI core\r
3399 if (EFI_ERROR(Status)) {\r
3400 Status = FindCorePeSection(SubFvImageHeader, SubFvImageHeader->FvLength, EFI_FV_FILETYPE_PEI_CORE, &CorePe32);\r
3401 }\r
3402\r
3403 if (!EFI_ERROR(Status)) {\r
3404 Status = GetCoreMachineType(CorePe32, &MachineType);\r
3405 if (EFI_ERROR(Status)) {\r
3406 Error(NULL, 0, 3000, "Invalid", "Could not get the PE32 machine type for SEC/PEI Core.");\r
3407 return EFI_ABORTED;\r
3408 }\r
3409\r
fb0b35e0 3410 // machine type is ARM, set a flag so ARM reset vector processing occurs\r
eca22f36
EC
3411 if ((MachineType == EFI_IMAGE_MACHINE_ARMT) || (MachineType == EFI_IMAGE_MACHINE_AARCH64)) {\r
3412 VerboseMsg("Located ARM/AArch64 SEC/PEI core in child FV");\r
3413 mArm = TRUE;\r
3414 }\r
3415 }\r
3416\r
52302d4d
LG
3417 //\r
3418 // Rebase on Flash\r
3419 //\r
3420 SubFvBaseAddress = FvInfo->BaseAddress + (UINTN) SubFvImageHeader - (UINTN) FfsFile + XipOffset;\r
3421 mFvBaseAddress[mFvBaseAddressNumber ++ ] = SubFvBaseAddress;\r
3422 }\r
3423\r
3424 return EFI_SUCCESS;\r
3425}\r
3426\r
30fdf114 3427EFI_STATUS\r
f7496d71
LG
3428FfsRebase (\r
3429 IN OUT FV_INFO *FvInfo,\r
3430 IN CHAR8 *FileName,\r
30fdf114
LG
3431 IN OUT EFI_FFS_FILE_HEADER *FfsFile,\r
3432 IN UINTN XipOffset,\r
3433 IN FILE *FvMapFile\r
3434 )\r
3435/*++\r
3436\r
3437Routine Description:\r
3438\r
3439 This function determines if a file is XIP and should be rebased. It will\r
3440 rebase any PE32 sections found in the file using the base address.\r
3441\r
3442Arguments:\r
f7496d71 3443\r
fb0b35e0 3444 FvInfo A pointer to FV_INFO structure.\r
30fdf114
LG
3445 FileName Ffs File PathName\r
3446 FfsFile A pointer to Ffs file image.\r
3447 XipOffset The offset address to use for rebasing the XIP file image.\r
3448 FvMapFile FvMapFile to record the function address in one Fvimage\r
3449\r
3450Returns:\r
3451\r
3452 EFI_SUCCESS The image was properly rebased.\r
3453 EFI_INVALID_PARAMETER An input parameter is invalid.\r
3454 EFI_ABORTED An error occurred while rebasing the input file image.\r
3455 EFI_OUT_OF_RESOURCES Could not allocate a required resource.\r
3456 EFI_NOT_FOUND No compressed sections could be found.\r
3457\r
3458--*/\r
3459{\r
3460 EFI_STATUS Status;\r
3461 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
f7496d71 3462 PE_COFF_LOADER_IMAGE_CONTEXT OrigImageContext;\r
30fdf114
LG
3463 EFI_PHYSICAL_ADDRESS XipBase;\r
3464 EFI_PHYSICAL_ADDRESS NewPe32BaseAddress;\r
30fdf114
LG
3465 UINTN Index;\r
3466 EFI_FILE_SECTION_POINTER CurrentPe32Section;\r
3467 EFI_FFS_FILE_STATE SavedState;\r
3468 EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;\r
3469 EFI_TE_IMAGE_HEADER *TEImageHeader;\r
30fdf114
LG
3470 UINT8 *MemoryImagePointer;\r
3471 EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
1be2ed90 3472 CHAR8 PeFileName [MAX_LONG_FILE_PATH];\r
30fdf114
LG
3473 CHAR8 *Cptr;\r
3474 FILE *PeFile;\r
3475 UINT8 *PeFileBuffer;\r
3476 UINT32 PeFileSize;\r
3477 CHAR8 *PdbPointer;\r
e8a47801
LG
3478 UINT32 FfsHeaderSize;\r
3479 UINT32 CurSecHdrSize;\r
30fdf114 3480\r
f7496d71 3481 Index = 0;\r
30fdf114 3482 MemoryImagePointer = NULL;\r
30fdf114
LG
3483 TEImageHeader = NULL;\r
3484 ImgHdr = NULL;\r
3485 SectionHeader = NULL;\r
3486 Cptr = NULL;\r
3487 PeFile = NULL;\r
3488 PeFileBuffer = NULL;\r
3489\r
3490 //\r
79b74a03 3491 // Don't need to relocate image when BaseAddress is zero and no ForceRebase Flag specified.\r
30fdf114 3492 //\r
79b74a03 3493 if ((FvInfo->BaseAddress == 0) && (FvInfo->ForceRebase == -1)) {\r
52302d4d 3494 return EFI_SUCCESS;\r
30fdf114 3495 }\r
f7496d71 3496\r
79b74a03
LG
3497 //\r
3498 // If ForceRebase Flag specified to FALSE, will always not take rebase action.\r
3499 //\r
3500 if (FvInfo->ForceRebase == 0) {\r
3501 return EFI_SUCCESS;\r
3502 }\r
3503\r
3504\r
52302d4d 3505 XipBase = FvInfo->BaseAddress + XipOffset;\r
30fdf114
LG
3506\r
3507 //\r
3508 // We only process files potentially containing PE32 sections.\r
3509 //\r
3510 switch (FfsFile->Type) {\r
3511 case EFI_FV_FILETYPE_SECURITY_CORE:\r
3512 case EFI_FV_FILETYPE_PEI_CORE:\r
3513 case EFI_FV_FILETYPE_PEIM:\r
3514 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
3515 case EFI_FV_FILETYPE_DRIVER:\r
3516 case EFI_FV_FILETYPE_DXE_CORE:\r
3517 break;\r
52302d4d
LG
3518 case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:\r
3519 //\r
3520 // Rebase the inside FvImage.\r
3521 //\r
3522 GetChildFvFromFfs (FvInfo, FfsFile, XipOffset);\r
3523\r
3524 //\r
3525 // Search PE/TE section in FV sectin.\r
3526 //\r
3527 break;\r
30fdf114
LG
3528 default:\r
3529 return EFI_SUCCESS;\r
3530 }\r
e8a47801
LG
3531\r
3532 FfsHeaderSize = GetFfsHeaderLength(FfsFile);\r
30fdf114
LG
3533 //\r
3534 // Rebase each PE32 section\r
3535 //\r
3536 Status = EFI_SUCCESS;\r
3537 for (Index = 1;; Index++) {\r
3538 //\r
3539 // Init Value\r
3540 //\r
3541 NewPe32BaseAddress = 0;\r
f7496d71 3542\r
30fdf114
LG
3543 //\r
3544 // Find Pe Image\r
3545 //\r
3546 Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);\r
3547 if (EFI_ERROR (Status)) {\r
3548 break;\r
3549 }\r
e8a47801 3550 CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader);\r
30fdf114
LG
3551\r
3552 //\r
3553 // Initialize context\r
3554 //\r
3555 memset (&ImageContext, 0, sizeof (ImageContext));\r
e8a47801 3556 ImageContext.Handle = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize);\r
30fdf114
LG
3557 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
3558 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
3559 if (EFI_ERROR (Status)) {\r
fd171542 3560 Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int) Status);\r
30fdf114
LG
3561 return Status;\r
3562 }\r
3563\r
4afd3d04
LG
3564 if ( (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) ||\r
3565 (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64) ) {\r
30fdf114
LG
3566 mArm = TRUE;\r
3567 }\r
3568\r
ad1db975
AC
3569 if (ImageContext.Machine == EFI_IMAGE_MACHINE_RISCV64) {\r
3570 mRiscV = TRUE;\r
3571 }\r
3572\r
30fdf114
LG
3573 //\r
3574 // Keep Image Context for PE image in FV\r
3575 //\r
3576 memcpy (&OrigImageContext, &ImageContext, sizeof (ImageContext));\r
f7496d71 3577\r
30fdf114
LG
3578 //\r
3579 // Get File PdbPointer\r
3580 //\r
3581 PdbPointer = PeCoffLoaderGetPdbPointer (ImageContext.Handle);\r
3582\r
3583 //\r
3584 // Get PeHeader pointer\r
3585 //\r
e8a47801 3586 ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize + ImageContext.PeCoffHeaderOffset);\r
30fdf114
LG
3587\r
3588 //\r
3589 // Calculate the PE32 base address, based on file type\r
3590 //\r
3591 switch (FfsFile->Type) {\r
3592 case EFI_FV_FILETYPE_SECURITY_CORE:\r
3593 case EFI_FV_FILETYPE_PEI_CORE:\r
3594 case EFI_FV_FILETYPE_PEIM:\r
3595 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
30fdf114
LG
3596 //\r
3597 // Check if section-alignment and file-alignment match or not\r
3598 //\r
3599 if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {\r
3600 //\r
3601 // Xip module has the same section alignment and file alignment.\r
3602 //\r
3c3277f2 3603 Error (NULL, 0, 3000, "Invalid", "PE image Section-Alignment and File-Alignment do not match : %s.", FileName);\r
30fdf114
LG
3604 return EFI_ABORTED;\r
3605 }\r
3606 //\r
f7496d71 3607 // PeImage has no reloc section. It will try to get reloc data from the original EFI image.\r
30fdf114
LG
3608 //\r
3609 if (ImageContext.RelocationsStripped) {\r
3610 //\r
f7496d71 3611 // Construct the original efi file Name\r
30fdf114 3612 //\r
fc42d0e8
HW
3613 if (strlen (FileName) >= MAX_LONG_FILE_PATH) {\r
3614 Error (NULL, 0, 2000, "Invalid", "The file name %s is too long.", FileName);\r
3615 return EFI_ABORTED;\r
3616 }\r
3617 strncpy (PeFileName, FileName, MAX_LONG_FILE_PATH - 1);\r
3618 PeFileName[MAX_LONG_FILE_PATH - 1] = 0;\r
30fdf114
LG
3619 Cptr = PeFileName + strlen (PeFileName);\r
3620 while (*Cptr != '.') {\r
3621 Cptr --;\r
3622 }\r
3623 if (*Cptr != '.') {\r
3624 Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
3625 return EFI_ABORTED;\r
3626 } else {\r
3627 *(Cptr + 1) = 'e';\r
3628 *(Cptr + 2) = 'f';\r
3629 *(Cptr + 3) = 'i';\r
3630 *(Cptr + 4) = '\0';\r
3631 }\r
1be2ed90 3632 PeFile = fopen (LongFilePath (PeFileName), "rb");\r
30fdf114
LG
3633 if (PeFile == NULL) {\r
3634 Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);\r
3635 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
3636 //return EFI_ABORTED;\r
3637 break;\r
3638 }\r
3639 //\r
3640 // Get the file size\r
3641 //\r
3642 PeFileSize = _filelength (fileno (PeFile));\r
3643 PeFileBuffer = (UINT8 *) malloc (PeFileSize);\r
3644 if (PeFileBuffer == NULL) {\r
320ba37a 3645 fclose (PeFile);\r
30fdf114
LG
3646 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
3647 return EFI_OUT_OF_RESOURCES;\r
3648 }\r
3649 //\r
3650 // Read Pe File\r
3651 //\r
3652 fread (PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);\r
3653 //\r
3654 // close file\r
3655 //\r
3656 fclose (PeFile);\r
3657 //\r
3658 // Handle pointer to the original efi image.\r
3659 //\r
3660 ImageContext.Handle = PeFileBuffer;\r
3661 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
3662 if (EFI_ERROR (Status)) {\r
fd171542 3663 Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int) Status);\r
30fdf114
LG
3664 return Status;\r
3665 }\r
3666 ImageContext.RelocationsStripped = FALSE;\r
3667 }\r
3668\r
e8a47801 3669 NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile;\r
30fdf114
LG
3670 break;\r
3671\r
3672 case EFI_FV_FILETYPE_DRIVER:\r
3673 case EFI_FV_FILETYPE_DXE_CORE:\r
52302d4d
LG
3674 //\r
3675 // Check if section-alignment and file-alignment match or not\r
3676 //\r
3677 if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {\r
3678 //\r
3679 // Xip module has the same section alignment and file alignment.\r
3680 //\r
3c3277f2 3681 Error (NULL, 0, 3000, "Invalid", "PE image Section-Alignment and File-Alignment do not match : %s.", FileName);\r
52302d4d 3682 return EFI_ABORTED;\r
30fdf114 3683 }\r
e8a47801 3684 NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile;\r
30fdf114
LG
3685 break;\r
3686\r
3687 default:\r
3688 //\r
3689 // Not supported file type\r
3690 //\r
3691 return EFI_SUCCESS;\r
3692 }\r
f7496d71 3693\r
30fdf114 3694 //\r
52302d4d 3695 // Relocation doesn't exist\r
30fdf114 3696 //\r
52302d4d
LG
3697 if (ImageContext.RelocationsStripped) {\r
3698 Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);\r
3699 continue;\r
3700 }\r
30fdf114 3701\r
52302d4d
LG
3702 //\r
3703 // Relocation exist and rebase\r
3704 //\r
3705 //\r
3706 // Load and Relocate Image Data\r
3707 //\r
3708 MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
3709 if (MemoryImagePointer == NULL) {\r
3710 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
3711 return EFI_OUT_OF_RESOURCES;\r
3712 }\r
3713 memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
b36d134f 3714 ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN) ImageContext.SectionAlignment - 1));\r
f7496d71 3715\r
52302d4d
LG
3716 Status = PeCoffLoaderLoadImage (&ImageContext);\r
3717 if (EFI_ERROR (Status)) {\r
3718 Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);\r
30fdf114 3719 free ((VOID *) MemoryImagePointer);\r
52302d4d
LG
3720 return Status;\r
3721 }\r
f7496d71 3722\r
52302d4d
LG
3723 ImageContext.DestinationAddress = NewPe32BaseAddress;\r
3724 Status = PeCoffLoaderRelocateImage (&ImageContext);\r
3725 if (EFI_ERROR (Status)) {\r
ad1db975 3726 Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s Status=%d", FileName, Status);\r
52302d4d
LG
3727 free ((VOID *) MemoryImagePointer);\r
3728 return Status;\r
3729 }\r
3730\r
3731 //\r
3732 // Copy Relocated data to raw image file.\r
3733 //\r
3734 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (\r
3735 (UINTN) ImgHdr +\r
f7496d71
LG
3736 sizeof (UINT32) +\r
3737 sizeof (EFI_IMAGE_FILE_HEADER) +\r
52302d4d
LG
3738 ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader\r
3739 );\r
f7496d71 3740\r
52302d4d
LG
3741 for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {\r
3742 CopyMem (\r
f7496d71
LG
3743 (UINT8 *) CurrentPe32Section.Pe32Section + CurSecHdrSize + SectionHeader->PointerToRawData,\r
3744 (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress),\r
52302d4d
LG
3745 SectionHeader->SizeOfRawData\r
3746 );\r
3747 }\r
3748\r
3749 free ((VOID *) MemoryImagePointer);\r
3750 MemoryImagePointer = NULL;\r
3751 if (PeFileBuffer != NULL) {\r
3752 free (PeFileBuffer);\r
3753 PeFileBuffer = NULL;\r
30fdf114 3754 }\r
f7496d71 3755\r
30fdf114
LG
3756 //\r
3757 // Update Image Base Address\r
3758 //\r
3759 if (ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
52302d4d 3760 ImgHdr->Pe32.OptionalHeader.ImageBase = (UINT32) NewPe32BaseAddress;\r
30fdf114 3761 } else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
52302d4d 3762 ImgHdr->Pe32Plus.OptionalHeader.ImageBase = NewPe32BaseAddress;\r
30fdf114
LG
3763 } else {\r
3764 Error (NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",\r
fd171542 3765 ImgHdr->Pe32.OptionalHeader.Magic,\r
30fdf114
LG
3766 FileName\r
3767 );\r
3768 return EFI_ABORTED;\r
3769 }\r
3770\r
30fdf114
LG
3771 //\r
3772 // Now update file checksum\r
3773 //\r
3774 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
3775 SavedState = FfsFile->State;\r
3776 FfsFile->IntegrityCheck.Checksum.File = 0;\r
3777 FfsFile->State = 0;\r
b303ea72 3778 FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
e8a47801
LG
3779 (UINT8 *) ((UINT8 *)FfsFile + FfsHeaderSize),\r
3780 GetFfsFileLength (FfsFile) - FfsHeaderSize\r
b303ea72 3781 );\r
30fdf114
LG
3782 FfsFile->State = SavedState;\r
3783 }\r
3784\r
3785 //\r
3786 // Get this module function address from ModulePeMapFile and add them into FvMap file\r
3787 //\r
52302d4d 3788\r
30fdf114
LG
3789 //\r
3790 // Default use FileName as map file path\r
3791 //\r
3792 if (PdbPointer == NULL) {\r
3793 PdbPointer = FileName;\r
3794 }\r
3795\r
79714906 3796 WriteMapFile (FvMapFile, PdbPointer, FfsFile, NewPe32BaseAddress, &OrigImageContext);\r
30fdf114
LG
3797 }\r
3798\r
3799 if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&\r
3800 FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&\r
3801 FfsFile->Type != EFI_FV_FILETYPE_PEIM &&\r
52302d4d
LG
3802 FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER &&\r
3803 FfsFile->Type != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE\r
30fdf114
LG
3804 ) {\r
3805 //\r
3806 // Only Peim code may have a TE section\r
3807 //\r
3808 return EFI_SUCCESS;\r
3809 }\r
f7496d71 3810\r
30fdf114
LG
3811 //\r
3812 // Now process TE sections\r
3813 //\r
3814 for (Index = 1;; Index++) {\r
3815 NewPe32BaseAddress = 0;\r
f7496d71 3816\r
30fdf114
LG
3817 //\r
3818 // Find Te Image\r
3819 //\r
3820 Status = GetSectionByType (FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);\r
3821 if (EFI_ERROR (Status)) {\r
3822 break;\r
3823 }\r
e8a47801
LG
3824\r
3825 CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader);\r
f7496d71 3826\r
30fdf114
LG
3827 //\r
3828 // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off\r
3829 // by GenTEImage\r
3830 //\r
e8a47801 3831 TEImageHeader = (EFI_TE_IMAGE_HEADER *) ((UINT8 *) CurrentPe32Section.Pe32Section + CurSecHdrSize);\r
30fdf114
LG
3832\r
3833 //\r
3834 // Initialize context, load image info.\r
3835 //\r
3836 memset (&ImageContext, 0, sizeof (ImageContext));\r
3837 ImageContext.Handle = (VOID *) TEImageHeader;\r
3838 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
3839 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
3840 if (EFI_ERROR (Status)) {\r
fd171542 3841 Error (NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int) Status);\r
30fdf114
LG
3842 return Status;\r
3843 }\r
3844\r
4afd3d04
LG
3845 if ( (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) ||\r
3846 (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64) ) {\r
30fdf114
LG
3847 mArm = TRUE;\r
3848 }\r
3849\r
3850 //\r
3851 // Keep Image Context for TE image in FV\r
3852 //\r
3853 memcpy (&OrigImageContext, &ImageContext, sizeof (ImageContext));\r
3854\r
3855 //\r
3856 // Get File PdbPointer\r
3857 //\r
3858 PdbPointer = PeCoffLoaderGetPdbPointer (ImageContext.Handle);\r
30fdf114
LG
3859\r
3860 //\r
3861 // Set new rebased address.\r
3862 //\r
3863 NewPe32BaseAddress = XipBase + (UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \\r
3864 - TEImageHeader->StrippedSize - (UINTN) FfsFile;\r
3865\r
3866 //\r
3867 // if reloc is stripped, try to get the original efi image to get reloc info.\r
3868 //\r
52302d4d 3869 if (ImageContext.RelocationsStripped) {\r
30fdf114 3870 //\r
f7496d71 3871 // Construct the original efi file name\r
30fdf114 3872 //\r
fc42d0e8
HW
3873 if (strlen (FileName) >= MAX_LONG_FILE_PATH) {\r
3874 Error (NULL, 0, 2000, "Invalid", "The file name %s is too long.", FileName);\r
3875 return EFI_ABORTED;\r
3876 }\r
3877 strncpy (PeFileName, FileName, MAX_LONG_FILE_PATH - 1);\r
3878 PeFileName[MAX_LONG_FILE_PATH - 1] = 0;\r
30fdf114
LG
3879 Cptr = PeFileName + strlen (PeFileName);\r
3880 while (*Cptr != '.') {\r
3881 Cptr --;\r
3882 }\r
3883\r
3884 if (*Cptr != '.') {\r
3885 Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
3886 return EFI_ABORTED;\r
3887 } else {\r
3888 *(Cptr + 1) = 'e';\r
3889 *(Cptr + 2) = 'f';\r
3890 *(Cptr + 3) = 'i';\r
3891 *(Cptr + 4) = '\0';\r
3892 }\r
3893\r
1be2ed90 3894 PeFile = fopen (LongFilePath (PeFileName), "rb");\r
30fdf114
LG
3895 if (PeFile == NULL) {\r
3896 Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);\r
3897 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
3898 //return EFI_ABORTED;\r
3899 } else {\r
3900 //\r
3901 // Get the file size\r
3902 //\r
3903 PeFileSize = _filelength (fileno (PeFile));\r
3904 PeFileBuffer = (UINT8 *) malloc (PeFileSize);\r
3905 if (PeFileBuffer == NULL) {\r
320ba37a 3906 fclose (PeFile);\r
30fdf114
LG
3907 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
3908 return EFI_OUT_OF_RESOURCES;\r
3909 }\r
3910 //\r
3911 // Read Pe File\r
3912 //\r
3913 fread (PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);\r
3914 //\r
3915 // close file\r
3916 //\r
3917 fclose (PeFile);\r
3918 //\r
3919 // Append reloc section into TeImage\r
3920 //\r
3921 ImageContext.Handle = PeFileBuffer;\r
3922 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
3923 if (EFI_ERROR (Status)) {\r
fd171542 3924 Error (NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int) Status);\r
30fdf114
LG
3925 return Status;\r
3926 }\r
3927 ImageContext.RelocationsStripped = FALSE;\r
3928 }\r
3929 }\r
52302d4d
LG
3930 //\r
3931 // Relocation doesn't exist\r
3932 //\r
3933 if (ImageContext.RelocationsStripped) {\r
3934 Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);\r
3935 continue;\r
3936 }\r
30fdf114
LG
3937\r
3938 //\r
3939 // Relocation exist and rebase\r
3940 //\r
52302d4d
LG
3941 //\r
3942 // Load and Relocate Image Data\r
3943 //\r
3944 MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
3945 if (MemoryImagePointer == NULL) {\r
3946 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
3947 return EFI_OUT_OF_RESOURCES;\r
3948 }\r
3949 memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
b36d134f 3950 ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN) ImageContext.SectionAlignment - 1));\r
52302d4d
LG
3951\r
3952 Status = PeCoffLoaderLoadImage (&ImageContext);\r
3953 if (EFI_ERROR (Status)) {\r
3954 Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);\r
30fdf114 3955 free ((VOID *) MemoryImagePointer);\r
52302d4d
LG
3956 return Status;\r
3957 }\r
3958 //\r
3959 // Reloacate TeImage\r
f7496d71 3960 //\r
52302d4d
LG
3961 ImageContext.DestinationAddress = NewPe32BaseAddress;\r
3962 Status = PeCoffLoaderRelocateImage (&ImageContext);\r
3963 if (EFI_ERROR (Status)) {\r
3964 Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName);\r
3965 free ((VOID *) MemoryImagePointer);\r
3966 return Status;\r
3967 }\r
f7496d71 3968\r
52302d4d
LG
3969 //\r
3970 // Copy the relocated image into raw image file.\r
3971 //\r
3972 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TEImageHeader + 1);\r
3973 for (Index = 0; Index < TEImageHeader->NumberOfSections; Index ++, SectionHeader ++) {\r
3974 if (!ImageContext.IsTeImage) {\r
3975 CopyMem (\r
f7496d71
LG
3976 (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,\r
3977 (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress),\r
52302d4d
LG
3978 SectionHeader->SizeOfRawData\r
3979 );\r
3980 } else {\r
3981 CopyMem (\r
f7496d71
LG
3982 (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,\r
3983 (VOID*) (UINTN) (ImageContext.ImageAddress + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->VirtualAddress),\r
52302d4d
LG
3984 SectionHeader->SizeOfRawData\r
3985 );\r
30fdf114
LG
3986 }\r
3987 }\r
f7496d71 3988\r
52302d4d
LG
3989 //\r
3990 // Free the allocated memory resource\r
3991 //\r
3992 free ((VOID *) MemoryImagePointer);\r
3993 MemoryImagePointer = NULL;\r
3994 if (PeFileBuffer != NULL) {\r
3995 free (PeFileBuffer);\r
3996 PeFileBuffer = NULL;\r
3997 }\r
f7496d71 3998\r
30fdf114
LG
3999 //\r
4000 // Update Image Base Address\r
4001 //\r
4002 TEImageHeader->ImageBase = NewPe32BaseAddress;\r
4003\r
4004 //\r
4005 // Now update file checksum\r
4006 //\r
4007 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
4008 SavedState = FfsFile->State;\r
4009 FfsFile->IntegrityCheck.Checksum.File = 0;\r
4010 FfsFile->State = 0;\r
b303ea72 4011 FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
e8a47801
LG
4012 (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize),\r
4013 GetFfsFileLength (FfsFile) - FfsHeaderSize\r
b303ea72 4014 );\r
30fdf114
LG
4015 FfsFile->State = SavedState;\r
4016 }\r
4017 //\r
4018 // Get this module function address from ModulePeMapFile and add them into FvMap file\r
4019 //\r
52302d4d 4020\r
30fdf114
LG
4021 //\r
4022 // Default use FileName as map file path\r
4023 //\r
4024 if (PdbPointer == NULL) {\r
4025 PdbPointer = FileName;\r
4026 }\r
4027\r
4028 WriteMapFile (\r
f7496d71
LG
4029 FvMapFile,\r
4030 PdbPointer,\r
79714906 4031 FfsFile,\r
f7496d71 4032 NewPe32BaseAddress,\r
30fdf114
LG
4033 &OrigImageContext\r
4034 );\r
4035 }\r
f7496d71 4036\r
30fdf114
LG
4037 return EFI_SUCCESS;\r
4038}\r
4039\r
4040EFI_STATUS\r
4041FindApResetVectorPosition (\r
4042 IN MEMORY_FILE *FvImage,\r
4043 OUT UINT8 **Pointer\r
4044 )\r
4045/*++\r
4046\r
4047Routine Description:\r
4048\r
4049 Find the position in this FvImage to place Ap reset vector.\r
4050\r
4051Arguments:\r
4052\r
4053 FvImage Memory file for the FV memory image.\r
4054 Pointer Pointer to pointer to position.\r
4055\r
4056Returns:\r
4057\r
4058 EFI_NOT_FOUND - No satisfied position is found.\r
4059 EFI_SUCCESS - The suitable position is return.\r
4060\r
4061--*/\r
4062{\r
4063 EFI_FFS_FILE_HEADER *PadFile;\r
4064 UINT32 Index;\r
4065 EFI_STATUS Status;\r
4066 UINT8 *FixPoint;\r
4067 UINT32 FileLength;\r
4068\r
4069 for (Index = 1; ;Index ++) {\r
4070 //\r
4071 // Find Pad File to add ApResetVector info\r
4072 //\r
4073 Status = GetFileByType (EFI_FV_FILETYPE_FFS_PAD, Index, &PadFile);\r
4074 if (EFI_ERROR (Status) || (PadFile == NULL)) {\r
4075 //\r
4076 // No Pad file to be found.\r
4077 //\r
4078 break;\r
4079 }\r
4080 //\r
4081 // Get Pad file size.\r
4082 //\r
e8a47801 4083 FileLength = GetFfsFileLength(PadFile);\r
f7496d71 4084 FileLength = (FileLength + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1);\r
30fdf114
LG
4085 //\r
4086 // FixPoint must be align on 0x1000 relative to FvImage Header\r
4087 //\r
e8a47801 4088 FixPoint = (UINT8*) PadFile + GetFfsHeaderLength(PadFile);\r
30fdf114
LG
4089 FixPoint = FixPoint + 0x1000 - (((UINTN) FixPoint - (UINTN) FvImage->FileImage) & 0xFFF);\r
4090 //\r
4091 // FixPoint be larger at the last place of one fv image.\r
4092 //\r
4093 while (((UINTN) FixPoint + SIZEOF_STARTUP_DATA_ARRAY - (UINTN) PadFile) <= FileLength) {\r
4094 FixPoint += 0x1000;\r
4095 }\r
4096 FixPoint -= 0x1000;\r
f7496d71 4097\r
e8a47801 4098 if ((UINTN) FixPoint < ((UINTN) PadFile + GetFfsHeaderLength(PadFile))) {\r
30fdf114
LG
4099 //\r
4100 // No alignment FixPoint in this Pad File.\r
4101 //\r
4102 continue;\r
4103 }\r
4104\r
f7496d71 4105 if ((UINTN) FvImage->Eof - (UINTN)FixPoint <= 0x20000) {\r
30fdf114
LG
4106 //\r
4107 // Find the position to place ApResetVector\r
4108 //\r
4109 *Pointer = FixPoint;\r
4110 return EFI_SUCCESS;\r
4111 }\r
4112 }\r
f7496d71 4113\r
30fdf114
LG
4114 return EFI_NOT_FOUND;\r
4115}\r
4116\r
4117EFI_STATUS\r
4118ParseCapInf (\r
4119 IN MEMORY_FILE *InfFile,\r
4120 OUT CAP_INFO *CapInfo\r
4121 )\r
4122/*++\r
4123\r
4124Routine Description:\r
4125\r
4126 This function parses a Cap.INF file and copies info into a CAP_INFO structure.\r
4127\r
4128Arguments:\r
4129\r
4130 InfFile Memory file image.\r
4131 CapInfo Information read from INF file.\r
4132\r
4133Returns:\r
4134\r
4135 EFI_SUCCESS INF file information successfully retrieved.\r
4136 EFI_ABORTED INF file has an invalid format.\r
4137 EFI_NOT_FOUND A required string was not found in the INF file.\r
4138--*/\r
4139{\r
1be2ed90 4140 CHAR8 Value[MAX_LONG_FILE_PATH];\r
30fdf114
LG
4141 UINT64 Value64;\r
4142 UINTN Index, Number;\r
4143 EFI_STATUS Status;\r
4144\r
4145 //\r
4146 // Initialize Cap info\r
4147 //\r
4148 // memset (CapInfo, 0, sizeof (CAP_INFO));\r
4149 //\r
4150\r
4151 //\r
4152 // Read the Capsule Guid\r
4153 //\r
4154 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_GUID_STRING, 0, Value);\r
4155 if (Status == EFI_SUCCESS) {\r
4156 //\r
4157 // Get the Capsule Guid\r
4158 //\r
4159 Status = StringToGuid (Value, &CapInfo->CapGuid);\r
4160 if (EFI_ERROR (Status)) {\r
4161 Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_GUID_STRING, Value);\r
4162 return EFI_ABORTED;\r
4163 }\r
4164 DebugMsg (NULL, 0, 9, "Capsule Guid", "%s = %s", EFI_CAPSULE_GUID_STRING, Value);\r
4165 }\r
4166\r
4167 //\r
4168 // Read the Capsule Header Size\r
4169 //\r
4170 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_HEADER_SIZE_STRING, 0, Value);\r
4171 if (Status == EFI_SUCCESS) {\r
4172 Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
4173 if (EFI_ERROR (Status)) {\r
4174 Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING, Value);\r
4175 return EFI_ABORTED;\r
4176 }\r
4177 CapInfo->HeaderSize = (UINT32) Value64;\r
4178 DebugMsg (NULL, 0, 9, "Capsule Header size", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING, Value);\r
4179 }\r
4180\r
4181 //\r
4182 // Read the Capsule Flag\r
4183 //\r
4184 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_FLAGS_STRING, 0, Value);\r
4185 if (Status == EFI_SUCCESS) {\r
4186 if (strstr (Value, "PopulateSystemTable") != NULL) {\r
4187 CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE;\r
fd171542 4188 if (strstr (Value, "InitiateReset") != NULL) {\r
4189 CapInfo->Flags |= CAPSULE_FLAGS_INITIATE_RESET;\r
4190 }\r
30fdf114 4191 } else if (strstr (Value, "PersistAcrossReset") != NULL) {\r
f7496d71 4192 CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET;\r
fd171542 4193 if (strstr (Value, "InitiateReset") != NULL) {\r
4194 CapInfo->Flags |= CAPSULE_FLAGS_INITIATE_RESET;\r
4195 }\r
30fdf114
LG
4196 } else {\r
4197 Error (NULL, 0, 2000, "Invalid parameter", "invalid Flag setting for %s.", EFI_CAPSULE_FLAGS_STRING);\r
4198 return EFI_ABORTED;\r
4199 }\r
4200 DebugMsg (NULL, 0, 9, "Capsule Flag", Value);\r
4201 }\r
4202\r
e8a47801
LG
4203 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_OEM_CAPSULE_FLAGS_STRING, 0, Value);\r
4204 if (Status == EFI_SUCCESS) {\r
4205 Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
4206 if (EFI_ERROR (Status) || Value64 > 0xffff) {\r
4207 Error (NULL, 0, 2000, "Invalid parameter",\r
4208 "invalid Flag setting for %s. Must be integer value between 0x0000 and 0xffff.",\r
4209 EFI_OEM_CAPSULE_FLAGS_STRING);\r
4210 return EFI_ABORTED;\r
4211 }\r
4212 CapInfo->Flags |= Value64;\r
4213 DebugMsg (NULL, 0, 9, "Capsule Extend Flag", Value);\r
4214 }\r
4215\r
30fdf114
LG
4216 //\r
4217 // Read Capsule File name\r
4218 //\r
4219 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FILE_NAME_STRING, 0, Value);\r
4220 if (Status == EFI_SUCCESS) {\r
4221 //\r
4222 // Get output file name\r
4223 //\r
4224 strcpy (CapInfo->CapName, Value);\r
4225 }\r
4226\r
4227 //\r
4228 // Read the Capsule FileImage\r
4229 //\r
4230 Number = 0;\r
4231 for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_CAP; Index++) {\r
4232 if (CapInfo->CapFiles[Index][0] != '\0') {\r
4233 continue;\r
4234 }\r
4235 //\r
4236 // Read the capsule file name\r
4237 //\r
4238 Status = FindToken (InfFile, FILES_SECTION_STRING, EFI_FILE_NAME_STRING, Number++, Value);\r
4239\r
4240 if (Status == EFI_SUCCESS) {\r
4241 //\r
4242 // Add the file\r
4243 //\r
4244 strcpy (CapInfo->CapFiles[Index], Value);\r
f7496d71 4245 DebugMsg (NULL, 0, 9, "Capsule component file", "the %uth file name is %s", (unsigned) Index, CapInfo->CapFiles[Index]);\r
30fdf114
LG
4246 } else {\r
4247 break;\r
4248 }\r
4249 }\r
f7496d71 4250\r
30fdf114
LG
4251 if (Index == 0) {\r
4252 Warning (NULL, 0, 0, "Capsule components are not specified.", NULL);\r
4253 }\r
4254\r
4255 return EFI_SUCCESS;\r
4256}\r
4257\r
4258EFI_STATUS\r
4259GenerateCapImage (\r
4260 IN CHAR8 *InfFileImage,\r
4261 IN UINTN InfFileSize,\r
4262 IN CHAR8 *CapFileName\r
4263 )\r
4264/*++\r
4265\r
4266Routine Description:\r
4267\r
4268 This is the main function which will be called from application to create UEFI Capsule image.\r
4269\r
4270Arguments:\r
4271\r
4272 InfFileImage Buffer containing the INF file contents.\r
4273 InfFileSize Size of the contents of the InfFileImage buffer.\r
4274 CapFileName Requested name for the Cap file.\r
4275\r
4276Returns:\r
4277\r
4278 EFI_SUCCESS Function completed successfully.\r
4279 EFI_OUT_OF_RESOURCES Could not allocate required resources.\r
4280 EFI_ABORTED Error encountered.\r
4281 EFI_INVALID_PARAMETER A required parameter was NULL.\r
4282\r
4283--*/\r
4284{\r
4285 UINT32 CapSize;\r
4286 UINT8 *CapBuffer;\r
4287 EFI_CAPSULE_HEADER *CapsuleHeader;\r
4288 MEMORY_FILE InfMemoryFile;\r
4289 UINT32 FileSize;\r
4290 UINT32 Index;\r
4291 FILE *fpin, *fpout;\r
4292 EFI_STATUS Status;\r
f7496d71 4293\r
30fdf114
LG
4294 if (InfFileImage != NULL) {\r
4295 //\r
4296 // Initialize file structures\r
4297 //\r
4298 InfMemoryFile.FileImage = InfFileImage;\r
4299 InfMemoryFile.CurrentFilePointer = InfFileImage;\r
4300 InfMemoryFile.Eof = InfFileImage + InfFileSize;\r
f7496d71 4301\r
30fdf114
LG
4302 //\r
4303 // Parse the Cap inf file for header information\r
4304 //\r
4305 Status = ParseCapInf (&InfMemoryFile, &mCapDataInfo);\r
4306 if (Status != EFI_SUCCESS) {\r
4307 return Status;\r
4308 }\r
4309 }\r
f7496d71 4310\r
30fdf114
LG
4311 if (mCapDataInfo.HeaderSize == 0) {\r
4312 //\r
4313 // make header size align 16 bytes.\r
4314 //\r
4315 mCapDataInfo.HeaderSize = sizeof (EFI_CAPSULE_HEADER);\r
4316 mCapDataInfo.HeaderSize = (mCapDataInfo.HeaderSize + 0xF) & ~0xF;\r
4317 }\r
4318\r
4319 if (mCapDataInfo.HeaderSize < sizeof (EFI_CAPSULE_HEADER)) {\r
4320 Error (NULL, 0, 2000, "Invalid parameter", "The specified HeaderSize cannot be less than the size of EFI_CAPSULE_HEADER.");\r
4321 return EFI_INVALID_PARAMETER;\r
4322 }\r
f7496d71 4323\r
30fdf114
LG
4324 if (CapFileName == NULL && mCapDataInfo.CapName[0] != '\0') {\r
4325 CapFileName = mCapDataInfo.CapName;\r
4326 }\r
f7496d71 4327\r
30fdf114
LG
4328 if (CapFileName == NULL) {\r
4329 Error (NULL, 0, 2001, "Missing required argument", "Output Capsule file name");\r
4330 return EFI_INVALID_PARAMETER;\r
4331 }\r
f7496d71 4332\r
30fdf114
LG
4333 //\r
4334 // Set Default Capsule Guid value\r
4335 //\r
4336 if (CompareGuid (&mCapDataInfo.CapGuid, &mZeroGuid) == 0) {\r
4337 memcpy (&mCapDataInfo.CapGuid, &mDefaultCapsuleGuid, sizeof (EFI_GUID));\r
4338 }\r
4339 //\r
4340 // Calculate the size of capsule image.\r
4341 //\r
4342 Index = 0;\r
4343 FileSize = 0;\r
4344 CapSize = mCapDataInfo.HeaderSize;\r
4345 while (mCapDataInfo.CapFiles [Index][0] != '\0') {\r
1be2ed90 4346 fpin = fopen (LongFilePath (mCapDataInfo.CapFiles[Index]), "rb");\r
30fdf114
LG
4347 if (fpin == NULL) {\r
4348 Error (NULL, 0, 0001, "Error opening file", mCapDataInfo.CapFiles[Index]);\r
4349 return EFI_ABORTED;\r
4350 }\r
4351 FileSize = _filelength (fileno (fpin));\r
4352 CapSize += FileSize;\r
4353 fclose (fpin);\r
4354 Index ++;\r
4355 }\r
4356\r
4357 //\r
4358 // Allocate buffer for capsule image.\r
4359 //\r
4360 CapBuffer = (UINT8 *) malloc (CapSize);\r
4361 if (CapBuffer == NULL) {\r
4362 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated for creating the capsule.");\r
4363 return EFI_OUT_OF_RESOURCES;\r
4364 }\r
4365\r
4366 //\r
4367 // Initialize the capsule header to zero\r
4368 //\r
4369 memset (CapBuffer, 0, mCapDataInfo.HeaderSize);\r
f7496d71 4370\r
30fdf114
LG
4371 //\r
4372 // create capsule header and get capsule body\r
4373 //\r
4374 CapsuleHeader = (EFI_CAPSULE_HEADER *) CapBuffer;\r
4375 memcpy (&CapsuleHeader->CapsuleGuid, &mCapDataInfo.CapGuid, sizeof (EFI_GUID));\r
4376 CapsuleHeader->HeaderSize = mCapDataInfo.HeaderSize;\r
4377 CapsuleHeader->Flags = mCapDataInfo.Flags;\r
4378 CapsuleHeader->CapsuleImageSize = CapSize;\r
4379\r
4380 Index = 0;\r
4381 FileSize = 0;\r
4382 CapSize = CapsuleHeader->HeaderSize;\r
4383 while (mCapDataInfo.CapFiles [Index][0] != '\0') {\r
1be2ed90 4384 fpin = fopen (LongFilePath (mCapDataInfo.CapFiles[Index]), "rb");\r
30fdf114
LG
4385 if (fpin == NULL) {\r
4386 Error (NULL, 0, 0001, "Error opening file", mCapDataInfo.CapFiles[Index]);\r
4387 free (CapBuffer);\r
4388 return EFI_ABORTED;\r
4389 }\r
4390 FileSize = _filelength (fileno (fpin));\r
4391 fread (CapBuffer + CapSize, 1, FileSize, fpin);\r
4392 fclose (fpin);\r
4393 Index ++;\r
4394 CapSize += FileSize;\r
4395 }\r
f7496d71 4396\r
30fdf114
LG
4397 //\r
4398 // write capsule data into the output file\r
4399 //\r
1be2ed90 4400 fpout = fopen (LongFilePath (CapFileName), "wb");\r
30fdf114
LG
4401 if (fpout == NULL) {\r
4402 Error (NULL, 0, 0001, "Error opening file", CapFileName);\r
4403 free (CapBuffer);\r
4404 return EFI_ABORTED;\r
4405 }\r
4406\r
4407 fwrite (CapBuffer, 1, CapSize, fpout);\r
4408 fclose (fpout);\r
6db97871 4409 free (CapBuffer);\r
f7496d71 4410\r
fd171542 4411 VerboseMsg ("The size of the generated capsule image is %u bytes", (unsigned) CapSize);\r
30fdf114
LG
4412\r
4413 return EFI_SUCCESS;\r
4414}\r