3 Copyright (c) 2004, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Generate Dependency Expression ("GenDepex")
20 Infix to Postfix Algorithm
22 This code has been scrubbed to be free of having any EFI core tree dependencies.
23 It should build in any environment that supports a standard C-library w/ string
24 operations and File I/O services.
26 As an example of usage, consider the following:
28 The input user file could be something like "Sample.DXS" whose contents are
33 NOT (DISK_IO_PROTOCOL AND SIMPLE_FILE_SYSTEM_PROTOCOL)
34 OR EFI_PXE_BASE_CODE_PROTOCOL
37 This file is then washed through the C-preprocessor, viz.,
39 cl /EP Sample.DXS > Sample.TMP1
41 This yields the following file "Sample.TMP1" whose contents are
44 NOT ({ 0xce345171, 0xba0b, 0x11d2, 0x8e, 0x4f, 0x0, 0xa0, 0xc9, 0x69, 0x72,
45 0x3b } AND { 0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69,
46 0x72, 0x3b }) OR { 0x03c4e603, 0xac28, 0x11d3, 0x9a, 0x2d, 0x00, 0x90, 0x27,
50 This file, in turn, will be fed into the utility, viz.,
52 GenDepex Sample.TMP1 Sample.TMP2
54 With a file that is 55 bytes long:
56 55 bytes for the grammar binary
58 GUID Instance - 16 bytes
60 GUID Instance - 16 bytes
64 GUID Instance - 16 bytes
68 The file "Sample.TMP2" could be fed via a Section-builder utility
69 (GenSection) that would be used for the creation of a dependency
70 section file (.DPX) which in turn would be used by a generate FFS
71 utility (GenFfsFile) to produce a DXE driver/core (.DXE) or
72 a DXE application (.APP) file.
74 Complies with Tiano C Coding Standards Document, version 0.31, 12 Dec 2000.
80 #define TOOL_NAME "GenDepex"
89 PrintGenDepexUtilityInfo (
96 Displays the standard utility information to SDTOUT.
109 "%s, Tiano Dependency Expression Generation Utility. Version %d.%d.\n",
111 UTILITY_MAJOR_VERSION
,
112 UTILITY_MINOR_VERSION
114 printf ("Copyright (C) 1996-2002 Intel Corporation. All rights reserved.\n\n");
118 PrintGenDepexUsageInfo (
125 Displays the utility usage syntax to STDOUT.
138 "Usage: %s -I <INFILE> -O <OUTFILE> [-P <Optional Boundary for padding up>] \n",
141 printf (" Where:\n");
142 printf (" <INFILE> is the input pre-processed dependency text files name.\n");
143 printf (" <OUTFILE> is the output binary dependency files name.\n");
144 printf (" <Optional Boundary for padding up> is the padding integer value.\n");
145 printf (" This is the boundary to align the output file size to.\n");
156 Pop an element from the Opcode stack.
160 Stack Current top of the OpCode stack location
164 DEPENDENCY_OPCODE OpCode at the top of the OpCode stack.
165 Stack New top of the OpCode stack location
170 DEPENDENCY_OPCODE
*OpCodePtr
;
181 IN DEPENDENCY_OPCODE OpCode
187 Push an element onto the Opcode Stack
191 Stack Current top of the OpCode stack location
192 OpCode OpCode to push onto the stack
196 Stack New top of the OpCode stack location
200 DEPENDENCY_OPCODE
*OpCodePtr
;
209 GenerateDependencyExpression (
211 IN OUT
FILE *OutFile
,
212 IN INT8 Padding OPTIONAL
218 This takes the pre-compiled dependency text file and
219 converts it into a binary dependency file.
221 The BNF for the dependency expression is as follows
222 (from the DXE 1.0 Draft specification).
224 The inputted BNF grammar is thus:
225 <depex> ::= sor <dep> |
232 <bool> ::= <bool> and <term> |
236 <term> ::= not <factor> |
239 <factor> ::= ( <bool> ) |
247 The outputed binary grammer is thus:
248 <depex> ::= sor <dep> |
249 before <depinst> <dep> |
250 after <depinst> <dep> |
255 <bool> ::= <bool> and <term> |
256 <bool> or <term> | <term>
258 <term> ::= not <factor> |
261 <factor> ::= ( <bool> ) |
270 <depinst> ::= push GUID
274 BugBug: A correct grammer is parsed correctly. A file that violates the
275 grammer may parse when it should generate an error. There is some
276 error checking and it covers most of the case when it's an include
277 of definition issue. An ill formed expresion may not be detected.
281 InFile - Input pre-compiled text file of the dependency expression.
282 This needs to be in ASCII.
283 The file pointer can not be NULL.
285 OutFile - Binary dependency file.
286 The file pointer can not be NULL.
288 Padding - OPTIONAL integer value to pad the output file to.
293 EFI_SUCCESS The function completed successfully.
294 EFI_INVALID_PARAMETER One of the parameters in the text file was invalid.
295 EFI_OUT_OF_RESOURCES Unable to allocate memory.
296 EFI_ABORTED An misc error occurred.
302 INT8
*EvaluationStack
;
316 UINTN ArgCountParsed
;
317 DEPENDENCY_OPCODE Opcode
;
324 memset (Line
, 0, LINESIZE
);
328 EvaluationStack
= (INT8
*) malloc (EVAL_STACK_SIZE
);
330 if (EvaluationStack
!= NULL
) {
331 StackPtr
= EvaluationStack
;
333 printf ("Unable to allocate memory to EvaluationStack - Out of resources\n");
334 return EFI_OUT_OF_RESOURCES
;
337 Results
= (UINTN
) fseek (InFile
, 0, SEEK_END
);
340 printf ("FSEEK failed - Aborted\n");
344 FileSize
= ftell (InFile
);
346 if (FileSize
== -1L) {
347 printf ("FTELL failed - Aborted\n");
351 Buffer
= (INT8
*) malloc (FileSize
+ BUFFER_SIZE
);
353 if (Buffer
== NULL
) {
354 printf ("Unable to allocate memory to Buffer - Out of resources\n");
355 free (EvaluationStack
);
357 Results
= (UINTN
) fclose (InFile
);
359 printf ("FCLOSE failed\n");
362 Results
= (UINTN
) fclose (OutFile
);
364 printf ("FCLOSE failed\n");
367 return EFI_OUT_OF_RESOURCES
;
370 Results
= (UINTN
) fseek (InFile
, 0, SEEK_SET
);
373 printf ("FSEEK failed - Aborted\n");
377 fread (Buffer
, FileSize
, 1, InFile
);
380 Pend
= Ptrx
+ FileSize
- strlen (DEPENDENCY_END
);
384 while ((Index
--) && NotDone
) {
386 if (strncmp (Pend
, DEPENDENCY_END
, strlen (DEPENDENCY_END
)) == 0) {
394 printf ("Couldn't find end string %s\n", DEPENDENCY_END
);
396 Results
= (UINTN
) fclose (InFile
);
398 printf ("FCLOSE failed\n");
401 Results
= (UINTN
) fclose (OutFile
);
403 printf ("FCLOSE failed\n");
407 free (EvaluationStack
);
409 return EFI_INVALID_PARAMETER
;
415 while ((Index
--) && NotDone
) {
417 if (strncmp (Ptrx
, DEPENDENCY_START
, strlen (DEPENDENCY_START
)) == 0) {
418 Ptrx
+= sizeof (DEPENDENCY_START
);
421 // BUGBUG -- should Index be decremented by sizeof(DEPENDENCY_START)?
429 printf ("Couldn't find start string %s\n", DEPENDENCY_START
);
431 Results
= (UINTN
) fclose (InFile
);
433 printf ("FCLOSE failed\n");
436 Results
= (UINTN
) fclose (OutFile
);
438 printf ("FCLOSE failed\n");
442 free (EvaluationStack
);
444 return EFI_INVALID_PARAMETER
;
447 // validate the syntax of expression
449 if (!ParseDepex (Ptrx
, Pend
- Ptrx
- 1)) {
450 printf ("The syntax of expression is wrong\n");
452 Results
= (UINTN
) fclose (InFile
);
454 printf ("FCLOSE failed\n");
457 Results
= (UINTN
) fclose (OutFile
);
459 printf ("FCLOSE failed\n");
463 free (EvaluationStack
);
465 return EFI_INVALID_PARAMETER
;
470 while ((Index
--) && NotDone
) {
474 } else if (*Ptrx
== '\n' || *Ptrx
== '\r') {
476 } else if (strncmp (Ptrx
, OPERATOR_SOR
, strlen (OPERATOR_SOR
)) == 0) {
478 // Checks for some invalid dependencies
482 printf ("A BEFORE operator was detected.\n");
483 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
484 return EFI_INVALID_PARAMETER
;
486 } else if (After_Flag
) {
488 printf ("An AFTER operator was detected.\n");
489 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
490 return EFI_INVALID_PARAMETER
;
492 } else if (SOR_Flag
) {
494 printf ("Another SOR operator was detected.\n");
495 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
496 return EFI_INVALID_PARAMETER
;
498 } else if (Dep_Flag
) {
500 printf ("The Schedule On Request - SOR operator must be the first operator following DEPENDENCY_START\n");
501 return EFI_INVALID_PARAMETER
;
505 // BUGBUG - This was not in the spec but is in the CORE code
506 // An OPERATOR_SOR has to be first - following the DEPENDENCY_START
508 fputc (EFI_DEP_SOR
, OutFile
);
510 Ptrx
+= sizeof (OPERATOR_SOR
);
514 } else if (strncmp (Ptrx
, OPERATOR_BEFORE
, strlen (OPERATOR_BEFORE
)) == 0) {
516 // Checks for some invalid dependencies
520 printf ("Another BEFORE operator was detected.\n");
521 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
522 return EFI_INVALID_PARAMETER
;
524 } else if (After_Flag
) {
526 printf ("An AFTER operator was detected.\n");
527 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
528 return EFI_INVALID_PARAMETER
;
530 } else if (SOR_Flag
) {
532 printf ("A SOR operator was detected.\n");
533 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
534 return EFI_INVALID_PARAMETER
;
536 } else if (Dep_Flag
) {
538 printf ("The BEFORE operator must be the first operator following DEPENDENCY_START\n");
539 return EFI_INVALID_PARAMETER
;
542 fputc (EFI_DEP_BEFORE
, OutFile
);
544 Ptrx
+= sizeof (OPERATOR_BEFORE
);
547 } else if (strncmp (Ptrx
, OPERATOR_AFTER
, strlen (OPERATOR_AFTER
)) == 0) {
549 // Checks for some invalid dependencies
553 printf ("A BEFORE operator was detected.\n");
554 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
555 return EFI_INVALID_PARAMETER
;
557 } else if (After_Flag
) {
559 printf ("Another AFTER operator was detected.\n");
560 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
561 return EFI_INVALID_PARAMETER
;
563 } else if (SOR_Flag
) {
565 printf ("A SOR operator was detected.\n");
566 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
567 return EFI_INVALID_PARAMETER
;
569 } else if (Dep_Flag
) {
571 printf ("The AFTER operator must be the first operator following DEPENDENCY_START\n");
572 return EFI_INVALID_PARAMETER
;
575 fputc (EFI_DEP_AFTER
, OutFile
);
577 Ptrx
+= sizeof (OPERATOR_AFTER
);
581 } else if (strncmp (Ptrx
, OPERATOR_AND
, strlen (OPERATOR_AND
)) == 0) {
582 while (StackPtr
!= EvaluationStack
) {
583 Opcode
= PopOpCode ((VOID
**) &StackPtr
);
584 if (Opcode
!= DXE_DEP_LEFT_PARENTHESIS
) {
585 fputc (Opcode
, OutFile
);
588 PushOpCode ((VOID
**) &StackPtr
, DXE_DEP_LEFT_PARENTHESIS
);
593 PushOpCode ((VOID
**) &StackPtr
, EFI_DEP_AND
);
594 Ptrx
+= sizeof (OPERATOR_AND
);
597 } else if (strncmp (Ptrx
, OPERATOR_OR
, strlen (OPERATOR_OR
)) == 0) {
598 while (StackPtr
!= EvaluationStack
) {
599 Opcode
= PopOpCode ((VOID
**) &StackPtr
);
600 if (Opcode
!= DXE_DEP_LEFT_PARENTHESIS
) {
601 fputc (Opcode
, OutFile
);
604 PushOpCode ((VOID
**) &StackPtr
, DXE_DEP_LEFT_PARENTHESIS
);
609 PushOpCode ((VOID
**) &StackPtr
, EFI_DEP_OR
);
610 Ptrx
+= sizeof (OPERATOR_OR
);
613 } else if (strncmp (Ptrx
, OPERATOR_NOT
, strlen (OPERATOR_NOT
)) == 0) {
614 while (StackPtr
!= EvaluationStack
) {
615 Opcode
= PopOpCode ((VOID
**) &StackPtr
);
616 if (Opcode
!= DXE_DEP_LEFT_PARENTHESIS
) {
617 fputc (Opcode
, OutFile
);
620 PushOpCode ((VOID
**) &StackPtr
, DXE_DEP_LEFT_PARENTHESIS
);
625 PushOpCode ((VOID
**) &StackPtr
, EFI_DEP_NOT
);
626 Ptrx
+= sizeof (OPERATOR_NOT
);
629 } else if (*Ptrx
== '\t') {
631 printf ("File contains tabs. This violates the coding standard\n");
632 return EFI_INVALID_PARAMETER
;
634 } else if (*Ptrx
== '\n') {
636 // Skip the newline character in the file
640 } else if (strncmp (Ptrx
, OPERATOR_LEFT_PARENTHESIS
, strlen (OPERATOR_LEFT_PARENTHESIS
)) == 0) {
641 PushOpCode ((VOID
**) &StackPtr
, DXE_DEP_LEFT_PARENTHESIS
);
643 Ptrx
+= strlen (OPERATOR_LEFT_PARENTHESIS
);
646 } else if (strncmp (Ptrx
, OPERATOR_RIGHT_PARENTHESIS
, strlen (OPERATOR_RIGHT_PARENTHESIS
)) == 0) {
647 while (StackPtr
!= EvaluationStack
) {
648 Opcode
= PopOpCode ((VOID
**) &StackPtr
);
649 if (Opcode
!= DXE_DEP_LEFT_PARENTHESIS
) {
650 fputc (Opcode
, OutFile
);
657 Ptrx
+= strlen (OPERATOR_RIGHT_PARENTHESIS
);
660 } else if (strncmp (Ptrx
, OPERATOR_TRUE
, strlen (OPERATOR_TRUE
)) == 0) {
662 fputc (EFI_DEP_TRUE
, OutFile
);
667 // OutFileSize += sizeof (EFI_DEP_TRUE);
671 Ptrx
+= strlen (OPERATOR_TRUE
);
673 } else if (strncmp (Ptrx
, OPERATOR_FALSE
, strlen (OPERATOR_FALSE
)) == 0) {
675 fputc (EFI_DEP_FALSE
, OutFile
);
680 // OutFileSize += sizeof (EFI_DEP_FALSE);
684 Ptrx
+= strlen (OPERATOR_FALSE
);
686 } else if (*Ptrx
== '{') {
695 // This is an array of UINT32s. sscanf will trash memory
696 // if you try to read into a UINT8 with a %x formatter.
697 UINT32 Guid_Data4
[8];
699 ArgCountParsed
= sscanf (
701 "%x, %x, %x, { %x, %x, %x, %x, %x, %x, %x, %x }",
715 // Now we can copy the 32 bit ints into the GUID.
716 for (byte_index
=0; byte_index
<8; byte_index
++) {
717 Guid
.Data4
[byte_index
] = (UINT8
) Guid_Data4
[byte_index
];
721 if (ArgCountParsed
!= 11) {
722 printf ("We have found an illegal GUID\n");
723 printf ("Fix your depex\n");
727 while (*Ptrx
!= '}') {
732 while (*Ptrx
!= '}') {
736 // Absorb the closing }
741 // Don't provide a PUSH Opcode for the Before and After case
743 if ((!Before_Flag
) && (!After_Flag
)) {
744 fputc (EFI_DEP_PUSH
, OutFile
);
748 fwrite (&Guid
, sizeof (EFI_GUID
), 1, OutFile
);
750 OutFileSize
+= sizeof (EFI_GUID
);
753 } else if (strncmp (Ptrx
, DEPENDENCY_END
, strlen (DEPENDENCY_END
)) == 0) {
757 // Not a valid construct. Null terminate somewhere out there and
758 // print an error message.
761 printf (TOOL_NAME
" ERROR: Unrecognized input at: \"%s\"...\n", Ptrx
);
762 return EFI_INVALID_PARAMETER
;
768 while (StackPtr
!= EvaluationStack
) {
769 fputc (PopOpCode ((VOID
**) &StackPtr
), OutFile
);
773 if (OutFileSize
== 0) {
774 printf ("Grammer contains no operators or constants\n");
775 return EFI_INVALID_PARAMETER
;
778 fputc (EFI_DEP_END
, OutFile
);
783 // Checks for invalid padding values
787 printf ("The inputted padding value was %d\n", Padding
);
788 printf ("The optional padding value can not be less than ZERO\n");
789 return EFI_INVALID_PARAMETER
;
791 } else if (Padding
> 0) {
793 while ((OutFileSize
% Padding
) != 0) {
795 fputc (' ', OutFile
);
800 Results
= (UINTN
) fclose (InFile
);
802 printf ("FCLOSE failed\n");
805 Results
= (UINTN
) fclose (OutFile
);
807 printf ("FCLOSE failed\n");
811 free (EvaluationStack
);
814 } // End GenerateDependencyExpression function
825 Parse user entries. Print some rudimentary help
829 argc The count of input arguments
830 argv The input arguments string array
834 EFI_SUCCESS The function completed successfully.
835 EFI_INVALID_PARAMETER One of the input parameters was invalid or one of the parameters in the text file was invalid.
836 EFI_OUT_OF_RESOURCES Unable to allocate memory.
837 EFI_ABORTED Unable to open/create a file or a misc error.
840 // TODO: ] - add argument and description to function comment
858 printf ("Not enough arguments\n");
859 PrintGenDepexUsageInfo ();
860 return EFI_INVALID_PARAMETER
;
863 for (Index
= 1; Index
< argc
- 1; Index
++) {
865 if ((strcmp (argv
[Index
], "-I") == 0) || (strcmp (argv
[Index
], "-i") == 0)) {
869 InFile
= fopen (argv
[Index
+ 1], "rb");
873 printf ("GenDepex only allows one INPUT (-I) argument\n");
874 return EFI_INVALID_PARAMETER
;
877 } else if ((strcmp (argv
[Index
], "-O") == 0) || (strcmp (argv
[Index
], "-o") == 0)) {
881 OutFile
= fopen (argv
[Index
+ 1], "wb");
885 printf ("GenDepex only allows one OUTPUT (-O) argument\n");
886 return EFI_INVALID_PARAMETER
;
889 } else if ((strcmp (argv
[Index
], "-P") == 0) || (strcmp (argv
[Index
], "-p") == 0)) {
893 Padding
= (UINT8
) atoi (argv
[Index
+ 1]);
897 printf ("GenDepex only allows one PADDING (-P) argument\n");
898 return EFI_INVALID_PARAMETER
;
903 PrintGenDepexUtilityInfo ();
905 if (InFile
== NULL
) {
906 printf ("Can not open <INFILE> for reading.\n");
907 PrintGenDepexUsageInfo ();
911 if (OutFile
== NULL
) {
912 printf ("Can not open <OUTFILE> for writting.\n");
913 PrintGenDepexUsageInfo ();
917 return GenerateDependencyExpression (InFile
, OutFile
, Padding
);