Commit | Line | Data |
---|---|---|
3eb9473e | 1 | /*++\r |
2 | \r | |
3e99020d | 3 | Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>\r |
4b1e1121 | 4 | This program and the accompanying materials \r |
3eb9473e | 5 | are licensed and made available under the terms and conditions of the BSD License \r |
6 | which accompanies this distribution. The full text of the license may be found at \r | |
7 | http://opensource.org/licenses/bsd-license.php \r | |
8 | \r | |
9 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r | |
10 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r | |
11 | \r | |
12 | Module Name:\r | |
13 | \r | |
14 | FWVolume.c\r | |
15 | \r | |
16 | Abstract:\r | |
17 | \r | |
18 | This module contains functionality to keep track of files destined for\r | |
19 | multiple firmware volues. It saves them up, and when told to, dumps the\r | |
20 | file names out to some files used as input to other utilities that\r | |
21 | actually generate the FVs.\r | |
22 | \r | |
23 | --*/\r | |
24 | \r | |
25 | #include <windows.h> // for max_path definition\r | |
26 | #include <stdio.h>\r | |
27 | #include <string.h>\r | |
28 | #include <stdlib.h> // for malloc()\r | |
29 | #include "Common.h"\r | |
30 | #include "DSCFile.h"\r | |
31 | #include "FWVolume.h"\r | |
32 | \r | |
33 | #define FV_INF_DIR "FV_INF_DIR" // symbol for where we create the FV INF file\r | |
34 | #define FV_FILENAME "FV_FILENAME" // symbol for the current FV.INF filename\r | |
35 | #define EFI_BASE_ADDRESS "EFI_BASE_ADDRESS"\r | |
36 | #define DEFAULT_FV_INF_DIR "FV" // default dir for where we create the FV INF file\r | |
37 | #define DEFAULT_FV_DIR "$(BUILD_DIR)" // where the FV file comes from\r | |
3eb9473e | 38 | \r |
3eb9473e | 39 | typedef struct {\r |
40 | char *ComponentType;\r | |
41 | char *Extension;\r | |
42 | } COMP_TYPE_EXTENSION;\r | |
43 | \r | |
44 | //\r | |
45 | // Use a linked list of these to keep track of all the FV names used\r | |
46 | //\r | |
47 | typedef struct _FV_LIST {\r | |
48 | struct _FV_LIST *Next;\r | |
49 | char FVFileName[MAX_PATH];\r | |
50 | char BaseAddress[MAX_LINE_LEN];\r | |
51 | SMART_FILE *FVFilePtr;\r | |
52 | SMART_FILE *AprioriFilePtr;\r | |
53 | char *Processor;\r | |
54 | int ComponentsInstance; // highest [components.n] section with a file for this FV\r | |
55 | } FV_LIST;\r | |
56 | \r | |
57 | //\r | |
58 | // Use a linked list of these to keep track of all FFS files built. When\r | |
59 | // we're done, we turn the info into the FV INF files used to build the\r | |
60 | // firmware volumes.\r | |
61 | //\r | |
62 | typedef struct _FILE_LIST {\r | |
63 | struct _FILE_LIST *Next;\r | |
64 | char *FileName;\r | |
65 | char *BaseFileName;\r | |
66 | char *FVs; // from FV=x,y,z\r | |
67 | char *BaseName; // only needed for duplicate basename check\r | |
68 | char *Processor; // only needed for duplicate basename check\r | |
69 | char Apriori[100]; // of format "FVRecovery:1,FVMain:2" from APRIORI define\r | |
70 | char *Guid; // guid string\r | |
71 | int ComponentsInstance; // which [components.n] section it's in\r | |
72 | } FILE_LIST;\r | |
73 | \r | |
74 | typedef struct _LINKED_LIST {\r | |
75 | struct _LINKED_LIST *Next;\r | |
76 | void *Data;\r | |
77 | } LINKED_LIST;\r | |
78 | \r | |
79 | static FILE_LIST *mFileList;\r | |
80 | static FILE_LIST *mLastFile;\r | |
81 | static char *mXRefFileName = NULL;\r | |
82 | static FV_LIST *mNonFfsFVList = NULL;\r | |
83 | \r | |
84 | //\r | |
85 | // Whenever an FV name is referenced, then add it to our list of known\r | |
86 | // FV's using these.\r | |
87 | //\r | |
88 | static FV_LIST *mFVList = NULL;\r | |
89 | static FV_LIST *mFVListLast = NULL;\r | |
90 | \r | |
91 | //\r | |
92 | // We use this list so that from a given component type, we can determine\r | |
93 | // the name of the file on disk. For example, if we're given a file's\r | |
94 | // guid and base name, and we know it's a "bs_driver", then we can look\r | |
95 | // up "bs_driver" in this array and know that the file (after it's built)\r | |
96 | // name is GUID-BASENAME.DXE\r | |
97 | //\r | |
98 | static const COMP_TYPE_EXTENSION mCompTypeExtension[] = {\r | |
99 | {\r | |
100 | "bs_driver",\r | |
101 | ".dxe"\r | |
102 | },\r | |
103 | {\r | |
104 | "rt_driver",\r | |
105 | ".dxe"\r | |
106 | },\r | |
107 | {\r | |
108 | "sal_rt_driver",\r | |
109 | ".dxe"\r | |
110 | },\r | |
111 | {\r | |
112 | "security_core",\r | |
113 | ".sec"\r | |
114 | },\r | |
115 | {\r | |
116 | "pei_core",\r | |
117 | ".pei"\r | |
118 | },\r | |
119 | {\r | |
120 | "pic_peim",\r | |
121 | ".pei"\r | |
122 | },\r | |
123 | {\r | |
124 | "pe32_peim",\r | |
125 | ".pei"\r | |
126 | },\r | |
127 | {\r | |
128 | "relocatable_peim",\r | |
129 | ".pei"\r | |
130 | },\r | |
131 | {\r | |
132 | "binary",\r | |
133 | ".ffs"\r | |
134 | },\r | |
135 | {\r | |
136 | "application",\r | |
137 | ".app"\r | |
138 | },\r | |
139 | {\r | |
140 | "file",\r | |
141 | ".ffs"\r | |
142 | },\r | |
143 | {\r | |
144 | "fvimagefile",\r | |
145 | ".fvi"\r | |
146 | },\r | |
147 | {\r | |
148 | "rawfile",\r | |
149 | ".raw"\r | |
150 | },\r | |
151 | {\r | |
152 | "apriori",\r | |
153 | ".ffs"\r | |
154 | },\r | |
155 | {\r | |
156 | "combined_peim_driver",\r | |
157 | ".pei"\r | |
158 | },\r | |
159 | {\r | |
160 | NULL,\r | |
161 | NULL\r | |
162 | }\r | |
163 | };\r | |
164 | \r | |
165 | static\r | |
166 | void\r | |
167 | CFVFreeFileList (\r | |
168 | VOID\r | |
169 | );\r | |
170 | \r | |
171 | static\r | |
172 | char *\r | |
173 | UpperCaseString (\r | |
174 | char *Str\r | |
175 | );\r | |
176 | \r | |
177 | static\r | |
178 | BOOLEAN\r | |
179 | InSameFv (\r | |
180 | char *FVs1,\r | |
181 | char *FVs2\r | |
182 | );\r | |
183 | \r | |
184 | static\r | |
185 | void\r | |
186 | AddFirmwareVolumes (\r | |
187 | char *FVs,\r | |
3e99020d | 188 | int ComponentsInstance\r |
3eb9473e | 189 | );\r |
190 | \r | |
191 | static\r | |
192 | BOOLEAN\r | |
193 | OrderInFvList (\r | |
194 | char *FvList,\r | |
195 | char *FvName,\r | |
196 | int *Order\r | |
197 | );\r | |
198 | \r | |
199 | int\r | |
200 | GetBaseAddress (\r | |
201 | char *Name,\r | |
202 | char *BaseAddress\r | |
203 | )\r | |
204 | {\r | |
205 | char *Start;\r | |
206 | char *Cptr;\r | |
207 | char CSave;\r | |
208 | char *Value;\r | |
209 | \r | |
210 | Start = Name;\r | |
211 | while (*Name && isspace (*Name)) {\r | |
212 | Name++;\r | |
213 | }\r | |
214 | \r | |
215 | if (!*Name) {\r | |
216 | return STATUS_ERROR;\r | |
217 | }\r | |
218 | //\r | |
219 | // Find the end of the name. Either space or a '='.\r | |
220 | //\r | |
221 | for (Value = Name; *Value && !isspace (*Value) && (*Value != '='); Value++)\r | |
222 | ;\r | |
223 | if (!*Value) {\r | |
224 | return STATUS_ERROR;\r | |
225 | }\r | |
226 | //\r | |
227 | // Look for the '='\r | |
228 | //\r | |
229 | Cptr = Value;\r | |
230 | while (*Value && (*Value != '=')) {\r | |
231 | Value++;\r | |
232 | }\r | |
233 | \r | |
234 | if (!*Value) {\r | |
235 | return STATUS_ERROR;\r | |
236 | }\r | |
237 | //\r | |
238 | // Now truncate the name\r | |
239 | //\r | |
240 | CSave = *Cptr;\r | |
241 | *Cptr = 0;\r | |
242 | if (_stricmp (Name, EFI_BASE_ADDRESS) != 0) {\r | |
243 | return STATUS_ERROR;\r | |
244 | }\r | |
245 | \r | |
246 | *Cptr = CSave;\r | |
247 | //\r | |
248 | // Skip over the = and then any spaces\r | |
249 | //\r | |
250 | Value++;\r | |
251 | while (*Value && isspace (*Value)) {\r | |
252 | Value++;\r | |
253 | }\r | |
254 | //\r | |
255 | // Find end of string, checking for quoted string\r | |
256 | //\r | |
257 | if (*Value == '\"') {\r | |
258 | Value++;\r | |
259 | for (Cptr = Value; *Cptr && *Cptr != '\"'; Cptr++)\r | |
260 | ;\r | |
261 | } else {\r | |
262 | for (Cptr = Value; *Cptr && !isspace (*Cptr); Cptr++)\r | |
263 | ;\r | |
264 | }\r | |
265 | //\r | |
266 | // Null terminate the value string\r | |
267 | //\r | |
268 | CSave = *Cptr;\r | |
269 | *Cptr = 0;\r | |
270 | strcpy (BaseAddress, Value);\r | |
271 | *Cptr = CSave;\r | |
272 | \r | |
273 | return STATUS_SUCCESS;\r | |
274 | }\r | |
275 | \r | |
276 | int\r | |
277 | CFVAddFVFile (\r | |
278 | char *Name,\r | |
279 | char *ComponentType,\r | |
280 | char *FVs,\r | |
281 | int ComponentsInstance,\r | |
282 | char *FFSExt,\r | |
283 | char *Processor,\r | |
284 | char *Apriori,\r | |
285 | char *BaseName,\r | |
286 | char *Guid\r | |
287 | )\r | |
288 | /*++\r | |
289 | \r | |
290 | Routine Description:\r | |
291 | \r | |
292 | Add a file to the list of files in one or more firmware volumes.\r | |
293 | \r | |
294 | Arguments:\r | |
295 | \r | |
296 | Name - $(FILE_GUID)-$(BASE_NAME), or filename\r | |
297 | ComponentType - type of component being added. Required so we know the\r | |
298 | resultant file name after it has been built\r | |
299 | FVs - string of commma-separated FVs that the given file is\r | |
300 | to be added to. For example, FVs="FV0001,FV0002"\r | |
301 | FFSExt - FFS filename extension of the file after it has been built.\r | |
302 | This is passed in to us in case we don't know the default\r | |
303 | filename extension based on the component type.\r | |
304 | Processor - the target processor which the FV is being built for\r | |
305 | Apriori - pointer to the definition of APRIORI. For example APRIORI="FvRecovery:1,FvMain:4"\r | |
306 | \r | |
307 | Returns:\r | |
308 | \r | |
309 | STATUS_SUCCESS if successful\r | |
310 | \r | |
311 | --*/\r | |
312 | {\r | |
313 | FILE_LIST *Ptr;\r | |
314 | char FileName[MAX_PATH];\r | |
315 | char Str[MAX_PATH];\r | |
316 | int i;\r | |
317 | char *Sym;\r | |
318 | \r | |
319 | // If they provided a filename extension for this type of file, then use it.\r | |
320 | // If they did not provide a filename extension, search our list for a\r | |
321 | // matching component type and use the extension appropriate for this\r | |
322 | // component type.\r | |
323 | //\r | |
324 | if (FFSExt == NULL) {\r | |
325 | //\r | |
326 | // They didn't give us a filename extension. Figure it out from the\r | |
327 | // component type.\r | |
328 | //\r | |
329 | for (i = 0; mCompTypeExtension[i].ComponentType != NULL; i++) {\r | |
330 | if (_stricmp (ComponentType, mCompTypeExtension[i].ComponentType) == 0) {\r | |
331 | FFSExt = mCompTypeExtension[i].Extension;\r | |
332 | break;\r | |
333 | }\r | |
334 | }\r | |
335 | //\r | |
336 | // If we don't know the file extension, then error out. Just means\r | |
337 | // the need to define "FFS_EXT = raw" in the component INF file.\r | |
338 | //\r | |
339 | if (mCompTypeExtension[i].ComponentType == NULL) {\r | |
340 | Error (\r | |
341 | NULL,\r | |
342 | 0,\r | |
343 | 0,\r | |
344 | ComponentType,\r | |
345 | "unknown component type - must define FFS_EXT for built filename extension in component INF file"\r | |
346 | );\r | |
347 | return STATUS_ERROR;\r | |
348 | }\r | |
349 | }\r | |
350 | //\r | |
351 | // We now have all the parts to the FFS filename. Prepend the path to it if\r | |
352 | // it's not a full pathname.\r | |
353 | // See if they overrode the default base directory for the FV files.\r | |
354 | //\r | |
355 | if (!IsAbsolutePath (Name)) {\r | |
356 | Sym = GetSymbolValue (FV_DIR);\r | |
357 | if (Sym == NULL) {\r | |
358 | Sym = DEFAULT_FV_DIR;\r | |
359 | }\r | |
360 | //\r | |
361 | // Create the file path. Something like $(BUILD_DIR)\$(PROCESSOR)\$(GUID)-$(BASE_NAME).ext\r | |
362 | // If the extension is non-zero length, then make sure there's a dot in it.\r | |
363 | //\r | |
364 | if ((strlen (FFSExt) > 0) && (FFSExt[0] != '.')) {\r | |
365 | sprintf (Str, "%s\\%s\\%s.%s", Sym, Processor, Name, FFSExt);\r | |
366 | } else {\r | |
367 | sprintf (Str, "%s\\%s\\%s%s", Sym, Processor, Name, FFSExt);\r | |
368 | }\r | |
369 | \r | |
370 | ExpandSymbols (Str, FileName, sizeof (FileName), EXPANDMODE_NO_UNDEFS);\r | |
371 | } else {\r | |
372 | strcpy (FileName, Name);\r | |
373 | }\r | |
374 | //\r | |
375 | // Traverse the list of files we have so far and make sure we don't have\r | |
376 | // any duplicate basenames. If the base name and processor match, then we'll\r | |
377 | // have build issues, so don't allow it. We also don't allow the same file GUID\r | |
378 | // in the same FV which will cause boot time error if we allow this.\r | |
379 | //\r | |
380 | Ptr = mFileList;\r | |
381 | while (Ptr != NULL) {\r | |
382 | if ((Ptr->BaseName != NULL) && (BaseName != NULL) && (_stricmp (BaseName, Ptr->BaseName) == 0)) {\r | |
383 | if ((Ptr->Processor != NULL) && (Processor != NULL) && (_stricmp (Processor, Ptr->Processor) == 0)) {\r | |
384 | Error (NULL, 0, 0, BaseName, "duplicate base name specified");\r | |
385 | return STATUS_ERROR;\r | |
386 | }\r | |
387 | }\r | |
388 | \r | |
389 | if ((Ptr->Guid != NULL) && (Guid != NULL) && (_stricmp (Guid, Ptr->Guid) == 0)) {\r | |
390 | if ((Ptr->FVs != NULL) && (FVs != NULL) && (InSameFv (FVs, Ptr->FVs))) {\r | |
391 | Error (NULL, 0, 0, Guid, "duplicate Guid specified in the same FV for %s and %s", \r | |
392 | (Ptr->BaseName==NULL)?"Unknown":Ptr->BaseName, \r | |
393 | (BaseName==NULL)?"Unknown":BaseName);\r | |
394 | return STATUS_ERROR;\r | |
395 | }\r | |
396 | }\r | |
397 | \r | |
398 | Ptr = Ptr->Next;\r | |
399 | }\r | |
400 | //\r | |
401 | // Allocate a new structure so we can add this file to the list of\r | |
402 | // files.\r | |
403 | //\r | |
404 | Ptr = (FILE_LIST *) malloc (sizeof (FILE_LIST));\r | |
405 | if (Ptr == NULL) {\r | |
406 | Error (NULL, 0, 0, NULL, "failed to allocate memory");\r | |
407 | return STATUS_ERROR;\r | |
408 | }\r | |
409 | \r | |
410 | memset ((char *) Ptr, 0, sizeof (FILE_LIST));\r | |
411 | Ptr->FileName = (char *) malloc (strlen (FileName) + 1);\r | |
412 | if (Ptr->FileName == NULL) {\r | |
413 | Error (NULL, 0, 0, NULL, "failed to allocate memory");\r | |
414 | return STATUS_ERROR;\r | |
415 | }\r | |
416 | \r | |
417 | strcpy (Ptr->FileName, FileName);\r | |
418 | Ptr->ComponentsInstance = ComponentsInstance;\r | |
419 | //\r | |
420 | // Allocate memory to save the FV list if it's going into an FV.\r | |
421 | //\r | |
422 | if ((FVs != NULL) && (FVs[0] != 0)) {\r | |
423 | Ptr->FVs = (char *) malloc (strlen (FVs) + 1);\r | |
424 | if (Ptr->FVs == NULL) {\r | |
425 | Error (NULL, 0, 0, NULL, "failed to allocate memory");\r | |
426 | return STATUS_ERROR;\r | |
427 | }\r | |
428 | \r | |
429 | strcpy (Ptr->FVs, FVs);\r | |
430 | }\r | |
431 | \r | |
432 | Ptr->BaseFileName = (char *) malloc (strlen (Name) + 1);\r | |
433 | if (Ptr->BaseFileName == NULL) {\r | |
434 | Error (NULL, 0, 0, NULL, "failed to allocate memory");\r | |
435 | return STATUS_ERROR;\r | |
436 | }\r | |
437 | \r | |
438 | strcpy (Ptr->BaseFileName, Name);\r | |
439 | //\r | |
440 | // Allocate memory for the basename if they gave us one. May not have one\r | |
441 | // if the user is simply adding pre-existing binary files to the image.\r | |
442 | //\r | |
443 | if (BaseName != NULL) {\r | |
444 | Ptr->BaseName = (char *) malloc (strlen (BaseName) + 1);\r | |
445 | if (Ptr->BaseName == NULL) {\r | |
446 | Error (NULL, 0, 0, NULL, "failed to allocate memory");\r | |
447 | return STATUS_ERROR;\r | |
448 | }\r | |
449 | \r | |
450 | strcpy (Ptr->BaseName, BaseName);\r | |
451 | }\r | |
452 | //\r | |
453 | // Allocate memory for the processor name\r | |
454 | //\r | |
455 | if (Processor != NULL) {\r | |
456 | Ptr->Processor = (char *) malloc (strlen (Processor) + 1);\r | |
457 | if (Ptr->Processor == NULL) {\r | |
458 | Error (NULL, 0, 0, NULL, "failed to allocate memory");\r | |
459 | return STATUS_ERROR;\r | |
460 | }\r | |
461 | \r | |
462 | strcpy (Ptr->Processor, Processor);\r | |
463 | }\r | |
464 | //\r | |
465 | // Allocate memory for the guid name\r | |
466 | //\r | |
467 | if (Guid != NULL) {\r | |
468 | Ptr->Guid = (char *) malloc (strlen (Guid) + 1);\r | |
469 | if (Ptr->Guid == NULL) {\r | |
470 | Error (NULL, 0, 0, NULL, "failed to allocate memory");\r | |
471 | return STATUS_ERROR;\r | |
472 | }\r | |
473 | \r | |
474 | strcpy (Ptr->Guid, Guid);\r | |
475 | }\r | |
476 | //\r | |
477 | // If non-null apriori symbol, then save the apriori list for this file\r | |
478 | //\r | |
479 | if (Apriori != NULL) {\r | |
480 | strcpy (Ptr->Apriori, Apriori);\r | |
481 | }\r | |
482 | \r | |
483 | if (mFileList == NULL) {\r | |
484 | mFileList = Ptr;\r | |
485 | } else {\r | |
486 | mLastFile->Next = Ptr;\r | |
487 | }\r | |
488 | \r | |
489 | mLastFile = Ptr;\r | |
490 | //\r | |
491 | // Add these firmware volumes to the list of known firmware\r | |
492 | // volume names.\r | |
493 | //\r | |
3e99020d | 494 | AddFirmwareVolumes (FVs, ComponentsInstance);\r |
3eb9473e | 495 | \r |
496 | return STATUS_SUCCESS;\r | |
497 | }\r | |
498 | \r | |
499 | void\r | |
500 | CFVConstructor (\r | |
501 | VOID\r | |
502 | )\r | |
503 | {\r | |
504 | mFileList = NULL;\r | |
505 | mLastFile = NULL;\r | |
506 | }\r | |
507 | \r | |
508 | void\r | |
509 | CFVDestructor (\r | |
510 | VOID\r | |
511 | )\r | |
512 | {\r | |
513 | CFVFreeFileList ();\r | |
514 | //\r | |
515 | // Free up our firmware volume list\r | |
516 | //\r | |
517 | while (mFVList != NULL) {\r | |
518 | mFVListLast = mFVList->Next;\r | |
3e99020d | 519 | free (mFVList);\r |
3eb9473e | 520 | mFVList = mFVListLast;\r |
521 | }\r | |
522 | }\r | |
523 | \r | |
524 | static\r | |
525 | void\r | |
526 | CFVFreeFileList (\r | |
527 | VOID\r | |
528 | )\r | |
529 | {\r | |
530 | FILE_LIST *Next;\r | |
531 | while (mFileList != NULL) {\r | |
532 | if (mFileList->FileName != NULL) {\r | |
533 | free (mFileList->FileName);\r | |
534 | }\r | |
535 | \r | |
536 | if (mFileList->FVs != NULL) {\r | |
537 | free (mFileList->FVs);\r | |
538 | }\r | |
539 | \r | |
540 | free (mFileList->BaseFileName);\r | |
541 | if (mFileList->BaseName != NULL) {\r | |
542 | free (mFileList->BaseName);\r | |
543 | }\r | |
544 | \r | |
545 | if (mFileList->Processor != NULL) {\r | |
546 | free (mFileList->Processor);\r | |
547 | }\r | |
548 | \r | |
549 | if (mFileList->Guid != NULL) {\r | |
550 | free (mFileList->Guid);\r | |
551 | }\r | |
552 | \r | |
553 | Next = mFileList->Next;\r | |
554 | free (mFileList);\r | |
555 | mFileList = Next;\r | |
556 | }\r | |
557 | \r | |
558 | mFileList = NULL;\r | |
559 | }\r | |
560 | \r | |
561 | int\r | |
562 | CFVWriteInfFiles (\r | |
563 | DSC_FILE *DSC,\r | |
564 | FILE *MakeFptr\r | |
565 | )\r | |
566 | /*++\r | |
567 | \r | |
568 | Routine Description:\r | |
569 | \r | |
570 | After processing all components in a DSC file, create the firmware\r | |
571 | volume INF files. We actually do a lot more here.\r | |
572 | \r | |
573 | * Create the FVxxx.inf file that is used by GenFvImage\r | |
574 | * Create the Apriori files for each firmware volume that requires one\r | |
575 | * Create makefile.out macros for FVxxx_FILES = FVxxx_FILES AnotherFile\r | |
576 | so you can do incremental builds of firmware volumes.\r | |
577 | * For each FV, emit its build commands to makefile.out\r | |
578 | \r | |
579 | Arguments:\r | |
580 | \r | |
581 | DSC - pointer to a DSC_FILE object to extract info from\r | |
582 | MakeFptr - pointer to the output makefile\r | |
583 | \r | |
584 | Returns:\r | |
585 | \r | |
586 | 0 if successful\r | |
587 | non-zero otherwise\r | |
588 | \r | |
589 | --*/\r | |
590 | {\r | |
591 | FILE_LIST *FileListPtr;\r | |
592 | FV_LIST *FVList;\r | |
593 | FV_LIST *LastFVList;\r | |
594 | FV_LIST *FVPtr;\r | |
595 | SECTION *Section;\r | |
596 | char *StartCptr;\r | |
597 | char *EndCptr;\r | |
598 | char CSave;\r | |
599 | char Str[MAX_PATH];\r | |
600 | char Line[MAX_LINE_LEN];\r | |
601 | char ExpandedLine[MAX_LINE_LEN];\r | |
602 | char FVDir[MAX_PATH];\r | |
603 | FILE *XRefFptr;\r | |
604 | int AprioriCounter;\r | |
605 | int AprioriCount;\r | |
606 | int AprioriPosition;\r | |
607 | BOOLEAN AprioriFound;\r | |
608 | int ComponentsInstance;\r | |
609 | int ComponentCount;\r | |
610 | \r | |
611 | //\r | |
612 | // Use this to keep track of all the firmware volume names\r | |
613 | //\r | |
614 | FVList = NULL;\r | |
615 | LastFVList = NULL;\r | |
616 | //\r | |
617 | // See if they specified a FV directory to dump the FV files out to. If not,\r | |
618 | // then use the default. Then create the output directory.\r | |
619 | //\r | |
620 | StartCptr = GetSymbolValue (FV_INF_DIR);\r | |
621 | if (StartCptr == NULL) {\r | |
622 | ExpandSymbols (DEFAULT_FV_INF_DIR, FVDir, sizeof (FVDir), EXPANDMODE_NO_UNDEFS);\r | |
623 | } else {\r | |
624 | strcpy (FVDir, StartCptr);\r | |
625 | }\r | |
626 | //\r | |
627 | // Make sure the fv directory path ends in /\r | |
628 | //\r | |
629 | CSave = FVDir[strlen (FVDir) - 1];\r | |
630 | if ((CSave != '\\') && (CSave != '/')) {\r | |
631 | strcat (FVDir, "\\");\r | |
632 | }\r | |
633 | //\r | |
634 | // Traverse the list of all files, determine which FV each is in, then\r | |
635 | // write out the file's name to the output FVxxx.inf file.\r | |
636 | //\r | |
637 | for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) {\r | |
638 | //\r | |
639 | // Parse all the "FV1,FV2..." in the FVs\r | |
640 | //\r | |
641 | if (FileListPtr->FVs != NULL) {\r | |
642 | //\r | |
643 | // Process each fv this file is in\r | |
644 | //\r | |
645 | StartCptr = FileListPtr->FVs;\r | |
646 | while (*StartCptr) {\r | |
647 | EndCptr = StartCptr;\r | |
648 | while (*EndCptr && (*EndCptr != ',')) {\r | |
649 | EndCptr++;\r | |
650 | }\r | |
651 | \r | |
652 | CSave = *EndCptr;\r | |
653 | *EndCptr = 0;\r | |
654 | //\r | |
655 | // Ok, we have a fv name, now see if we've already opened\r | |
656 | // an fv output file of this name.\r | |
657 | //\r | |
658 | for (FVPtr = FVList; FVPtr != NULL; FVPtr = FVPtr->Next) {\r | |
659 | if (_stricmp (FVPtr->FVFileName, StartCptr) == 0) {\r | |
660 | break;\r | |
661 | }\r | |
662 | }\r | |
663 | //\r | |
664 | // If we didn't find one, then create a new one\r | |
665 | //\r | |
666 | if (FVPtr == NULL) {\r | |
667 | //\r | |
668 | // Create a new one, add it to the list\r | |
669 | //\r | |
670 | FVPtr = (FV_LIST *) malloc (sizeof (FV_LIST));\r | |
671 | if (FVPtr == NULL) {\r | |
672 | Error (NULL, 0, 0, NULL, "failed to allocate memory for FV");\r | |
673 | return STATUS_ERROR;\r | |
674 | }\r | |
675 | \r | |
676 | memset ((char *) FVPtr, 0, sizeof (FV_LIST));\r | |
677 | //\r | |
678 | // Add it to the end of our list\r | |
679 | //\r | |
680 | if (FVList == NULL) {\r | |
681 | FVList = FVPtr;\r | |
682 | } else {\r | |
683 | LastFVList->Next = FVPtr;\r | |
684 | }\r | |
685 | \r | |
686 | LastFVList = FVPtr;\r | |
687 | //\r | |
688 | // Save the FV name in the FileName pointer so we can compare\r | |
689 | // for any future FV names specified.\r | |
690 | //\r | |
691 | strcpy (FVPtr->FVFileName, StartCptr);\r | |
692 | \r | |
693 | //\r | |
694 | // Add a symbol for the FV filename\r | |
695 | //\r | |
696 | UpperCaseString (FVPtr->FVFileName);\r | |
697 | AddSymbol (FV_FILENAME, FVPtr->FVFileName, SYM_LOCAL | SYM_OVERWRITE);\r | |
698 | //\r | |
699 | // Now create the FVx.inf filename from the fv name and\r | |
700 | // default filename extension. Dump it in the FV directory\r | |
701 | // as well.\r | |
702 | //\r | |
703 | strcpy (Str, FVDir);\r | |
704 | strcat (Str, FVPtr->FVFileName);\r | |
705 | strcat (Str, ".inf");\r | |
706 | //\r | |
707 | // Create the directory path for our new fv.inf output file.\r | |
708 | //\r | |
709 | MakeFilePath (Str);\r | |
710 | if ((FVPtr->FVFilePtr = SmartOpen (Str)) == NULL) {\r | |
711 | Error (NULL, 0, 0, Str, "could not open FV output file");\r | |
712 | return STATUS_ERROR;\r | |
713 | }\r | |
714 | //\r | |
715 | // Now copy the [fv.$(FV).options] to the fv INF file\r | |
716 | //\r | |
717 | sprintf (Str, "fv.%s.options", StartCptr);\r | |
718 | Section = DSCFileFindSection (DSC, Str);\r | |
719 | if (Section != NULL) {\r | |
720 | SmartWrite (FVPtr->FVFilePtr, "[options]\n");\r | |
721 | while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {\r | |
722 | ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0);\r | |
723 | SmartWrite (FVPtr->FVFilePtr, ExpandedLine);\r | |
724 | GetBaseAddress (ExpandedLine, FVPtr->BaseAddress);\r | |
725 | }\r | |
726 | } else {\r | |
727 | Error (NULL, 0, 0, Str, "could not find FV section in description file");\r | |
728 | }\r | |
729 | //\r | |
730 | // Copy the [fv.$(FV).attributes] to the fv INF file\r | |
731 | //\r | |
732 | sprintf (Str, "fv.%s.attributes", StartCptr);\r | |
733 | Section = DSCFileFindSection (DSC, Str);\r | |
734 | if (Section != NULL) {\r | |
735 | SmartWrite (FVPtr->FVFilePtr, "[attributes]\n");\r | |
736 | while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {\r | |
737 | ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0);\r | |
738 | SmartWrite (FVPtr->FVFilePtr, ExpandedLine);\r | |
739 | }\r | |
740 | } else {\r | |
741 | Error (NULL, 0, 0, Str, "Could not find FV section in description file");\r | |
742 | }\r | |
743 | //\r | |
744 | // Start the files section\r | |
745 | //\r | |
746 | SmartWrite (FVPtr->FVFilePtr, "\n[files]\n");\r | |
747 | }\r | |
748 | //\r | |
749 | // Now write the FV filename to the FV.inf file. Prepend $(PROCESSOR) on\r | |
750 | // it.\r | |
751 | //\r | |
752 | sprintf (ExpandedLine, "EFI_FILE_NAME = %s\n", FileListPtr->FileName);\r | |
753 | SmartWrite (FVPtr->FVFilePtr, ExpandedLine);\r | |
754 | \r | |
755 | //\r | |
756 | // Next FV on the FV list\r | |
757 | //\r | |
758 | *EndCptr = CSave;\r | |
759 | StartCptr = EndCptr;\r | |
760 | if (*StartCptr) {\r | |
761 | StartCptr++;\r | |
762 | }\r | |
763 | }\r | |
764 | }\r | |
765 | }\r | |
766 | //\r | |
767 | // Now we walk the list of firmware volumes and create the APRIORI list\r | |
768 | // file for it .\r | |
769 | //\r | |
770 | for (FVPtr = FVList; FVPtr != NULL; FVPtr = FVPtr->Next) {\r | |
771 | //\r | |
772 | // Run through all the files and count up how many are to be\r | |
773 | // added to the apriori list for this FV. Then when we're done\r | |
774 | // we'll make sure we processed them all. We do this in case they\r | |
775 | // skipped an apriori index for a given FV.\r | |
776 | //\r | |
777 | AprioriCount = 0;\r | |
778 | for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) {\r | |
779 | if (OrderInFvList (FileListPtr->Apriori, FVPtr->FVFileName, &AprioriPosition)) {\r | |
780 | //\r | |
781 | // Emit an error if the index was 0, or they didn't give one.\r | |
782 | //\r | |
783 | if (AprioriPosition == 0) {\r | |
784 | Error (\r | |
785 | GetSymbolValue (DSC_FILENAME),\r | |
786 | 1,\r | |
787 | 0,\r | |
788 | "apriori indexes are 1-based",\r | |
789 | "component %s:APRIORI=%s",\r | |
790 | FileListPtr->BaseName,\r | |
791 | FileListPtr->Apriori\r | |
792 | );\r | |
793 | } else {\r | |
794 | AprioriCount++;\r | |
795 | }\r | |
796 | \r | |
797 | }\r | |
798 | }\r | |
799 | //\r | |
800 | // Now scan the files as we increment our apriori index\r | |
801 | //\r | |
802 | AprioriCounter = 0;\r | |
803 | do {\r | |
804 | AprioriFound = 0;\r | |
805 | AprioriCounter++;\r | |
806 | for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) {\r | |
807 | //\r | |
808 | // If in the apriori list for this fv, print the name. Open the\r | |
809 | // file first if we have to.\r | |
810 | //\r | |
811 | if ((FileListPtr->Apriori[0] != 0) &&\r | |
812 | (OrderInFvList (FileListPtr->Apriori, FVPtr->FVFileName, &AprioriPosition))\r | |
813 | ) {\r | |
814 | if (AprioriPosition == AprioriCounter) {\r | |
815 | //\r | |
816 | // If we've already found one for this index, emit an error. Decrement the\r | |
817 | // count of how files we are to process so we don't emit another error for\r | |
818 | // a miscount below.\r | |
819 | //\r | |
820 | if (AprioriFound) {\r | |
821 | Error (\r | |
822 | GetSymbolValue (DSC_FILENAME),\r | |
823 | 1,\r | |
824 | 0,\r | |
825 | "duplicate apriori index found",\r | |
826 | "%s:%d",\r | |
827 | FVPtr->FVFileName,\r | |
828 | AprioriCounter\r | |
829 | );\r | |
830 | AprioriCount--;\r | |
831 | }\r | |
832 | \r | |
833 | AprioriFound = 1;\r | |
834 | //\r | |
835 | // Open the apriori output file if we haven't already\r | |
836 | //\r | |
837 | if (FVPtr->AprioriFilePtr == NULL) {\r | |
838 | strcpy (Str, FVDir);\r | |
839 | strcat (Str, FVPtr->FVFileName);\r | |
840 | strcat (Str, ".apr");\r | |
841 | if ((FVPtr->AprioriFilePtr = SmartOpen (Str)) == NULL) {\r | |
842 | Error (NULL, 0, 0, Str, "could not open output Apriori file for writing");\r | |
843 | return STATUS_ERROR;\r | |
844 | }\r | |
845 | }\r | |
846 | \r | |
847 | sprintf (ExpandedLine, "%s\n", FileListPtr->BaseFileName);\r | |
848 | SmartWrite (FVPtr->AprioriFilePtr, ExpandedLine);\r | |
849 | }\r | |
850 | }\r | |
851 | }\r | |
852 | } while (AprioriFound);\r | |
853 | //\r | |
854 | // See if they skipped an apriori position for this FV\r | |
855 | //\r | |
856 | if (AprioriCount != (AprioriCounter - 1)) {\r | |
857 | Error (\r | |
858 | GetSymbolValue (DSC_FILENAME),\r | |
859 | 1,\r | |
860 | 0,\r | |
861 | "apriori index skipped",\r | |
862 | "%s:%d",\r | |
863 | FVPtr->FVFileName,\r | |
864 | AprioriCounter\r | |
865 | );\r | |
866 | }\r | |
867 | }\r | |
868 | //\r | |
869 | // Traverse the list of all files again, and create a macro in the output makefile\r | |
870 | // that defines all the files in each fv. For example, for each FV file, create a line:\r | |
871 | // FV0001_FILES = $(FV_0001_FILES) xxxx-yyy.dxe.\r | |
872 | // This can then be used as a dependency in their makefile.\r | |
873 | // Also if they wanted us to dump a cross-reference, do that now.\r | |
874 | //\r | |
875 | if (mXRefFileName != NULL) {\r | |
876 | if ((XRefFptr = fopen (mXRefFileName, "w")) == NULL) {\r | |
877 | Message (\r | |
878 | 0,\r | |
879 | "Failed to open cross-reference file '%s' for writing\n",\r | |
880 | mXRefFileName\r | |
881 | );\r | |
882 | }\r | |
883 | } else {\r | |
884 | XRefFptr = NULL;\r | |
885 | }\r | |
886 | \r | |
887 | for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) {\r | |
888 | //\r | |
889 | // Parse all the "FV1,FV2..." in the FV field that came from FV=FVa,FVb,... on the\r | |
890 | // component line in the DSC file.\r | |
891 | //\r | |
892 | if (FileListPtr->FVs != NULL) {\r | |
893 | //\r | |
894 | // If generating a cross-reference file, dump the data\r | |
895 | //\r | |
896 | if (XRefFptr != NULL) {\r | |
897 | if ((FileListPtr->Guid != NULL) && (FileListPtr->BaseName != NULL) && (FileListPtr->Processor)) {\r | |
898 | fprintf (\r | |
899 | XRefFptr,\r | |
900 | "%s %s %s\n",\r | |
901 | FileListPtr->Guid,\r | |
902 | FileListPtr->BaseName,\r | |
903 | FileListPtr->Processor\r | |
904 | );\r | |
905 | }\r | |
906 | }\r | |
907 | //\r | |
908 | // Convert to uppercase since we're going to use the name as a macro variable name\r | |
909 | // in the makefile.\r | |
910 | //\r | |
911 | UpperCaseString (FileListPtr->FVs);\r | |
912 | //\r | |
913 | // Process each FV this file is in to write fvxxx_FILES = $(fvxxx_FILES) Guid-BaseName.ffs\r | |
914 | //\r | |
915 | StartCptr = FileListPtr->FVs;\r | |
916 | while (*StartCptr) {\r | |
917 | EndCptr = StartCptr;\r | |
918 | while (*EndCptr && (*EndCptr != ',')) {\r | |
919 | EndCptr++;\r | |
920 | }\r | |
921 | \r | |
922 | CSave = *EndCptr;\r | |
923 | *EndCptr = 0;\r | |
924 | fprintf (\r | |
925 | MakeFptr,\r | |
926 | "%s_FILES = $(%s_FILES) %s\n",\r | |
927 | StartCptr,\r | |
928 | StartCptr,\r | |
929 | FileListPtr->FileName\r | |
930 | );\r | |
931 | //\r | |
932 | // Next FV on the FV list\r | |
933 | //\r | |
934 | *EndCptr = CSave;\r | |
935 | StartCptr = EndCptr;\r | |
936 | if (*StartCptr) {\r | |
937 | StartCptr++;\r | |
938 | }\r | |
939 | }\r | |
940 | }\r | |
941 | }\r | |
942 | \r | |
943 | fprintf (MakeFptr, "\n");\r | |
944 | \r | |
945 | //\r | |
946 | // Now go through the list of all NonFFS FVs they specified and search for\r | |
947 | // a [build.fv.$(FV)] or [build.fv] command and emit the commands to the\r | |
3e99020d | 948 | // output makefile. Add them to the "fvs_0" target as well.\r |
3eb9473e | 949 | //\r |
950 | if (mNonFfsFVList != NULL) {\r | |
3e99020d | 951 | fprintf (MakeFptr, "fvs_0 ::");\r |
3eb9473e | 952 | FVPtr = mNonFfsFVList;\r |
953 | while (FVPtr != NULL) {\r | |
954 | fprintf (MakeFptr, " %s%s.fv", FVDir, FVPtr->FVFileName);\r | |
955 | FVPtr = FVPtr->Next;\r | |
956 | }\r | |
957 | \r | |
958 | fprintf (MakeFptr, "\n\n");\r | |
959 | FVPtr = mNonFfsFVList;\r | |
960 | while (FVPtr != NULL) {\r | |
961 | //\r | |
962 | // Save the position in the file\r | |
963 | //\r | |
964 | DSCFileSavePosition (DSC);\r | |
965 | //\r | |
966 | // first try to find a build section specific for this fv.\r | |
967 | //\r | |
968 | sprintf (Str, "build.fv.%s", FVPtr->FVFileName);\r | |
969 | Section = DSCFileFindSection (DSC, Str);\r | |
970 | if (Section == NULL) {\r | |
971 | sprintf (Str, "build.fv");\r | |
972 | Section = DSCFileFindSection (DSC, Str);\r | |
973 | }\r | |
974 | \r | |
975 | if (Section == NULL) {\r | |
976 | Warning (\r | |
977 | NULL,\r | |
978 | 0,\r | |
979 | 0,\r | |
980 | NULL,\r | |
981 | "No [build.fv.%s] nor [%s] section found in description file for building %s",\r | |
982 | FVPtr->FVFileName,\r | |
983 | Str,\r | |
984 | FVPtr->FVFileName\r | |
985 | );\r | |
986 | } else {\r | |
987 | //\r | |
988 | // Add a symbol for the FV filename\r | |
989 | //\r | |
990 | UpperCaseString (FVPtr->FVFileName);\r | |
991 | AddSymbol (FV_FILENAME, FVPtr->FVFileName, SYM_LOCAL | SYM_OVERWRITE);\r | |
992 | AddSymbol (EFI_BASE_ADDRESS, FVPtr->BaseAddress, SYM_LOCAL | SYM_OVERWRITE);\r | |
993 | \r | |
994 | //\r | |
995 | // Now copy the build commands from the section to the makefile\r | |
996 | //\r | |
997 | while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {\r | |
998 | ExpandSymbols (\r | |
999 | Line,\r | |
1000 | ExpandedLine,\r | |
1001 | sizeof (ExpandedLine),\r | |
1002 | EXPANDMODE_NO_DESTDIR | EXPANDMODE_NO_SOURCEDIR\r | |
1003 | );\r | |
1004 | \r | |
1005 | fprintf (MakeFptr, ExpandedLine);\r | |
1006 | }\r | |
1007 | }\r | |
1008 | \r | |
1009 | FVPtr = FVPtr->Next;\r | |
1010 | DSCFileRestorePosition (DSC);\r | |
1011 | }\r | |
1012 | }\r | |
3e99020d | 1013 | \r |
3eb9473e | 1014 | //\r |
3e99020d | 1015 | // Get the components count\r |
3eb9473e | 1016 | //\r |
3e99020d LG |
1017 | ComponentCount = -1;\r |
1018 | for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) {\r | |
1019 | if (FileListPtr->ComponentsInstance > ComponentCount) {\r | |
1020 | ComponentCount = FileListPtr->ComponentsInstance;\r | |
3eb9473e | 1021 | }\r |
3e99020d LG |
1022 | }\r |
1023 | ComponentCount++;\r | |
3eb9473e | 1024 | \r |
3e99020d LG |
1025 | //\r |
1026 | // Now print firmware volumes build targets fvs_0, fvs_1 etc.\r | |
1027 | //\r | |
1028 | for (ComponentsInstance = 0; ComponentsInstance < ComponentCount; ComponentsInstance++) {\r | |
1029 | fprintf (MakeFptr, "fvs_%d ::", ComponentsInstance);\r | |
3eb9473e | 1030 | for (FVPtr = mFVList; FVPtr != NULL; FVPtr = FVPtr->Next) {\r |
1031 | if (FVPtr->ComponentsInstance == ComponentsInstance) {\r | |
1032 | fprintf (MakeFptr, " %s%s.fv", FVDir, FVPtr->FVFileName);\r | |
1033 | }\r | |
1034 | }\r | |
3e99020d LG |
1035 | fprintf (MakeFptr, "\n\n");\r |
1036 | }\r | |
1037 | \r | |
1038 | //\r | |
1039 | // Create an "fvs" target that builds everything. It has to be a mix of \r | |
1040 | // components and FV's in order. For example:\r | |
1041 | // fvs :: components_0 fvs_0 components_1 fvs_1\r | |
1042 | //\r | |
1043 | fprintf (MakeFptr, "fvs ::");\r | |
1044 | for (ComponentsInstance = 0; ComponentsInstance < ComponentCount; ComponentsInstance++) {\r | |
1045 | fprintf (MakeFptr, " components_%d fvs_%d", ComponentsInstance, ComponentsInstance);\r | |
3eb9473e | 1046 | }\r |
3eb9473e | 1047 | fprintf (MakeFptr, "\n\n");\r |
1048 | \r | |
1049 | //\r | |
1050 | // Create a "components" target for build convenience. It should\r | |
1051 | // look something like:\r | |
1052 | // components : components_0 components_1...\r | |
1053 | //\r | |
1054 | if (ComponentCount > 0) {\r | |
1055 | fprintf (MakeFptr, "components :");\r | |
1056 | for (ComponentsInstance = 0; ComponentsInstance < ComponentCount; ComponentsInstance++) {\r | |
1057 | fprintf (MakeFptr, " components_%d", ComponentsInstance);\r | |
1058 | }\r | |
1059 | \r | |
1060 | fprintf (MakeFptr, "\n\n");\r | |
1061 | }\r | |
1062 | //\r | |
1063 | // Now go through the list of all FV's defined and search for\r | |
1064 | // a [build.fv.$(FV)] or [build.fv] command and emit the commands to the\r | |
1065 | // output makefile.\r | |
1066 | //\r | |
1067 | FVPtr = mFVList;\r | |
1068 | while (FVPtr != NULL) {\r | |
1069 | if (FVPtr->FVFileName[0]) {\r | |
1070 | //\r | |
1071 | // Save the position in the file\r | |
1072 | //\r | |
1073 | DSCFileSavePosition (DSC);\r | |
1074 | //\r | |
1075 | // First try to find a build section specific for this FV.\r | |
1076 | //\r | |
1077 | sprintf (Str, "build.fv.%s", FVPtr->FVFileName);\r | |
1078 | Section = DSCFileFindSection (DSC, Str);\r | |
1079 | if (Section == NULL) {\r | |
1080 | sprintf (Str, "build.fv");\r | |
1081 | Section = DSCFileFindSection (DSC, Str);\r | |
1082 | }\r | |
1083 | \r | |
1084 | if (Section == NULL) {\r | |
1085 | Error (\r | |
1086 | NULL,\r | |
1087 | 0,\r | |
1088 | 0,\r | |
1089 | NULL,\r | |
1090 | "no [build.fv.%s] nor [%s] section found in description file for building %s",\r | |
1091 | FVPtr->FVFileName,\r | |
1092 | Str,\r | |
1093 | FVPtr->FVFileName\r | |
1094 | );\r | |
1095 | } else {\r | |
1096 | //\r | |
1097 | // Add a symbol for the FV filename\r | |
1098 | //\r | |
1099 | UpperCaseString (FVPtr->FVFileName);\r | |
1100 | AddSymbol (FV_FILENAME, FVPtr->FVFileName, SYM_LOCAL | SYM_OVERWRITE);\r | |
1101 | AddSymbol (EFI_BASE_ADDRESS, FVPtr->BaseAddress, SYM_LOCAL | SYM_OVERWRITE);\r | |
1102 | \r | |
1103 | //\r | |
1104 | // Now copy the build commands from the section to the makefile\r | |
1105 | //\r | |
1106 | while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {\r | |
1107 | ExpandSymbols (\r | |
1108 | Line,\r | |
1109 | ExpandedLine,\r | |
1110 | sizeof (ExpandedLine),\r | |
1111 | EXPANDMODE_NO_DESTDIR | EXPANDMODE_NO_SOURCEDIR\r | |
1112 | );\r | |
1113 | fprintf (MakeFptr, ExpandedLine);\r | |
1114 | }\r | |
1115 | }\r | |
1116 | \r | |
1117 | DSCFileRestorePosition (DSC);\r | |
1118 | }\r | |
1119 | \r | |
1120 | FVPtr = FVPtr->Next;\r | |
1121 | }\r | |
1122 | //\r | |
1123 | // Close all the files and free up the memory\r | |
1124 | //\r | |
1125 | while (FVList != NULL) {\r | |
1126 | FVPtr = FVList->Next;\r | |
1127 | if (FVList->FVFilePtr != NULL) {\r | |
1128 | SmartClose (FVList->FVFilePtr);\r | |
1129 | }\r | |
1130 | \r | |
1131 | if (FVList->AprioriFilePtr != NULL) {\r | |
1132 | SmartClose (FVList->AprioriFilePtr);\r | |
1133 | }\r | |
1134 | \r | |
1135 | free (FVList);\r | |
1136 | FVList = FVPtr;\r | |
1137 | }\r | |
1138 | \r | |
1139 | while (mNonFfsFVList != NULL) {\r | |
1140 | FVPtr = mNonFfsFVList->Next;\r | |
1141 | free (mNonFfsFVList);\r | |
1142 | mNonFfsFVList = FVPtr;\r | |
1143 | }\r | |
1144 | \r | |
1145 | if (XRefFptr != NULL) {\r | |
1146 | fclose (XRefFptr);\r | |
1147 | }\r | |
1148 | \r | |
1149 | return STATUS_SUCCESS;\r | |
1150 | }\r | |
1151 | \r | |
1152 | int\r | |
1153 | NonFFSFVWriteInfFiles (\r | |
1154 | DSC_FILE *DSC,\r | |
1155 | char *FileName\r | |
1156 | )\r | |
1157 | /*++\r | |
1158 | \r | |
1159 | Routine Description:\r | |
1160 | \r | |
1161 | Generate a Non FFS fv file. It can only some variables,\r | |
1162 | or simply contains nothing except header.\r | |
1163 | \r | |
1164 | Arguments:\r | |
1165 | \r | |
1166 | DSC - pointer to a DSC_FILE object to extract info from\r | |
1167 | FileName - pointer to the fv file\r | |
1168 | \r | |
1169 | Returns:\r | |
1170 | \r | |
1171 | STATUS_SUCCESS if successful\r | |
1172 | non-STATUS_SUCCESS otherwise\r | |
1173 | \r | |
1174 | --*/\r | |
1175 | {\r | |
1176 | FV_LIST *FVPtr;\r | |
1177 | SECTION *Section;\r | |
1178 | char *StartCptr;\r | |
1179 | char *EndCptr;\r | |
1180 | char CSave;\r | |
1181 | char Str[MAX_PATH];\r | |
1182 | char Line[MAX_LINE_LEN];\r | |
1183 | char ExpandedLine[MAX_LINE_LEN];\r | |
1184 | char FVDir[MAX_PATH];\r | |
1185 | \r | |
1186 | //\r | |
1187 | // See if they specified a FV directory to dump the FV files out to. If not,\r | |
1188 | // then use the default. Then create the output directory.\r | |
1189 | //\r | |
1190 | DSCFileSavePosition (DSC);\r | |
1191 | StartCptr = GetSymbolValue (FV_INF_DIR);\r | |
1192 | if (StartCptr == NULL) {\r | |
1193 | ExpandSymbols (DEFAULT_FV_INF_DIR, FVDir, sizeof (FVDir), EXPANDMODE_NO_UNDEFS);\r | |
1194 | } else {\r | |
1195 | strcpy (FVDir, StartCptr);\r | |
1196 | }\r | |
1197 | \r | |
1198 | //\r | |
1199 | // Make sure the fv directory path ends in /\r | |
1200 | //\r | |
1201 | CSave = FVDir[strlen (FVDir) - 1];\r | |
1202 | if ((CSave != '\\') && (CSave != '/')) {\r | |
1203 | strcat (FVDir, "\\");\r | |
1204 | }\r | |
1205 | \r | |
1206 | StartCptr = FileName;\r | |
1207 | while (*StartCptr) {\r | |
1208 | EndCptr = StartCptr;\r | |
1209 | while (*EndCptr && (*EndCptr != ',')) {\r | |
1210 | EndCptr++;\r | |
1211 | }\r | |
1212 | \r | |
1213 | CSave = *EndCptr;\r | |
1214 | *EndCptr = 0;\r | |
1215 | //\r | |
1216 | // Ok, we have a fv name, now see if we've already opened\r | |
1217 | // an fv output file of this name.\r | |
1218 | //\r | |
1219 | for (FVPtr = mNonFfsFVList; FVPtr != NULL; FVPtr = FVPtr->Next) {\r | |
1220 | if (_stricmp (FVPtr->FVFileName, StartCptr) == 0) {\r | |
1221 | break;\r | |
1222 | }\r | |
1223 | }\r | |
1224 | //\r | |
1225 | // If there is already one with the same name, wrong\r | |
1226 | //\r | |
1227 | if (FVPtr != NULL) {\r | |
1228 | DSCFileRestorePosition (DSC);\r | |
1229 | return STATUS_ERROR;\r | |
1230 | }\r | |
1231 | //\r | |
1232 | // Create a new one, add it to the list\r | |
1233 | //\r | |
1234 | FVPtr = (FV_LIST *) malloc (sizeof (FV_LIST));\r | |
1235 | if (FVPtr == NULL) {\r | |
1236 | Error (__FILE__, __LINE__, 0, "failed to allocate memory", NULL);\r | |
1237 | DSCFileRestorePosition (DSC);\r | |
1238 | return STATUS_ERROR;\r | |
1239 | }\r | |
1240 | \r | |
1241 | memset ((char *) FVPtr, 0, sizeof (FV_LIST));\r | |
1242 | FVPtr->Next = mNonFfsFVList;\r | |
1243 | mNonFfsFVList = FVPtr;\r | |
1244 | //\r | |
1245 | // Save the FV name in the FileName pointer so we can compare\r | |
1246 | // for any future FV names specified.\r | |
1247 | //\r | |
1248 | strcpy (FVPtr->FVFileName, StartCptr);\r | |
1249 | //\r | |
1250 | // Add a symbol for the FV filename\r | |
1251 | //\r | |
1252 | UpperCaseString (FVPtr->FVFileName);\r | |
1253 | AddSymbol (FV_FILENAME, FVPtr->FVFileName, SYM_LOCAL | SYM_OVERWRITE);\r | |
1254 | \r | |
1255 | //\r | |
1256 | // Now create the FVx.inf filename from the fv name and\r | |
1257 | // default filename extension. Dump it in the FV directory\r | |
1258 | // as well.\r | |
1259 | //\r | |
1260 | strcpy (Str, FVDir);\r | |
1261 | strcat (Str, FVPtr->FVFileName);\r | |
1262 | strcat (Str, ".inf");\r | |
1263 | //\r | |
1264 | // Create the directory path for our new fv.inf output file.\r | |
1265 | //\r | |
1266 | MakeFilePath (Str);\r | |
1267 | if ((FVPtr->FVFilePtr = SmartOpen (Str)) == NULL) {\r | |
1268 | Error (NULL, 0, 0, Str, "could not open FV output file");\r | |
1269 | DSCFileRestorePosition (DSC);\r | |
1270 | return STATUS_ERROR;\r | |
1271 | }\r | |
1272 | //\r | |
1273 | // Now copy the [fv.fvfile.options] to the fv file\r | |
1274 | //\r | |
1275 | sprintf (Str, "fv.%s.options", StartCptr);\r | |
1276 | Section = DSCFileFindSection (DSC, Str);\r | |
1277 | if (Section != NULL) {\r | |
1278 | SmartWrite (FVPtr->FVFilePtr, "[options]\n");\r | |
1279 | while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {\r | |
1280 | ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0);\r | |
1281 | SmartWrite (FVPtr->FVFilePtr, ExpandedLine);\r | |
1282 | GetBaseAddress (ExpandedLine, FVPtr->BaseAddress);\r | |
1283 | }\r | |
1284 | } else {\r | |
1285 | Warning (NULL, 0, 0, NULL, "Could not find FV section '%s' in description file", Str);\r | |
1286 | }\r | |
1287 | //\r | |
1288 | // Copy the [fv.fvfile.attributes] to the fv file\r | |
1289 | //\r | |
1290 | sprintf (Str, "fv.%s.attributes", StartCptr);\r | |
1291 | Section = DSCFileFindSection (DSC, Str);\r | |
1292 | if (Section != NULL) {\r | |
1293 | SmartWrite (FVPtr->FVFilePtr, "[attributes]\n");\r | |
1294 | while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {\r | |
1295 | ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0);\r | |
1296 | SmartWrite (FVPtr->FVFilePtr, ExpandedLine);\r | |
1297 | }\r | |
1298 | } else {\r | |
1299 | Warning (NULL, 0, 0, NULL, "Could not find FV section '%s' in description file", Str);\r | |
1300 | }\r | |
1301 | //\r | |
1302 | // Copy the [fv.fvfile.components] to the fv file\r | |
1303 | //\r | |
1304 | sprintf (Str, "fv.%s.components", StartCptr);\r | |
1305 | Section = DSCFileFindSection (DSC, Str);\r | |
1306 | if (Section != NULL) {\r | |
1307 | SmartWrite (FVPtr->FVFilePtr, "[components]\n");\r | |
1308 | while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {\r | |
1309 | ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0);\r | |
1310 | SmartWrite (FVPtr->FVFilePtr, ExpandedLine);\r | |
1311 | }\r | |
1312 | } else {\r | |
1313 | //\r | |
1314 | // An empty FV is allowed to contain nothing\r | |
1315 | //\r | |
1316 | }\r | |
1317 | //\r | |
1318 | // Close the file\r | |
1319 | //\r | |
1320 | SmartClose (FVPtr->FVFilePtr);\r | |
1321 | //\r | |
1322 | // Next FV in FileName\r | |
1323 | //\r | |
1324 | *EndCptr = CSave;\r | |
1325 | StartCptr = EndCptr;\r | |
1326 | if (*StartCptr) {\r | |
1327 | StartCptr++;\r | |
1328 | }\r | |
1329 | }\r | |
1330 | \r | |
1331 | DSCFileRestorePosition (DSC);\r | |
1332 | return STATUS_SUCCESS;\r | |
1333 | }\r | |
1334 | \r | |
1335 | static\r | |
1336 | void\r | |
1337 | AddFirmwareVolumes (\r | |
1338 | char *FVs,\r | |
3e99020d | 1339 | int ComponentsInstance\r |
3eb9473e | 1340 | )\r |
1341 | {\r | |
1342 | FV_LIST *FvPtr;\r | |
1343 | char *StartPtr;\r | |
1344 | char *EndPtr;\r | |
1345 | char SaveChar;\r | |
1346 | \r | |
1347 | if ((FVs != NULL) && (FVs[0] != 0)) {\r | |
1348 | //\r | |
1349 | // Extract each FV name from the string. It's from the DSC file "FV=FvRecover,FvMain"\r | |
1350 | //\r | |
1351 | StartPtr = FVs;\r | |
1352 | while (*StartPtr != 0) {\r | |
1353 | EndPtr = StartPtr;\r | |
1354 | while (*EndPtr && (*EndPtr != ',')) {\r | |
1355 | EndPtr++;\r | |
1356 | }\r | |
1357 | \r | |
1358 | SaveChar = *EndPtr;\r | |
1359 | *EndPtr = 0;\r | |
1360 | //\r | |
1361 | // Look through our list of known firmware volumes and see if we've\r | |
1362 | // already added it.\r | |
1363 | //\r | |
1364 | for (FvPtr = mFVList; FvPtr != NULL; FvPtr = FvPtr->Next) {\r | |
1365 | if (_stricmp (FvPtr->FVFileName, StartPtr) == 0) {\r | |
1366 | break;\r | |
1367 | }\r | |
1368 | }\r | |
1369 | //\r | |
1370 | // If we didn't find a match, then create a new one\r | |
1371 | //\r | |
1372 | if (FvPtr == NULL) {\r | |
3e99020d | 1373 | FvPtr = malloc (sizeof (FV_LIST));\r |
3eb9473e | 1374 | if (FvPtr == NULL) {\r |
1375 | Error (__FILE__, __LINE__, 0, "application error", "memory allocation failed");\r | |
1376 | return ;\r | |
1377 | }\r | |
1378 | \r | |
1379 | memset (FvPtr, 0, sizeof (FV_LIST));\r | |
1380 | strcpy (FvPtr->FVFileName, StartPtr);\r | |
1381 | if (mFVList == NULL) {\r | |
1382 | mFVList = FvPtr;\r | |
1383 | } else {\r | |
1384 | mFVListLast->Next = FvPtr;\r | |
1385 | }\r | |
1386 | \r | |
1387 | mFVListLast = FvPtr;\r | |
1388 | }\r | |
1389 | //\r | |
1390 | // If this component's section number is higher than that of this\r | |
1391 | // FV, then set the FV's to it.\r | |
1392 | //\r | |
1393 | if (FvPtr->ComponentsInstance < ComponentsInstance) {\r | |
1394 | FvPtr->ComponentsInstance = ComponentsInstance;\r | |
1395 | }\r | |
1396 | //\r | |
1397 | // If we found then end of the FVs in the string, then we're done.\r | |
1398 | // Always restore the original string's contents.\r | |
1399 | //\r | |
1400 | if (SaveChar != 0) {\r | |
1401 | *EndPtr = SaveChar;\r | |
1402 | StartPtr = EndPtr + 1;\r | |
1403 | } else {\r | |
1404 | StartPtr = EndPtr;\r | |
1405 | }\r | |
1406 | }\r | |
1407 | }\r | |
1408 | }\r | |
1409 | \r | |
1410 | static\r | |
1411 | BOOLEAN\r | |
1412 | OrderInFvList (\r | |
1413 | char *FvList,\r | |
1414 | char *FvName,\r | |
1415 | int *Order\r | |
1416 | )\r | |
1417 | {\r | |
1418 | //\r | |
1419 | // Given FvList of format "FV_a,FV_b,FV_c" or "FV_a:1,FV_b:2" and\r | |
1420 | // FvName of format "FV_c", determine if FvName is in FvList. If\r | |
1421 | // FV_a:1 format, then return the value after the colon.\r | |
1422 | //\r | |
1423 | while (*FvList) {\r | |
1424 | //\r | |
1425 | // If it matches for the length of FvName...\r | |
1426 | //\r | |
1427 | if (_strnicmp (FvList, FvName, strlen (FvName)) == 0) {\r | |
1428 | //\r | |
1429 | // Then see if the match string in FvList is terminated at the\r | |
1430 | // same length.\r | |
1431 | //\r | |
1432 | if ((FvList[strlen (FvName)] == ',') || (FvList[strlen (FvName)] == 0)) {\r | |
1433 | *Order = 0;\r | |
1434 | return TRUE;\r | |
1435 | } else if (FvList[strlen (FvName)] == ':') {\r | |
1436 | *Order = atoi (FvList + strlen (FvName) + 1);\r | |
1437 | return TRUE;\r | |
1438 | }\r | |
1439 | }\r | |
1440 | //\r | |
1441 | // Skip to next FV in the comma-separated list\r | |
1442 | //\r | |
1443 | while ((*FvList != ',') && (*FvList != 0)) {\r | |
1444 | FvList++;\r | |
1445 | }\r | |
1446 | //\r | |
1447 | // Skip over comma\r | |
1448 | //\r | |
1449 | if (*FvList == ',') {\r | |
1450 | FvList++;\r | |
1451 | }\r | |
1452 | }\r | |
1453 | \r | |
1454 | return FALSE;\r | |
1455 | }\r | |
1456 | \r | |
1457 | static\r | |
1458 | char *\r | |
1459 | UpperCaseString (\r | |
1460 | char *Str\r | |
1461 | )\r | |
1462 | {\r | |
1463 | char *Cptr;\r | |
1464 | \r | |
1465 | for (Cptr = Str; *Cptr; Cptr++) {\r | |
1466 | *Cptr = (char) toupper (*Cptr);\r | |
1467 | }\r | |
1468 | \r | |
1469 | return Str;\r | |
1470 | }\r | |
1471 | \r | |
1472 | static\r | |
1473 | BOOLEAN\r | |
1474 | InSameFv (\r | |
1475 | char *FVs1,\r | |
1476 | char *FVs2\r | |
1477 | )\r | |
1478 | {\r | |
1479 | char *StartCptr1;\r | |
1480 | char *StartCptr2;\r | |
1481 | char *EndCptr1;\r | |
1482 | char *EndCptr2;\r | |
1483 | char CSave1;\r | |
1484 | char CSave2;\r | |
1485 | \r | |
1486 | //\r | |
1487 | // Process each FV in first FV list\r | |
1488 | //\r | |
1489 | StartCptr1 = FVs1;\r | |
1490 | while (*StartCptr1) {\r | |
1491 | EndCptr1 = StartCptr1;\r | |
1492 | while (*EndCptr1 && (*EndCptr1 != ',')) {\r | |
1493 | EndCptr1++;\r | |
1494 | }\r | |
1495 | \r | |
1496 | CSave1 = *EndCptr1;\r | |
1497 | *EndCptr1 = 0; \r | |
1498 | \r | |
1499 | if (*StartCptr1) {\r | |
1500 | //\r | |
1501 | // Process each FV in second FV list\r | |
1502 | //\r | |
1503 | StartCptr2 = FVs2;\r | |
1504 | while (*StartCptr2) {\r | |
1505 | EndCptr2 = StartCptr2;\r | |
1506 | while (*EndCptr2 && (*EndCptr2 != ',')) {\r | |
1507 | EndCptr2++;\r | |
1508 | }\r | |
1509 | \r | |
1510 | CSave2 = *EndCptr2;\r | |
1511 | *EndCptr2 = 0; \r | |
1512 | \r | |
1513 | if (_stricmp (StartCptr1, StartCptr2) == 0) {\r | |
1514 | *EndCptr1 = CSave1;\r | |
1515 | *EndCptr2 = CSave2;\r | |
1516 | return TRUE;\r | |
1517 | }\r | |
1518 | \r | |
1519 | //\r | |
1520 | // Next FV on the second FV list\r | |
1521 | //\r | |
1522 | *EndCptr2 = CSave2;\r | |
1523 | StartCptr2 = EndCptr2;\r | |
1524 | if (*StartCptr2) {\r | |
1525 | StartCptr2++;\r | |
1526 | }\r | |
1527 | } \r | |
1528 | }\r | |
1529 | \r | |
1530 | //\r | |
1531 | // Next FV on the first FV list\r | |
1532 | //\r | |
1533 | *EndCptr1 = CSave1;\r | |
1534 | StartCptr1 = EndCptr1;\r | |
1535 | if (*StartCptr1) {\r | |
1536 | StartCptr1++;\r | |
1537 | }\r | |
1538 | } \r | |
1539 | \r | |
1540 | return FALSE;\r | |
1541 | }\r | |
1542 | \r | |
1543 | int\r | |
1544 | CFVSetXRefFileName (\r | |
1545 | char *FileName\r | |
1546 | )\r | |
1547 | {\r | |
1548 | mXRefFileName = FileName;\r | |
1549 | return 0;\r | |
1550 | }\r |