]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/EfiRom/EfiRom.c
BaseTools/EfiRom: Add multiple device id support
[mirror_edk2.git] / BaseTools / Source / C / EfiRom / EfiRom.c
CommitLineData
30fdf114 1/** @file\r
97fa0ee9 2Utility program to create an EFI option ROM image from binary and EFI PE32 files.\r
30fdf114 3\r
ef6cd66a 4Copyright (c) 1999 - 2017, Intel Corporation. All rights reserved.<BR>\r
30fdf114
LG
5This program and the accompanying materials are licensed and made available \r
6under the terms and conditions of the BSD License which accompanies this \r
7distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
30fdf114
LG
13**/\r
14\r
15#include "EfiUtilityMsgs.h"\r
16#include "ParseInf.h"\r
17#include "EfiRom.h"\r
18\r
19UINT64 DebugLevel = 0;\r
20\r
21int\r
22main (\r
23 int Argc,\r
24 char *Argv[]\r
25 )\r
26/*++\r
27\r
28Routine Description:\r
29 \r
30 Given an EFI image filename, create a ROM-able image by creating an option \r
31 ROM header and PCI data structure, filling them in, and then writing the\r
32 option ROM header + PCI data structure + EFI image out to the output file.\r
33\r
34Arguments:\r
35\r
36 Argc - standard C main() argument count\r
37\r
38 Argv - standard C main() argument list\r
39\r
40Returns:\r
41\r
42 0 success\r
43 non-zero otherwise\r
44\r
45--*/\r
46{\r
47 CHAR8 *Ext;\r
48 FILE *FptrOut;\r
49 UINT32 Status;\r
50 FILE_LIST *FList;\r
51 UINT32 TotalSize;\r
52 UINT32 Size;\r
53 CHAR8 *Ptr0;\r
54\r
55 SetUtilityName(UTILITY_NAME);\r
56\r
57 Status = STATUS_SUCCESS;\r
58 FptrOut = NULL;\r
59\r
60 //\r
61 // Parse the command line arguments\r
62 //\r
63 if (ParseCommandLine (Argc, Argv, &mOptions)) {\r
64 return STATUS_ERROR;\r
65 }\r
66\r
67 if (mOptions.Quiet) {\r
68 SetPrintLevel(40);\r
69 } else if (mOptions.Verbose) {\r
70 SetPrintLevel(15);\r
71 } else if (mOptions.Debug) {\r
72 SetPrintLevel(DebugLevel);\r
73 }\r
74 \r
75 if (mOptions.Verbose) {\r
76 VerboseMsg("%s tool start.\n", UTILITY_NAME);\r
77 }\r
78 \r
79 //\r
80 // If dumping an image, then do that and quit\r
81 //\r
82 if (mOptions.DumpOption == 1) {\r
fd171542 83 if (mOptions.FileList != NULL) {\r
84 if ((Ptr0 = strstr ((CONST CHAR8 *) mOptions.FileList->FileName, DEFAULT_OUTPUT_EXTENSION)) != NULL) {\r
30fdf114
LG
85 DumpImage (mOptions.FileList);\r
86 goto BailOut;\r
87 } else {\r
88 Error (NULL, 0, 1002, "No PciRom input file", "No *.rom input file");\r
89 goto BailOut;\r
90 }\r
91 }\r
92 }\r
93 //\r
94 // Determine the output filename. Either what they specified on\r
95 // the command line, or the first input filename with a different extension.\r
96 //\r
97 if (!mOptions.OutFileName[0]) {\r
02875ba2
HW
98 if (mOptions.FileList != NULL) {\r
99 strcpy (mOptions.OutFileName, mOptions.FileList->FileName);\r
100 //\r
101 // Find the last . on the line and replace the filename extension with\r
102 // the default\r
103 //\r
104 for (Ext = mOptions.OutFileName + strlen (mOptions.OutFileName) - 1;\r
105 (Ext >= mOptions.OutFileName) && (*Ext != '.') && (*Ext != '\\');\r
106 Ext--\r
107 )\r
108 ;\r
109 //\r
110 // If dot here, then insert extension here, otherwise append\r
111 //\r
112 if (*Ext != '.') {\r
113 Ext = mOptions.OutFileName + strlen (mOptions.OutFileName);\r
114 }\r
30fdf114 115\r
02875ba2
HW
116 strcpy (Ext, DEFAULT_OUTPUT_EXTENSION);\r
117 }\r
30fdf114
LG
118 }\r
119 //\r
120 // Make sure we don't have the same filename for input and output files\r
121 //\r
122 for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) {\r
123 if (stricmp (mOptions.OutFileName, FList->FileName) == 0) {\r
124 Status = STATUS_ERROR;\r
99e55970 125 Error (NULL, 0, 1002, "Invalid input parameter", "Input and output file names must be different - %s = %s.", FList->FileName, mOptions.OutFileName);\r
30fdf114
LG
126 goto BailOut;\r
127 }\r
128 }\r
129 //\r
130 // Now open our output file\r
131 //\r
1be2ed90 132 if ((FptrOut = fopen (LongFilePath (mOptions.OutFileName), "wb")) == NULL) {\r
30fdf114
LG
133 Error (NULL, 0, 0001, "Error opening file", "Error opening file %s", mOptions.OutFileName);\r
134 goto BailOut;\r
135 }\r
136 //\r
137 // Process all our files\r
138 //\r
139 TotalSize = 0;\r
140 for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) {\r
141 Size = 0;\r
142 if ((FList->FileFlags & FILE_FLAG_EFI) != 0) {\r
143 if (mOptions.Verbose) {\r
144 VerboseMsg("Processing EFI file %s\n", FList->FileName);\r
145 }\r
146\r
9f3a38cd 147 Status = ProcessEfiFile (FptrOut, FList, mOptions.VendId, mOptions.DevIdList[0], &Size);\r
30fdf114
LG
148 } else if ((FList->FileFlags & FILE_FLAG_BINARY) !=0 ) {\r
149 if (mOptions.Verbose) {\r
150 VerboseMsg("Processing binary file %s\n", FList->FileName);\r
151 }\r
152\r
153 Status = ProcessBinFile (FptrOut, FList, &Size);\r
154 } else {\r
155 Error (NULL, 0, 2000, "Invalid parameter", "File type not specified, it must be either an EFI or binary file: %s.", FList->FileName);\r
156 Status = STATUS_ERROR;\r
157 }\r
158\r
159 if (mOptions.Verbose) {\r
fd171542 160 VerboseMsg(" Output size = 0x%X\n", (unsigned) Size);\r
30fdf114
LG
161 }\r
162\r
163 if (Status != STATUS_SUCCESS) {\r
164 break;\r
165 }\r
166\r
167 TotalSize += Size;\r
168 }\r
169 //\r
170 // Check total size\r
171 //\r
172 if (TotalSize > MAX_OPTION_ROM_SIZE) {\r
99e55970 173 Error (NULL, 0, 2000, "Invalid parameter", "Option ROM image size exceeds limit of 0x%X bytes.", MAX_OPTION_ROM_SIZE);\r
30fdf114
LG
174 Status = STATUS_ERROR;\r
175 }\r
176\r
177BailOut:\r
178 if (Status == STATUS_SUCCESS) {\r
30fdf114
LG
179 //\r
180 // Clean up our file list\r
181 //\r
182 while (mOptions.FileList != NULL) {\r
183 FList = mOptions.FileList->Next;\r
184 free (mOptions.FileList);\r
185 mOptions.FileList = FList;\r
186 }\r
30fdf114 187\r
9f3a38cd
DV
188 //\r
189 // Clean up device ID list\r
190 //\r
191 if (mOptions.DevIdList != NULL) {\r
192 free (mOptions.DevIdList);\r
193 }\r
194 }\r
1e124de0
HW
195 if (FptrOut != NULL) {\r
196 fclose (FptrOut);\r
197 }\r
198\r
30fdf114
LG
199 if (mOptions.Verbose) {\r
200 VerboseMsg("%s tool done with return code is 0x%x.\n", UTILITY_NAME, GetUtilityStatus ());\r
201 }\r
202\r
203 return GetUtilityStatus (); \r
204}\r
205\r
206static\r
207int\r
208ProcessBinFile (\r
209 FILE *OutFptr,\r
210 FILE_LIST *InFile,\r
211 UINT32 *Size\r
212 )\r
213/*++\r
214\r
215Routine Description:\r
216 \r
217 Process a binary input file.\r
218\r
219Arguments:\r
220\r
221 OutFptr - file pointer to output binary ROM image file we're creating\r
222 InFile - structure contains information on the binary file to process\r
223 Size - pointer to where to return the size added to the output file\r
224\r
225Returns:\r
226\r
227 0 - successful\r
228\r
229--*/\r
230{\r
231 FILE *InFptr;\r
232 UINT32 TotalSize;\r
233 UINT32 FileSize;\r
234 UINT8 *Buffer;\r
235 UINT32 Status;\r
236 PCI_EXPANSION_ROM_HEADER *RomHdr;\r
237 PCI_DATA_STRUCTURE *PciDs23;\r
238 PCI_3_0_DATA_STRUCTURE *PciDs30;\r
239 UINT32 Index;\r
240 UINT8 ByteCheckSum;\r
2bc3256c 241 UINT16 CodeType;\r
30fdf114 242 \r
fd171542 243 PciDs23 = NULL;\r
244 PciDs30 = NULL;\r
30fdf114
LG
245 Status = STATUS_SUCCESS;\r
246\r
247 //\r
248 // Try to open the input file\r
249 //\r
1be2ed90 250 if ((InFptr = fopen (LongFilePath (InFile->FileName), "rb")) == NULL) {\r
ef6cd66a 251 Error (NULL, 0, 0001, "Error opening file", "%s", InFile->FileName);\r
30fdf114
LG
252 return STATUS_ERROR;\r
253 }\r
254 //\r
255 // Seek to the end of the input file and get the file size. Then allocate\r
256 // a buffer to read it in to.\r
257 //\r
258 fseek (InFptr, 0, SEEK_END);\r
259 FileSize = ftell (InFptr);\r
260 if (mOptions.Verbose) {\r
fd171542 261 VerboseMsg(" File size = 0x%X\n", (unsigned) FileSize);\r
30fdf114
LG
262 }\r
263\r
264 fseek (InFptr, 0, SEEK_SET);\r
265 Buffer = (UINT8 *) malloc (FileSize);\r
266 if (Buffer == NULL) {\r
267 Error (NULL, 0, 4003, "Resource", "memory cannot be allocated!");\r
268 Status = STATUS_ERROR;\r
269 goto BailOut;\r
270 }\r
271\r
272 if (fread (Buffer, FileSize, 1, InFptr) != 1) {\r
273 Error (NULL, 0, 2000, "Invalid", "Failed to read all bytes from input file.");\r
274 Status = STATUS_ERROR;\r
275 goto BailOut;\r
276 }\r
277 //\r
278 // Total size must be an even multiple of 512 bytes, and can't exceed\r
279 // the option ROM image size.\r
280 //\r
281 TotalSize = FileSize;\r
282 if (TotalSize & 0x1FF) {\r
283 TotalSize = (TotalSize + 0x200) &~0x1ff;\r
284 }\r
285\r
286 if (TotalSize > MAX_OPTION_ROM_SIZE) {\r
287 Error (NULL, 0, 3001, "Invalid", "Option ROM image %s size exceeds limit of 0x%X bytes.", InFile->FileName, MAX_OPTION_ROM_SIZE);\r
288 Status = STATUS_ERROR;\r
289 goto BailOut;\r
290 }\r
291 //\r
292 // Return the size to the caller so they can keep track of the running total.\r
293 //\r
294 *Size = TotalSize;\r
295\r
296 //\r
297 // Crude check to make sure it's a legitimate ROM image\r
298 //\r
299 RomHdr = (PCI_EXPANSION_ROM_HEADER *) Buffer;\r
300 if (RomHdr->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
301 Error (NULL, 0, 2000, "Invalid parameter", "ROM image file has an invalid ROM signature.");\r
302 Status = STATUS_ERROR;\r
303 goto BailOut;\r
304 }\r
305 //\r
306 // Make sure the pointer to the PCI data structure is within the size of the image.\r
307 // Then check it for valid signature.\r
308 //\r
309 if ((RomHdr->PcirOffset > FileSize) || (RomHdr->PcirOffset == 0)) {\r
310 Error (NULL, 0, 2000, "Invalid parameter", "Invalid PCI data structure offset.");\r
311 Status = STATUS_ERROR;\r
312 goto BailOut;\r
313 }\r
314\r
315 //\r
316 // Check the header is conform to PCI2.3 or PCI3.0\r
317 //\r
318 if (mOptions.Pci23 == 1) {\r
319 PciDs23 = (PCI_DATA_STRUCTURE *) (Buffer + RomHdr->PcirOffset);\r
320 if (PciDs23->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {\r
321 Error (NULL, 0, 2000, "Invalid parameter", "PCI data structure has an invalid signature.");\r
322 Status = STATUS_ERROR;\r
323 goto BailOut;\r
324 }\r
325 } else {\r
326 //\r
327 // Default setting is PCI3.0 header\r
328 //\r
329 PciDs30 = (PCI_3_0_DATA_STRUCTURE *)(Buffer + RomHdr->PcirOffset);\r
330 if (PciDs30->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {\r
331 Error (NULL, 0, 2000, "Invalid parameter", "PCI data structure has an invalid signature.");\r
332 Status = STATUS_ERROR;\r
333 goto BailOut;\r
334 }\r
335 }\r
336\r
337 //\r
338 // ReSet Option Rom size\r
339 //\r
340 if (mOptions.Pci23 == 1) {\r
341 PciDs23->ImageLength = (UINT16) (TotalSize / 512);\r
2bc3256c 342 CodeType = PciDs23->CodeType;\r
30fdf114
LG
343 } else {\r
344 PciDs30->ImageLength = (UINT16) (TotalSize / 512);\r
2bc3256c 345 CodeType = PciDs30->CodeType;\r
30fdf114
LG
346 }\r
347\r
348 //\r
349 // If this is the last image, then set the LAST bit unless requested not\r
350 // to via the command-line -n argument. Otherwise, make sure you clear it.\r
351 //\r
352 if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) {\r
353 if (mOptions.Pci23 == 1) {\r
354 PciDs23->Indicator = INDICATOR_LAST;\r
355 } else {\r
356 PciDs30->Indicator = INDICATOR_LAST;\r
357 }\r
358 } else {\r
359 if (mOptions.Pci23 == 1) {\r
360 PciDs23->Indicator = 0;\r
361 } else {\r
362 PciDs30->Indicator = 0;\r
363 }\r
364 }\r
365\r
2bc3256c
LG
366 if (CodeType != PCI_CODE_TYPE_EFI_IMAGE) {\r
367 ByteCheckSum = 0;\r
368 for (Index = 0; Index < FileSize - 1; Index++) {\r
369 ByteCheckSum = (UINT8) (ByteCheckSum + Buffer[Index]);\r
370 }\r
30fdf114 371\r
2bc3256c
LG
372 Buffer[FileSize - 1] = (UINT8) ((~ByteCheckSum) + 1);\r
373 if (mOptions.Verbose) {\r
374 VerboseMsg(" Checksum = %02x\n\n", Buffer[FileSize - 1]);\r
375 }\r
30fdf114
LG
376 }\r
377\r
378 //\r
379 // Now copy the input file contents out to the output file\r
380 //\r
381 if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) {\r
382 Error (NULL, 0, 0005, "Failed to write all file bytes to output file.", NULL);\r
383 Status = STATUS_ERROR;\r
384 goto BailOut;\r
385 }\r
386\r
387 TotalSize -= FileSize;\r
388 //\r
389 // Pad the rest of the image to make it a multiple of 512 bytes\r
390 //\r
391 while (TotalSize > 0) {\r
392 putc (~0, OutFptr);\r
393 TotalSize--;\r
394 }\r
395\r
396BailOut:\r
397 if (InFptr != NULL) {\r
398 fclose (InFptr);\r
399 }\r
400\r
401 if (Buffer != NULL) {\r
402 free (Buffer);\r
403 }\r
404 //\r
405 // Print the file name if errors occurred\r
406 //\r
407 if (Status != STATUS_SUCCESS) {\r
408 Error (NULL, 0, 0003, "Error", "Error parsing file: %s", InFile->FileName);\r
409 }\r
410\r
411 return Status;\r
412}\r
413\r
414static\r
415int\r
416ProcessEfiFile (\r
417 FILE *OutFptr,\r
418 FILE_LIST *InFile,\r
419 UINT16 VendId,\r
420 UINT16 DevId,\r
421 UINT32 *Size\r
422 )\r
423/*++\r
424\r
425Routine Description:\r
426 \r
427 Process a PE32 EFI file.\r
428\r
429Arguments:\r
430\r
431 OutFptr - file pointer to output binary ROM image file we're creating\r
432 InFile - structure contains information on the PE32 file to process\r
433 VendId - vendor ID as required in the option ROM header\r
434 DevId - device ID as required in the option ROM header\r
435 Size - pointer to where to return the size added to the output file\r
436\r
437Returns:\r
438\r
439 0 - successful\r
440\r
441--*/\r
442{\r
443 UINT32 Status;\r
444 FILE *InFptr;\r
445 EFI_PCI_EXPANSION_ROM_HEADER RomHdr;\r
446 PCI_DATA_STRUCTURE PciDs23;\r
447 PCI_3_0_DATA_STRUCTURE PciDs30;\r
448 UINT32 FileSize;\r
449 UINT32 CompressedFileSize;\r
450 UINT8 *Buffer;\r
451 UINT8 *CompressedBuffer;\r
452 UINT8 *TempBufferPtr;\r
453 UINT32 TotalSize;\r
454 UINT32 HeaderSize;\r
455 UINT16 MachineType;\r
456 UINT16 SubSystem;\r
457 UINT32 HeaderPadBytes;\r
2bc3256c
LG
458 UINT32 PadBytesBeforeImage;\r
459 UINT32 PadBytesAfterImage;\r
9f3a38cd 460 UINT32 DevIdListSize;\r
30fdf114
LG
461\r
462 //\r
463 // Try to open the input file\r
464 //\r
1be2ed90 465 if ((InFptr = fopen (LongFilePath (InFile->FileName), "rb")) == NULL) {\r
30fdf114
LG
466 Error (NULL, 0, 0001, "Open file error", "Error opening file: %s", InFile->FileName);\r
467 return STATUS_ERROR;\r
468 }\r
469 //\r
470 // Initialize our buffer pointers to null.\r
471 //\r
472 Buffer = NULL;\r
473 CompressedBuffer = NULL;\r
474\r
475 //\r
476 // Double-check the file to make sure it's what we expect it to be\r
477 //\r
478 Status = CheckPE32File (InFptr, &MachineType, &SubSystem);\r
479 if (Status != STATUS_SUCCESS) {\r
480 goto BailOut;\r
481 }\r
482 //\r
483 // Seek to the end of the input file and get the file size\r
484 //\r
485 fseek (InFptr, 0, SEEK_END);\r
486 FileSize = ftell (InFptr);\r
487\r
488 //\r
489 // Get the size of the headers we're going to put in front of the image. The\r
490 // EFI header must be aligned on a 4-byte boundary, so pad accordingly.\r
491 //\r
492 if (sizeof (RomHdr) & 0x03) {\r
493 HeaderPadBytes = 4 - (sizeof (RomHdr) & 0x03);\r
494 } else {\r
495 HeaderPadBytes = 0;\r
496 }\r
497 \r
498 //\r
499 // For Pci3.0 to use the different data structure.\r
500 //\r
501 if (mOptions.Pci23 == 1) {\r
502 HeaderSize = sizeof (PCI_DATA_STRUCTURE) + HeaderPadBytes + sizeof (EFI_PCI_EXPANSION_ROM_HEADER);\r
503 } else {\r
9f3a38cd
DV
504 if (mOptions.DevIdCount > 1) {\r
505 //\r
506 // Write device ID list when more than one device ID is specified.\r
507 // Leave space for list plus terminator.\r
508 //\r
509 DevIdListSize = (mOptions.DevIdCount + 1) * sizeof (UINT16);\r
510 } else {\r
511 DevIdListSize = 0;\r
512 }\r
513 HeaderSize = sizeof (PCI_3_0_DATA_STRUCTURE) + HeaderPadBytes + DevIdListSize + sizeof (EFI_PCI_EXPANSION_ROM_HEADER);\r
30fdf114
LG
514 }\r
515\r
516 if (mOptions.Verbose) {\r
fd171542 517 VerboseMsg(" File size = 0x%X\n", (unsigned) FileSize);\r
30fdf114
LG
518 }\r
519 //\r
520 // Allocate memory for the entire file (in case we have to compress), then\r
521 // seek back to the beginning of the file and read it into our buffer.\r
522 //\r
523 Buffer = (UINT8 *) malloc (FileSize);\r
524 if (Buffer == NULL) {\r
525 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
526 Status = STATUS_ERROR;\r
527 goto BailOut;\r
528 }\r
529\r
530 fseek (InFptr, 0, SEEK_SET);\r
531 if (fread (Buffer, FileSize, 1, InFptr) != 1) {\r
532 Error (NULL, 0, 0004, "Error reading file", "File %s", InFile->FileName);\r
533 Status = STATUS_ERROR;\r
534 goto BailOut;\r
535 }\r
536 //\r
537 // Now determine the size of the final output file. It's either the header size\r
538 // plus the file's size, or the header size plus the compressed file size.\r
539 //\r
540 if ((InFile->FileFlags & FILE_FLAG_COMPRESS) != 0) {\r
541 //\r
542 // Allocate a buffer into which we can compress the image, compress it,\r
543 // and use that size as the new size.\r
544 //\r
545 CompressedBuffer = (UINT8 *) malloc (FileSize);\r
546 if (CompressedBuffer == NULL) {\r
547 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
548 Status = STATUS_ERROR;\r
549 goto BailOut;\r
550 }\r
551\r
552 CompressedFileSize = FileSize;\r
553 Status = EfiCompress (Buffer, FileSize, CompressedBuffer, &CompressedFileSize);\r
554 if (Status != STATUS_SUCCESS) {\r
555 Error (NULL, 0, 0007, "Error compressing file!", NULL);\r
556 goto BailOut;\r
557 }\r
558 //\r
559 // Now compute the size, then swap buffer pointers.\r
560 //\r
561 if (mOptions.Verbose) {\r
fd171542 562 VerboseMsg(" Comp size = 0x%X\n", (unsigned) CompressedFileSize);\r
30fdf114
LG
563 }\r
564\r
565 TotalSize = CompressedFileSize + HeaderSize;\r
566 FileSize = CompressedFileSize;\r
567 TempBufferPtr = Buffer;\r
568 Buffer = CompressedBuffer;\r
569 CompressedBuffer = TempBufferPtr;\r
570 } else {\r
571 TotalSize = FileSize + HeaderSize;\r
572 }\r
573 //\r
574 // Total size must be an even multiple of 512 bytes\r
575 //\r
576 if (TotalSize & 0x1FF) {\r
577 TotalSize = (TotalSize + 0x200) &~0x1ff;\r
578 }\r
579 //\r
2bc3256c
LG
580 // Workaround:\r
581 // If compressed, put the pad bytes after the image,\r
582 // else put the pad bytes before the image.\r
583 //\r
584 if ((InFile->FileFlags & FILE_FLAG_COMPRESS) != 0) {\r
585 PadBytesBeforeImage = 0;\r
586 PadBytesAfterImage = TotalSize - (FileSize + HeaderSize);\r
587 } else {\r
588 PadBytesBeforeImage = TotalSize - (FileSize + HeaderSize);\r
589 PadBytesAfterImage = 0;\r
590 }\r
591 //\r
30fdf114
LG
592 // Check size\r
593 //\r
594 if (TotalSize > MAX_OPTION_ROM_SIZE) {\r
595 Error (NULL, 0, 2000, "Invalid", "Option ROM image %s size exceeds limit of 0x%X bytes.", InFile->FileName, MAX_OPTION_ROM_SIZE); \r
596 Status = STATUS_ERROR;\r
597 goto BailOut;\r
598 }\r
599 //\r
600 // Return the size to the caller so they can keep track of the running total.\r
601 //\r
602 *Size = TotalSize;\r
603\r
604 //\r
605 // Now fill in the ROM header. These values come from chapter 18 of the\r
606 // EFI 1.02 specification.\r
607 //\r
608 memset (&RomHdr, 0, sizeof (RomHdr));\r
609 RomHdr.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE;\r
610 RomHdr.InitializationSize = (UINT16) (TotalSize / 512);\r
611 RomHdr.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE;\r
612 RomHdr.EfiSubsystem = SubSystem;\r
613 RomHdr.EfiMachineType = MachineType;\r
2bc3256c 614 RomHdr.EfiImageHeaderOffset = (UINT16) (HeaderSize + PadBytesBeforeImage);\r
30fdf114
LG
615 RomHdr.PcirOffset = (UINT16) (sizeof (RomHdr) + HeaderPadBytes);\r
616 //\r
617 // Set image as compressed or not\r
618 //\r
619 if (InFile->FileFlags & FILE_FLAG_COMPRESS) {\r
620 RomHdr.CompressionType = EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED;\r
621 }\r
622 //\r
623 // Fill in the PCI data structure\r
624 //\r
625 if (mOptions.Pci23 == 1) {\r
626 memset (&PciDs23, 0, sizeof (PCI_DATA_STRUCTURE));\r
627 } else {\r
628 memset (&PciDs30, 0, sizeof (PCI_3_0_DATA_STRUCTURE));\r
629 }\r
630\r
631 if (mOptions.Pci23 == 1) {\r
632 PciDs23.Signature = PCI_DATA_STRUCTURE_SIGNATURE;\r
633 PciDs23.VendorId = VendId;\r
634 PciDs23.DeviceId = DevId;\r
635 PciDs23.Length = (UINT16) sizeof (PCI_DATA_STRUCTURE);\r
636 PciDs23.Revision = 0;\r
637 //\r
638 // Class code and code revision from the command line (optional)\r
639 //\r
640 PciDs23.ClassCode[0] = (UINT8) InFile->ClassCode;\r
641 PciDs23.ClassCode[1] = (UINT8) (InFile->ClassCode >> 8);\r
642 PciDs23.ClassCode[2] = (UINT8) (InFile->ClassCode >> 16);\r
643 PciDs23.ImageLength = RomHdr.InitializationSize;\r
644 PciDs23.CodeRevision = InFile->CodeRevision;\r
645 PciDs23.CodeType = PCI_CODE_TYPE_EFI_IMAGE;\r
646 } else {\r
647 PciDs30.Signature = PCI_DATA_STRUCTURE_SIGNATURE;\r
648 PciDs30.VendorId = VendId;\r
649 PciDs30.DeviceId = DevId;\r
9f3a38cd
DV
650 if (mOptions.DevIdCount > 1) {\r
651 //\r
652 // Place device list immediately after PCI structure\r
653 //\r
654 PciDs30.DeviceListOffset = (UINT16) sizeof (PCI_3_0_DATA_STRUCTURE);\r
655 } else {\r
656 PciDs30.DeviceListOffset = 0;\r
657 }\r
30fdf114
LG
658 PciDs30.Length = (UINT16) sizeof (PCI_3_0_DATA_STRUCTURE);\r
659 PciDs30.Revision = 0x3;\r
660 //\r
661 // Class code and code revision from the command line (optional)\r
662 //\r
663 PciDs30.ClassCode[0] = (UINT8) InFile->ClassCode;\r
664 PciDs30.ClassCode[1] = (UINT8) (InFile->ClassCode >> 8);\r
665 PciDs30.ClassCode[2] = (UINT8) (InFile->ClassCode >> 16);\r
666 PciDs30.ImageLength = RomHdr.InitializationSize;\r
667 PciDs30.CodeRevision = InFile->CodeRevision;\r
668 PciDs30.CodeType = PCI_CODE_TYPE_EFI_IMAGE;\r
669 PciDs30.MaxRuntimeImageLength = 0; // to be fixed\r
670 PciDs30.ConfigUtilityCodeHeaderOffset = 0; // to be fixed\r
671 PciDs30.DMTFCLPEntryPointOffset = 0; // to be fixed\r
672 }\r
673 //\r
674 // If this is the last image, then set the LAST bit unless requested not\r
675 // to via the command-line -n argument.\r
676 //\r
677 if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) {\r
678 if (mOptions.Pci23 == 1) {\r
679 PciDs23.Indicator = INDICATOR_LAST;\r
680 } else {\r
681 PciDs30.Indicator = INDICATOR_LAST;}\r
682 } else {\r
683 if (mOptions.Pci23 == 1) {\r
684 PciDs23.Indicator = 0;\r
685 } else {\r
686 PciDs30.Indicator = 0;\r
687 }\r
688 }\r
689 //\r
690 // Write the ROM header to the output file\r
691 //\r
692 if (fwrite (&RomHdr, sizeof (RomHdr), 1, OutFptr) != 1) {\r
693 Error (NULL, 0, 0002, "Failed to write ROM header to output file!", NULL);\r
694 Status = STATUS_ERROR;\r
695 goto BailOut;\r
696 }\r
697\r
698 //\r
699 // Write pad bytes to align the PciDs\r
700 //\r
701 while (HeaderPadBytes > 0) {\r
702 if (putc (0, OutFptr) == EOF) {\r
703 Error (NULL, 0, 0002, "Failed to write ROM header pad bytes to output file!", NULL);\r
704 Status = STATUS_ERROR;\r
705 goto BailOut;\r
706 }\r
707\r
708 HeaderPadBytes--;\r
709 }\r
710 //\r
711 // Write the PCI data structure header to the output file\r
712 //\r
713 if (mOptions.Pci23 == 1) {\r
714 if (fwrite (&PciDs23, sizeof (PciDs23), 1, OutFptr) != 1) {\r
715 Error (NULL, 0, 0002, "Failed to write PCI ROM header to output file!", NULL);\r
716 Status = STATUS_ERROR;\r
717 goto BailOut;\r
718 } \r
719 } else {\r
720 if (fwrite (&PciDs30, sizeof (PciDs30), 1, OutFptr) != 1) {\r
721 Error (NULL, 0, 0002, "Failed to write PCI ROM header to output file!", NULL);\r
722 Status = STATUS_ERROR;\r
723 goto BailOut;\r
724 } \r
725 }\r
2bc3256c 726\r
9f3a38cd
DV
727 //\r
728 // Write the Device ID list to the output file\r
729 //\r
730 if (mOptions.DevIdCount > 1) {\r
731 if (fwrite (mOptions.DevIdList, sizeof (UINT16), mOptions.DevIdCount, OutFptr) != mOptions.DevIdCount) {\r
732 Error (NULL, 0, 0002, "Failed to write PCI device list to output file!", NULL);\r
733 Status = STATUS_ERROR;\r
734 goto BailOut;\r
735 }\r
736 //\r
737 // Write two-byte terminating 0 at the end of the device list\r
738 //\r
739 if (putc (0, OutFptr) == EOF || putc (0, OutFptr) == EOF) {\r
740 Error (NULL, 0, 0002, "Failed to write PCI device list to output file!", NULL);\r
741 Status = STATUS_ERROR;\r
742 goto BailOut;\r
743 }\r
744 }\r
745\r
746\r
30fdf114 747 //\r
2bc3256c 748 // Pad head to make it a multiple of 512 bytes\r
30fdf114 749 //\r
2bc3256c
LG
750 while (PadBytesBeforeImage > 0) {\r
751 if (putc (~0, OutFptr) == EOF) {\r
752 Error (NULL, 0, 2000, "Failed to write trailing pad bytes output file!", NULL);\r
753 Status = STATUS_ERROR;\r
754 goto BailOut;\r
755 }\r
756 PadBytesBeforeImage--;\r
757 }\r
30fdf114
LG
758 //\r
759 // Now dump the input file's contents to the output file\r
760 //\r
761 if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) {\r
762 Error (NULL, 0, 0002, "Failed to write all file bytes to output file!", NULL);\r
763 Status = STATUS_ERROR;\r
764 goto BailOut;\r
765 }\r
766\r
30fdf114
LG
767 //\r
768 // Pad the rest of the image to make it a multiple of 512 bytes\r
769 //\r
2bc3256c 770 while (PadBytesAfterImage > 0) {\r
30fdf114
LG
771 if (putc (~0, OutFptr) == EOF) {\r
772 Error (NULL, 0, 2000, "Failed to write trailing pad bytes output file!", NULL);\r
773 Status = STATUS_ERROR;\r
774 goto BailOut;\r
775 }\r
776\r
2bc3256c 777 PadBytesAfterImage--;\r
30fdf114
LG
778 }\r
779\r
780BailOut:\r
781 if (InFptr != NULL) {\r
782 fclose (InFptr);\r
783 }\r
784 //\r
785 // Free up our buffers\r
786 //\r
787 if (Buffer != NULL) {\r
788 free (Buffer);\r
789 }\r
790\r
791 if (CompressedBuffer != NULL) {\r
792 free (CompressedBuffer);\r
793 }\r
794 //\r
795 // Print the file name if errors occurred\r
796 //\r
797 if (Status != STATUS_SUCCESS) {\r
798 Error (NULL, 0, 0003, "Error parsing", "Error parsing file: %s", InFile->FileName);\r
799 }\r
800\r
801 return Status;\r
802}\r
803\r
804static\r
805int\r
806CheckPE32File (\r
807 FILE *Fptr,\r
808 UINT16 *MachineType,\r
809 UINT16 *SubSystem\r
810 )\r
811/*++\r
812\r
813Routine Description:\r
814 \r
815 Given a file pointer to a supposed PE32 image file, verify that it is indeed a\r
816 PE32 image file, and then return the machine type in the supplied pointer.\r
817\r
818Arguments:\r
819\r
820 Fptr File pointer to the already-opened PE32 file\r
821 MachineType Location to stuff the machine type of the PE32 file. This is needed\r
822 because the image may be Itanium-based, IA32, or EBC.\r
823\r
824Returns:\r
825\r
826 0 success\r
827 non-zero otherwise\r
828\r
829--*/\r
830{\r
831 EFI_IMAGE_DOS_HEADER DosHeader;\r
832 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr;\r
833\r
834 //\r
835 // Position to the start of the file\r
836 //\r
837 fseek (Fptr, 0, SEEK_SET);\r
838\r
839 //\r
840 // Read the DOS header\r
841 //\r
842 if (fread (&DosHeader, sizeof (DosHeader), 1, Fptr) != 1) {\r
843 Error (NULL, 0, 0004, "Failed to read the DOS stub from the input file!", NULL);\r
844 return STATUS_ERROR;\r
845 }\r
846 //\r
847 // Check the magic number (0x5A4D)\r
848 //\r
849 if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
850 Error (NULL, 0, 2000, "Invalid parameter", "Input file does not appear to be a PE32 image (magic number)!");\r
851 return STATUS_ERROR;\r
852 }\r
853 //\r
854 // Position into the file and check the PE signature\r
855 //\r
856 fseek (Fptr, (long) DosHeader.e_lfanew, SEEK_SET);\r
857\r
858 //\r
859 // Read PE headers\r
860 //\r
861 if (fread (&PeHdr, sizeof (PeHdr), 1, Fptr) != 1) {\r
862 Error (NULL, 0, 0004, "Failed to read PE/COFF headers from input file!", NULL);\r
863 return STATUS_ERROR;\r
864 }\r
865\r
866\r
867 //\r
868 // Check the PE signature in the header "PE\0\0"\r
869 //\r
870 if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {\r
871 Error (NULL, 0, 2000, "Invalid parameter", "Input file does not appear to be a PE32 image (signature)!");\r
872 return STATUS_ERROR;\r
873 }\r
874\r
875 memcpy ((char *) MachineType, &PeHdr.Pe32.FileHeader.Machine, 2);\r
876\r
877 if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
878 *SubSystem = PeHdr.Pe32.OptionalHeader.Subsystem;\r
879 } else if (PeHdr.Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
880 *SubSystem = PeHdr.Pe32Plus.OptionalHeader.Subsystem;\r
881 } else {\r
882 Error (NULL, 0, 2000, "Invalid parameter", "Unable to find subsystem type!");\r
883 return STATUS_ERROR;\r
884 }\r
885\r
886 if (mOptions.Verbose) {\r
fd171542 887 VerboseMsg(" Got subsystem = 0x%X from image\n", *SubSystem);\r
30fdf114
LG
888 }\r
889\r
890 //\r
891 // File was successfully identified as a PE32\r
892 //\r
893 return STATUS_SUCCESS;\r
894}\r
895\r
896static\r
897int\r
898ParseCommandLine (\r
899 int Argc,\r
900 char *Argv[],\r
901 OPTIONS *Options\r
902 )\r
903/*++\r
904\r
905Routine Description:\r
906 \r
907 Given the Argc/Argv program arguments, and a pointer to an options structure,\r
908 parse the command-line options and check their validity.\r
909\r
910\r
911Arguments:\r
912\r
913 Argc - standard C main() argument count\r
914 Argv[] - standard C main() argument list\r
915 Options - pointer to a structure to store the options in\r
916\r
917Returns:\r
918\r
919 STATUS_SUCCESS success\r
920 non-zero otherwise\r
921\r
922--*/\r
923{\r
924 FILE_LIST *FileList;\r
925 FILE_LIST *PrevFileList;\r
926 UINT32 FileFlags;\r
927 UINT32 ClassCode;\r
928 UINT32 CodeRevision;\r
929 EFI_STATUS Status;\r
fb4ea38c 930 INTN ReturnStatus;\r
30fdf114
LG
931 BOOLEAN EfiRomFlag;\r
932 UINT64 TempValue;\r
9f3a38cd
DV
933 char *OptionName;\r
934 UINT16 *DevIdList;\r
30fdf114 935\r
fb4ea38c 936 ReturnStatus = 0;\r
30fdf114
LG
937 FileFlags = 0;\r
938 EfiRomFlag = FALSE;\r
939\r
940 //\r
941 // Clear out the options\r
942 //\r
943 memset ((char *) Options, 0, sizeof (OPTIONS));\r
944\r
945 //\r
946 // To avoid compile warnings\r
947 //\r
948 FileList = PrevFileList = NULL;\r
949\r
9f3a38cd
DV
950 Options->DevIdList = NULL;\r
951 Options->DevIdCount = 0;\r
952\r
30fdf114
LG
953 ClassCode = 0;\r
954 CodeRevision = 0;\r
955 //\r
956 // Skip over the program name\r
957 //\r
958 Argc--;\r
959 Argv++;\r
960\r
961 //\r
962 // If no arguments, assume they want usage info\r
963 //\r
964 if (Argc == 0) {\r
965 Usage ();\r
966 return STATUS_ERROR;\r
967 }\r
968 \r
969 if ((stricmp(Argv[0], "-h") == 0) || (stricmp(Argv[0], "--help") == 0)) {\r
970 Usage();\r
971 return STATUS_ERROR;\r
972 }\r
973 \r
974 if ((stricmp(Argv[0], "--version") == 0)) {\r
975 Version();\r
976 return STATUS_ERROR;\r
977 }\r
978\r
979 //\r
980 // Process until no more arguments\r
981 //\r
982 while (Argc > 0) {\r
983 if (Argv[0][0] == '-') {\r
984 //\r
985 // Vendor ID specified with -f\r
986 //\r
987 if (stricmp (Argv[0], "-f") == 0) {\r
988 //\r
989 // Make sure there's another parameter\r
990 //\r
991 Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);\r
992 if (EFI_ERROR (Status)) {\r
993 Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);\r
fb4ea38c
HW
994 ReturnStatus = 1;\r
995 goto Done;\r
30fdf114
LG
996 }\r
997 if (TempValue >= 0x10000) {\r
998 Error (NULL, 0, 2000, "Invalid option value", "Vendor Id %s out of range!", Argv[1]);\r
fb4ea38c
HW
999 ReturnStatus = 1;\r
1000 goto Done;\r
30fdf114
LG
1001 }\r
1002 Options->VendId = (UINT16) TempValue;\r
1003 Options->VendIdValid = 1;\r
1004\r
1005 Argv++;\r
1006 Argc--;\r
1007 } else if (stricmp (Argv[0], "-i") == 0) {\r
9f3a38cd
DV
1008\r
1009 OptionName = Argv[0];\r
1010\r
30fdf114 1011 //\r
9f3a38cd
DV
1012 // Device IDs specified with -i\r
1013 // Make sure there's at least one more parameter\r
30fdf114 1014 //\r
9f3a38cd
DV
1015 if (Argc < 1) {\r
1016 Error (NULL, 0, 2000, "Invalid parameter", "Missing Device Id with %s option!", OptionName);\r
fb4ea38c
HW
1017 ReturnStatus = 1;\r
1018 goto Done;\r
30fdf114 1019 }\r
9f3a38cd
DV
1020\r
1021 //\r
1022 // Process until another dash-argument parameter or the end of the list\r
1023 //\r
1024 while (Argc > 1 && Argv[1][0] != '-') {\r
1025 Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);\r
1026 if (EFI_ERROR (Status)) {\r
1027 Error (NULL, 0, 2000, "Invalid option value", "%s = %s", OptionName, Argv[1]);\r
1028 ReturnStatus = 1;\r
1029 goto Done;\r
1030 }\r
1031 //\r
1032 // Don't allow device IDs greater than 16 bits\r
1033 // Don't allow 0, since it is used as a list terminator\r
1034 //\r
1035 if (TempValue >= 0x10000 || TempValue == 0) {\r
1036 Error (NULL, 0, 2000, "Invalid option value", "Device Id %s out of range!", Argv[1]);\r
1037 ReturnStatus = 1;\r
1038 goto Done;\r
1039 }\r
1040\r
1041 DevIdList = (UINT16*) realloc (Options->DevIdList, (Options->DevIdCount + 1) * sizeof (UINT16));\r
1042 if (DevIdList == NULL) {\r
1043 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!", NULL);\r
1044 ReturnStatus = 1;\r
1045 goto Done;\r
1046 }\r
1047 Options->DevIdList = DevIdList;\r
1048\r
1049 Options->DevIdList[Options->DevIdCount++] = (UINT16) TempValue;\r
1050\r
1051 Argv++;\r
1052 Argc--;\r
30fdf114 1053 }\r
30fdf114 1054\r
30fdf114
LG
1055 } else if ((stricmp (Argv[0], "-o") == 0) || (stricmp (Argv[0], "--output") == 0)) {\r
1056 //\r
1057 // Output filename specified with -o\r
1058 // Make sure there's another parameter\r
1059 //\r
1060 if (Argv[1] == NULL || Argv[1][0] == '-') {\r
1061 Error (NULL, 0, 2000, "Invalid parameter", "Missing output file name with %s option!", Argv[0]);\r
fb4ea38c
HW
1062 ReturnStatus = STATUS_ERROR;\r
1063 goto Done;\r
30fdf114 1064 }\r
47affb48
HW
1065 if (strlen (Argv[1]) > MAX_PATH - 1) {\r
1066 Error (NULL, 0, 2000, "Invalid parameter", "Output file name %s is too long!", Argv[1]);\r
fb4ea38c
HW
1067 ReturnStatus = STATUS_ERROR;\r
1068 goto Done;\r
47affb48
HW
1069 }\r
1070 strncpy (Options->OutFileName, Argv[1], MAX_PATH - 1);\r
1071 Options->OutFileName[MAX_PATH - 1] = 0;\r
30fdf114
LG
1072\r
1073 Argv++;\r
1074 Argc--;\r
1075 } else if ((stricmp (Argv[0], "-h") == 0) || (stricmp (Argv[0], "--help") == 0)) {\r
1076 //\r
1077 // Help option\r
1078 //\r
1079 Usage ();\r
fb4ea38c
HW
1080 ReturnStatus = STATUS_ERROR;\r
1081 goto Done;\r
30fdf114
LG
1082 } else if (stricmp (Argv[0], "-b") == 0) {\r
1083 //\r
1084 // Specify binary files with -b\r
1085 //\r
1086 FileFlags = FILE_FLAG_BINARY;\r
1087 } else if ((stricmp (Argv[0], "-e") == 0) || (stricmp (Argv[0], "-ec") == 0)) {\r
1088 //\r
1089 // Specify EFI files with -e. Specify EFI-compressed with -c.\r
1090 //\r
1091 FileFlags = FILE_FLAG_EFI;\r
1092 if ((Argv[0][2] == 'c') || (Argv[0][2] == 'C')) {\r
1093 FileFlags |= FILE_FLAG_COMPRESS;\r
1094 }\r
1095 //\r
1096 // Specify not to set the LAST bit in the last file with -n\r
1097 //\r
1098 } else if (stricmp (Argv[0], "-n") == 0) {\r
1099 Options->NoLast = 1;\r
1100 } else if (((stricmp (Argv[0], "-v") == 0)) || ((stricmp (Argv[0], "--verbose") == 0))) {\r
1101 //\r
1102 // -v for verbose\r
1103 //\r
1104 Options->Verbose = 1;\r
1105 } else if (stricmp (Argv[0], "--debug") == 0) {\r
1106 Status = AsciiStringToUint64(Argv[1], FALSE, &DebugLevel);\r
1107 if (EFI_ERROR (Status)) {\r
1108 Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);\r
fb4ea38c
HW
1109 ReturnStatus = 1;\r
1110 goto Done;\r
30fdf114
LG
1111 }\r
1112 if (DebugLevel > 9) {\r
fd171542 1113 Error (NULL, 0, 2000, "Invalid option value", "Debug Level range is 0-9, current input level is %d", Argv[1]);\r
fb4ea38c
HW
1114 ReturnStatus = 1;\r
1115 goto Done;\r
30fdf114
LG
1116 }\r
1117 if (DebugLevel>=5 && DebugLevel<=9) {\r
1118 Options->Debug = TRUE;\r
1119 } else {\r
1120 Options->Debug = FALSE;\r
1121 }\r
1122 Argv++;\r
1123 Argc--;\r
1124 } else if ((stricmp (Argv[0], "--quiet") == 0) || (stricmp (Argv[0], "-q") == 0)) {\r
1125 Options->Quiet = TRUE;\r
1126 } else if ((stricmp (Argv[0], "--dump") == 0) || (stricmp (Argv[0], "-d") == 0)) {\r
1127 //\r
1128 // -dump for dumping a ROM image. In this case, say that the device id\r
1129 // and vendor id are valid so we don't have to specify bogus ones on the\r
1130 // command line.\r
1131 //\r
1132 Options->DumpOption = 1;\r
1133\r
1134 Options->VendIdValid = 1;\r
9f3a38cd 1135 Options->DevIdCount = 1;\r
30fdf114
LG
1136 FileFlags = FILE_FLAG_BINARY;\r
1137 } else if ((stricmp (Argv[0], "-l") == 0) || (stricmp (Argv[0], "--class-code") == 0)) {\r
1138 //\r
1139 // Class code value for the next file in the list.\r
1140 // Make sure there's another parameter\r
1141 //\r
1142 Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);\r
1143 if (EFI_ERROR (Status)) {\r
1144 Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);\r
fb4ea38c
HW
1145 ReturnStatus = 1;\r
1146 goto Done;\r
30fdf114
LG
1147 }\r
1148 ClassCode = (UINT32) TempValue;\r
1149 if (ClassCode & 0xFF000000) {\r
1150 Error (NULL, 0, 2000, "Invalid parameter", "Class code %s out of range!", Argv[1]);\r
fb4ea38c
HW
1151 ReturnStatus = STATUS_ERROR;\r
1152 goto Done;\r
30fdf114
LG
1153 }\r
1154 if (FileList != NULL && FileList->ClassCode == 0) {\r
1155 FileList->ClassCode = ClassCode;\r
1156 }\r
1157 Argv++;\r
1158 Argc--;\r
1159 } else if ((stricmp (Argv[0], "-r") == 0) || (stricmp (Argv[0], "--Revision") == 0)) {\r
1160 //\r
1161 // Code revision in the PCI data structure. The value is for the next\r
1162 // file in the list.\r
1163 // Make sure there's another parameter\r
1164 //\r
1165 Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);\r
1166 if (EFI_ERROR (Status)) {\r
1167 Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);\r
fb4ea38c
HW
1168 ReturnStatus = 1;\r
1169 goto Done;\r
30fdf114
LG
1170 }\r
1171 CodeRevision = (UINT32) TempValue;\r
1172 if (CodeRevision & 0xFFFF0000) {\r
1173 Error (NULL, 0, 2000, "Invalid parameter", "Code revision %s out of range!", Argv[1]);\r
fb4ea38c
HW
1174 ReturnStatus = STATUS_ERROR;\r
1175 goto Done;\r
30fdf114
LG
1176 }\r
1177 if (FileList != NULL && FileList->CodeRevision == 0) {\r
1178 FileList->CodeRevision = (UINT16) CodeRevision;\r
1179 }\r
1180 Argv++;\r
1181 Argc--;\r
1182 } else if ((stricmp (Argv[0], "-p") == 0) || (stricmp (Argv[0], "--pci23") == 0)) {\r
1183 //\r
1184 // Default layout meets PCI 3.0 specifications, specifying this flag will for a PCI 2.3 layout.\r
1185 //\r
1186 mOptions.Pci23 = 1;\r
1187 } else {\r
1188 Error (NULL, 0, 2000, "Invalid parameter", "Invalid option specified: %s", Argv[0]);\r
fb4ea38c
HW
1189 ReturnStatus = STATUS_ERROR;\r
1190 goto Done;\r
30fdf114
LG
1191 }\r
1192 } else {\r
1193 //\r
1194 // Not a slash-option argument. Must be a file name. Make sure they've specified\r
1195 // -e or -b already.\r
1196 //\r
1197 if ((FileFlags & (FILE_FLAG_BINARY | FILE_FLAG_EFI)) == 0) {\r
1198 Error (NULL, 0, 2000, "Invalid parameter", "Missing -e or -b with input file %s!", Argv[0]);\r
fb4ea38c
HW
1199 ReturnStatus = STATUS_ERROR;\r
1200 goto Done;\r
30fdf114
LG
1201 }\r
1202 //\r
1203 // Check Efi Option RomImage\r
1204 //\r
1205 if ((FileFlags & FILE_FLAG_EFI) == FILE_FLAG_EFI) {\r
1206 EfiRomFlag = TRUE;\r
1207 }\r
1208 //\r
1209 // Create a new file structure\r
1210 //\r
1211 FileList = (FILE_LIST *) malloc (sizeof (FILE_LIST));\r
1212 if (FileList == NULL) {\r
1213 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!", NULL);\r
fb4ea38c
HW
1214 ReturnStatus = STATUS_ERROR;\r
1215 goto Done;\r
30fdf114
LG
1216 }\r
1217 \r
1218 //\r
1219 // set flag and class code for this image.\r
1220 //\r
1221 memset ((char *) FileList, 0, sizeof (FILE_LIST));\r
1222 FileList->FileName = Argv[0];\r
1223 FileList->FileFlags = FileFlags;\r
1224 FileList->ClassCode = ClassCode;\r
1225 FileList->CodeRevision = (UINT16) CodeRevision;\r
1226 ClassCode = 0;\r
1227 CodeRevision = 0;\r
1228\r
1229 if (Options->FileList == NULL) {\r
1230 Options->FileList = FileList;\r
1231 } else {\r
1232 if (PrevFileList == NULL) {\r
1233 PrevFileList = FileList;\r
1234 } else { \r
1235 PrevFileList->Next = FileList;\r
1236 }\r
1237 }\r
1238\r
1239 PrevFileList = FileList;\r
1240 }\r
1241 //\r
1242 // Next argument\r
1243 //\r
1244 Argv++;\r
1245 Argc--;\r
1246 }\r
1247\r
1248 //\r
1249 // Must have specified some files\r
1250 //\r
1251 if (Options->FileList == NULL) {\r
1252 Error (NULL, 0, 2000, "Invalid parameter", "Missing input file name!");\r
fb4ea38c
HW
1253 //\r
1254 // No memory allocation, return directly.\r
1255 //\r
30fdf114
LG
1256 return STATUS_ERROR;\r
1257 }\r
1258\r
1259 //\r
1260 // For EFI OptionRom image, Make sure a device ID and vendor ID are both specified.\r
1261 //\r
1262 if (EfiRomFlag) {\r
1263 if (!Options->VendIdValid) {\r
1264 Error (NULL, 0, 2000, "Missing Vendor ID in command line", NULL);\r
fb4ea38c
HW
1265 ReturnStatus = STATUS_ERROR;\r
1266 goto Done;\r
30fdf114
LG
1267 }\r
1268 \r
9f3a38cd 1269 if (!Options->DevIdCount) {\r
30fdf114 1270 Error (NULL, 0, 2000, "Missing Device ID in command line", NULL);\r
fb4ea38c
HW
1271 ReturnStatus = STATUS_ERROR;\r
1272 goto Done;\r
1273 }\r
1274 }\r
1275\r
9f3a38cd
DV
1276 if (Options->DevIdCount > 1 && Options->Pci23) {\r
1277 Error (NULL, 0, 2000, "Invalid parameter", "PCI 3.0 is required when specifying multiple Device IDs");\r
1278 ReturnStatus = STATUS_ERROR;\r
1279 goto Done;\r
1280 }\r
1281\r
fb4ea38c
HW
1282Done:\r
1283 if (ReturnStatus != 0) {\r
1284 while (Options->FileList != NULL) {\r
1285 FileList = Options->FileList->Next;\r
1286 free (Options->FileList);\r
1287 Options->FileList = FileList;\r
30fdf114
LG
1288 }\r
1289 }\r
1290\r
fb4ea38c 1291 return ReturnStatus;\r
30fdf114
LG
1292}\r
1293\r
1294static\r
1295void\r
1296Version (\r
1297 VOID\r
1298 )\r
1299/*++\r
1300\r
1301Routine Description:\r
1302 \r
1303 Print version information for this utility.\r
1304\r
1305Arguments:\r
1306\r
1307 None.\r
1308\r
1309Returns:\r
1310\r
1311 Nothing.\r
1312--*/\r
1313{\r
b36d134f 1314 fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);\r
30fdf114
LG
1315}\r
1316 \r
1317static\r
1318void\r
1319Usage (\r
1320 VOID\r
1321 )\r
1322/*++\r
1323\r
1324Routine Description:\r
1325 \r
1326 Print usage information for this utility.\r
1327\r
1328Arguments:\r
1329\r
1330 None.\r
1331\r
1332Returns:\r
1333\r
1334 Nothing.\r
1335\r
1336--*/\r
1337{\r
1338 //\r
1339 // Summary usage\r
1340 //\r
d0acc87a 1341 fprintf (stdout, "Usage: %s -f VendorId -i DeviceId [options] [file name<s>] \n\n", UTILITY_NAME);\r
30fdf114
LG
1342 \r
1343 //\r
1344 // Copyright declaration\r
1345 // \r
ef6cd66a 1346 fprintf (stdout, "Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.\n\n");\r
30fdf114
LG
1347\r
1348 //\r
1349 // Details Option\r
1350 //\r
1351 fprintf (stdout, "Options:\n");\r
1352 fprintf (stdout, " -o FileName, --output FileName\n\\r
d0acc87a 1353 File will be created to store the output content.\n");\r
30fdf114
LG
1354 fprintf (stdout, " -e EfiFileName\n\\r
1355 EFI PE32 image files.\n");\r
1356 fprintf (stdout, " -ec EfiFileName\n\\r
1357 EFI PE32 image files and will be compressed.\n");\r
1358 fprintf (stdout, " -b BinFileName\n\\r
1359 Legacy binary files.\n");\r
1360 fprintf (stdout, " -l ClassCode\n\\r
1361 Hex ClassCode in the PCI data structure header.\n");\r
1362 fprintf (stdout, " -r Rev Hex Revision in the PCI data structure header.\n");\r
1363 fprintf (stdout, " -n Not to automatically set the LAST bit in the last file.\n");\r
1364 fprintf (stdout, " -f VendorId\n\\r
d0acc87a 1365 Hex PCI Vendor ID for the device OpROM, must be specified\n");\r
30fdf114 1366 fprintf (stdout, " -i DeviceId\n\\r
9f3a38cd 1367 One or more hex PCI Device IDs for the device OpROM, must be specified\n");\r
30fdf114
LG
1368 fprintf (stdout, " -p, --pci23\n\\r
1369 Default layout meets PCI 3.0 specifications\n\\r
1370 specifying this flag will for a PCI 2.3 layout.\n");\r
1371 fprintf (stdout, " -d, --dump\n\\r
1372 Dump the headers of an existing option ROM image.\n");\r
1373 fprintf (stdout, " -v, --verbose\n\\r
1374 Turn on verbose output with informational messages.\n");\r
1375 fprintf (stdout, " --version Show program's version number and exit.\n");\r
1376 fprintf (stdout, " -h, --help\n\\r
1377 Show this help message and exit.\n");\r
1378 fprintf (stdout, " -q, --quiet\n\\r
1379 Disable all messages except FATAL ERRORS.\n");\r
1380 fprintf (stdout, " --debug [#,0-9]\n\\r
1381 Enable debug messages at level #.\n"); \r
1382}\r
1383\r
1384static\r
1385void\r
1386DumpImage (\r
1387 FILE_LIST *InFile\r
1388 )\r
1389/*++\r
1390\r
1391Routine Description:\r
1392\r
1393 Dump the headers of an existing option ROM image\r
1394\r
1395Arguments:\r
1396\r
1397 InFile - the file name of an existing option ROM image\r
1398\r
1399Returns:\r
1400\r
1401 none\r
1402\r
1403--*/\r
1404{\r
1405 PCI_EXPANSION_ROM_HEADER PciRomHdr;\r
1406 FILE *InFptr;\r
1407 UINT32 ImageStart;\r
1408 UINT32 ImageCount;\r
1409 EFI_PCI_EXPANSION_ROM_HEADER EfiRomHdr;\r
1410 PCI_DATA_STRUCTURE PciDs23;\r
1411 PCI_3_0_DATA_STRUCTURE PciDs30;\r
9f3a38cd 1412 UINT16 DevId;\r
30fdf114
LG
1413\r
1414 //\r
1415 // Open the input file\r
1416 //\r
1be2ed90 1417 if ((InFptr = fopen (LongFilePath (InFile->FileName), "rb")) == NULL) {\r
30fdf114
LG
1418 Error (NULL, 0, 0001, "Error opening file", InFile->FileName);\r
1419 return ;\r
1420 }\r
1421 //\r
1422 // Go through the image and dump the header stuff for each\r
1423 //\r
1424 ImageCount = 0;\r
1425 for (;;) {\r
1426 //\r
1427 // Save our postition in the file, since offsets in the headers\r
1428 // are relative to the particular image.\r
1429 //\r
1430 ImageStart = ftell (InFptr);\r
1431 ImageCount++;\r
1432\r
1433 //\r
1434 // Read the option ROM header. Have to assume a raw binary image for now.\r
1435 //\r
1436 if (fread (&PciRomHdr, sizeof (PciRomHdr), 1, InFptr) != 1) {\r
1437 Error (NULL, 0, 3001, "Not supported", "Failed to read PCI ROM header from file!");\r
1438 goto BailOut;\r
1439 }\r
1440\r
1441 //\r
1442 // Dump the contents of the header\r
1443 //\r
fd171542 1444 fprintf (stdout, "Image %u -- Offset 0x%X\n", (unsigned) ImageCount, (unsigned) ImageStart);\r
30fdf114 1445 fprintf (stdout, " ROM header contents\n");\r
fd171542 1446 fprintf (stdout, " Signature 0x%04X\n", PciRomHdr.Signature);\r
1447 fprintf (stdout, " PCIR offset 0x%04X\n", PciRomHdr.PcirOffset);\r
30fdf114
LG
1448 //\r
1449 // Find PCI data structure\r
1450 //\r
1451 if (fseek (InFptr, ImageStart + PciRomHdr.PcirOffset, SEEK_SET)) {\r
1452 Error (NULL, 0, 3001, "Not supported", "Failed to seek to PCI data structure!");\r
1453 goto BailOut;\r
1454 }\r
1455 //\r
1456 // Read and dump the PCI data structure\r
1457 //\r
1458 memset (&PciDs23, 0, sizeof (PciDs23));\r
1459 memset (&PciDs30, 0, sizeof (PciDs30));\r
1460 if (mOptions.Pci23 == 1) {\r
1461 if (fread (&PciDs23, sizeof (PciDs23), 1, InFptr) != 1) {\r
1462 Error (NULL, 0, 3001, "Not supported", "Failed to read PCI data structure from file %s!", InFile->FileName);\r
1463 goto BailOut;\r
1464 }\r
1465 } else {\r
1466 if (fread (&PciDs30, sizeof (PciDs30), 1, InFptr) != 1) {\r
1467 Error (NULL, 0, 3001, "Not supported", "Failed to read PCI data structure from file %s!", InFile->FileName);\r
1468 goto BailOut;\r
1469 }\r
1470 }\r
1471 if (mOptions.Verbose) {\r
1472 VerboseMsg("Read PCI data structure from file %s", InFile->FileName);\r
1473 }\r
1474\r
1475 //fprintf (stdout, " PCI Data Structure\n");\r
1476 if (mOptions.Pci23 == 1) {\r
1477 fprintf (\r
1478 stdout,\r
1479 " Signature %c%c%c%c\n",\r
1480 (char) PciDs23.Signature,\r
1481 (char) (PciDs23.Signature >> 8),\r
1482 (char) (PciDs23.Signature >> 16),\r
1483 (char) (PciDs23.Signature >> 24)\r
1484 );\r
1485 fprintf (stdout, " Vendor ID 0x%04X\n", PciDs23.VendorId);\r
1486 fprintf (stdout, " Device ID 0x%04X\n", PciDs23.DeviceId);\r
1487 fprintf (stdout, " Length 0x%04X\n", PciDs23.Length);\r
1488 fprintf (stdout, " Revision 0x%04X\n", PciDs23.Revision);\r
1489 fprintf (\r
1490 stdout,\r
1491 " Class Code 0x%06X\n",\r
fd171542 1492 (unsigned) (PciDs23.ClassCode[0] | (PciDs23.ClassCode[1] << 8) | (PciDs23.ClassCode[2] << 16))\r
30fdf114 1493 );\r
fd171542 1494 fprintf (stdout, " Image size 0x%X\n", (unsigned) PciDs23.ImageLength * 512);\r
30fdf114 1495 fprintf (stdout, " Code revision: 0x%04X\n", PciDs23.CodeRevision);\r
fd171542 1496 fprintf (stdout, " Indicator 0x%02X", PciDs23.Indicator);\r
30fdf114
LG
1497 } else {\r
1498 fprintf (\r
1499 stdout,\r
1500 " Signature %c%c%c%c\n",\r
1501 (char) PciDs30.Signature,\r
1502 (char) (PciDs30.Signature >> 8),\r
1503 (char) (PciDs30.Signature >> 16),\r
1504 (char) (PciDs30.Signature >> 24)\r
1505 );\r
1506 fprintf (stdout, " Vendor ID 0x%04X\n", PciDs30.VendorId);\r
1507 fprintf (stdout, " Device ID 0x%04X\n", PciDs30.DeviceId);\r
1508 fprintf (stdout, " Length 0x%04X\n", PciDs30.Length);\r
1509 fprintf (stdout, " Revision 0x%04X\n", PciDs30.Revision);\r
fd171542 1510 fprintf (stdout, " DeviceListOffset 0x%02X\n", PciDs30.DeviceListOffset); \r
9f3a38cd
DV
1511 if (PciDs30.DeviceListOffset) {\r
1512 //\r
1513 // Print device ID list\r
1514 //\r
1515 fprintf (stdout, " Device list contents\n");\r
1516 if (fseek (InFptr, ImageStart + PciRomHdr.PcirOffset + PciDs30.DeviceListOffset, SEEK_SET)) {\r
1517 Error (NULL, 0, 3001, "Not supported", "Failed to seek to PCI device ID list!");\r
1518 goto BailOut;\r
1519 }\r
1520\r
1521 //\r
1522 // Loop until terminating 0\r
1523 //\r
1524 do {\r
1525 if (fread (&DevId, sizeof (DevId), 1, InFptr) != 1) {\r
1526 Error (NULL, 0, 3001, "Not supported", "Failed to read PCI device ID list from file %s!", InFile->FileName);\r
1527 goto BailOut;\r
1528 }\r
1529 if (DevId) {\r
1530 fprintf (stdout, " 0x%04X\n", DevId);\r
1531 }\r
1532 } while (DevId);\r
1533\r
1534 }\r
30fdf114
LG
1535 fprintf (\r
1536 stdout,\r
1537 " Class Code 0x%06X\n",\r
fd171542 1538 (unsigned) (PciDs30.ClassCode[0] | (PciDs30.ClassCode[1] << 8) | (PciDs30.ClassCode[2] << 16))\r
30fdf114 1539 );\r
fd171542 1540 fprintf (stdout, " Image size 0x%X\n", (unsigned) PciDs30.ImageLength * 512);\r
30fdf114 1541 fprintf (stdout, " Code revision: 0x%04X\n", PciDs30.CodeRevision);\r
fd171542 1542 fprintf (stdout, " MaxRuntimeImageLength 0x%02X\n", PciDs30.MaxRuntimeImageLength);\r
1543 fprintf (stdout, " ConfigUtilityCodeHeaderOffset 0x%02X\n", PciDs30.ConfigUtilityCodeHeaderOffset);\r
1544 fprintf (stdout, " DMTFCLPEntryPointOffset 0x%02X\n", PciDs30.DMTFCLPEntryPointOffset); \r
1545 fprintf (stdout, " Indicator 0x%02X", PciDs30.Indicator); \r
30fdf114
LG
1546 }\r
1547 //\r
1548 // Print the indicator, used to flag the last image\r
1549 //\r
1550 if (PciDs23.Indicator == INDICATOR_LAST || PciDs30.Indicator == INDICATOR_LAST) {\r
1551 fprintf (stdout, " (last image)\n");\r
1552 } else {\r
1553 fprintf (stdout, "\n");\r
1554 }\r
1555 //\r
1556 // Print the code type. If EFI code, then we can provide more info.\r
1557 //\r
1558 if (mOptions.Pci23 == 1) {\r
fd171542 1559 fprintf (stdout, " Code type 0x%02X", PciDs23.CodeType);\r
30fdf114 1560 } else {\r
fd171542 1561 fprintf (stdout, " Code type 0x%02X", PciDs30.CodeType); \r
30fdf114
LG
1562 }\r
1563 if (PciDs23.CodeType == PCI_CODE_TYPE_EFI_IMAGE || PciDs30.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {\r
1564 fprintf (stdout, " (EFI image)\n");\r
1565 //\r
1566 // Re-read the header as an EFI ROM header, then dump more info\r
1567 //\r
1568 fprintf (stdout, " EFI ROM header contents\n");\r
1569 if (fseek (InFptr, ImageStart, SEEK_SET)) {\r
1570 Error (NULL, 0, 5001, "Failed to re-seek to ROM header structure!", NULL);\r
1571 goto BailOut;\r
1572 }\r
1573\r
1574 if (fread (&EfiRomHdr, sizeof (EfiRomHdr), 1, InFptr) != 1) {\r
1575 Error (NULL, 0, 5001, "Failed to read EFI PCI ROM header from file!", NULL);\r
1576 goto BailOut;\r
1577 }\r
1578 //\r
1579 // Now dump more info\r
1580 //\r
fd171542 1581 fprintf (stdout, " EFI Signature 0x%04X\n", (unsigned) EfiRomHdr.EfiSignature);\r
30fdf114
LG
1582 fprintf (\r
1583 stdout,\r
1584 " Compression Type 0x%04X ",\r
fd171542 1585 EfiRomHdr.CompressionType\r
30fdf114
LG
1586 );\r
1587 if (EfiRomHdr.CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {\r
1588 fprintf (stdout, "(compressed)\n");\r
1589 } else {\r
1590 fprintf (stdout, "(not compressed)\n");\r
1591 }\r
1592\r
1593 fprintf (\r
1594 stdout,\r
1595 " Machine type 0x%04X (%s)\n",\r
1596 EfiRomHdr.EfiMachineType,\r
1597 GetMachineTypeStr (EfiRomHdr.EfiMachineType)\r
1598 );\r
1599 fprintf (\r
1600 stdout,\r
1601 " Subsystem 0x%04X (%s)\n",\r
1602 EfiRomHdr.EfiSubsystem,\r
1603 GetSubsystemTypeStr (EfiRomHdr.EfiSubsystem)\r
1604 );\r
1605 fprintf (\r
1606 stdout,\r
1607 " EFI image offset 0x%04X (@0x%X)\n",\r
fd171542 1608 EfiRomHdr.EfiImageHeaderOffset,\r
1609 EfiRomHdr.EfiImageHeaderOffset + (unsigned) ImageStart\r
30fdf114
LG
1610 );\r
1611\r
1612 } else {\r
1613 //\r
1614 // Not an EFI image\r
1615 //\r
1616 fprintf (stdout, "\n");\r
1617 }\r
1618 //\r
1619 // If code type is EFI image, then dump it as well?\r
1620 //\r
1621 // if (PciDs.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {\r
1622 // }\r
1623 //\r
1624 // If last image, then we're done\r
1625 //\r
1626 if (PciDs23.Indicator == INDICATOR_LAST || PciDs30.Indicator == INDICATOR_LAST) {\r
1627 goto BailOut;\r
1628 }\r
1629 //\r
1630 // Seek to the start of the next image\r
1631 //\r
1632 if (mOptions.Pci23 == 1) {\r
1633 if (fseek (InFptr, ImageStart + (PciDs23.ImageLength * 512), SEEK_SET)) {\r
1634 Error (NULL, 0, 3001, "Not supported", "Failed to seek to next image!");\r
1635 goto BailOut;\r
1636 }\r
1637 } else {\r
1638 if (fseek (InFptr, ImageStart + (PciDs30.ImageLength * 512), SEEK_SET)) {\r
1639 Error (NULL, 0, 3001, "Not supported", "Failed to seek to next image!");\r
1640 goto BailOut;\r
1641 }\r
1642 }\r
1643 }\r
1644\r
1645BailOut:\r
1646 fclose (InFptr);\r
1647}\r
1648\r
1649char *\r
1650GetMachineTypeStr (\r
1651 UINT16 MachineType\r
1652 )\r
1653/*++\r
1654\r
1655Routine Description:\r
1656\r
1657 GC_TODO: Add function description\r
1658\r
1659Arguments:\r
1660\r
1661 MachineType - GC_TODO: add argument description\r
1662\r
1663Returns:\r
1664\r
1665 GC_TODO: add return values\r
1666\r
1667--*/\r
1668{\r
1669 int Index;\r
1670\r
1671 for (Index = 0; mMachineTypes[Index].Name != NULL; Index++) {\r
1672 if (mMachineTypes[Index].Value == MachineType) {\r
1673 return mMachineTypes[Index].Name;\r
1674 }\r
1675 }\r
1676\r
1677 return "unknown";\r
1678}\r
1679\r
1680static\r
1681char *\r
1682GetSubsystemTypeStr (\r
1683 UINT16 SubsystemType\r
1684 )\r
1685/*++\r
1686\r
1687Routine Description:\r
1688\r
1689 GC_TODO: Add function description\r
1690\r
1691Arguments:\r
1692\r
1693 SubsystemType - GC_TODO: add argument description\r
1694\r
1695Returns:\r
1696\r
1697 GC_TODO: add return values\r
1698\r
1699--*/\r
1700{\r
1701 int Index;\r
1702\r
1703 for (Index = 0; mSubsystemTypes[Index].Name != NULL; Index++) {\r
1704 if (mSubsystemTypes[Index].Value == SubsystemType) {\r
1705 return mSubsystemTypes[Index].Name;\r
1706 }\r
1707 }\r
1708\r
1709 return "unknown";\r
1710}\r