]> git.proxmox.com Git - mirror_edk2.git/blame - Tools/CCode/Source/GenFvImage/GenFvImageLib.c
Fix the issues caused by EfiCompress.h was changed to Compress.h.
[mirror_edk2.git] / Tools / CCode / Source / GenFvImage / GenFvImageLib.c
CommitLineData
878ddf1f 1/*++\r
2i\r
3\r
4Copyright (c) 2004, Intel Corporation \r
5All rights reserved. This program and the accompanying materials \r
6are licensed and made available under the terms and conditions of the BSD License \r
7which accompanies this distribution. The full text of the license may be found at \r
8http://opensource.org/licenses/bsd-license.php \r
9 \r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
12\r
13Module Name:\r
14\r
15 GenFvImageLib.c\r
16\r
17Abstract:\r
18\r
19 This file contains functions required to generate a Firmware Volume.\r
20\r
21--*/\r
22\r
23//\r
24// Include files\r
25//\r
878ddf1f 26#ifdef __GNUC__\r
27#include <uuid/uuid.h>\r
28#include <sys/stat.h>\r
29#endif\r
30#include <string.h>\r
31#ifndef __GNUC__\r
32#include <io.h>\r
33#endif\r
34#include <assert.h>\r
ce53a8c3 35\r
36#include <Common/UefiBaseTypes.h>\r
37#include <Common/FirmwareVolumeImageFormat.h>\r
38#include <Common/Variable.h>\r
39#include <Common/WorkingBlockHeader.h>\r
40#include <Guid/FirmwareFileSystem.h>\r
41\r
878ddf1f 42#include "GenFvImageLib.h"\r
43#include "GenFvImageLibInternal.h"\r
ce53a8c3 44#include "CommonLib.h"\r
45#include "Crc32.h"\r
46#include "EfiUtilityMsgs.h"\r
47#include "FvLib.h"\r
b2b5e78f 48#include "Compress.h"\r
ce53a8c3 49#include "WinNtInclude.h"\r
878ddf1f 50\r
1d940d05 51//\r
52// Different file separater for Linux and Windows\r
53//\r
54#ifdef __GNUC__\r
55#define FILE_SEP_CHAR '/'\r
56#define FILE_SEP_STRING "/"\r
57#else\r
58#define FILE_SEP_CHAR '\\'\r
59#define FILE_SEP_STRING "\\"\r
60#endif\r
61\r
d3f75347 62static UINT32 MaxFfsAlignment = 0;\r
878ddf1f 63//\r
64// Local function prototypes\r
65//\r
66EFI_STATUS\r
67GetPe32Info (\r
68 IN UINT8 *Pe32,\r
69 OUT UINT32 *EntryPoint,\r
70 OUT UINT32 *BaseOfCode,\r
71 OUT UINT16 *MachineType\r
72 );\r
73\r
74//\r
75// Local function implementations.\r
76//\r
77EFI_GUID FfsGuid = EFI_FIRMWARE_FILE_SYSTEM_GUID;\r
78EFI_GUID DefaultFvPadFileNameGuid = { 0x78f54d4, 0xcc22, 0x4048, 0x9e, 0x94, 0x87, 0x9c, 0x21, 0x4d, 0x56, 0x2f };\r
79\r
80//\r
81// This data array will be located at the base of the Firmware Volume Header (FVH)\r
82// in the boot block. It must not exceed 14 bytes of code. The last 2 bytes\r
83// will be used to keep the FVH checksum consistent.\r
84// This code will be run in response to a starutp IPI for HT-enabled systems.\r
85//\r
86#define SIZEOF_STARTUP_DATA_ARRAY 0x10\r
87\r
88UINT8 m128kRecoveryStartupApDataArray[SIZEOF_STARTUP_DATA_ARRAY] = {\r
89 //\r
90 // EA D0 FF 00 F0 ; far jmp F000:FFD0\r
91 // 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes\r
92 // 0, 0 ; Checksum Padding\r
93 //\r
94 0xEA,\r
95 0xD0,\r
96 0xFF,\r
97 0x0,\r
98 0xF0,\r
99 0x00,\r
100 0x00,\r
101 0x00,\r
102 0x00,\r
103 0x00,\r
104 0x00,\r
105 0x00,\r
106 0x00,\r
107 0x00,\r
108 0x00,\r
109 0x00\r
110};\r
111\r
112UINT8 m64kRecoveryStartupApDataArray[SIZEOF_STARTUP_DATA_ARRAY] = {\r
113 //\r
114 // EB CE ; jmp short ($-0x30)\r
115 // ; (from offset 0x0 to offset 0xFFD0)\r
116 // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes\r
117 // 0, 0 ; Checksum Padding\r
118 //\r
119 0xEB,\r
120 0xCE,\r
121 0x00,\r
122 0x00,\r
123 0x00,\r
124 0x00,\r
125 0x00,\r
126 0x00,\r
127 0x00,\r
128 0x00,\r
129 0x00,\r
130 0x00,\r
131 0x00,\r
132 0x00,\r
133 0x00,\r
134 0x00\r
135};\r
136\r
137EFI_STATUS\r
138ParseFvInf (\r
139 IN MEMORY_FILE *InfFile,\r
140 IN FV_INFO *FvInfo\r
141 )\r
142/*++\r
143\r
144Routine Description:\r
145\r
146 This function parses a FV.INF file and copies info into a FV_INFO structure.\r
147\r
148Arguments:\r
149\r
150 InfFile Memory file image.\r
151 FvInfo Information read from INF file.\r
152\r
153Returns:\r
154\r
155 EFI_SUCCESS INF file information successfully retrieved.\r
156 EFI_ABORTED INF file has an invalid format.\r
157 EFI_NOT_FOUND A required string was not found in the INF file.\r
158--*/\r
159{\r
160 CHAR8 Value[_MAX_PATH];\r
161 UINT64 Value64;\r
162 UINTN Index;\r
163 EFI_STATUS Status;\r
164\r
165 //\r
166 // Initialize FV info\r
167 //\r
168 memset (FvInfo, 0, sizeof (FV_INFO));\r
169\r
170 //\r
171 // Read the FV base address\r
172 //\r
173 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_BASE_ADDRESS_STRING, 0, Value);\r
174\r
175 if (Status == EFI_SUCCESS) {\r
176 //\r
177 // Get the base address\r
178 //\r
179 Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
180 if (EFI_ERROR (Status)) {\r
181 Error (NULL, 0, 0, EFI_FV_BASE_ADDRESS_STRING, "invalid value");\r
182 return EFI_ABORTED;\r
183 }\r
184\r
185 FvInfo->BaseAddress = Value64;\r
186 } else {\r
187 Error (NULL, 0, 0, EFI_FV_BASE_ADDRESS_STRING, "could not find value");\r
188 return EFI_ABORTED;\r
189 }\r
190 //\r
191 // Read the FV Guid\r
192 //\r
193 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_GUID_STRING, 0, Value);\r
194\r
195 if (Status == EFI_SUCCESS) {\r
196 //\r
197 // Get the guid value\r
198 //\r
199 Status = StringToGuid (Value, &FvInfo->FvGuid);\r
200 if (EFI_ERROR (Status)) {\r
201 memcpy (&FvInfo->FvGuid, &FfsGuid, sizeof (EFI_GUID));\r
202 }\r
203 } else {\r
204 memcpy (&FvInfo->FvGuid, &FfsGuid, sizeof (EFI_GUID));\r
205 }\r
206 //\r
207 // Read the FV file name\r
208 //\r
209 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_FILE_NAME_STRING, 0, Value);\r
210\r
211 if (Status == EFI_SUCCESS) {\r
212 //\r
213 // copy the file name\r
214 //\r
215 strcpy (FvInfo->FvName, Value);\r
216 } else {\r
217 Error (NULL, 0, 0, EFI_FV_FILE_NAME_STRING, "value not specified");\r
218 return EFI_ABORTED;\r
219 }\r
220 //\r
221 // Read the Sym file name\r
222 //\r
223 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_SYM_FILE_NAME_STRING, 0, Value);\r
224\r
225 if (Status == EFI_SUCCESS) {\r
226 //\r
227 // copy the file name\r
228 //\r
229 strcpy (FvInfo->SymName, Value);\r
230 } else {\r
231 //\r
232 // Symbols not required, so init to NULL.\r
233 //\r
234 strcpy (FvInfo->SymName, "");\r
235 }\r
236 //\r
237 // Read the read disabled capability attribute\r
238 //\r
239 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_READ_DISABLED_CAP_STRING, 0, Value);\r
240\r
241 if (Status == EFI_SUCCESS) {\r
242 //\r
243 // Update the read disabled flag\r
244 //\r
245 if (strcmp (Value, TRUE_STRING) == 0) {\r
246 FvInfo->FvAttributes |= EFI_FVB_READ_DISABLED_CAP;\r
247 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
248 Error (NULL, 0, 0, EFI_FVB_READ_DISABLED_CAP_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
249 return EFI_ABORTED;\r
250 }\r
251 } else {\r
252 Error (NULL, 0, 0, EFI_FVB_READ_DISABLED_CAP_STRING, "value not specified");\r
253 return Status;\r
254 }\r
255 //\r
256 // Read the read enabled capability attribute\r
257 //\r
258 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_READ_ENABLED_CAP_STRING, 0, Value);\r
259\r
260 if (Status == EFI_SUCCESS) {\r
261 //\r
262 // Update the read disabled flag\r
263 //\r
264 if (strcmp (Value, TRUE_STRING) == 0) {\r
265 FvInfo->FvAttributes |= EFI_FVB_READ_ENABLED_CAP;\r
266 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
267 Error (NULL, 0, 0, EFI_FVB_READ_ENABLED_CAP_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
268 return EFI_ABORTED;\r
269 }\r
270 } else {\r
271 Error (NULL, 0, 0, EFI_FVB_READ_ENABLED_CAP_STRING, "value not specified");\r
272 return Status;\r
273 }\r
274 //\r
275 // Read the read status attribute\r
276 //\r
277 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_READ_STATUS_STRING, 0, Value);\r
278\r
279 if (Status == EFI_SUCCESS) {\r
280 //\r
281 // Update the read disabled flag\r
282 //\r
283 if (strcmp (Value, TRUE_STRING) == 0) {\r
284 FvInfo->FvAttributes |= EFI_FVB_READ_STATUS;\r
285 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
286 Error (NULL, 0, 0, EFI_FVB_READ_STATUS_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
287 return EFI_ABORTED;\r
288 }\r
289 } else {\r
290 Error (NULL, 0, 0, EFI_FVB_READ_STATUS_STRING, "value not specified");\r
291 return Status;\r
292 }\r
293 //\r
294 // Read the write disabled capability attribute\r
295 //\r
296 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_WRITE_DISABLED_CAP_STRING, 0, Value);\r
297\r
298 if (Status == EFI_SUCCESS) {\r
299 //\r
300 // Update the write disabled flag\r
301 //\r
302 if (strcmp (Value, TRUE_STRING) == 0) {\r
303 FvInfo->FvAttributes |= EFI_FVB_WRITE_DISABLED_CAP;\r
304 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
305 Error (NULL, 0, 0, EFI_FVB_WRITE_DISABLED_CAP_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
306 return EFI_ABORTED;\r
307 }\r
308 } else {\r
309 Error (NULL, 0, 0, EFI_FVB_WRITE_DISABLED_CAP_STRING, "value not specified");\r
310 return Status;\r
311 }\r
312 //\r
313 // Read the write enabled capability attribute\r
314 //\r
315 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_WRITE_ENABLED_CAP_STRING, 0, Value);\r
316\r
317 if (Status == EFI_SUCCESS) {\r
318 //\r
319 // Update the write disabled flag\r
320 //\r
321 if (strcmp (Value, TRUE_STRING) == 0) {\r
322 FvInfo->FvAttributes |= EFI_FVB_WRITE_ENABLED_CAP;\r
323 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
324 Error (NULL, 0, 0, EFI_FVB_WRITE_ENABLED_CAP_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
325 return EFI_ABORTED;\r
326 }\r
327 } else {\r
328 Error (NULL, 0, 0, EFI_FVB_WRITE_ENABLED_CAP_STRING, "value not specified");\r
329 return Status;\r
330 }\r
331 //\r
332 // Read the write status attribute\r
333 //\r
334 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_WRITE_STATUS_STRING, 0, Value);\r
335\r
336 if (Status == EFI_SUCCESS) {\r
337 //\r
338 // Update the write disabled flag\r
339 //\r
340 if (strcmp (Value, TRUE_STRING) == 0) {\r
341 FvInfo->FvAttributes |= EFI_FVB_WRITE_STATUS;\r
342 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
343 Error (NULL, 0, 0, EFI_FVB_WRITE_STATUS_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
344 return EFI_ABORTED;\r
345 }\r
346 } else {\r
347 Error (NULL, 0, 0, EFI_FVB_WRITE_STATUS_STRING, "value not specified");\r
348 return Status;\r
349 }\r
350 //\r
351 // Read the lock capability attribute\r
352 //\r
353 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_LOCK_CAP_STRING, 0, Value);\r
354\r
355 if (Status == EFI_SUCCESS) {\r
356 //\r
357 // Update the attribute flag\r
358 //\r
359 if (strcmp (Value, TRUE_STRING) == 0) {\r
360 FvInfo->FvAttributes |= EFI_FVB_LOCK_CAP;\r
361 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
362 Error (NULL, 0, 0, EFI_FVB_LOCK_CAP_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
363 return EFI_ABORTED;\r
364 }\r
365 } else {\r
366 Error (NULL, 0, 0, EFI_FVB_LOCK_CAP_STRING, "value not specified");\r
367 return Status;\r
368 }\r
369 //\r
370 // Read the lock status attribute\r
371 //\r
372 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_LOCK_STATUS_STRING, 0, Value);\r
373\r
374 if (Status == EFI_SUCCESS) {\r
375 //\r
376 // Update the attribute flag\r
377 //\r
378 if (strcmp (Value, TRUE_STRING) == 0) {\r
379 FvInfo->FvAttributes |= EFI_FVB_LOCK_STATUS;\r
380 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
381 Error (NULL, 0, 0, EFI_FVB_LOCK_STATUS_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
382 return EFI_ABORTED;\r
383 }\r
384 } else {\r
385 Error (NULL, 0, 0, EFI_FVB_LOCK_STATUS_STRING, "value not specified");\r
386 return Status;\r
387 }\r
388 //\r
389 // Read the sticky write attribute\r
390 //\r
391 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_STICKY_WRITE_STRING, 0, Value);\r
392\r
393 if (Status == EFI_SUCCESS) {\r
394 //\r
395 // Update the attribute flag\r
396 //\r
397 if (strcmp (Value, TRUE_STRING) == 0) {\r
398 FvInfo->FvAttributes |= EFI_FVB_STICKY_WRITE;\r
399 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
400 Error (NULL, 0, 0, EFI_FVB_STICKY_WRITE_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
401 return EFI_ABORTED;\r
402 }\r
403 } else {\r
404 Error (NULL, 0, 0, EFI_FVB_STICKY_WRITE_STRING, "value not specified");\r
405 return Status;\r
406 }\r
407 //\r
408 // Read the memory mapped attribute\r
409 //\r
410 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_MEMORY_MAPPED_STRING, 0, Value);\r
411\r
412 if (Status == EFI_SUCCESS) {\r
413 //\r
414 // Update the attribute flag\r
415 //\r
416 if (strcmp (Value, TRUE_STRING) == 0) {\r
417 FvInfo->FvAttributes |= EFI_FVB_MEMORY_MAPPED;\r
418 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
419 Error (NULL, 0, 0, EFI_FVB_MEMORY_MAPPED_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
420 return EFI_ABORTED;\r
421 }\r
422 } else {\r
423 Error (NULL, 0, 0, EFI_FVB_MEMORY_MAPPED_STRING, "value not specified");\r
424 return Status;\r
425 }\r
426 //\r
427 // Read the erase polarity attribute\r
428 //\r
429 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ERASE_POLARITY_STRING, 0, Value);\r
430\r
431 if (Status == EFI_SUCCESS) {\r
432 //\r
433 // Update the attribute flag\r
434 //\r
435 if (strcmp (Value, ONE_STRING) == 0) {\r
436 FvInfo->FvAttributes |= EFI_FVB_ERASE_POLARITY;\r
437 } else if (strcmp (Value, ZERO_STRING) != 0) {\r
438 Error (NULL, 0, 0, EFI_FVB_ERASE_POLARITY_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
439 return EFI_ABORTED;\r
440 }\r
441 } else {\r
442 Error (NULL, 0, 0, EFI_FVB_ERASE_POLARITY_STRING, "value not specified");\r
443 return Status;\r
444 }\r
445 //\r
446 // Read the alignment capabilities attribute\r
447 //\r
448 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_CAP_STRING, 0, Value);\r
449\r
450 if (Status == EFI_SUCCESS) {\r
451 //\r
452 // Update attribute\r
453 //\r
454 if (strcmp (Value, TRUE_STRING) == 0) {\r
455 FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_CAP;\r
456 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
457 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_CAP_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
458 return EFI_ABORTED;\r
459 }\r
460 } else {\r
461 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_CAP_STRING, "value not specified");\r
462 return Status;\r
463 }\r
464 //\r
465 // Read the word alignment capability attribute\r
466 //\r
467 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_2_STRING, 0, Value);\r
468\r
469 if (Status == EFI_SUCCESS) {\r
470 //\r
471 // Update attribute\r
472 //\r
473 if (strcmp (Value, TRUE_STRING) == 0) {\r
474 FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_2;\r
475 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
476 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_2_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
477 return EFI_ABORTED;\r
478 }\r
479 } else {\r
480 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_2_STRING, "value not specified");\r
481 return Status;\r
482 }\r
483 //\r
484 // Read the dword alignment capability attribute\r
485 //\r
486 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_4_STRING, 0, Value);\r
487\r
488 if (Status == EFI_SUCCESS) {\r
489 //\r
490 // Update attribute\r
491 //\r
492 if (strcmp (Value, TRUE_STRING) == 0) {\r
493 FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_4;\r
494 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
495 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_4_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
496 return EFI_ABORTED;\r
497 }\r
498 } else {\r
499 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_4_STRING, "value not specified");\r
500 return Status;\r
501 }\r
502 //\r
503 // Read the word alignment capability attribute\r
504 //\r
505 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_8_STRING, 0, Value);\r
506\r
507 if (Status == EFI_SUCCESS) {\r
508 //\r
509 // Update attribute\r
510 //\r
511 if (strcmp (Value, TRUE_STRING) == 0) {\r
512 FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_8;\r
513 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
514 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_8_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
515 return EFI_ABORTED;\r
516 }\r
517 } else {\r
518 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_8_STRING, "value not specified");\r
519 return Status;\r
520 }\r
521 //\r
522 // Read the qword alignment capability attribute\r
523 //\r
524 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_16_STRING, 0, Value);\r
525\r
526 if (Status == EFI_SUCCESS) {\r
527 //\r
528 // Update attribute\r
529 //\r
530 if (strcmp (Value, TRUE_STRING) == 0) {\r
531 FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_16;\r
532 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
533 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_16_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
534 return EFI_ABORTED;\r
535 }\r
536 } else {\r
537 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_16_STRING, "value not specified");\r
538 return Status;\r
539 }\r
540 //\r
541 // Read the 32 byte alignment capability attribute\r
542 //\r
543 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_32_STRING, 0, Value);\r
544\r
545 if (Status == EFI_SUCCESS) {\r
546 //\r
547 // Update attribute\r
548 //\r
549 if (strcmp (Value, TRUE_STRING) == 0) {\r
550 FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_32;\r
551 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
552 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_32_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
553 return EFI_ABORTED;\r
554 }\r
555 } else {\r
556 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_32_STRING, "value not specified");\r
557 return Status;\r
558 }\r
559 //\r
560 // Read the 64 byte alignment capability attribute\r
561 //\r
562 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_64_STRING, 0, Value);\r
563\r
564 if (Status == EFI_SUCCESS) {\r
565 //\r
566 // Update attribute\r
567 //\r
568 if (strcmp (Value, TRUE_STRING) == 0) {\r
569 FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_64;\r
570 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
571 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_64_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
572 return EFI_ABORTED;\r
573 }\r
574 } else {\r
575 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_64_STRING, "value not specified");\r
576 return Status;\r
577 }\r
578 //\r
579 // Read the 128 byte alignment capability attribute\r
580 //\r
581 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_128_STRING, 0, Value);\r
582\r
583 if (Status == EFI_SUCCESS) {\r
584 //\r
585 // Update attribute\r
586 //\r
587 if (strcmp (Value, TRUE_STRING) == 0) {\r
588 FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_128;\r
589 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
590 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_128_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
591 return EFI_ABORTED;\r
592 }\r
593 } else {\r
594 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_128_STRING, "value not specified");\r
595 return Status;\r
596 }\r
597 //\r
598 // Read the 256 byte alignment capability attribute\r
599 //\r
600 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_256_STRING, 0, Value);\r
601\r
602 if (Status == EFI_SUCCESS) {\r
603 //\r
604 // Update attribute\r
605 //\r
606 if (strcmp (Value, TRUE_STRING) == 0) {\r
607 FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_256;\r
608 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
609 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_256_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
610 return EFI_ABORTED;\r
611 }\r
612 } else {\r
613 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_256_STRING, "value not specified");\r
614 return Status;\r
615 }\r
616 //\r
617 // Read the 512 byte alignment capability attribute\r
618 //\r
619 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_512_STRING, 0, Value);\r
620\r
621 if (Status == EFI_SUCCESS) {\r
622 //\r
623 // Update attribute\r
624 //\r
625 if (strcmp (Value, TRUE_STRING) == 0) {\r
626 FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_512;\r
627 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
628 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_512_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
629 return EFI_ABORTED;\r
630 }\r
631 } else {\r
632 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_512_STRING, "value not specified");\r
633 return Status;\r
634 }\r
635 //\r
636 // Read the 1K byte alignment capability attribute\r
637 //\r
638 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_1K_STRING, 0, Value);\r
639\r
640 if (Status == EFI_SUCCESS) {\r
641 //\r
642 // Update attribute\r
643 //\r
644 if (strcmp (Value, TRUE_STRING) == 0) {\r
645 FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_1K;\r
646 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
647 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_1K_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
648 return EFI_ABORTED;\r
649 }\r
650 } else {\r
651 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_1K_STRING, "value not specified");\r
652 return Status;\r
653 }\r
654 //\r
655 // Read the 2K byte alignment capability attribute\r
656 //\r
657 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_2K_STRING, 0, Value);\r
658\r
659 if (Status == EFI_SUCCESS) {\r
660 //\r
661 // Update attribute\r
662 //\r
663 if (strcmp (Value, TRUE_STRING) == 0) {\r
664 FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_2K;\r
665 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
666 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_2K_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
667 return EFI_ABORTED;\r
668 }\r
669 } else {\r
670 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_2K_STRING, "value not specified");\r
671 return Status;\r
672 }\r
673 //\r
674 // Read the 4K byte alignment capability attribute\r
675 //\r
676 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_4K_STRING, 0, Value);\r
677\r
678 if (Status == EFI_SUCCESS) {\r
679 //\r
680 // Update attribute\r
681 //\r
682 if (strcmp (Value, TRUE_STRING) == 0) {\r
683 FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_4K;\r
684 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
685 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_4K_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
686 return EFI_ABORTED;\r
687 }\r
688 } else {\r
689 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_4K_STRING, "value not specified");\r
690 return Status;\r
691 }\r
692 //\r
693 // Read the 8K byte alignment capability attribute\r
694 //\r
695 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_8K_STRING, 0, Value);\r
696\r
697 if (Status == EFI_SUCCESS) {\r
698 //\r
699 // Update attribute\r
700 //\r
701 if (strcmp (Value, TRUE_STRING) == 0) {\r
702 FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_8K;\r
703 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
704 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_8K_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
705 return EFI_ABORTED;\r
706 }\r
707 } else {\r
708 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_8K_STRING, "value not specified");\r
709 return Status;\r
710 }\r
711 //\r
712 // Read the 16K byte alignment capability attribute\r
713 //\r
714 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_16K_STRING, 0, Value);\r
715\r
716 if (Status == EFI_SUCCESS) {\r
717 //\r
718 // Update attribute\r
719 //\r
720 if (strcmp (Value, TRUE_STRING) == 0) {\r
721 FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_16K;\r
722 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
723 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_16K_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
724 return EFI_ABORTED;\r
725 }\r
726 } else {\r
727 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_16K_STRING, "value not specified");\r
728 return Status;\r
729 }\r
730 //\r
731 // Read the 32K byte alignment capability attribute\r
732 //\r
733 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_32K_STRING, 0, Value);\r
734\r
735 if (Status == EFI_SUCCESS) {\r
736 //\r
737 // Update attribute\r
738 //\r
739 if (strcmp (Value, TRUE_STRING) == 0) {\r
740 FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_32K;\r
741 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
742 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_32K_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
743 return EFI_ABORTED;\r
744 }\r
745 } else {\r
746 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_32K_STRING, "value not specified");\r
747 return Status;\r
748 }\r
749 //\r
750 // Read the 64K byte alignment capability attribute\r
751 //\r
752 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_64K_STRING, 0, Value);\r
753\r
754 if (Status == EFI_SUCCESS) {\r
755 //\r
756 // Update attribute\r
757 //\r
758 if (strcmp (Value, TRUE_STRING) == 0) {\r
759 FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_64K;\r
760 } else if (strcmp (Value, FALSE_STRING) != 0) {\r
761 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_64K_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
762 return EFI_ABORTED;\r
763 }\r
764 } else {\r
765 Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_64K_STRING, "value not specified");\r
766 return Status;\r
767 }\r
768\r
769 if (!(FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_CAP) &&\r
770 (\r
771 (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_2) ||\r
772 (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_4) ||\r
773 (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_8) ||\r
774 (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_16) ||\r
775 (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_32) ||\r
776 (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_64) ||\r
777 (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_128) ||\r
778 (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_256) ||\r
779 (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_512) ||\r
780 (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_1K) ||\r
781 (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_2K) ||\r
782 (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_4K) ||\r
783 (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_8K) ||\r
784 (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_16K) ||\r
785 (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_32K) ||\r
786 (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_64K)\r
787 )\r
788 ) {\r
789 Error (\r
790 NULL,\r
791 0,\r
792 0,\r
793 "illegal combination of alignment attributes",\r
794 "if %s is not %s, no individual alignments can be %s",\r
795 EFI_FVB_ALIGNMENT_CAP_STRING,\r
796 TRUE_STRING,\r
797 TRUE_STRING\r
798 );\r
799 return EFI_ABORTED;\r
800 }\r
801 //\r
802 // Read block maps\r
803 //\r
804 for (Index = 0; Index < MAX_NUMBER_OF_FV_BLOCKS; Index++) {\r
805 //\r
806 // Read the number of blocks\r
807 //\r
808 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_NUM_BLOCKS_STRING, Index, Value);\r
809\r
810 if (Status == EFI_SUCCESS) {\r
811 //\r
812 // Update the number of blocks\r
813 //\r
814 Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
815 if (EFI_ERROR (Status)) {\r
816 Error (NULL, 0, 0, Value, "invalid value for %s", EFI_NUM_BLOCKS_STRING);\r
817 return EFI_ABORTED;\r
818 }\r
819\r
820 FvInfo->FvBlocks[Index].NumBlocks = (UINT32) Value64;\r
821 } else {\r
822 //\r
823 // If there is no number of blocks, but there is a size, then we have a mismatched pair\r
824 // and should return an error.\r
825 //\r
826 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_BLOCK_SIZE_STRING, Index, Value);\r
827 if (!EFI_ERROR (Status)) {\r
828 Error (NULL, 0, 0, "must specify both", "%s and %s", EFI_NUM_BLOCKS_STRING, EFI_BLOCK_SIZE_STRING);\r
829 return EFI_ABORTED;\r
830 } else {\r
831 //\r
832 // We are done\r
833 //\r
834 break;\r
835 }\r
836 }\r
837 //\r
838 // Read the size of blocks\r
839 //\r
840 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_BLOCK_SIZE_STRING, Index, Value);\r
841\r
842 if (Status == EFI_SUCCESS) {\r
843 //\r
844 // Update the number of blocks\r
845 //\r
846 Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
847 if (EFI_ERROR (Status)) {\r
848 Error (NULL, 0, 0, Value, "invalid value specified for %s", EFI_BLOCK_SIZE_STRING);\r
849 return EFI_ABORTED;\r
850 }\r
851\r
852 FvInfo->FvBlocks[Index].BlockLength = (UINT32) Value64;\r
853 } else {\r
854 //\r
855 // There is a number of blocks, but there is no size, so we have a mismatched pair\r
856 // and should return an error.\r
857 //\r
858 Error (NULL, 0, 0, "must specify both", "%s and %s", EFI_NUM_BLOCKS_STRING, EFI_BLOCK_SIZE_STRING);\r
859 return EFI_ABORTED;\r
860 }\r
861 }\r
862 //\r
863 // Read files\r
864 //\r
865 for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_FV; Index++) {\r
866 //\r
867 // Read the number of blocks\r
868 //\r
869 Status = FindToken (InfFile, FILES_SECTION_STRING, EFI_FILE_NAME_STRING, Index, Value);\r
870\r
871 if (Status == EFI_SUCCESS) {\r
872 //\r
873 // Add the file\r
874 //\r
875 strcpy (FvInfo->FvFiles[Index], Value);\r
876 } else {\r
877 break;\r
878 }\r
879 }\r
880\r
881 if (FindSection (InfFile, COMPONENT_SECTION_STRING)) {\r
882 Index = 0;\r
883 //\r
884 // Read component FV_VARIABLE\r
885 //\r
886 Status = FindToken (InfFile, COMPONENT_SECTION_STRING, EFI_NV_VARIABLE_STRING, 0, Value);\r
887\r
888 if (Status == EFI_SUCCESS) {\r
889 //\r
890 // Add the component\r
891 //\r
892 strcpy (FvInfo->FvComponents[Index].ComponentName, EFI_NV_VARIABLE_STRING);\r
893 Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
894 if (EFI_ERROR (Status)) {\r
895 printf ("ERROR: %s is not a valid integer.\n", EFI_NV_VARIABLE_STRING);\r
896 return EFI_ABORTED;\r
897 }\r
898\r
899 FvInfo->FvComponents[Index].Size = (UINTN) Value64;\r
900 } else {\r
901 printf ("WARNING: Could not read %s.\n", EFI_NV_VARIABLE_STRING);\r
902 }\r
903\r
904 Index++;\r
905 //\r
906 // Read component FV_EVENT_LOG\r
907 //\r
908 Status = FindToken (InfFile, COMPONENT_SECTION_STRING, EFI_NV_EVENT_LOG_STRING, 0, Value);\r
909\r
910 if (Status == EFI_SUCCESS) {\r
911 //\r
912 // Add the component\r
913 //\r
914 strcpy (FvInfo->FvComponents[Index].ComponentName, EFI_NV_EVENT_LOG_STRING);\r
915 Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
916 if (EFI_ERROR (Status)) {\r
917 printf ("ERROR: %s is not a valid integer.\n", EFI_NV_EVENT_LOG_STRING);\r
918 return EFI_ABORTED;\r
919 }\r
920\r
921 FvInfo->FvComponents[Index].Size = (UINTN) Value64;\r
922 } else {\r
923 printf ("WARNING: Could not read %s.\n", EFI_NV_EVENT_LOG_STRING);\r
924 }\r
925\r
926 Index++;\r
927 //\r
928 // Read component FV_FTW_WORKING\r
929 //\r
930 Status = FindToken (InfFile, COMPONENT_SECTION_STRING, EFI_NV_FTW_WORKING_STRING, 0, Value);\r
931\r
932 if (Status == EFI_SUCCESS) {\r
933 //\r
934 // Add the component\r
935 //\r
936 strcpy (FvInfo->FvComponents[Index].ComponentName, EFI_NV_FTW_WORKING_STRING);\r
937 Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
938 if (EFI_ERROR (Status)) {\r
939 printf ("ERROR: %s is not a valid integer.\n", EFI_NV_FTW_WORKING_STRING);\r
940 return EFI_ABORTED;\r
941 }\r
942\r
943 FvInfo->FvComponents[Index].Size = (UINTN) Value64;\r
944 } else {\r
945 printf ("WARNING: Could not read %s.\n", EFI_NV_FTW_WORKING_STRING);\r
946 }\r
947\r
948 Index++;\r
949 //\r
950 // Read component FV_FTW_SPARE\r
951 //\r
952 Status = FindToken (InfFile, COMPONENT_SECTION_STRING, EFI_NV_FTW_SPARE_STRING, 0, Value);\r
953\r
954 if (Status == EFI_SUCCESS) {\r
955 //\r
956 // Add the component\r
957 //\r
958 strcpy (FvInfo->FvComponents[Index].ComponentName, EFI_NV_FTW_SPARE_STRING);\r
959 Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
960 if (EFI_ERROR (Status)) {\r
961 printf ("ERROR: %s is not a valid integer.\n", EFI_NV_FTW_SPARE_STRING);\r
962 return EFI_ABORTED;\r
963 }\r
964\r
965 FvInfo->FvComponents[Index].Size = (UINTN) Value64;\r
966 } else {\r
967 printf ("WARNING: Could not read %s.\n", EFI_NV_FTW_SPARE_STRING);\r
968 }\r
969 }\r
970 //\r
971 // Compute size for easy access later\r
972 //\r
973 FvInfo->Size = 0;\r
974 for (Index = 0; FvInfo->FvBlocks[Index].NumBlocks; Index++) {\r
975 FvInfo->Size += FvInfo->FvBlocks[Index].NumBlocks * FvInfo->FvBlocks[Index].BlockLength;\r
976 }\r
977\r
978 return EFI_SUCCESS;\r
979}\r
980\r
981VOID\r
982UpdateFfsFileState (\r
983 IN EFI_FFS_FILE_HEADER *FfsFile,\r
984 IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader\r
985 )\r
986/*++\r
987\r
988Routine Description:\r
989\r
990 This function changes the FFS file attributes based on the erase polarity\r
991 of the FV.\r
992\r
993Arguments:\r
994\r
995 FfsFile File header.\r
996 FvHeader FV header.\r
997\r
998Returns:\r
999\r
1000 None\r
1001\r
1002--*/\r
1003{\r
1004 if (FvHeader->Attributes & EFI_FVB_ERASE_POLARITY) {\r
1005 FfsFile->State = (UINT8)~(FfsFile->State);\r
1006 }\r
1007}\r
1008\r
1009EFI_STATUS\r
1010ReadFfsAlignment (\r
1011 IN EFI_FFS_FILE_HEADER *FfsFile,\r
1012 IN OUT UINT32 *Alignment\r
1013 )\r
1014/*++\r
1015\r
1016Routine Description:\r
1017\r
1018 This function determines the alignment of the FFS input file from the file\r
1019 attributes.\r
1020\r
1021Arguments:\r
1022\r
1023 FfsFile FFS file to parse\r
1024 Alignment The minimum required alignment of the FFS file, in bytes\r
1025\r
1026Returns:\r
1027\r
1028 EFI_SUCCESS The function completed successfully.\r
1029 EFI_INVALID_PARAMETER One of the input parameters was invalid.\r
1030 EFI_ABORTED An error occurred.\r
1031\r
1032--*/\r
1033{\r
1034 //\r
1035 // Verify input parameters.\r
1036 //\r
1037 if (FfsFile == NULL || Alignment == NULL) {\r
1038 return EFI_INVALID_PARAMETER;\r
1039 }\r
1040\r
1041 switch ((FfsFile->Attributes >> 3) & 0x07) {\r
1042\r
1043 case 0:\r
1044 //\r
d3f75347 1045 // 8 byte alignment, mini alignment requirement for FFS file. \r
878ddf1f 1046 //\r
d3f75347 1047 *Alignment = (1 << 3);\r
878ddf1f 1048 break;\r
1049\r
1050 case 1:\r
1051 //\r
1052 // 16 byte alignment\r
1053 //\r
1054 *Alignment = (1 << 4);\r
1055 break;\r
1056\r
1057 case 2:\r
1058 //\r
1059 // 128 byte alignment\r
1060 //\r
1061 *Alignment = (1 << 7);\r
1062 break;\r
1063\r
1064 case 3:\r
1065 //\r
1066 // 512 byte alignment\r
1067 //\r
1068 *Alignment = (1 << 9);\r
1069 break;\r
1070\r
1071 case 4:\r
1072 //\r
1073 // 1K byte alignment\r
1074 //\r
1075 *Alignment = (1 << 10);\r
1076 break;\r
1077\r
1078 case 5:\r
1079 //\r
1080 // 4K byte alignment\r
1081 //\r
1082 *Alignment = (1 << 12);\r
1083 break;\r
1084\r
1085 case 6:\r
1086 //\r
1087 // 32K byte alignment\r
1088 //\r
1089 *Alignment = (1 << 15);\r
1090 break;\r
1091\r
1092 case 7:\r
1093 //\r
1094 // 64K byte alignment\r
1095 //\r
1096 *Alignment = (1 << 16);\r
1097 break;\r
1098\r
1099 default:\r
1100 Error (NULL, 0, 0, "nvalid file attribute calculated, this is most likely a utility error", NULL);\r
1101 return EFI_ABORTED;\r
1102 }\r
1103\r
1104 return EFI_SUCCESS;\r
1105}\r
1106\r
1107EFI_STATUS\r
1108AddPadFile (\r
1109 IN OUT MEMORY_FILE *FvImage,\r
1110 IN UINT32 DataAlignment\r
1111 )\r
1112/*++\r
1113\r
1114Routine Description:\r
1115\r
1116 This function adds a pad file to the FV image if it required to align the\r
1117 data of the next file.\r
1118\r
1119Arguments:\r
1120\r
1121 FvImage The memory image of the FV to add it to. The current offset\r
1122 must be valid.\r
1123 DataAlignment The data alignment of the next FFS file.\r
1124\r
1125Returns:\r
1126\r
1127 EFI_SUCCESS The function completed successfully.\r
1128 EFI_INVALID_PARAMETER One of the input parameters was invalid.\r
1129 EFI_OUT_OF_RESOURCES Insufficient resources exist in the FV to complete\r
1130 the pad file add.\r
1131\r
1132--*/\r
1133{\r
1134 EFI_FFS_FILE_HEADER *PadFile;\r
1135 EFI_GUID PadFileGuid;\r
1136 UINTN PadFileSize;\r
1137\r
1138 //\r
1139 // Verify input parameters.\r
1140 //\r
1141 if (FvImage == NULL) {\r
1142 return EFI_INVALID_PARAMETER;\r
1143 }\r
1144 //\r
1145 // Basic assumption is we start from an 8 byte aligned address\r
1146 // and our file header is a multiple of 8 bytes\r
1147 //\r
1148 assert ((UINTN) FvImage->CurrentFilePointer % 8 == 0);\r
1149 assert (sizeof (EFI_FFS_FILE_HEADER) % 8 == 0);\r
1150\r
1151 //\r
1152 // Check if a pad file is necessary\r
1153 //\r
1154 if (((UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + sizeof (EFI_FFS_FILE_HEADER)) % DataAlignment == 0) {\r
1155 return EFI_SUCCESS;\r
1156 }\r
1157 //\r
1158 // Write pad file header\r
1159 //\r
1160 PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer;\r
1161\r
1162 //\r
1163 // Verify that we have enough space for the file header\r
1164 //\r
1165 if ((UINTN) (PadFile + sizeof (EFI_FFS_FILE_HEADER)) >= (UINTN) FvImage->Eof) {\r
1166 return EFI_OUT_OF_RESOURCES;\r
1167 }\r
1168\r
1169#ifdef __GNUC__\r
1170 {\r
1171 uuid_t tmp_id;\r
1172 uuid_generate (tmp_id);\r
1173 memcpy (&PadFileGuid, tmp_id, sizeof (EFI_GUID));\r
1174 }\r
1175#else\r
1176 UuidCreate (&PadFileGuid);\r
1177#endif\r
1178 memset (PadFile, 0, sizeof (EFI_FFS_FILE_HEADER));\r
1179 memcpy (&PadFile->Name, &PadFileGuid, sizeof (EFI_GUID));\r
1180 PadFile->Type = EFI_FV_FILETYPE_FFS_PAD;\r
1181 PadFile->Attributes = 0;\r
1182\r
1183 //\r
1184 // Calculate the pad file size\r
1185 //\r
1186 //\r
1187 // This is the earliest possible valid offset (current plus pad file header\r
1188 // plus the next file header)\r
1189 //\r
1190 PadFileSize = (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + (sizeof (EFI_FFS_FILE_HEADER) * 2);\r
1191\r
1192 //\r
1193 // Add whatever it takes to get to the next aligned address\r
1194 //\r
1195 while ((PadFileSize % DataAlignment) != 0) {\r
1196 PadFileSize++;\r
1197 }\r
1198 //\r
1199 // Subtract the next file header size\r
1200 //\r
1201 PadFileSize -= sizeof (EFI_FFS_FILE_HEADER);\r
1202\r
1203 //\r
1204 // Subtract the starting offset to get size\r
1205 //\r
1206 PadFileSize -= (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage;\r
1207\r
1208 //\r
1209 // Write pad file size (calculated size minus next file header size)\r
1210 //\r
1211 PadFile->Size[0] = (UINT8) (PadFileSize & 0xFF);\r
1212 PadFile->Size[1] = (UINT8) ((PadFileSize >> 8) & 0xFF);\r
1213 PadFile->Size[2] = (UINT8) ((PadFileSize >> 16) & 0xFF);\r
1214\r
1215 //\r
1216 // Fill in checksums and state, they must be 0 for checksumming.\r
1217 //\r
1218 PadFile->IntegrityCheck.Checksum.Header = 0;\r
1219 PadFile->IntegrityCheck.Checksum.File = 0;\r
1220 PadFile->State = 0;\r
1221 PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, sizeof (EFI_FFS_FILE_HEADER));\r
1222 if (PadFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
1223 PadFile->IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) PadFile, PadFileSize);\r
1224 } else {\r
1225 PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
1226 }\r
1227\r
1228 PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;\r
1229 UpdateFfsFileState (\r
1230 (EFI_FFS_FILE_HEADER *) PadFile,\r
1231 (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage\r
1232 );\r
1233\r
1234 //\r
1235 // Verify that we have enough space (including the padding\r
1236 //\r
1237 if ((UINTN) (PadFile + sizeof (EFI_FFS_FILE_HEADER)) >= (UINTN) FvImage->Eof) {\r
1238 return EFI_OUT_OF_RESOURCES;\r
1239 }\r
1240 //\r
1241 // Update the current FV pointer\r
1242 //\r
1243 FvImage->CurrentFilePointer += PadFileSize;\r
1244\r
1245 return EFI_SUCCESS;\r
1246}\r
1247\r
1248BOOLEAN\r
1249IsVtfFile (\r
1250 IN EFI_FFS_FILE_HEADER *FileBuffer\r
1251 )\r
1252/*++\r
1253\r
1254Routine Description:\r
1255\r
1256 This function checks the header to validate if it is a VTF file\r
1257\r
1258Arguments:\r
1259\r
1260 FileBuffer Buffer in which content of a file has been read.\r
1261\r
1262Returns:\r
1263\r
1264 TRUE If this is a VTF file\r
1265 FALSE If this is not a VTF file\r
1266\r
1267--*/\r
1268{\r
1269 EFI_GUID VtfGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;\r
1270 if (!memcmp (&FileBuffer->Name, &VtfGuid, sizeof (EFI_GUID))) {\r
1271 return TRUE;\r
1272 } else {\r
1273 return FALSE;\r
1274 }\r
1275}\r
1276\r
1277EFI_STATUS\r
1278FfsRebaseImageRead (\r
1279 IN VOID *FileHandle,\r
1280 IN UINTN FileOffset,\r
1281 IN OUT UINT32 *ReadSize,\r
1282 OUT VOID *Buffer\r
1283 )\r
1284/*++\r
1285\r
1286Routine Description:\r
1287\r
1288 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
1289\r
1290Arguments:\r
1291\r
1292 FileHandle - The handle to the PE/COFF file\r
1293\r
1294 FileOffset - The offset, in bytes, into the file to read\r
1295\r
1296 ReadSize - The number of bytes to read from the file starting at FileOffset\r
1297\r
1298 Buffer - A pointer to the buffer to read the data into.\r
1299\r
1300Returns:\r
1301\r
1302 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
1303\r
1304--*/\r
1305{\r
1306 CHAR8 *Destination8;\r
1307 CHAR8 *Source8;\r
1308 UINT32 Length;\r
1309\r
1310 Destination8 = Buffer;\r
1311 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
1312 Length = *ReadSize;\r
1313 while (Length--) {\r
1314 *(Destination8++) = *(Source8++);\r
1315 }\r
1316\r
1317 return EFI_SUCCESS;\r
1318}\r
1319\r
878ddf1f 1320\r
1321EFI_STATUS\r
1322AddSymFile (\r
1323 IN UINT64 BaseAddress,\r
1324 IN EFI_FFS_FILE_HEADER *FfsFile,\r
1325 IN OUT MEMORY_FILE *SymImage,\r
1326 IN CHAR8 *SourceFileName\r
1327 )\r
1328/*++\r
1329\r
1330Routine Description:\r
1331\r
1332 This function adds the SYM tokens in the source file to the destination file.\r
1333 The SYM tokens are updated to reflect the base address.\r
1334\r
1335Arguments:\r
1336\r
1337 BaseAddress The base address for the new SYM tokens.\r
1338 FfsFile Pointer to the beginning of the FFS file in question.\r
1339 SymImage The memory file to update with symbol information.\r
1340 SourceFileName The source file.\r
1341\r
1342Returns:\r
1343\r
1344 EFI_SUCCESS The function completed successfully.\r
1345 EFI_INVALID_PARAMETER One of the input parameters was invalid.\r
1346 EFI_ABORTED An error occurred.\r
1347\r
1348--*/\r
1349{\r
1350 FILE *SourceFile;\r
1351\r
1352 CHAR8 Buffer[_MAX_PATH];\r
1353 CHAR8 Type[_MAX_PATH];\r
1354 CHAR8 Address[_MAX_PATH];\r
1355 CHAR8 Section[_MAX_PATH];\r
1356 CHAR8 Token[_MAX_PATH];\r
1357 CHAR8 SymFileName[_MAX_PATH];\r
1358 CHAR8 CodeModuleName[_MAX_PATH];\r
1359 CHAR8 *Ptr;\r
1360\r
1361 UINT64 TokenAddress;\r
1362\r
1363 EFI_STATUS Status;\r
1364 EFI_FILE_SECTION_POINTER Pe32Section;\r
1365 UINT32 EntryPoint;\r
1366 UINT32 BaseOfCode;\r
1367 UINT16 MachineType;\r
878ddf1f 1368\r
878ddf1f 1369 //\r
1370 // Verify input parameters.\r
1371 //\r
1372 if (BaseAddress == 0 || FfsFile == NULL || SymImage == NULL || SourceFileName == NULL) {\r
1373 Error (NULL, 0, 0, "invalid parameter passed to AddSymFile()", NULL);\r
1374 return EFI_INVALID_PARAMETER;\r
1375 }\r
1376 //\r
1377 // Check if we want to add this file\r
1378 //\r
1379 //\r
1380 // Get the file name\r
1381 //\r
1382 strcpy (Buffer, SourceFileName);\r
1383\r
1384 //\r
1385 // Copy the file name for the path of the sym file and truncate the name portion.\r
1386 //\r
1387 strcpy (SymFileName, Buffer);\r
1d940d05 1388 Ptr = strrchr (SymFileName, FILE_SEP_CHAR);\r
878ddf1f 1389 assert (Ptr);\r
1390 Ptr[0] = 0;\r
1391\r
1392 //\r
1393 // Find the file extension and make it lower case\r
1394 //\r
1395 Ptr = strrchr (SymFileName, '.');\r
1396 if (Ptr != NULL) {\r
1397 strlwr (Ptr);\r
1398 }\r
1399 //\r
1400 // Check if it is PEI file\r
1401 //\r
1402 if (strstr (Buffer, ".pei") != NULL) {\r
1403 //\r
1404 // Find the human readable portion\r
1405 //\r
1406 if (!strtok (Buffer, "-") ||\r
1407 !strtok (NULL, "-") ||\r
1408 !strtok (NULL, "-") ||\r
1409 !strtok (NULL, "-") ||\r
1410 !strtok (NULL, "-") ||\r
1411 !strcpy (Buffer, strtok (NULL, "."))\r
1412 ) {\r
1413 Error (NULL, 0, 0, "failed to find human readable portion of the file name in AddSymFile()", NULL);\r
1414 return EFI_ABORTED;\r
1415 }\r
1416 //\r
1417 // Save code module name\r
1418 //\r
1419 strcpy (CodeModuleName, Buffer);\r
1420\r
1421 //\r
1422 // Add the symbol file name and extension to the file path.\r
1423 //\r
1424 strcat (Buffer, ".sym");\r
1d940d05 1425 strcat (SymFileName, FILE_SEP_CHAR);\r
878ddf1f 1426 strcat (SymFileName, Buffer);\r
1427 } else {\r
1428 //\r
1429 // Only handle PEIM files.\r
1430 //\r
1431 return EFI_SUCCESS;\r
1432 }\r
1433 //\r
1434 // Find PE32 section\r
1435 //\r
1436 Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
1437\r
1438 //\r
1439 // BUGBUG: Assume if no PE32 section it is PIC and hardcode base address\r
1440 //\r
1441 if (Status == EFI_NOT_FOUND) {\r
1442 Status = GetSectionByType (FfsFile, EFI_SECTION_TE, 1, &Pe32Section);\r
a651e231
LG
1443 }\r
1444\r
1445 if (Status == EFI_SUCCESS) {\r
878ddf1f 1446 Status = GetPe32Info (\r
1447 (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
1448 &EntryPoint,\r
1449 &BaseOfCode,\r
1450 &MachineType\r
1451 );\r
a651e231
LG
1452 } else if (Status == EFI_NOT_FOUND) {\r
1453 //\r
1454 // For PIC, hardcode.\r
1455 //\r
1456 BaseOfCode = 0x60;\r
1457 Status = EFI_SUCCESS;\r
1458 } else {\r
1459 Error (NULL, 0, 0, "could not parse a PE32 section from the PEI file", NULL);\r
1460 return Status;\r
878ddf1f 1461 }\r
a651e231
LG
1462\r
1463 if (EFI_ERROR (Status)) {\r
1464 Error (NULL, 0, 0, "GetPe32Info() could not get PE32 entry point for PEI file", NULL);\r
1465 return Status;\r
1466 }\r
1467\r
878ddf1f 1468 //\r
1469 // Open the source file\r
1470 //\r
1471 SourceFile = fopen (SymFileName, "r");\r
1472 if (SourceFile == NULL) {\r
1473 //\r
1474 // SYM files are not required.\r
1475 //\r
1476 return EFI_SUCCESS;\r
1477 }\r
1478 //\r
1479 // Read the first line\r
1480 //\r
1481 if (fgets (Buffer, _MAX_PATH, SourceFile) == NULL) {\r
1482 Buffer[0] = 0;\r
1483 }\r
1484 //\r
1485 // Make sure it matches the expected sym format\r
1486 //\r
1487 if (strcmp (Buffer, "TEXTSYM format | V1.0\n")) {\r
1488 fclose (SourceFile);\r
1489 Error (NULL, 0, 0, "AddSymFile() found unexpected sym format in input file", NULL);\r
1490 return EFI_ABORTED;\r
1491 }\r
1492 //\r
1493 // Read in the file\r
1494 //\r
1495 while (feof (SourceFile) == 0) {\r
1496 //\r
1497 // Read a line\r
1498 //\r
1499 if (fscanf (\r
1500 SourceFile,\r
1501 "%s | %s | %s | %s\n",\r
1502 Type,\r
1503 Address,\r
1504 Section,\r
1505 Token\r
1506 ) == 4) {\r
1507 //\r
1508 // If the token starts with "??" ignore it\r
1509 //\r
1510 if (Token[0] == '?' && Token[1] == '?') {\r
1511 continue;\r
1512 }\r
1513 //\r
1514 // Get the token address\r
1515 //\r
1516 AsciiStringToUint64 (Address, TRUE, &TokenAddress);\r
1517\r
1518 //\r
1519 // Add the base address\r
1520 //\r
1521 TokenAddress += BaseAddress;\r
1522\r
1523 //\r
a651e231 1524 // If PE32 or TE section then find the start of code. For PIC it is hardcoded.\r
878ddf1f 1525 //\r
a651e231 1526 if (Pe32Section.Pe32Section) {\r
878ddf1f 1527 //\r
1528 // Add the offset of the PE32 section\r
1529 //\r
1530 TokenAddress += (UINTN) Pe32Section.Pe32Section - (UINTN) FfsFile;\r
1531\r
1532 //\r
1533 // Add the size of the PE32 section header\r
1534 //\r
1535 TokenAddress += sizeof (EFI_PE32_SECTION);\r
878ddf1f 1536 } else {\r
1537 //\r
a651e231 1538 // For PIC hardcoded.\r
878ddf1f 1539 //\r
1540 TokenAddress += 0x28;\r
1541 }\r
a651e231 1542\r
878ddf1f 1543 //\r
1544 // Add the beginning of the code\r
1545 //\r
1546 TokenAddress += BaseOfCode;\r
1547\r
1548 sprintf (\r
1549 Buffer,\r
1550 "%s | %016I64X | %s | _%s%s\n",\r
1551 Type,\r
1552 TokenAddress,\r
1553 Section,\r
1554 CodeModuleName,\r
1555 Token\r
1556 );\r
1557 memcpy (SymImage->CurrentFilePointer, Buffer, strlen (Buffer) + 1);\r
1558 SymImage->CurrentFilePointer = (UINT8 *) (((UINTN) SymImage->CurrentFilePointer) + strlen (Buffer) + 1);\r
1559 }\r
1560 }\r
1561\r
1562 fclose (SourceFile);\r
1563 return EFI_SUCCESS;\r
1564}\r
1565\r
1566EFI_STATUS\r
1567AddFile (\r
1568 IN OUT MEMORY_FILE *FvImage,\r
1569 IN FV_INFO *FvInfo,\r
1570 IN UINTN Index,\r
1571 IN OUT EFI_FFS_FILE_HEADER **VtfFileImage,\r
1572 IN OUT MEMORY_FILE *SymImage\r
1573 )\r
1574/*++\r
1575\r
1576Routine Description:\r
1577\r
1578 This function adds a file to the FV image. The file will pad to the\r
1579 appropriate alignment if required.\r
1580\r
1581Arguments:\r
1582\r
1583 FvImage The memory image of the FV to add it to. The current offset\r
1584 must be valid.\r
1585 FvInfo Pointer to information about the FV.\r
1586 Index The file in the FvInfo file list to add.\r
1587 VtfFileImage A pointer to the VTF file within the FvImage. If this is equal\r
1588 to the end of the FvImage then no VTF previously found.\r
1589 SymImage The memory image of the Sym file to update if symbols are present.\r
1590 The current offset must be valid.\r
1591\r
1592Returns:\r
1593\r
1594 EFI_SUCCESS The function completed successfully.\r
1595 EFI_INVALID_PARAMETER One of the input parameters was invalid.\r
1596 EFI_ABORTED An error occurred.\r
1597 EFI_OUT_OF_RESOURCES Insufficient resources exist to complete the add.\r
1598\r
1599--*/\r
1600{\r
1601 FILE *NewFile;\r
1602 UINTN FileSize;\r
1603 UINT8 *FileBuffer;\r
1604 UINTN NumBytesRead;\r
1605 UINT32 CurrentFileAlignment;\r
1606 EFI_STATUS Status;\r
1607 EFI_PHYSICAL_ADDRESS CurrentFileBaseAddress;\r
1608 UINT8 VtfHeaderChecksum;\r
1609 UINT8 VtfFileChecksum;\r
1610 UINT8 FileState;\r
1611 EFI_FFS_FILE_TAIL TailValue;\r
1612 UINT32 TailSize;\r
1613 //\r
1614 // Verify input parameters.\r
1615 //\r
1616 if (FvImage == NULL || FvInfo == NULL || FvInfo->FvFiles[Index][0] == 0 || VtfFileImage == NULL || SymImage == NULL) {\r
1617 return EFI_INVALID_PARAMETER;\r
1618 }\r
1619 //\r
1620 // Read the file to add\r
1621 //\r
1622 NewFile = fopen (FvInfo->FvFiles[Index], "rb");\r
1623\r
1624 if (NewFile == NULL) {\r
1625 Error (NULL, 0, 0, FvInfo->FvFiles[Index], "failed to open file for reading");\r
1626 return EFI_ABORTED;\r
1627 }\r
1628 //\r
1629 // Get the file size\r
1630 //\r
878ddf1f 1631 FileSize = _filelength (fileno (NewFile));\r
878ddf1f 1632\r
1633 //\r
1634 // Read the file into a buffer\r
1635 //\r
1636 FileBuffer = malloc (FileSize);\r
1637 if (FileBuffer == NULL) {\r
1638 Error (NULL, 0, 0, "memory allocation failure", NULL);\r
1639 return EFI_OUT_OF_RESOURCES;\r
1640 }\r
1641\r
1642 NumBytesRead = fread (FileBuffer, sizeof (UINT8), FileSize, NewFile);\r
1643\r
1644 //\r
1645 // Done with the file, from this point on we will just use the buffer read.\r
1646 //\r
1647 fclose (NewFile);\r
1648\r
1649 //\r
1650 // Verify read successful\r
1651 //\r
1652 if (NumBytesRead != sizeof (UINT8) * FileSize) {\r
1653 free (FileBuffer);\r
1654 Error (NULL, 0, 0, FvInfo->FvFiles[Index], "failed to read input file contents");\r
1655 return EFI_ABORTED;\r
1656 }\r
1657 //\r
1658 // Verify space exists to add the file\r
1659 //\r
1660 if (FileSize > (UINTN) ((UINTN) *VtfFileImage - (UINTN) FvImage->CurrentFilePointer)) {\r
1661 Error (NULL, 0, 0, FvInfo->FvFiles[Index], "insufficient space remains to add the file");\r
1662 return EFI_OUT_OF_RESOURCES;\r
1663 }\r
1664 //\r
1665 // Update the file state based on polarity of the FV.\r
1666 //\r
1667 UpdateFfsFileState (\r
1668 (EFI_FFS_FILE_HEADER *) FileBuffer,\r
1669 (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage\r
1670 );\r
1671\r
1672 //\r
1673 // If we have a VTF file, add it at the top.\r
1674 //\r
1675 if (IsVtfFile ((EFI_FFS_FILE_HEADER *) FileBuffer)) {\r
1676 if ((UINTN) *VtfFileImage == (UINTN) FvImage->Eof) {\r
1677 //\r
1678 // No previous VTF, add this one.\r
1679 //\r
1680 *VtfFileImage = (EFI_FFS_FILE_HEADER *) (UINTN) ((UINTN) FvImage->FileImage + FvInfo->Size - FileSize);\r
1681 //\r
1682 // Sanity check. The file MUST align appropriately\r
1683 //\r
1684 if ((((UINTN) *VtfFileImage) & 0x07) != 0) {\r
1685 Error (NULL, 0, 0, "VTF file does not align on 8-byte boundary", NULL);\r
1686 }\r
1687 //\r
1688 // copy VTF File Header\r
1689 //\r
1690 memcpy (*VtfFileImage, FileBuffer, sizeof (EFI_FFS_FILE_HEADER));\r
1691\r
1692 //\r
1693 // Copy VTF body\r
1694 //\r
1695 memcpy (\r
1696 (UINT8 *) *VtfFileImage + sizeof (EFI_FFS_FILE_HEADER),\r
1697 FileBuffer + sizeof (EFI_FFS_FILE_HEADER),\r
1698 FileSize - sizeof (EFI_FFS_FILE_HEADER)\r
1699 );\r
1700\r
1701 //\r
1702 // re-calculate the VTF File Header\r
1703 //\r
1704 FileState = (*VtfFileImage)->State;\r
1705 (*VtfFileImage)->State = 0;\r
1706 *(UINT32 *) ((*VtfFileImage)->Size) = FileSize;\r
1707 (*VtfFileImage)->IntegrityCheck.Checksum.Header = 0;\r
1708 (*VtfFileImage)->IntegrityCheck.Checksum.File = 0;\r
1709\r
1710 VtfHeaderChecksum = CalculateChecksum8 ((UINT8 *) *VtfFileImage, sizeof (EFI_FFS_FILE_HEADER));\r
1711 (*VtfFileImage)->IntegrityCheck.Checksum.Header = VtfHeaderChecksum;\r
1712 //\r
1713 // Determine if it has a tail\r
1714 //\r
1715 if ((*VtfFileImage)->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
1716 TailSize = sizeof (EFI_FFS_FILE_TAIL);\r
1717 } else {\r
1718 TailSize = 0;\r
1719 }\r
1720\r
1721 if ((*VtfFileImage)->Attributes & FFS_ATTRIB_CHECKSUM) {\r
1722 VtfFileChecksum = CalculateChecksum8 ((UINT8 *) *VtfFileImage, FileSize - TailSize);\r
1723 (*VtfFileImage)->IntegrityCheck.Checksum.File = VtfFileChecksum;\r
1724 } else {\r
1725 (*VtfFileImage)->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
1726 }\r
1727 //\r
1728 // If it has a file tail, update it\r
1729 //\r
1730 if ((*VtfFileImage)->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
1731 TailValue = (EFI_FFS_FILE_TAIL) (~((*VtfFileImage)->IntegrityCheck.TailReference));\r
1732 *(EFI_FFS_FILE_TAIL *) (((UINTN) (*VtfFileImage) + GetLength ((*VtfFileImage)->Size) - sizeof (EFI_FFS_FILE_TAIL))) = TailValue;\r
1733 }\r
1734 (*VtfFileImage)->State = FileState;\r
1735 free (FileBuffer);\r
1736 return EFI_SUCCESS;\r
1737 } else {\r
1738 //\r
1739 // Already found a VTF file.\r
1740 //\r
1741 Error (NULL, 0, 0, "multiple VTF files are illegal in a single FV", NULL);\r
1742 free (FileBuffer);\r
1743 return EFI_ABORTED;\r
1744 }\r
1745 }\r
1746 //\r
1747 // Check if alignment is required\r
1748 //\r
1749 Status = ReadFfsAlignment ((EFI_FFS_FILE_HEADER *) FileBuffer, &CurrentFileAlignment);\r
1750 if (EFI_ERROR (Status)) {\r
1751 printf ("ERROR: Could not determine alignment of file %s.\n", FvInfo->FvFiles[Index]);\r
1752 free (FileBuffer);\r
1753 return EFI_ABORTED;\r
1754 }\r
d3f75347
LG
1755 \r
1756 //\r
1757 // Find the largest alignment of all the FFS files in the FV\r
1758 //\r
1759 if (CurrentFileAlignment > MaxFfsAlignment) {\r
1760 MaxFfsAlignment = CurrentFileAlignment;\r
1761 }\r
878ddf1f 1762 //\r
1763 // Add pad file if necessary\r
1764 //\r
1765 Status = AddPadFile (FvImage, CurrentFileAlignment);\r
1766 if (EFI_ERROR (Status)) {\r
1767 printf ("ERROR: Could not align the file data properly.\n");\r
1768 free (FileBuffer);\r
1769 return EFI_ABORTED;\r
1770 }\r
1771 //\r
1772 // Add file\r
1773 //\r
1774 if ((FvImage->CurrentFilePointer + FileSize) < FvImage->Eof) {\r
1775 //\r
1776 // Copy the file\r
1777 //\r
1778 memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize);\r
1779\r
1780 //\r
1781 // If the file is XIP, rebase\r
1782 //\r
1783 CurrentFileBaseAddress = FvInfo->BaseAddress + ((UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage);\r
1784 //\r
1785 // Status = RebaseFfsFile ((EFI_FFS_FILE_HEADER*) FvImage->CurrentFilePointer, CurrentFileBaseAddress);\r
1786 // if (EFI_ERROR(Status)) {\r
1787 // printf ("ERROR: Could not rebase the file %s.\n", FvInfo->FvFiles[Index]);\r
1788 // return EFI_ABORTED;\r
1789 // }\r
1790 //\r
1791 // Update Symbol file\r
1792 //\r
1793 Status = AddSymFile (\r
1794 CurrentFileBaseAddress,\r
1795 (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer,\r
1796 SymImage,\r
1797 FvInfo->FvFiles[Index]\r
1798 );\r
1799 assert (!EFI_ERROR (Status));\r
1800\r
1801 //\r
1802 // Update the current pointer in the FV image\r
1803 //\r
1804 FvImage->CurrentFilePointer += FileSize;\r
1805 } else {\r
1806 printf ("ERROR: The firmware volume is out of space, could not add file %s.\n", FvInfo->FvFiles[Index]);\r
1807 return EFI_ABORTED;\r
1808 }\r
1809 //\r
1810 // Make next file start at QWord Boundry\r
1811 //\r
1812 while (((UINTN) FvImage->CurrentFilePointer & 0x07) != 0) {\r
1813 FvImage->CurrentFilePointer++;\r
1814 }\r
1815 //\r
1816 // Free allocated memory.\r
1817 //\r
1818 free (FileBuffer);\r
1819\r
1820 return EFI_SUCCESS;\r
1821}\r
1822\r
1823EFI_STATUS\r
1824AddVariableBlock (\r
1825 IN UINT8 *FvImage,\r
1826 IN UINTN Size,\r
1827 IN FV_INFO *FvInfo\r
1828 )\r
1829{\r
1830 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
1831 VARIABLE_STORE_HEADER *VarStoreHeader;\r
1832 //\r
1833 // Variable block should exclude FvHeader. Since the length of\r
1834 // FvHeader depends on the block map, which is variable length,\r
1835 // we could only decide the actual variable block length here.\r
1836 //\r
1837 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvImage;\r
1838 FvImage = FvImage + FvHeader->HeaderLength;\r
1839\r
1840 VarStoreHeader = (VARIABLE_STORE_HEADER *) FvImage;\r
1841\r
1842 VarStoreHeader->Signature = VARIABLE_STORE_SIGNATURE;\r
1843 VarStoreHeader->Size = Size - FvHeader->HeaderLength;\r
1844 VarStoreHeader->Format = VARIABLE_STORE_FORMATTED;\r
1845 VarStoreHeader->State = VARIABLE_STORE_HEALTHY;\r
1846 VarStoreHeader->Reserved = 0;\r
1847 VarStoreHeader->Reserved1 = 0;\r
1848\r
1849 return EFI_SUCCESS;\r
1850}\r
1851\r
1852EFI_STATUS\r
1853AddEventLogBlock (\r
1854 IN UINT8 *FvImage,\r
1855 IN UINTN Size,\r
1856 IN FV_INFO *FvInfo\r
1857 )\r
1858{\r
1859 return EFI_SUCCESS;\r
1860}\r
1861\r
1862EFI_STATUS\r
1863AddFTWWorkingBlock (\r
1864 IN UINT8 *FvImage,\r
1865 IN UINTN Size,\r
1866 IN FV_INFO *FvInfo\r
1867 )\r
1868{\r
1869 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FTWHeader;\r
1870 UINT32 Crc32;\r
1871\r
1872 Crc32 = 0;\r
1873 FTWHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FvImage;\r
1874 memcpy (&FTWHeader->Signature, &(FvInfo->FvGuid), sizeof (EFI_GUID));\r
1875 FTWHeader->WriteQueueSize = Size - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER);\r
1876 CalculateCrc32 (FvImage, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER), &Crc32);\r
1877 FTWHeader->Crc = Crc32;\r
1878 if (FvInfo->FvAttributes & EFI_FVB_ERASE_POLARITY) {\r
1879 FTWHeader->WorkingBlockValid = 0;\r
1880 FTWHeader->WorkingBlockInvalid = 1;\r
1881 } else {\r
1882 FTWHeader->WorkingBlockValid = 1;\r
1883 FTWHeader->WorkingBlockInvalid = 0;\r
1884 }\r
1885\r
1886 return EFI_SUCCESS;\r
1887}\r
1888\r
1889EFI_STATUS\r
1890AddFTWSpareBlock (\r
1891 IN UINT8 *FvImage,\r
1892 IN UINTN Size,\r
1893 IN FV_INFO *FvInfo\r
1894 )\r
1895{\r
1896 return EFI_SUCCESS;\r
1897}\r
1898\r
1899EFI_STATUS\r
1900GenNonFFSFv (\r
1901 IN UINT8 *FvImage,\r
1902 IN FV_INFO *FvInfo\r
1903 )\r
1904/*++\r
1905\r
1906Routine Description:\r
1907\r
1908 This function generate the non FFS FV image, such as the working block\r
1909 and spare block. How each component of the FV is built is component\r
1910 specific.\r
1911\r
1912Arguments:\r
1913\r
1914 FvImage The memory image of the FV to add it to. The current offset\r
1915 must be valid.\r
1916 FvInfo Pointer to information about the FV.\r
1917\r
1918Returns:\r
1919\r
1920 EFI_SUCCESS The function completed successfully.\r
1921 EFI_INVALID_PARAMETER One of the input parameters was invalid.\r
1922 EFI_ABORTED An error occurred.\r
1923 EFI_OUT_OF_RESOURCES Insufficient resources exist to complete the add.\r
1924\r
1925--*/\r
1926{\r
1927 UINTN Index;\r
1928 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
1929 UINT64 TotalSize;\r
1930\r
1931 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvImage;\r
1932 TotalSize = 0;\r
1933\r
1934 for (Index = 0; FvInfo->FvComponents[Index].Size != 0; Index++) {\r
1935 if (stricmp (FvInfo->FvComponents[Index].ComponentName, EFI_NV_VARIABLE_STRING) == 0) {\r
1936 AddVariableBlock (FvImage, FvInfo->FvComponents[Index].Size, FvInfo);\r
1937 } else if (stricmp (FvInfo->FvComponents[Index].ComponentName, EFI_NV_EVENT_LOG_STRING) == 0) {\r
1938 AddEventLogBlock (FvImage, FvInfo->FvComponents[Index].Size, FvInfo);\r
1939 } else if (stricmp (FvInfo->FvComponents[Index].ComponentName, EFI_NV_FTW_WORKING_STRING) == 0) {\r
1940 AddFTWWorkingBlock (FvImage, FvInfo->FvComponents[Index].Size, FvInfo);\r
1941 } else if (stricmp (FvInfo->FvComponents[Index].ComponentName, EFI_NV_FTW_SPARE_STRING) == 0) {\r
1942 AddFTWSpareBlock (FvImage, FvInfo->FvComponents[Index].Size, FvInfo);\r
1943 } else {\r
1944 printf ("Error. Unknown Non-FFS block %s \n", FvInfo->FvComponents[Index].ComponentName);\r
1945 return EFI_ABORTED;\r
1946 }\r
1947\r
1948 FvImage = FvImage + FvInfo->FvComponents[Index].Size;\r
1949 TotalSize = TotalSize + FvInfo->FvComponents[Index].Size;\r
1950 }\r
1951 //\r
1952 // Index and TotalSize is zero mean there's no component, so this is an empty fv\r
1953 //\r
1954 if ((Index != 0 || TotalSize != 0) && TotalSize != FvInfo->Size) {\r
1955 printf ("Error. Component size does not sum up to FV size.\n");\r
1956 return EFI_ABORTED;\r
1957 }\r
1958\r
1959 return EFI_SUCCESS;\r
1960}\r
1961\r
1962EFI_STATUS\r
1963PadFvImage (\r
1964 IN MEMORY_FILE *FvImage,\r
1965 IN EFI_FFS_FILE_HEADER *VtfFileImage\r
1966 )\r
1967/*++\r
1968\r
1969Routine Description:\r
1970\r
1971 This function places a pad file between the last file in the FV and the VTF\r
1972 file if the VTF file exists.\r
1973\r
1974Arguments:\r
1975\r
1976 FvImage Memory file for the FV memory image\r
1977 VtfFileImage The address of the VTF file. If this is the end of the FV\r
1978 image, no VTF exists and no pad file is needed.\r
1979\r
1980Returns:\r
1981\r
1982 EFI_SUCCESS Completed successfully.\r
1983 EFI_INVALID_PARAMETER One of the input parameters was NULL.\r
1984\r
1985--*/\r
1986{\r
1987 EFI_FFS_FILE_HEADER *PadFile;\r
1988 UINTN FileSize;\r
1989\r
1990 //\r
1991 // If there is no VTF or the VTF naturally follows the previous file without a\r
1992 // pad file, then there's nothing to do\r
1993 //\r
1994 if ((UINTN) VtfFileImage == (UINTN) FvImage->Eof || (void *) FvImage->CurrentFilePointer == (void *) VtfFileImage) {\r
1995 return EFI_SUCCESS;\r
1996 }\r
1997 //\r
1998 // Pad file starts at beginning of free space\r
1999 //\r
2000 PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer;\r
2001\r
2002 //\r
2003 // write header\r
2004 //\r
2005 memset (PadFile, 0, sizeof (EFI_FFS_FILE_HEADER));\r
2006 memcpy (&PadFile->Name, &DefaultFvPadFileNameGuid, sizeof (EFI_GUID));\r
2007 PadFile->Type = EFI_FV_FILETYPE_FFS_PAD;\r
2008 PadFile->Attributes = 0;\r
2009\r
2010 //\r
2011 // FileSize includes the EFI_FFS_FILE_HEADER\r
2012 //\r
2013 FileSize = (UINTN) VtfFileImage - (UINTN) FvImage->CurrentFilePointer;\r
2014 PadFile->Size[0] = (UINT8) (FileSize & 0x000000FF);\r
2015 PadFile->Size[1] = (UINT8) ((FileSize & 0x0000FF00) >> 8);\r
2016 PadFile->Size[2] = (UINT8) ((FileSize & 0x00FF0000) >> 16);\r
2017\r
2018 //\r
2019 // Fill in checksums and state, must be zero during checksum calculation.\r
2020 //\r
2021 PadFile->IntegrityCheck.Checksum.Header = 0;\r
2022 PadFile->IntegrityCheck.Checksum.File = 0;\r
2023 PadFile->State = 0;\r
2024 PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, sizeof (EFI_FFS_FILE_HEADER));\r
2025 if (PadFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
2026 PadFile->IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) PadFile, FileSize);\r
2027 } else {\r
2028 PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
2029 }\r
2030\r
2031 PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;\r
2032\r
2033 UpdateFfsFileState (\r
2034 (EFI_FFS_FILE_HEADER *) PadFile,\r
2035 (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage\r
2036 );\r
2037 //\r
2038 // Update the current FV pointer\r
2039 //\r
2040 FvImage->CurrentFilePointer = FvImage->Eof;\r
2041\r
2042 return EFI_SUCCESS;\r
2043}\r
2044\r
2045EFI_STATUS\r
2046UpdateResetVector (\r
2047 IN MEMORY_FILE *FvImage,\r
2048 IN FV_INFO *FvInfo,\r
2049 IN EFI_FFS_FILE_HEADER *VtfFile\r
2050 )\r
2051/*++\r
2052\r
2053Routine Description:\r
2054\r
2055 This parses the FV looking for the PEI core and then plugs the address into\r
2056 the SALE_ENTRY point of the BSF/VTF for IPF and does BUGBUG TBD action to\r
2057 complete an IA32 Bootstrap FV.\r
2058\r
2059Arguments:\r
2060\r
2061 FvImage Memory file for the FV memory image\r
2062 FvInfo Information read from INF file.\r
2063 VtfFile Pointer to the VTF file in the FV image.\r
2064\r
2065Returns:\r
2066\r
2067 EFI_SUCCESS Function Completed successfully.\r
2068 EFI_ABORTED Error encountered.\r
2069 EFI_INVALID_PARAMETER A required parameter was NULL.\r
2070 EFI_NOT_FOUND PEI Core file not found.\r
2071\r
2072--*/\r
2073{\r
2074 EFI_FFS_FILE_HEADER *PeiCoreFile;\r
2075 EFI_FFS_FILE_HEADER *SecCoreFile;\r
2076 EFI_STATUS Status;\r
2077 EFI_FILE_SECTION_POINTER Pe32Section;\r
2078 UINT32 EntryPoint;\r
2079 UINT32 BaseOfCode;\r
2080 UINT16 MachineType;\r
2081 EFI_PHYSICAL_ADDRESS PeiCorePhysicalAddress;\r
2082 EFI_PHYSICAL_ADDRESS SecCorePhysicalAddress;\r
2083 EFI_PHYSICAL_ADDRESS *SecCoreEntryAddressPtr;\r
2084 UINT32 *Ia32ResetAddressPtr;\r
2085 UINT8 *BytePointer;\r
2086 UINT8 *BytePointer2;\r
2087 UINT16 *WordPointer;\r
2088 UINT16 CheckSum;\r
2089 UINTN Index;\r
2090 EFI_FFS_FILE_STATE SavedState;\r
2091 EFI_FFS_FILE_TAIL TailValue;\r
2092 UINT32 TailSize;\r
2093 UINT64 FitAddress;\r
2094 FIT_TABLE *FitTablePtr;\r
2095\r
2096 //\r
2097 // Verify input parameters\r
2098 //\r
2099 if (FvImage == NULL || FvInfo == NULL || VtfFile == NULL) {\r
2100 return EFI_INVALID_PARAMETER;\r
2101 }\r
2102 //\r
2103 // Initialize FV library\r
2104 //\r
2105 InitializeFvLib (FvImage->FileImage, (UINTN) FvImage->Eof - (UINTN) FvImage->FileImage);\r
2106\r
2107 //\r
2108 // Verify VTF file\r
2109 //\r
2110 Status = VerifyFfsFile (VtfFile);\r
2111 if (EFI_ERROR (Status)) {\r
2112 return EFI_INVALID_PARAMETER;\r
2113 }\r
2114 //\r
2115 // Find the PEI Core\r
2116 //\r
2117 Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);\r
2118 if (EFI_ERROR (Status) || PeiCoreFile == NULL) {\r
2119 Error (NULL, 0, 0, "could not find the PEI core in the FV", NULL);\r
2120 return EFI_ABORTED;\r
2121 }\r
a651e231 2122\r
878ddf1f 2123 //\r
a651e231 2124 // PEI Core found, now find PE32 or TE section\r
878ddf1f 2125 //\r
2126 Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
a651e231
LG
2127 if (Status == EFI_NOT_FOUND) {\r
2128 Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);\r
2129 }\r
2130\r
878ddf1f 2131 if (EFI_ERROR (Status)) {\r
a651e231 2132 Error (NULL, 0, 0, "could not find PE32 or TE section in PEI core file", NULL);\r
878ddf1f 2133 return EFI_ABORTED;\r
2134 }\r
2135\r
2136 Status = GetPe32Info (\r
2137 (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
2138 &EntryPoint,\r
2139 &BaseOfCode,\r
2140 &MachineType\r
2141 );\r
a651e231 2142\r
878ddf1f 2143 if (EFI_ERROR (Status)) {\r
2144 Error (NULL, 0, 0, "could not get PE32 entry point for PEI core", NULL);\r
2145 return EFI_ABORTED;\r
2146 }\r
2147 //\r
2148 // Physical address is FV base + offset of PE32 + offset of the entry point\r
2149 //\r
2150 PeiCorePhysicalAddress = FvInfo->BaseAddress;\r
2151 PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
2152 PeiCorePhysicalAddress += EntryPoint;\r
2153\r
2154 if (MachineType == EFI_IMAGE_MACHINE_IA64) {\r
2155 //\r
2156 // Update PEI_CORE address\r
2157 //\r
2158 //\r
2159 // Set the uncached attribute bit in the physical address\r
2160 //\r
2161 PeiCorePhysicalAddress |= 0x8000000000000000ULL;\r
2162\r
2163 //\r
2164 // Check if address is aligned on a 16 byte boundary\r
2165 //\r
2166 if (PeiCorePhysicalAddress & 0xF) {\r
2167 printf (\r
2168 "ERROR: PEI_CORE entry point is not aligned on a 16 byte boundary, address specified is %Xh.\n",\r
2169 PeiCorePhysicalAddress\r
2170 );\r
2171 return EFI_ABORTED;\r
2172 }\r
2173 //\r
2174 // First Get the FIT table address\r
2175 //\r
2176 FitAddress = (*(UINT64 *) (FvImage->Eof - IPF_FIT_ADDRESS_OFFSET)) & 0xFFFFFFFF;\r
2177\r
2178 FitTablePtr = (FIT_TABLE *) (FvImage->FileImage + (FitAddress - FvInfo->BaseAddress));\r
2179\r
2180 Status = UpdatePeiCoreEntryInFit (FitTablePtr, PeiCorePhysicalAddress);\r
2181\r
2182 if (!EFI_ERROR (Status)) {\r
2183 UpdateFitCheckSum (FitTablePtr);\r
2184 }\r
2185 //\r
2186 // Find the Sec Core\r
2187 //\r
2188 Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile);\r
2189 if (EFI_ERROR (Status) || SecCoreFile == NULL) {\r
2190 Error (NULL, 0, 0, "could not find the Sec core in the FV", NULL);\r
2191 return EFI_ABORTED;\r
2192 }\r
2193 //\r
2194 // Sec Core found, now find PE32 section\r
2195 //\r
2196 Status = GetSectionByType (SecCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
2197 if (EFI_ERROR (Status)) {\r
2198 Error (NULL, 0, 0, "could not find PE32 section in SEC core file", NULL);\r
2199 return EFI_ABORTED;\r
2200 }\r
2201\r
2202 Status = GetPe32Info (\r
2203 (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
2204 &EntryPoint,\r
2205 &BaseOfCode,\r
2206 &MachineType\r
2207 );\r
2208 if (EFI_ERROR (Status)) {\r
2209 Error (NULL, 0, 0, "could not get PE32 entry point for SEC core", NULL);\r
2210 return EFI_ABORTED;\r
2211 }\r
2212 //\r
2213 // Physical address is FV base + offset of PE32 + offset of the entry point\r
2214 //\r
2215 SecCorePhysicalAddress = FvInfo->BaseAddress;\r
2216 SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
2217 SecCorePhysicalAddress += EntryPoint;\r
2218\r
2219 //\r
2220 // Update SEC_CORE address\r
2221 //\r
2222 //\r
2223 // Set the uncached attribute bit in the physical address\r
2224 //\r
2225 SecCorePhysicalAddress |= 0x8000000000000000ULL;\r
2226\r
2227 //\r
2228 // Update the address\r
2229 //\r
2230 SecCoreEntryAddressPtr = (EFI_PHYSICAL_ADDRESS *) ((UINTN) FvImage->Eof - IPF_SALE_ENTRY_ADDRESS_OFFSET);\r
2231 *SecCoreEntryAddressPtr = SecCorePhysicalAddress;\r
2232\r
2233 //\r
2234 // Check if address is aligned on a 16 byte boundary\r
2235 //\r
2236 if (SecCorePhysicalAddress & 0xF) {\r
2237 printf (\r
2238 "ERROR: SALE_ENTRY entry point is not aligned on a 16 byte boundary, address specified is %Xh.\n",\r
2239 SecCorePhysicalAddress\r
2240 );\r
2241 return EFI_ABORTED;\r
2242 }\r
2243 } else if (MachineType == EFI_IMAGE_MACHINE_IA32) {\r
2244 //\r
2245 // Get the location to update\r
2246 //\r
2247 Ia32ResetAddressPtr = (UINT32 *) ((UINTN) FvImage->Eof - IA32_PEI_CORE_ENTRY_OFFSET);\r
2248\r
2249 //\r
2250 // Write lower 32 bits of physical address\r
2251 //\r
2252 *Ia32ResetAddressPtr = (UINT32) PeiCorePhysicalAddress;\r
2253\r
2254 //\r
2255 // Update the BFV base address\r
2256 //\r
2257 Ia32ResetAddressPtr = (UINT32 *) ((UINTN) FvImage->Eof - 4);\r
2258 *Ia32ResetAddressPtr = (UINT32) (FvInfo->BaseAddress);\r
2259\r
2260 CheckSum = 0x0000;\r
2261\r
2262 //\r
2263 // Update the Startup AP in the FVH header block ZeroVector region.\r
2264 //\r
2265 BytePointer = (UINT8 *) ((UINTN) FvImage->FileImage);\r
2266 BytePointer2 = (FvInfo->Size == 0x10000) ? m64kRecoveryStartupApDataArray : m128kRecoveryStartupApDataArray;\r
2267 for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY; Index++) {\r
2268 *BytePointer++ = *BytePointer2++;\r
2269 }\r
2270 //\r
2271 // Calculate the checksum\r
2272 //\r
2273 WordPointer = (UINT16 *) ((UINTN) FvImage->FileImage);\r
2274 for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY / 2; Index++) {\r
2275 CheckSum = (UINT16) (CheckSum + ((UINT16) *WordPointer));\r
2276 WordPointer++;\r
2277 }\r
2278 //\r
2279 // Update the checksum field\r
2280 //\r
2281 BytePointer = (UINT8 *) ((UINTN) FvImage->FileImage);\r
2282 BytePointer += (SIZEOF_STARTUP_DATA_ARRAY - 2);\r
2283 WordPointer = (UINT16 *) BytePointer;\r
2284 *WordPointer = (UINT16) (0x10000 - (UINT32) CheckSum);\r
2285 } else {\r
2286 Error (NULL, 0, 0, "invalid machine type in PEI core", "machine type=0x%X", (UINT32) MachineType);\r
2287 return EFI_ABORTED;\r
2288 }\r
2289 //\r
2290 // Determine if it has an FFS file tail.\r
2291 //\r
2292 if (VtfFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
2293 TailSize = sizeof (EFI_FFS_FILE_TAIL);\r
2294 } else {\r
2295 TailSize = 0;\r
2296 }\r
2297 //\r
2298 // Now update file checksum\r
2299 //\r
2300 SavedState = VtfFile->State;\r
2301 VtfFile->IntegrityCheck.Checksum.File = 0;\r
2302 VtfFile->State = 0;\r
2303 if (VtfFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
2304 VtfFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
2305 (UINT8 *) VtfFile,\r
2306 GetLength (VtfFile->Size) - TailSize\r
2307 );\r
2308 } else {\r
2309 VtfFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
2310 }\r
2311\r
2312 VtfFile->State = SavedState;\r
2313\r
2314 //\r
2315 // Update tail if present\r
2316 //\r
2317 if (VtfFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
2318 TailValue = (EFI_FFS_FILE_TAIL) (~(VtfFile->IntegrityCheck.TailReference));\r
2319 *(EFI_FFS_FILE_TAIL *) (((UINTN) (VtfFile) + GetLength (VtfFile->Size) - sizeof (EFI_FFS_FILE_TAIL))) = TailValue;\r
2320 }\r
2321\r
2322 return EFI_SUCCESS;\r
2323}\r
2324\r
2325EFI_STATUS\r
2326GetPe32Info (\r
2327 IN UINT8 *Pe32,\r
2328 OUT UINT32 *EntryPoint,\r
2329 OUT UINT32 *BaseOfCode,\r
2330 OUT UINT16 *MachineType\r
2331 )\r
2332/*++\r
2333\r
2334Routine Description:\r
2335\r
a651e231
LG
2336 Retrieves the PE32 entry point offset and machine type from PE image or TeImage. \r
2337 See EfiImage.h for machine types. The entry point offset is from the beginning \r
2338 of the PE32 buffer passed in.\r
878ddf1f 2339\r
2340Arguments:\r
2341\r
2342 Pe32 Beginning of the PE32.\r
2343 EntryPoint Offset from the beginning of the PE32 to the image entry point.\r
2344 BaseOfCode Base address of code.\r
2345 MachineType Magic number for the machine type.\r
2346\r
2347Returns:\r
2348\r
2349 EFI_SUCCESS Function completed successfully.\r
2350 EFI_ABORTED Error encountered.\r
2351 EFI_INVALID_PARAMETER A required parameter was NULL.\r
2352 EFI_UNSUPPORTED The operation is unsupported.\r
2353\r
2354--*/\r
2355{\r
2356 EFI_IMAGE_DOS_HEADER *DosHeader;\r
2357 EFI_IMAGE_NT_HEADERS *NtHeader;\r
a651e231 2358 EFI_TE_IMAGE_HEADER *TeHeader;\r
878ddf1f 2359\r
2360 //\r
2361 // Verify input parameters\r
2362 //\r
2363 if (Pe32 == NULL) {\r
2364 return EFI_INVALID_PARAMETER;\r
2365 }\r
878ddf1f 2366\r
2367 //\r
a651e231 2368 // First check whether it is one TE Image.\r
878ddf1f 2369 //\r
a651e231
LG
2370 TeHeader = (EFI_TE_IMAGE_HEADER *) Pe32;\r
2371 if (TeHeader->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
2372 //\r
2373 // By TeImage Header to get output\r
2374 //\r
2375 *EntryPoint = TeHeader->AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;\r
2376 *BaseOfCode = TeHeader->BaseOfCode + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;\r
2377 *MachineType = TeHeader->Machine;\r
2378 } else {\r
2379 \r
2380 //\r
2381 // Then check whether \r
2382 // First is the DOS header\r
2383 //\r
2384 DosHeader = (EFI_IMAGE_DOS_HEADER *) Pe32;\r
2385 \r
2386 //\r
2387 // Verify DOS header is expected\r
2388 //\r
2389 if (DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
2390 printf ("ERROR: Unknown magic number in the DOS header, 0x%04X.\n", DosHeader->e_magic);\r
2391 return EFI_UNSUPPORTED;\r
2392 }\r
2393 //\r
2394 // Immediately following is the NT header.\r
2395 //\r
2396 NtHeader = (EFI_IMAGE_NT_HEADERS *) ((UINTN) Pe32 + DosHeader->e_lfanew);\r
2397 \r
2398 //\r
2399 // Verify NT header is expected\r
2400 //\r
2401 if (NtHeader->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
2402 printf ("ERROR: Unrecognized image signature 0x%08X.\n", NtHeader->Signature);\r
2403 return EFI_UNSUPPORTED;\r
2404 }\r
2405 //\r
2406 // Get output\r
2407 //\r
2408 *EntryPoint = NtHeader->OptionalHeader.AddressOfEntryPoint;\r
2409 *BaseOfCode = NtHeader->OptionalHeader.BaseOfCode;\r
2410 *MachineType = NtHeader->FileHeader.Machine;\r
878ddf1f 2411 }\r
878ddf1f 2412\r
2413 //\r
2414 // Verify machine type is supported\r
2415 //\r
2416 if (*MachineType != EFI_IMAGE_MACHINE_IA32 && *MachineType != EFI_IMAGE_MACHINE_IA64 && *MachineType != EFI_IMAGE_MACHINE_X64 && *MachineType != EFI_IMAGE_MACHINE_EBC) {\r
2417 printf ("ERROR: Unrecognized machine type in the PE32 file.\n");\r
2418 return EFI_UNSUPPORTED;\r
2419 }\r
2420\r
2421 return EFI_SUCCESS;\r
2422}\r
2423//\r
2424// Exposed function implementations (prototypes are defined in GenFvImageLib.h)\r
2425//\r
2426EFI_STATUS\r
2427GenerateFvImage (\r
2428 IN CHAR8 *InfFileImage,\r
2429 IN UINTN InfFileSize,\r
2430 OUT UINT8 **FvImage,\r
2431 OUT UINTN *FvImageSize,\r
2432 OUT CHAR8 **FvFileName,\r
2433 OUT UINT8 **SymImage,\r
2434 OUT UINTN *SymImageSize,\r
2435 OUT CHAR8 **SymFileName\r
2436 )\r
2437/*++\r
2438\r
2439Routine Description:\r
2440\r
2441 This is the main function which will be called from application.\r
2442\r
2443Arguments:\r
2444\r
2445 InfFileImage Buffer containing the INF file contents.\r
2446 InfFileSize Size of the contents of the InfFileImage buffer.\r
2447 FvImage Pointer to the FV image created.\r
2448 FvImageSize Size of the FV image created and pointed to by FvImage.\r
2449 FvFileName Requested name for the FV file.\r
2450 SymImage Pointer to the Sym image created.\r
2451 SymImageSize Size of the Sym image created and pointed to by SymImage.\r
2452 SymFileName Requested name for the Sym file.\r
2453\r
2454Returns:\r
2455\r
2456 EFI_SUCCESS Function completed successfully.\r
2457 EFI_OUT_OF_RESOURCES Could not allocate required resources.\r
2458 EFI_ABORTED Error encountered.\r
2459 EFI_INVALID_PARAMETER A required parameter was NULL.\r
2460\r
2461--*/\r
2462{\r
2463 EFI_STATUS Status;\r
2464 MEMORY_FILE InfMemoryFile;\r
2465 MEMORY_FILE FvImageMemoryFile;\r
2466 MEMORY_FILE SymImageMemoryFile;\r
2467 FV_INFO FvInfo;\r
2468 UINTN Index;\r
2469 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
2470 EFI_FFS_FILE_HEADER *VtfFileImage;\r
2471\r
2472 //\r
2473 // Check for invalid parameter\r
2474 //\r
2475 if (InfFileImage == NULL || FvImage == NULL || FvImageSize == NULL || FvFileName == NULL) {\r
2476 return EFI_INVALID_PARAMETER;\r
2477 }\r
2478 //\r
2479 // Initialize file structures\r
2480 //\r
2481 InfMemoryFile.FileImage = InfFileImage;\r
2482 InfMemoryFile.CurrentFilePointer = InfFileImage;\r
2483 InfMemoryFile.Eof = InfFileImage + InfFileSize;\r
2484\r
2485 //\r
2486 // Parse the FV inf file for header information\r
2487 //\r
2488 Status = ParseFvInf (&InfMemoryFile, &FvInfo);\r
2489 if (EFI_ERROR (Status)) {\r
2490 printf ("ERROR: Could not parse the input INF file.\n");\r
2491 return EFI_ABORTED;\r
2492 }\r
2493 //\r
2494 // Update the file name return values\r
2495 //\r
2496 strcpy (*FvFileName, FvInfo.FvName);\r
2497 strcpy (*SymFileName, FvInfo.SymName);\r
2498\r
2499 //\r
2500 // Calculate the FV size\r
2501 //\r
2502 *FvImageSize = FvInfo.Size;\r
2503\r
2504 //\r
2505 // Allocate the FV\r
2506 //\r
2507 *FvImage = malloc (*FvImageSize);\r
2508 if (*FvImage == NULL) {\r
2509 return EFI_OUT_OF_RESOURCES;\r
2510 }\r
2511 //\r
2512 // Allocate space for symbol file storage\r
2513 //\r
2514 *SymImage = malloc (SYMBOL_FILE_SIZE);\r
2515 if (*SymImage == NULL) {\r
2516 return EFI_OUT_OF_RESOURCES;\r
2517 }\r
2518 //\r
2519 // Initialize the FV to the erase polarity\r
2520 //\r
2521 if (FvInfo.FvAttributes & EFI_FVB_ERASE_POLARITY) {\r
2522 memset (*FvImage, -1, *FvImageSize);\r
2523 } else {\r
2524 memset (*FvImage, 0, *FvImageSize);\r
2525 }\r
2526 //\r
2527 // Initialize FV header\r
2528 //\r
2529 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) *FvImage;\r
2530\r
2531 //\r
2532 // Initialize the zero vector to all zeros.\r
2533 //\r
2534 memset (FvHeader->ZeroVector, 0, 16);\r
2535\r
2536 //\r
2537 // Copy the FFS GUID\r
2538 //\r
2539 memcpy (&FvHeader->FileSystemGuid, &FvInfo.FvGuid, sizeof (EFI_GUID));\r
2540\r
2541 FvHeader->FvLength = *FvImageSize;\r
2542 FvHeader->Signature = EFI_FVH_SIGNATURE;\r
2543 FvHeader->Attributes = FvInfo.FvAttributes;\r
2544 FvHeader->Revision = EFI_FVH_REVISION;\r
2545 FvHeader->Reserved[0] = 0;\r
2546 FvHeader->Reserved[1] = 0;\r
2547 FvHeader->Reserved[2] = 0;\r
2548\r
2549 //\r
2550 // Copy firmware block map\r
2551 //\r
2552 for (Index = 0; FvInfo.FvBlocks[Index].NumBlocks != 0; Index++) {\r
2553 FvHeader->FvBlockMap[Index].NumBlocks = FvInfo.FvBlocks[Index].NumBlocks;\r
2554 FvHeader->FvBlockMap[Index].BlockLength = FvInfo.FvBlocks[Index].BlockLength;\r
2555 }\r
2556 //\r
2557 // Add block map terminator\r
2558 //\r
2559 FvHeader->FvBlockMap[Index].NumBlocks = 0;\r
2560 FvHeader->FvBlockMap[Index].BlockLength = 0;\r
2561\r
2562 //\r
2563 // Complete the header\r
2564 //\r
2565 FvHeader->HeaderLength = (UINT16) (((UINTN) &(FvHeader->FvBlockMap[Index + 1])) - (UINTN) *FvImage);\r
2566 FvHeader->Checksum = 0;\r
2567 FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
2568\r
2569 //\r
2570 // If there is no FFS file, find and generate each components of the FV\r
2571 //\r
2572 if (FvInfo.FvFiles[0][0] == 0) {\r
2573 Status = GenNonFFSFv (*FvImage, &FvInfo);\r
2574 if (EFI_ERROR (Status)) {\r
2575 printf ("ERROR: Could not generate NonFFS FV.\n");\r
2576 free (*FvImage);\r
2577 return EFI_ABORTED;\r
2578 }\r
2579\r
2580 return EFI_SUCCESS;\r
2581 }\r
2582 //\r
2583 // Initialize our "file" view of the buffer\r
2584 //\r
2585 FvImageMemoryFile.FileImage = *FvImage;\r
2586 FvImageMemoryFile.CurrentFilePointer = *FvImage + FvHeader->HeaderLength;\r
2587 FvImageMemoryFile.Eof = *FvImage +*FvImageSize;\r
2588\r
2589 //\r
2590 // Initialize our "file" view of the symbol file.\r
2591 //\r
2592 SymImageMemoryFile.FileImage = *SymImage;\r
2593 SymImageMemoryFile.CurrentFilePointer = *SymImage;\r
2594 SymImageMemoryFile.Eof = *FvImage + SYMBOL_FILE_SIZE;\r
2595\r
2596 //\r
2597 // Initialize the FV library.\r
2598 //\r
2599 InitializeFvLib (FvImageMemoryFile.FileImage, FvInfo.Size);\r
2600\r
2601 //\r
2602 // Files start on 8 byte alignments, so move to the next 8 byte aligned\r
2603 // address. For now, just assert if it isn't. Currently FV header is\r
2604 // always a multiple of 8 bytes.\r
2605 // BUGBUG: Handle this better\r
2606 //\r
2607 assert ((((UINTN) FvImageMemoryFile.CurrentFilePointer) % 8) == 0);\r
2608\r
2609 //\r
2610 // Initialize the VTF file address.\r
2611 //\r
2612 VtfFileImage = (EFI_FFS_FILE_HEADER *) FvImageMemoryFile.Eof;\r
2613\r
2614 //\r
2615 // Add files to FV\r
2616 //\r
2617 for (Index = 0; FvInfo.FvFiles[Index][0] != 0; Index++) {\r
2618 //\r
2619 // Add the file\r
2620 //\r
2621 Status = AddFile (&FvImageMemoryFile, &FvInfo, Index, &VtfFileImage, &SymImageMemoryFile);\r
2622\r
2623 //\r
2624 // Exit if error detected while adding the file\r
2625 //\r
2626 if (EFI_ERROR (Status)) {\r
2627 printf ("ERROR: Could not add file %s.\n", FvInfo.FvFiles[Index]);\r
2628 free (*FvImage);\r
2629 return EFI_ABORTED;\r
2630 }\r
2631 }\r
2632 //\r
2633 // If there is a VTF file, some special actions need to occur.\r
2634 //\r
2635 if ((UINTN) VtfFileImage != (UINTN) FvImageMemoryFile.Eof) {\r
2636 //\r
2637 // Pad from the end of the last file to the beginning of the VTF file.\r
2638 //\r
2639 Status = PadFvImage (&FvImageMemoryFile, VtfFileImage);\r
2640 if (EFI_ERROR (Status)) {\r
2641 printf ("ERROR: Could not create the pad file between the last file and the VTF file.\n");\r
2642 free (*FvImage);\r
2643 return EFI_ABORTED;\r
2644 }\r
2645 //\r
2646 // Update reset vector (SALE_ENTRY for IPF)\r
2647 // Now for IA32 and IA64 platform, the fv which has bsf file must have the \r
2648 // EndAddress of 0xFFFFFFFF. Thus, only this type fv needs to update the \r
2649 // reset vector. If the PEI Core is found, the VTF file will probably get \r
2650 // corrupted by updating the entry point. \r
2651 //\r
2652 if ((FvInfo.BaseAddress + FvInfo.Size) == FV_IMAGES_TOP_ADDRESS) { \r
2653 Status = UpdateResetVector (&FvImageMemoryFile, &FvInfo, VtfFileImage);\r
2654 if (EFI_ERROR(Status)) { \r
2655 printf ("ERROR: Could not update the reset vector.\n"); \r
2656 free (*FvImage); \r
2657 return EFI_ABORTED; \r
2658 } \r
2659 }\r
2660 } \r
2661 //\r
2662 // Determine final Sym file size\r
2663 //\r
2664 *SymImageSize = SymImageMemoryFile.CurrentFilePointer - SymImageMemoryFile.FileImage;\r
d3f75347
LG
2665 \r
2666 //\r
2667 // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV\r
2668 //\r
2669 if (FvHeader->Attributes | EFI_FVB_ALIGNMENT_CAP) {\r
2670 for (Index = 1; Index <= 16; Index ++) {\r
2671 if ((1 << Index) < MaxFfsAlignment) {\r
2672 //\r
2673 // Unset the unsupported alignment attribute.\r
2674 //\r
2675 FvHeader->Attributes = FvHeader->Attributes & ~((1 << Index) * EFI_FVB_ALIGNMENT_CAP);\r
2676 } else {\r
2677 //\r
2678 // Set the supported alignment attribute.\r
2679 //\r
2680 FvHeader->Attributes = FvHeader->Attributes | ((1 << Index) * EFI_FVB_ALIGNMENT_CAP);\r
2681 }\r
2682 }\r
2683 \r
2684 //\r
2685 // Update Checksum for FvHeader\r
2686 //\r
2687 FvHeader->Checksum = 0;\r
2688 FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
2689 }\r
878ddf1f 2690\r
2691 return EFI_SUCCESS;\r
2692}\r
2693\r
2694EFI_STATUS\r
2695UpdatePeiCoreEntryInFit (\r
2696 IN FIT_TABLE *FitTablePtr,\r
2697 IN UINT64 PeiCorePhysicalAddress\r
2698 )\r
2699/*++\r
2700\r
2701Routine Description:\r
2702\r
2703 This function is used to update the Pei Core address in FIT, this can be used by Sec core to pass control from\r
2704 Sec to Pei Core\r
2705\r
2706Arguments:\r
2707\r
2708 FitTablePtr - The pointer of FIT_TABLE.\r
2709 PeiCorePhysicalAddress - The address of Pei Core entry.\r
2710\r
2711Returns:\r
2712\r
2713 EFI_SUCCESS - The PEI_CORE FIT entry was updated successfully.\r
2714 EFI_NOT_FOUND - Not found the PEI_CORE FIT entry.\r
2715\r
2716--*/\r
2717{\r
2718 FIT_TABLE *TmpFitPtr;\r
2719 UINTN Index;\r
2720 UINTN NumFitComponents;\r
2721\r
2722 TmpFitPtr = FitTablePtr;\r
2723 NumFitComponents = TmpFitPtr->CompSize;\r
2724\r
2725 for (Index = 0; Index < NumFitComponents; Index++) {\r
2726 if ((TmpFitPtr->CvAndType & FIT_TYPE_MASK) == COMP_TYPE_FIT_PEICORE) {\r
2727 TmpFitPtr->CompAddress = PeiCorePhysicalAddress;\r
2728 return EFI_SUCCESS;\r
2729 }\r
2730\r
2731 TmpFitPtr++;\r
2732 }\r
2733\r
2734 return EFI_NOT_FOUND;\r
2735}\r
2736\r
2737VOID\r
2738UpdateFitCheckSum (\r
2739 IN FIT_TABLE *FitTablePtr\r
2740 )\r
2741/*++\r
2742\r
2743Routine Description:\r
2744\r
2745 This function is used to update the checksum for FIT.\r
2746\r
2747\r
2748Arguments:\r
2749\r
2750 FitTablePtr - The pointer of FIT_TABLE.\r
2751\r
2752Returns:\r
2753\r
2754 None.\r
2755\r
2756--*/\r
2757{\r
2758 if ((FitTablePtr->CvAndType & CHECKSUM_BIT_MASK) >> 7) {\r
2759 FitTablePtr->CheckSum = 0;\r
2760 FitTablePtr->CheckSum = CalculateChecksum8 ((UINT8 *) FitTablePtr, FitTablePtr->CompSize * 16);\r
2761 }\r
2762}\r