3 Copyright (c) 2004-2006, 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"
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-2006 Intel Corporation. All rights reserved.\n");
125 Displays the utility usage syntax to STDOUT.
139 "\n Usage: %s -I InputFile -O OutputFile [-P <Optional Boundary for padding up>] \n",
142 printf (" Where:\n");
143 printf (" InputFile is the input pre-processed dependency text files name.\n");
144 printf (" OutputFile is the output binary dependency files name.\n");
145 printf (" <Optional Boundary for padding up> is the padding integer value.\n");
146 printf (" This is the boundary to align the output file size to.\n");
157 Pop an element from the Opcode stack.
161 Stack Current top of the OpCode stack location
165 DEPENDENCY_OPCODE OpCode at the top of the OpCode stack.
166 Stack New top of the OpCode stack location
171 DEPENDENCY_OPCODE
*OpCodePtr
;
182 IN DEPENDENCY_OPCODE OpCode
188 Push an element onto the Opcode Stack
192 Stack Current top of the OpCode stack location
193 OpCode OpCode to push onto the stack
197 Stack New top of the OpCode stack location
201 DEPENDENCY_OPCODE
*OpCodePtr
;
210 GenerateDependencyExpression (
212 IN OUT
FILE *OutFile
,
213 IN INT8 Padding OPTIONAL
219 This takes the pre-compiled dependency text file and
220 converts it into a binary dependency file.
222 The BNF for the dependency expression is as follows
223 (from the DXE 1.0 Draft specification).
225 The inputted BNF grammar is thus:
226 <depex> ::= sor <dep> |
233 <bool> ::= <bool> and <term> |
237 <term> ::= not <factor> |
240 <factor> ::= ( <bool> ) |
248 The outputed binary grammer is thus:
249 <depex> ::= sor <dep> |
250 before <depinst> <dep> |
251 after <depinst> <dep> |
256 <bool> ::= <bool> and <term> |
257 <bool> or <term> | <term>
259 <term> ::= not <factor> |
262 <factor> ::= ( <bool> ) |
271 <depinst> ::= push GUID
275 BugBug: A correct grammer is parsed correctly. A file that violates the
276 grammer may parse when it should generate an error. There is some
277 error checking and it covers most of the case when it's an include
278 of definition issue. An ill formed expresion may not be detected.
282 InFile - Input pre-compiled text file of the dependency expression.
283 This needs to be in ASCII.
284 The file pointer can not be NULL.
286 OutFile - Binary dependency file.
287 The file pointer can not be NULL.
289 Padding - OPTIONAL integer value to pad the output file to.
294 EFI_SUCCESS The function completed successfully.
295 EFI_INVALID_PARAMETER One of the parameters in the text file was invalid.
296 EFI_OUT_OF_RESOURCES Unable to allocate memory.
297 EFI_ABORTED An misc error occurred.
303 INT8
*EvaluationStack
;
317 UINTN ArgCountParsed
;
318 DEPENDENCY_OPCODE Opcode
;
325 memset (Line
, 0, LINESIZE
);
329 EvaluationStack
= (INT8
*) malloc (EVAL_STACK_SIZE
);
331 if (EvaluationStack
!= NULL
) {
332 StackPtr
= EvaluationStack
;
334 printf ("Unable to allocate memory to EvaluationStack - Out of resources\n");
335 return EFI_OUT_OF_RESOURCES
;
338 Results
= (UINTN
) fseek (InFile
, 0, SEEK_END
);
341 printf ("FSEEK failed - Aborted\n");
345 FileSize
= ftell (InFile
);
347 if (FileSize
== -1L) {
348 printf ("FTELL failed - Aborted\n");
352 Buffer
= (INT8
*) malloc (FileSize
+ BUFFER_SIZE
);
354 if (Buffer
== NULL
) {
355 printf ("Unable to allocate memory to Buffer - Out of resources\n");
356 free (EvaluationStack
);
358 Results
= (UINTN
) fclose (InFile
);
360 printf ("FCLOSE failed\n");
363 Results
= (UINTN
) fclose (OutFile
);
365 printf ("FCLOSE failed\n");
368 return EFI_OUT_OF_RESOURCES
;
371 Results
= (UINTN
) fseek (InFile
, 0, SEEK_SET
);
374 printf ("FSEEK failed - Aborted\n");
378 memset (Buffer
, 0, FileSize
+ BUFFER_SIZE
);
379 fread (Buffer
, FileSize
, 1, InFile
);
382 Pend
= Ptrx
+ FileSize
- strlen (DEPENDENCY_END
);
386 while ((Index
--) && NotDone
) {
388 if (strncmp (Pend
, DEPENDENCY_END
, strlen (DEPENDENCY_END
)) == 0) {
396 printf ("Couldn't find end string %s\n", DEPENDENCY_END
);
398 Results
= (UINTN
) fclose (InFile
);
400 printf ("FCLOSE failed\n");
403 Results
= (UINTN
) fclose (OutFile
);
405 printf ("FCLOSE failed\n");
409 free (EvaluationStack
);
411 return EFI_INVALID_PARAMETER
;
417 while ((Index
--) && NotDone
) {
419 if (strncmp (Ptrx
, DEPENDENCY_START
, strlen (DEPENDENCY_START
)) == 0) {
420 Ptrx
+= sizeof (DEPENDENCY_START
);
423 // BUGBUG -- should Index be decremented by sizeof(DEPENDENCY_START)?
431 printf ("Couldn't find start string %s\n", DEPENDENCY_START
);
433 Results
= (UINTN
) fclose (InFile
);
435 printf ("FCLOSE failed\n");
438 Results
= (UINTN
) fclose (OutFile
);
440 printf ("FCLOSE failed\n");
444 free (EvaluationStack
);
446 return EFI_INVALID_PARAMETER
;
449 // validate the syntax of expression
451 if (!ParseDepex (Ptrx
, Pend
- Ptrx
- 1)) {
452 printf ("The syntax of expression is wrong\n");
454 Results
= (UINTN
) fclose (InFile
);
456 printf ("FCLOSE failed\n");
459 Results
= (UINTN
) fclose (OutFile
);
461 printf ("FCLOSE failed\n");
465 free (EvaluationStack
);
467 return EFI_INVALID_PARAMETER
;
472 while ((Index
--) && NotDone
) {
476 } else if (*Ptrx
== '\n' || *Ptrx
== '\r') {
478 } else if (strncmp (Ptrx
, OPERATOR_SOR
, strlen (OPERATOR_SOR
)) == 0) {
480 // Checks for some invalid dependencies
484 printf ("A BEFORE operator was detected.\n");
485 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
486 return EFI_INVALID_PARAMETER
;
488 } else if (After_Flag
) {
490 printf ("An AFTER operator was detected.\n");
491 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
492 return EFI_INVALID_PARAMETER
;
494 } else if (SOR_Flag
) {
496 printf ("Another SOR operator was detected.\n");
497 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
498 return EFI_INVALID_PARAMETER
;
500 } else if (Dep_Flag
) {
502 printf ("The Schedule On Request - SOR operator must be the first operator following DEPENDENCY_START\n");
503 return EFI_INVALID_PARAMETER
;
507 // BUGBUG - This was not in the spec but is in the CORE code
508 // An OPERATOR_SOR has to be first - following the DEPENDENCY_START
510 fputc (EFI_DEP_SOR
, OutFile
);
512 Ptrx
+= sizeof (OPERATOR_SOR
);
516 } else if (strncmp (Ptrx
, OPERATOR_BEFORE
, strlen (OPERATOR_BEFORE
)) == 0) {
518 // Checks for some invalid dependencies
522 printf ("Another BEFORE operator was detected.\n");
523 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
524 return EFI_INVALID_PARAMETER
;
526 } else if (After_Flag
) {
528 printf ("An AFTER operator was detected.\n");
529 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
530 return EFI_INVALID_PARAMETER
;
532 } else if (SOR_Flag
) {
534 printf ("A SOR operator was detected.\n");
535 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
536 return EFI_INVALID_PARAMETER
;
538 } else if (Dep_Flag
) {
540 printf ("The BEFORE operator must be the first operator following DEPENDENCY_START\n");
541 return EFI_INVALID_PARAMETER
;
544 fputc (EFI_DEP_BEFORE
, OutFile
);
546 Ptrx
+= sizeof (OPERATOR_BEFORE
);
549 } else if (strncmp (Ptrx
, OPERATOR_AFTER
, strlen (OPERATOR_AFTER
)) == 0) {
551 // Checks for some invalid dependencies
555 printf ("A BEFORE operator was detected.\n");
556 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
557 return EFI_INVALID_PARAMETER
;
559 } else if (After_Flag
) {
561 printf ("Another AFTER operator was detected.\n");
562 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
563 return EFI_INVALID_PARAMETER
;
565 } else if (SOR_Flag
) {
567 printf ("A SOR operator was detected.\n");
568 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
569 return EFI_INVALID_PARAMETER
;
571 } else if (Dep_Flag
) {
573 printf ("The AFTER operator must be the first operator following DEPENDENCY_START\n");
574 return EFI_INVALID_PARAMETER
;
577 fputc (EFI_DEP_AFTER
, OutFile
);
579 Ptrx
+= sizeof (OPERATOR_AFTER
);
583 } else if (strncmp (Ptrx
, OPERATOR_AND
, strlen (OPERATOR_AND
)) == 0) {
584 while (StackPtr
!= EvaluationStack
) {
585 Opcode
= PopOpCode ((VOID
**) &StackPtr
);
586 if (Opcode
!= DXE_DEP_LEFT_PARENTHESIS
) {
587 fputc (Opcode
, OutFile
);
590 PushOpCode ((VOID
**) &StackPtr
, DXE_DEP_LEFT_PARENTHESIS
);
595 PushOpCode ((VOID
**) &StackPtr
, EFI_DEP_AND
);
596 Ptrx
+= sizeof (OPERATOR_AND
);
599 } else if (strncmp (Ptrx
, OPERATOR_OR
, strlen (OPERATOR_OR
)) == 0) {
600 while (StackPtr
!= EvaluationStack
) {
601 Opcode
= PopOpCode ((VOID
**) &StackPtr
);
602 if (Opcode
!= DXE_DEP_LEFT_PARENTHESIS
) {
603 fputc (Opcode
, OutFile
);
606 PushOpCode ((VOID
**) &StackPtr
, DXE_DEP_LEFT_PARENTHESIS
);
611 PushOpCode ((VOID
**) &StackPtr
, EFI_DEP_OR
);
612 Ptrx
+= sizeof (OPERATOR_OR
);
615 } else if (strncmp (Ptrx
, OPERATOR_NOT
, strlen (OPERATOR_NOT
)) == 0) {
616 while (StackPtr
!= EvaluationStack
) {
617 Opcode
= PopOpCode ((VOID
**) &StackPtr
);
618 if (Opcode
!= DXE_DEP_LEFT_PARENTHESIS
) {
619 fputc (Opcode
, OutFile
);
622 PushOpCode ((VOID
**) &StackPtr
, DXE_DEP_LEFT_PARENTHESIS
);
627 PushOpCode ((VOID
**) &StackPtr
, EFI_DEP_NOT
);
628 Ptrx
+= sizeof (OPERATOR_NOT
);
631 } else if (*Ptrx
== '\t') {
633 printf ("File contains tabs. This violates the coding standard\n");
634 return EFI_INVALID_PARAMETER
;
636 } else if (*Ptrx
== '\n') {
638 // Skip the newline character in the file
642 } else if (strncmp (Ptrx
, OPERATOR_LEFT_PARENTHESIS
, strlen (OPERATOR_LEFT_PARENTHESIS
)) == 0) {
643 PushOpCode ((VOID
**) &StackPtr
, DXE_DEP_LEFT_PARENTHESIS
);
645 Ptrx
+= strlen (OPERATOR_LEFT_PARENTHESIS
);
648 } else if (strncmp (Ptrx
, OPERATOR_RIGHT_PARENTHESIS
, strlen (OPERATOR_RIGHT_PARENTHESIS
)) == 0) {
649 while (StackPtr
!= EvaluationStack
) {
650 Opcode
= PopOpCode ((VOID
**) &StackPtr
);
651 if (Opcode
!= DXE_DEP_LEFT_PARENTHESIS
) {
652 fputc (Opcode
, OutFile
);
659 Ptrx
+= strlen (OPERATOR_RIGHT_PARENTHESIS
);
662 } else if (strncmp (Ptrx
, OPERATOR_TRUE
, strlen (OPERATOR_TRUE
)) == 0) {
664 fputc (EFI_DEP_TRUE
, OutFile
);
669 // OutFileSize += sizeof (EFI_DEP_TRUE);
673 Ptrx
+= strlen (OPERATOR_TRUE
);
675 } else if (strncmp (Ptrx
, OPERATOR_FALSE
, strlen (OPERATOR_FALSE
)) == 0) {
677 fputc (EFI_DEP_FALSE
, OutFile
);
682 // OutFileSize += sizeof (EFI_DEP_FALSE);
686 Ptrx
+= strlen (OPERATOR_FALSE
);
688 } else if (*Ptrx
== '{') {
697 // This is an array of UINT32s. sscanf will trash memory
698 // if you try to read into a UINT8 with a %x formatter.
699 UINT32 Guid_Data4
[8];
701 ArgCountParsed
= sscanf (
703 "%x, %x, %x, { %x, %x, %x, %x, %x, %x, %x, %x }",
717 // Now we can copy the 32 bit ints into the GUID.
718 for (byte_index
=0; byte_index
<8; byte_index
++) {
719 Guid
.Data4
[byte_index
] = (UINT8
) Guid_Data4
[byte_index
];
723 if (ArgCountParsed
!= 11) {
724 printf ("We have found an illegal GUID\n");
725 printf ("Fix your depex\n");
729 while (*Ptrx
!= '}') {
734 while (*Ptrx
!= '}') {
738 // Absorb the closing }
743 // Don't provide a PUSH Opcode for the Before and After case
745 if ((!Before_Flag
) && (!After_Flag
)) {
746 fputc (EFI_DEP_PUSH
, OutFile
);
750 fwrite (&Guid
, sizeof (EFI_GUID
), 1, OutFile
);
752 OutFileSize
+= sizeof (EFI_GUID
);
755 } else if (strncmp (Ptrx
, DEPENDENCY_END
, strlen (DEPENDENCY_END
)) == 0) {
759 // Not a valid construct. Null terminate somewhere out there and
760 // print an error message.
763 printf (TOOL_NAME
" ERROR: Unrecognized input at: \"%s\"...\n", Ptrx
);
764 return EFI_INVALID_PARAMETER
;
770 while (StackPtr
!= EvaluationStack
) {
771 fputc (PopOpCode ((VOID
**) &StackPtr
), OutFile
);
775 if (OutFileSize
== 0) {
776 printf ("Grammer contains no operators or constants\n");
777 return EFI_INVALID_PARAMETER
;
780 fputc (EFI_DEP_END
, OutFile
);
785 // Checks for invalid padding values
789 printf ("The inputted padding value was %d\n", Padding
);
790 printf ("The optional padding value can not be less than ZERO\n");
791 return EFI_INVALID_PARAMETER
;
793 } else if (Padding
> 0) {
795 while ((OutFileSize
% Padding
) != 0) {
797 fputc (' ', OutFile
);
802 Results
= (UINTN
) fclose (InFile
);
804 printf ("FCLOSE failed\n");
807 Results
= (UINTN
) fclose (OutFile
);
809 printf ("FCLOSE failed\n");
813 free (EvaluationStack
);
816 } // End GenerateDependencyExpression function
827 Parse user entries. Print some rudimentary help
831 argc The count of input arguments
832 argv The input arguments string array
836 EFI_SUCCESS The function completed successfully.
837 EFI_INVALID_PARAMETER One of the input parameters was invalid or one of the parameters in the text file was invalid.
838 EFI_OUT_OF_RESOURCES Unable to allocate memory.
839 EFI_ABORTED Unable to open/create a file or a misc error.
842 // TODO: ] - add argument and description to function comment
864 if ((strcmp(argv
[1], "-h") == 0) || (strcmp(argv
[1], "--help") == 0) ||
865 (strcmp(argv
[1], "-?") == 0) || (strcmp(argv
[1], "/?") == 0)) {
870 if ((strcmp(argv
[1], "-V") == 0) || (strcmp(argv
[1], "--version") == 0)) {
876 printf ("Not enough arguments\n");
878 return EFI_INVALID_PARAMETER
;
881 for (Index
= 1; Index
< argc
- 1; Index
++) {
883 if ((strcmp (argv
[Index
], "-I") == 0) || (strcmp (argv
[Index
], "-i") == 0)) {
887 InFile
= fopen (argv
[Index
+ 1], "rb");
891 printf ("GenDepex only allows one INPUT (-I) argument\n");
892 return EFI_INVALID_PARAMETER
;
895 } else if ((strcmp (argv
[Index
], "-O") == 0) || (strcmp (argv
[Index
], "-o") == 0)) {
899 OutFile
= fopen (argv
[Index
+ 1], "wb");
903 printf ("GenDepex only allows one OUTPUT (-O) argument\n");
904 return EFI_INVALID_PARAMETER
;
907 } else if ((strcmp (argv
[Index
], "-P") == 0) || (strcmp (argv
[Index
], "-p") == 0)) {
911 Padding
= (UINT8
) atoi (argv
[Index
+ 1]);
915 printf ("GenDepex only allows one PADDING (-P) argument\n");
916 return EFI_INVALID_PARAMETER
;
921 if (InFile
== NULL
) {
922 printf ("Can not open <INFILE> for reading.\n");
927 if (OutFile
== NULL
) {
928 printf ("Can not open <OUTFILE> for writting.\n");
933 return GenerateDependencyExpression (InFile
, OutFile
, Padding
);