1#!/bin/sh
2# Copyright 2015 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6# Pull out basic typdefs.
7cat $1 |
8  # Mark types tables and section boundaries.
9  sed 's/^[0-9][0-9]*\([.][0-9][0-9]*\)\+.*$/_SECTION_BOUNDARY/' |
10  sed 's/^Table [0-9]* . Definition of .*Types[^.]*$/_TYPES/' |
11  # Keep only table sections.
12  awk '/^_TYPES$/,/^_SECTION_BOUNDARY$/ { print $0; }' |
13  sed 's/^_TYPES$//' |
14  sed 's/^_SECTION_BOUNDARY$//' |
15  # Remove headers and footers.
16  sed 's/^.*Trusted Platform Module Library.*$//' |
17  sed 's/^.*Part 2: Structures.*$//' |
18  sed 's/^.*Family .2.0..*$//' |
19  sed 's/^.*Level 00 Revision.*$//' |
20  sed 's/^.*Published.*$//' |
21  sed 's/^.*Copyright.*$//' |
22  sed 's/^.*Page [0-9].*$//' |
23  sed 's/^.*October 31, 2013.*$//' |
24  # Remove table headers.
25  sed 's/^Type$//' | sed 's/^Name$//' | sed 's/^Description$//' |
26  # Remove leading spaces.
27  sed 's/^[ ][ ]*//' |
28  # Remove empty lines.
29  sed '/^$/d' |
30  # Mark begin and end and filter types.
31  awk '
32    BEGIN { print "_BEGIN_TYPES"; state = 0; }
33    /^[^ ]*$/ { if (!state) { print "_OLD_TYPE " $0; state = 1; }
34                else { print "_NEW_TYPE " $0; state = 0; } }
35    END { print "_END"; }
36  ' |
37  # Sanity check.  The format should now follow this grammar:
38  # Format:Begin||Typedef*||End
39  # Begin:_BEGIN_TYPES\n
40  # End:_END\n
41  # Typedef:OldType||NewType
42  # OldType:_OLD_TYPE <type>\n
43  # NewType:_NEW_TYPE <type>\n
44  awk '
45    BEGIN { RS = ""; }
46    $0 !~ /_BEGIN_TYPES\n(_OLD_TYPE[^\n]*\n_NEW_TYPE[^\n]*\n)*_END/ {
47      print "_ERROR: Format check failed."; }
48    { print $0; }
49  '
50
51# Pull out constant values.
52cat $1 |
53  # Mark constants tables and section boundaries.
54  sed 's/^[0-9][0-9]*\([.][0-9][0-9]*\)\+.*$/_SECTION_BOUNDARY/' |
55  sed 's/^Table [0-9]* . Definition of \(.*\) Constants[^.]*$/_CONSTANTS \1/' |
56  # Keep only table sections.
57  awk '/^_CONSTANTS .*$/,/^_SECTION_BOUNDARY$/ { print $0; }' |
58  sed 's/^_SECTION_BOUNDARY$//' |
59  # Remove headers and footers.
60  sed 's/^.*Trusted Platform Module Library.*$//' |
61  sed 's/^.*Part 2: Structures.*$//' |
62  sed 's/^.*Family .2.0..*$//' |
63  sed 's/^.*Level 00 Revision.*$//' |
64  sed 's/^.*Published.*$//' |
65  sed 's/^.*Copyright.*$//' |
66  sed 's/^.*Page [0-9].*$//' |
67  sed 's/^.*October 31, 2013.*$//' |
68  # Remove table headers.
69  sed 's/^Name$//' | sed 's/^Value$//' | sed 's/^Comments$//' |
70  # Remove leading spaces.
71  sed 's/^[ ][ ]*//' |
72  # Remove empty lines.
73  sed '/^$/d' |
74  # Mark begin and end.
75  awk '
76    BEGIN { print "_BEGIN_CONSTANTS"; }
77    { print $0; }
78    END { print "_END"; }
79  ' |
80  # Mark type.
81  awk '
82    BEGIN { FS = "[ ()]+"; }
83    { print $0; }
84    /^_CONSTANTS \(\w*\) .*$/ { print "_OLD_TYPE " $2;
85                                print "_NEW_TYPE " $NF; }
86  ' |
87  # Mark names and error return type.
88  sed 's/^\(TPM_[_A-Z0-9a]*\)$/_NAME \1/' |
89  sed 's/^\(TPM_CC_[_A-Z0-9a-z]*\)$/_NAME \1/' |
90  sed 's/^\(RC_[_A-Z0-9]*\)$/_NAME \1/' |
91  sed 's/^\(PT_[_A-Z0-9]*\)$/_NAME \1/' |
92  sed 's/^\(HR_[_A-Z0-9]*\)$/_NAME \1/' |
93  sed 's/^\([_A-Z0-9]*FIRST\)$/_NAME \1/' |
94  sed 's/^\([_A-Z0-9]*LAST\)$/_NAME \1/' |
95  sed 's/^\(PLATFORM_PERSISTENT\)$/_NAME \1/' |
96  sed 's/^\(#TPM_RC[_A-Z0-9]*\)$/_RETURN \1/' |
97  # Keep only names and return types
98  awk '
99    BEGIN { last_line_was_name = 0;
100            return_defined = 1;
101            FS = " |#"; }
102    /^_BEGIN_CONSTANTS$/ { print $0; }
103    /^_OLD_TYPE .*$/ { if (!return_defined) {  print "_RETURN TPM_RC_VALUE"; }
104                       return_defined = 0;
105                       print $0 }
106    /^_NEW_TYPE .*$/ { print $0; }
107    /^_NAME .*$/ { if (last_line_was_name) {
108                     last_line_was_name = 0;
109                     if ($0 !~ /[A-Z_0-9x +]*/) { print "_ERROR: Invalid value"; } }
110                   else { last_line_was_name = 1; print $0; } }
111    /^_RETURN .*$/ { print "_RETURN " $3;
112                     return_defined = 1; }
113    /^[^_].*$/   { if (last_line_was_name) {
114                     last_line_was_name = 0;
115                     if ($0 !~ /[A-Z_0-9x +]*/) { print "_ERROR: Invalid value"; } } }
116    /^_END$/ { if (!return_defined) { print "_RETURN TPM_RC_VALUE"; }
117               print $0; }
118  ' |
119  # Sanity check.  The format should now follow this grammar:
120  # Format:Begin||TableBlock*||End
121  # Begin:_BEGIN_CONSTANTS\n
122  # End:_END\n
123  # TableBlock:Typedef||Name*||Return
124  # Name:_NAME <name>\n
125  # Return:_RETURN <name>\n
126  # Typedef:OldType||NewType
127  # OldType:_OLD_TYPE <type>\n
128  # NewType:_NEW_TYPE <type>\n
129  awk '
130    BEGIN { RS = ""; }
131    $0 !~ /_BEGIN_CONSTANTS\n(_OLD_TYPE[^\n]*\n_NEW_TYPE[^\n]*\n(_NAME[^\n]*\n)*_RETURN[^\n]*\n)*_END/ {
132      print "_ERROR: Format check failed."; }
133    { print $0; }
134  '
135
136# Pull out attribute structs.
137cat $1 |
138  # Mark reserved bits.
139  sed 's/^\([0-9]\+:\?[0-9]* Reserved\)$/_RESERVED \1/' |
140  awk '
141    BEGIN { print "_BEGIN_ATTRIBUTE_STRUCTS";
142            FS = "[ ()]+|:";
143            in_attribute = 0; }
144    /^Table [0-9]* . Definition of \([A-Z_0-9]*\) TPM[A-Z_]* Bits[^.]*$/ {
145      print "_OLD_TYPE " $6;
146      print "_NEW_TYPE " $7;
147      in_attribute = 1; }
148    /^_RESERVED .*$/ { if (in_attribute && NF == 4) {
149                         print "_RESERVED " $3 "_" $2; }
150                       else if (in_attribute) {
151                         print "_RESERVED " $2; } }
152    END { print "_END"; }
153  ' |
154  # Sanity check.  The format should now follow this grammar:
155  # Format:Begin||TableBlock*||End
156  # Begin:_BEGIN_ATTRIBUTE_STRUCTS\n
157  # End:_END\n
158  # TableBlock:Typedef||Reserved*
159  # Reserved:_RESERVED <value>(_<value>)?\n
160  # Typedef:OldType||NewType
161  # OldType:_OLD_TYPE <type>\n
162  # NewType:_NEW_TYPE <type>\n
163  awk '
164    BEGIN { RS = ""; }
165    $0 !~ /_BEGIN_ATTRIBUTE_STRUCTS\n(_OLD_TYPE[^\n]*\n_NEW_TYPE[^\n]*\n(_RESERVED[^\n]*\n)*)*_END/ {
166      print "_ERROR: Format check failed."; }
167    { print $0; }
168  '
169
170# Pull out interface types.
171cat $1 |
172  # Mark interface tables and section boundaries.
173  sed 's/^[0-9][0-9]*\([.][0-9][0-9]*\)\+.*$/_SECTION_BOUNDARY/' |
174  sed 's/^Table [0-9]* . Definition of \(.*\) Type[^.s]*$/_INTERFACES \1/' |
175  # Keep only table sections.
176  awk '/^_INTERFACES .*$/,/^_SECTION_BOUNDARY$/ { print $0; }' |
177  sed 's/^_SECTION_BOUNDARY$//' |
178  # Remove headers and footers.
179  sed 's/^.*Trusted Platform Module Library.*$//' |
180  sed 's/^.*Part 2: Structures.*$//' |
181  sed 's/^.*Family .2.0..*$//' |
182  sed 's/^.*Level 00 Revision.*$//' |
183  sed 's/^.*Published.*$//' |
184  sed 's/^.*Copyright.*$//' |
185  sed 's/^.*Page [0-9].*$//' |
186  sed 's/^.*October 31, 2013.*$//' |
187  # Remove table headers.
188  sed 's/^Type$//' | sed 's/^Name$//' | sed 's/^Description$//' |
189  # Remove leading spaces.
190  sed 's/^[ ][ ]*//' |
191  # Remove empty lines.
192  sed '/^$/d' |
193  # Mark begin and end.
194  awk '
195    BEGIN { print "_BEGIN_INTERFACES"; }
196    { print $0; }
197    END { print "_END"; }
198  ' |
199  # Mark type.
200  awk '
201    BEGIN { FS = "[ ()]+"; }
202    { print $0; }
203    /^_INTERFACES \(\w*\) .*$/ { print "_OLD_TYPE " $2;
204                                print "_NEW_TYPE " $NF; }
205    /^_INTERFACES {[A-Z0-9]*} \(\w*\) .*$/ { print "_OLD_TYPE " $3;
206                                          print "_NEW_TYPE " $NF; }
207  ' |
208  # Mark names, bounds, conditional values, and return values.
209  sed 's/^\(TPM_[_A-Z0-9a]*\)$/_NAME \1/' |
210  sed 's/^\(TPM_CC_[_A-Z0-9a-z]*\)$/_NAME \1/' |
211  sed 's/^\(RC_[_A-Z0-9]*\)$/_NAME \1/' |
212  sed 's/^\(PT_[_A-Z0-9]*\)$/_NAME \1/' |
213  sed 's/^\(HR_[_A-Z0-9]*\)$/_NAME \1/' |
214  sed 's/^\([_A-Z0-9]*FIRST\)$/_NAME \1/' |
215  sed 's/^\([_A-Z0-9]*LAST\)$/_NAME \1/' |
216  sed 's/^\(PLATFORM_PERSISTENT\)$/_NAME \1/' |
217  sed 's/^\(NO\)$/_NAME \1/' |
218  sed 's/^\(YES\)$/_NAME \1/' |
219  sed 's/^\({[_A-Z0-9]*:[_A-Z0-9]*}\)$/_BOUND \1/' |
220  sed 's/^\(+[_A-Z0-9]*\)$/_CONDITIONAL \1/' |
221  sed 's/^\(#TPM_RC[_A-Z0-9]*\)$/_RETURN \1/' |
222  sed 's/^\(\$.*\)$/_SUBSTITUTE \1/' |
223  awk '
224    BEGIN { print "_BEGIN_INTERFACES";
225            FS = " |:|{|}|#|+";
226            ret = 1; }
227    /^_OLD_TYPE .*$/ { if (!ret) { print "_RETURN TPM_RC_VALUE"; }
228                       ret = 0; }
229    /^_.*_TYPE .*$/ { print $0; }
230    /^_NAME .*$/ { print $0; }
231    /^_SUBSTITUTE .*$/ { $2 = substr($2, 2, length($2)-1);
232                         print $0; }
233    /^_BOUND .*$/ { print "_MIN " $3;
234                    print "_MAX " $4; }
235    /^_CONDITIONAL .*$/ { print "_CONDITIONAL " $3; }
236    /^_RETURN .*$/ { print "_RETURN " $3;
237                     ret = 1; }
238    END { print "_END"; }
239  ' |
240  # Sanity check.  The format should now follow this grammar:
241  # Format:Begin||Tableblock*||End
242  # Begin:_BEGIN_INTERFACES\n
243  # End:_END\n
244  # Tableblock: Typedef||(Subval?|Name*)||Bound*||Conditional?||Return
245  # Name:_NAME <name>\n
246  # Subval:_SUBSTITUTE <name>\n
247  # Bound:Min||Max
248  # Min:_MIN <name>\n
249  # Max:_MAX <name>\n
250  # Conditional:_CONDITIONAL <name>\n
251  # Return:_RETURN <name>\n
252  # Typedef:OldType||NewType
253  # OldType:_OLD_TYPE <type>\n
254  # NewType:_NEW_TYPE <type>\n
255  awk '
256    BEGIN { RS = ""; }
257    $0 !~ /_BEGIN_INTERFACES\n(_OLD_TYPE[^\n]*\n_NEW_TYPE[^\n]*\n(_NAME[^\n]*\n)*(_SUBSTITUTE[^\n]*\n)?(_MIN[^\n]*\n_MAX[^\n]*\n)*(_CONDITIONAL[^\n]*\n)?(_RETURN[^\n]*\n)?)*_END/ {
258      print "_ERROR: Format check failed."; }
259    { print $0; }
260  '
261# Pull out structures.
262cat $1 |
263  # Mark tables and section boundaries.
264  sed 's/^[0-9][0-9]*\([.][0-9][0-9]*\)\+.*$/_SECTION_BOUNDARY/' |
265  sed 's/^Table [0-9]* . Definition of \(.*\) Structure[^.]*$/_STRUCTURE \1/' |
266  # Keep only table sections.
267  awk '/^_STRUCTURE .*$/,/^_SECTION_BOUNDARY$/ { print $0; }' |
268  sed 's/^_SECTION_BOUNDARY$//' |
269  # Remove headers and footers.
270  sed 's/^.*Trusted Platform Module Library.*$//' |
271  sed 's/^.*Part 2: Structures.*$//' |
272  sed 's/^.*Family .2.0..*$//' |
273  sed 's/^.*Level 00 Revision.*$//' |
274  sed 's/^.*Published.*$//' |
275  sed 's/^.*Copyright.*$//' |
276  sed 's/^.*Page [0-9].*$//' |
277  sed 's/^.*October 31, 2013.*$//' |
278  # Remove table headers.
279  sed 's/^Parameter$//' | sed 's/^Type$//' | sed 's/^Description$//' |
280  # Remove leading spaces.
281  sed 's/^[ ][ ]*//' |
282  # Remove empty lines.
283  sed '/^$/d' |
284  # Mark begin and end.
285  awk '
286    BEGIN { print "_BEGIN_STRUCTURES"; }
287    { print $0; }
288    END { print "_END"; }
289  ' |
290  # Mark field types.
291  sed 's/^\(+*TPM[_A-Z0-9+]*\)$/_TYPE \1/' |
292  sed 's/^\(UINT[0-9]*\)$/_TYPE \1/' |
293  sed 's/^\(BYTE*\)$/_TYPE \1/' |
294  # Mark field names and associated decorations
295  awk '
296    BEGIN { last_line = "";
297            FS = ":| |{|}|+|#"; }
298    /^_.*$/      { if ($1 != "_TYPE") { print $0; } }
299    /^_TYPE \+[A-Z0-9_]*$/ { print $1 " " $3;
300                             prefix = substr($3, 1, 4);
301                             if (last_line != "" && prefix == "TPMI") {
302                               print "_NAME " last_line " _PLUS";
303                             } else if (last_line != "") {
304                               print "_NAME " last_line;
305                             } else { print "_ERROR: Type with no name"; }
306                             last_line = ""; }
307    /^_TYPE [A-Z0-9_]*\+$/ { print $1 " " $2;
308                             prefix = substr($2, 1, 4);
309                             if (last_line != "" && prefix == "TPMI") {
310                               print "_NAME " last_line " _PLUS";
311                             } else if (last_line != "") {
312                               print "_NAME " last_line;
313                             } else { print "_ERROR: Type with no name"; }
314                             last_line = ""; }
315    /^_TYPE [A-Z0-9_]*$/ { print $0;
316                           if (last_line != "") { print "_NAME " last_line ; }
317                           else { print "_ERROR: Type with no name"; }
318                           if (extra_line != "") { print extra_line; }
319                           last_line = "";
320                           extra_line = ""; }
321    /^[^_].*$/   { last_line = $0; }
322    /^\[[^]]*\].*$/ { $1 = substr($1, 2, length($1)-1);
323                      sub(/\]/, " ", $0);
324                      last_line = $2 " _UNION " $1; }
325    /^.*\[[^]]*\]$/ { $1 = substr($1, 1, length($1)-1);
326                      sub(/\]/, " " , $0);
327                      last_line = $1 " _ARRAY " $2; }
328    /^.*\{[A-Z0-9_]*:\}$/ { last_line = $1;
329                            extra_line = "_MIN " $1 " " $3; }
330    /^.*\{:[A-Z0-9_]*\}$/ { last_line = $1;
331                            extra_line = "_MAX " $1 " " $3; }
332    /^.*\[[^]]*\] \{:[a-zA-Z0-9_()\/]*\}$/ { $2 = substr($2, 2, length($2)-2);
333                                   last_line = $1 " _ARRAY " $2;
334                                   extra_line = "_MAX " $2 " " $5 ; }
335    /^tag \{[A-Z_]*(, [A-Z_]*)*\}$/ { last_line = "tag";
336                                      extra_line = "_VALID " $3;
337                                      for (i = 4; i <= NF-1; i++)
338                                        extra_line = extra_line "\n_VALID " $i;
339                                      sub(/\,/, "", extra_line); }
340    /^size\=$/ { last_line = "size _CHECK" }
341    /^#.*$/ { print "_RETURN " $2; }
342  ' |
343  # Strip off structure modifiers
344  sed 's/^_STRUCTURE \((.*) \)*{.*} \(.*\)/_STRUCTURE \2/' |
345  # Sanity check.  The format should now follow this grammar:
346  # Format:Begin||Tableblock*||End
347  # Begin:_BEGIN_STRUCTURES\n
348  # End:_END\n
349  # Tableblock: Structure||(Field|Min|Max)*||Return?
350  # Structure:_STRUCTURE <name>\n
351  # Min:_MIN <name> <value>\n
352  # Max:_Max <name> <value>\n
353  # Return:_RETURN <name>\n
354  # Field: Type||Name||Valid*
355  # Type:_TYPE <name>\n
356  # Valid:_VALID <value>\n
357  # Name:_NAME <name>((( _UNION | _ARRAY )<value>)| _PLUS)?\n
358  # No sanity check here. Format is checked during generator.py
359  awk '
360    { print $0; }
361  '
362
363# Pull out unions.
364cat $1 |
365  # Mark tables and section boundaries.
366  sed 's/^[0-9][0-9]*\([.][0-9][0-9]*\)\+.*$/_SECTION_BOUNDARY/' |
367  sed 's/^Table [0-9]* . Definition of \(.*\) Union[^.]*$/_UNION \1/' |
368  # Keep only table sections.
369  awk '/^_UNION .*$/,/^_SECTION_BOUNDARY$/ { print $0; }' |
370  sed 's/^_SECTION_BOUNDARY$//' |
371  # Remove headers and footers.
372  sed 's/^.*Trusted Platform Module Library.*$//' |
373  sed 's/^.*Part 2: Structures.*$//' |
374  sed 's/^.*Family .2.0..*$//' |
375  sed 's/^.*Level 00 Revision.*$//' |
376  sed 's/^.*Published.*$//' |
377  sed 's/^.*Copyright.*$//' |
378  sed 's/^.*Page [0-9].*$//' |
379  sed 's/^.*October 31, 2013.*$//' |
380  # Remove table headers.
381  sed 's/^Parameter$//' | sed 's/^Type$//' | sed 's/^Selector$//' |
382  sed 's/^Description$//' |
383  # Remove leading spaces.
384  sed 's/^[ ][ ]*//' |
385  # Remove empty lines.
386  sed '/^$/d' |
387  # Mark begin and end.
388  awk '
389    BEGIN { print "_BEGIN_UNIONS"; }
390    { print $0; }
391    END { print "_END"; }
392  ' |
393  # Mark field types.
394  sed 's/^\(+*TPM[_A-Z0-9+a]*\)$/_TYPE \1/' |
395  sed 's/^\(UINT[0-9]*\)$/_TYPE \1/' |
396  sed 's/^\(BYTE*\)$/_TYPE \1/' |
397  # Mark field names and throw away everything else.
398  awk '
399    BEGIN { last_line = ""; }
400    /^_.*$/      { if ($0 !~ /^_TYPE .*$/) { last_line = ""; print $0; } }
401    /^_TYPE .*$/ { if (last_line !~ /^_TYPE .*$/) {
402                     if (last_line != "" &&
403                         last_line != "null" &&
404                         last_line != "NOTE") {
405                       print $0;
406                       print "_NAME " last_line; }
407                     else if (last_line == "") {
408                       print "_ERROR: Type with no name"; }
409                     last_line = $0; } }
410    /^[^_].*$/   { last_line = $0; }
411    /^.* \[[^]]*\]$/ { $2 = substr($2, 2, length($2)-2);
412                     last_line = $1 " _ARRAY " $2; }
413  ' |
414  # Sanity check.  The format should now follow this grammar:
415  # Format:Begin||TableBlock*||End
416  # Begin:_BEGIN_UNIONS\n
417  # End:_END\n
418  # TableBlock:TableTag||Field*
419  # TableTag:_UNION <name>\n
420  # Field:Type||Name
421  # Type:_TYPE <type>\n
422  # Name:_NAME <name>\n
423  awk '
424    BEGIN { RS = ""; }
425    $0 !~ /_BEGIN_UNIONS\n(_UNION[^\n]*\n(_TYPE[^\n]*\n_NAME[^\n]*\n)*)*_END/ {
426      print "_ERROR: Format check failed."; }
427    { print $0; }
428  '
429
430exit 0
431