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