blob: bac2cf8ff382a32ad2a3e75c8fe116b186f3bcec [file] [log] [blame]
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001#!/usr/bin/python2
2
3# Copyright 2015 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7"""A code generator for TPM 2.0 structures.
8
9The structure generator takes as input a structures file as emitted by the
10extract_structures.sh script. It outputs valid C into tpm_generated.{h,c}.
11tpm_generated.{h,c} consist of functions to marshal TPM2.0 structures.
12
13The input grammar is documented in extract_structures.sh. Sample input for
14structures looks like this:
15_BEGIN_TYPES
16_OLD_TYPE UINT32
17_NEW_TYPE TPM_HANDLE
18_END
19_BEGIN_CONSTANTS
20_CONSTANTS (UINT32) TPM_SPEC
21_TYPE UINT32
22_NAME TPM_SPEC_FAMILY
23_VALUE 0x322E3000
24_NAME TPM_SPEC_LEVEL
25_VALUE 00
26_END
27_BEGIN_STRUCTURES
28_STRUCTURE TPMS_TIME_INFO
29_TYPE UINT64
30_NAME time
31_TYPE TPMS_CLOCK_INFO
32_NAME clockInfo
33_END
34"""
35
36from __future__ import print_function
37
38import argparse
39import re
40import collections
41from subprocess import call
42
43import union_selectors
44
45_BASIC_TYPES = ['uint8_t', 'int8_t', 'uint16_t', 'int16_t', 'uint32_t',
46 'int32_t', 'uint64_t', 'int64_t']
47_OUTPUT_FILE_H = 'tpm_generated.h'
48_OUTPUT_FILE_CC = 'tpm_generated.c'
49_COPYRIGHT_HEADER = (
50 '// Copyright 2015 The Chromium OS Authors. All rights reserved.\n'
51 '// Use of this source code is governed by a BSD-style license that can '
52 'be\n'
53 '// found in the LICENSE file.\n'
54 '\n'
55 '// THIS CODE IS GENERATED - DO NOT MODIFY!\n')
56_HEADER_FILE_GUARD_HEADER = """
57#ifndef %(name)s
58#define %(name)s
59"""
60_HEADER_FILE_GUARD_FOOTER = """
61#endif // %(name)s
62"""
63_HEADER_FILE_INCLUDES = """
64#include <endian.h>
65#include <string.h>
66
67#include "TPM_Types.h"
68#include "Tpm.h"
69"""
70_IMPLEMENTATION_FILE_INCLUDES = """
71#include "tpm_generated.h"
72"""
73# Function signatures for generated marshaling code are specified in TCG TPM2.0
74# Library Specification, Part 4: Supporting Routines, sections 4.2.2 and 4.2.3.
75_MARSHAL_BASIC_TYPE = """
76UINT16 %(type)s_Marshal(%(type)s *source, BYTE **buffer, INT32 *size) {
Jocelyn Bohrfb668122015-07-30 10:17:56 -070077 %(type)s value_net = *source;
ChromeOS Developer9edfbac2015-07-17 16:33:16 -070078 if (!size || *size < sizeof(%(type)s)) {
79 return sizeof(%(type)s);
80 }
ChromeOS Developer9edfbac2015-07-17 16:33:16 -070081 switch (sizeof(%(type)s)) {
82 case 2:
83 value_net = htobe16(*source);
84 break;
85 case 4:
86 value_net = htobe32(*source);
87 break;
88 case 8:
89 value_net = htobe64(*source);
90 break;
91 default:
92 break;
93 }
94 memcpy(*buffer, &value_net, sizeof(%(type)s));
95 *buffer += sizeof(%(type)s);
96 *size -= sizeof(%(type)s);
97 return sizeof(%(type)s);
98}
99
100TPM_RC %(type)s_Unmarshal(%(type)s *target, BYTE **buffer, INT32 *size) {
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700101 %(type)s value_net = 0;
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700102 if (!size || *size < sizeof(%(type)s)) {
103 return TPM_RC_INSUFFICIENT;
104 }
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700105 memcpy(&value_net, *buffer, sizeof(%(type)s));
106 switch (sizeof(%(type)s)) {
107 case 2:
108 *target = be16toh(value_net);
109 break;
110 case 4:
111 *target = be32toh(value_net);
112 break;
113 case 8:
114 *target = be64toh(value_net);
115 break;
116 default:
117 *target = value_net;
118 }
119 *buffer += sizeof(%(type)s);
120 *size -= sizeof(%(type)s);
121 return TPM_RC_SUCCESS;
122}
123"""
124_STANDARD_MARSHAL_DECLARATION = """
125UINT16 %(type)s_Marshal(
126 %(type)s *source,
127 BYTE **buffer,
128 INT32 *size);
129
130TPM_RC %(type)s_Unmarshal(
131 %(type)s *target,
132 BYTE **buffer,
133 INT32 *size);
134"""
135
136def IsTPM2B(name):
137 return name.startswith('TPM2B_')
138
139
140class TPMType(object):
141 """Base type for all TPMTypes
142
143 Contains functions and string literals common to all TPM types.
144 """
145 # A function to marshal a TPM typedef.
146 _TYPEDEF_MARSHAL_FUNCTION = """
147UINT16 %(new_type)s_Marshal(
148 %(new_type)s *source,
149 BYTE **buffer,
150 INT32 *size) {
151 return %(old_type)s_Marshal(source, buffer, size);
152}
153"""
154 # The function signature and unmarshaling call to the base type of a TPM
155 # typedef. After the value is unmarshaled, additional validation code is
156 # generated based on tables in TCG TPM2.0 Library Specification, Part 2:
157 # Structures.
158 _TYPEDEF_UNMARSHAL_START = """
159TPM_RC %(new_type)s_Unmarshal(
160 %(new_type)s *target,
161 BYTE **buffer,
162 INT32 *size) {
163 TPM_RC result;
164 result = %(old_type)s_Unmarshal(target, buffer, size);
165 if (result != TPM_RC_SUCCESS) {
166 return result;
167 }"""
168 _UNMARSHAL_END = '\n return TPM_RC_SUCCESS;\n}\n'
169 # Snippets of code for value validation.
170 _VALUE_START_SWITCH = '\n switch (%(name)s) {'
171 _VALUE_CASE = '\n case %(value)s:'
172 _VALUE_CASE_IFDEF = '\n#ifdef %(value)s\n case %(value)s:\n#endif'
173 _VALUE_END_SWITCH = """
174 break;
175 default:
176 return %(error_code)s;
177 }"""
178 # A declaration for marshaling and unmarshaling functions for a TPM type.
179 _MARSHAL_DECLARATION = _STANDARD_MARSHAL_DECLARATION
180 # Snippets of code which make calls to marshaling functions. Marshals a value
181 # of type 'type' into a field 'name' within a structure. This is used in
182 # generation of structure and command marshaling code.
183 _MARSHAL_CALL = """
184 total_size += %(type)s_Marshal(
185 &source->%(name)s, buffer, size);"""
186 _UNMARSHAL_CALL = """
187 result = %(type)s_Unmarshal(
188 &target->%(name)s, buffer, size);
189 if (result != TPM_RC_SUCCESS) {
190 return result;
191 }"""
192
193 def HasConditional(self):
194 """Returns true if TPMType has a conditional value."""
195 return False
196
197 def OutputMarshalCall(self, out_file, field_type, field_name, extra_argument):
198 """Write a call to Marshal function for TPMType to |out_file|.
199
200 Accumulates a variable 'total_size' with the result of marshaling
201 field |field_name| in structure 'source'.
202
203 Args:
204 out_file: The output file.
205 field_type: The type of the field in 'source' struct to be marshalled.
206 field_name: The name of the field in 'source' struct to be marshalled.
207 extra_argument: Value representing a BOOL value, selector value, or array
208 length depending on context. Not used here.
209 """
210 out_file.write(self._MARSHAL_CALL % {'type': field_type,
211 'name': field_name})
212
213 def OutputUnmarshalCall(
214 self, out_file, field_type, field_name, extra_argument):
215 """Write a call to Unmarshal function for TPMType to |out_file|.
216
217 Assigns result of unmarshaling field |field_name| in structure 'source'
218 to variable 'result'. Returns if the unmarshalling was unsuccessful.
219
220 Args:
221 out_file: The output file.
222 field_type: The type of the field in 'target' struct to be unmarshalled.
223 field_name: The name of the field in 'target' struct to be unmarshalled.
224 extra_argument: Value representing a BOOL value or selector value
225 depending on context. Not used here.
226 """
227 out_file.write(self._UNMARSHAL_CALL % {'type': field_type,
228 'name': field_name})
229
230 def _OutputTypedefMarshalDecl(self, out_file, declared_types, typemap):
231 """Write marshal declarations for TPM typedefs to |out_file|.
232
233 Can only be called on Typedef, ConstantType, AttributeStruct, and
234 Interface objects.
235
236 Args:
237 out_file: The output file.
238 declared_types: A set of types for which marshal and unmarshal function
239 declarations have already been generated.
240 typemap: A dict mapping type names to the corresponding object.
241 """
242 if self.new_type in declared_types:
243 return
244 if self.old_type not in declared_types:
245 typemap[self.old_type].OutputMarshalDecl(
246 out_file, declared_types, typemap)
247 out_file.write(self._MARSHAL_DECLARATION % {'type': self.new_type})
248 declared_types.add(self.new_type)
249
250 def _OutputStructOrUnionMarshalDecl(self, out_file, declared_types, typemap):
251 """Write marshal declarations for a TPM Structure or Union.
252
253 Can only be called on Structure and Union objects.
254
255 Args:
256 out_file: The output file.
257 declared_types: A set of types for which marshal and unmarshal function
258 declarations have already been generated.
259 typemap: A dict mapping type names to the corresponding object.
260 """
261 # TPMU_NAME and TPMU_ENCRYPTED_SECRET type are never used across the
262 # interface.
263 if (self.name in declared_types or
264 self.name == 'TPMU_NAME' or
265 self.name == 'TPMU_ENCRYPTED_SECRET'):
266 return
267 out_file.write(self._MARSHAL_DECLARATION % {'type': self.name})
268 declared_types.add(self.name)
269
270class Typedef(TPMType):
271 """Represents a TPM typedef.
272
273 Attributes:
274 old_type: The existing type in a typedef statement.
275 new_type: The new type in a typedef statement.
276 """
277 # A function to unmarshal a TPM typedef with no extra validation.
278 _TYPEDEF_UNMARSHAL_FUNCTION = """
279TPM_RC %(new_type)s_Unmarshal(
280 %(new_type)s *target,
281 BYTE **buffer,
282 INT32 *size) {
283 return %(old_type)s_Unmarshal(target, buffer, size);
284}
285"""
286 def __init__(self, old_type, new_type):
287 """Initializes a Typedef instance.
288
289 Args:
290 old_type: The base type of the attribute structure.
291 new_type: The name of the type.
292 """
293 self.old_type = old_type
294 self.new_type = new_type
295
296 def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
297 """Writes marshal implementations for Typedef to |out_file|.
298
299 Args:
300 out_file: The output file.
301 marshalled_types: A set of types for which marshal and unmarshal functions
302 have already been generated.
303 typemap: A dict mapping type names to the corresponding object.
304 """
305 if self.new_type in marshalled_types:
306 return
307 if self.old_type not in marshalled_types:
308 typemap[self.old_type].OutputMarshalImpl(
309 out_file, marshalled_types, typemap)
310 out_file.write(self._TYPEDEF_MARSHAL_FUNCTION % {'old_type': self.old_type,
311 'new_type': self.new_type})
312 out_file.write(
313 self._TYPEDEF_UNMARSHAL_FUNCTION % {'old_type': self.old_type,
314 'new_type': self.new_type})
315 marshalled_types.add(self.new_type)
316
317 def OutputMarshalDecl(self, out_file, declared_types, typemap):
318 """Writes marshal declarations for Typedef to |out_file|.
319
320 Args:
321 out_file: The output file.
322 declared_types: A set of types for which marshal and unmarshal function
323 declarations have already been generated.
324 typemap: A dict mapping type names to the corresponding object.
325 """
326 self._OutputTypedefMarshalDecl(out_file, declared_types, typemap)
327
328class ConstantType(TPMType):
329 """Represents a TPM Constant type definition.
330
331 Attributes:
332 old_type: The base type of the constant (e.g. 'int').
333 new_type: The name of the type (e.g. 'TPM_RC').
334 valid_values: The list of valid values this type can take (e.g.
335 'TPM_RC_SUCCESS').
336 error_code: Error to be returned when unmarshalling is unsuccessful.
337 """
338 _CHECK_VALUE = """
339 if (*target == %(value)s) {
340 return TPM_RC_SUCCESS;
341 }"""
342 _CHECK_VALUE_IFDEF = """
343#ifdef %(value)s
344 if (*target == %(value)s) {
345 return TPM_RC_SUCCESS;
346 }
347#endif"""
348 _UNMARSHAL_END = """
349 return %(error_code)s;
350}
351"""
352 _IFDEF_TYPE_RE = re.compile(r'^TPM_(ALG|CC).*')
353
354 def __init__(self, old_type, new_type):
355 """Initializes a ConstantType instance.
356
357 Values are added to valid_values attribute during parsing.
358
359 Args:
360 old_type: The base type of the constant type.
361 new_type: The name of the type.
362 """
363 self.old_type = old_type
364 self.new_type = new_type
365 self.valid_values = []
366 self.error_code = 'TPM_RC_VALUE'
367
368 def _NeedsIfdef(self):
369 """Returns True if new_type is a type which needs ifdef enclosing."""
370 return self._IFDEF_TYPE_RE.search(self.new_type)
371
372 def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
373 """Writes marshal implementations for ConstantType to |out_file|.
374
375 Args:
376 out_file: The output file.
377 marshalled_types: A set of types for which marshal and unmarshal functions
378 have already been generated.
379 typemap: A dict mapping type names to the corresponding object.
380 """
381 if self.new_type in marshalled_types:
382 return
383 if self.old_type not in marshalled_types:
384 typemap[self.old_type].OutputMarshalImpl(
385 out_file, marshalled_types, typemap)
386 out_file.write(self._TYPEDEF_MARSHAL_FUNCTION % {'old_type': self.old_type,
387 'new_type': self.new_type})
388 out_file.write(self._TYPEDEF_UNMARSHAL_START % {'old_type': self.old_type,
389 'new_type': self.new_type})
390 for value in self.valid_values:
391 if self._NeedsIfdef():
392 out_file.write(self._CHECK_VALUE_IFDEF % {'value': value})
393 else:
394 out_file.write(self._CHECK_VALUE % {'value': value})
395 out_file.write(self._UNMARSHAL_END % {'error_code': self.error_code})
396 marshalled_types.add(self.new_type)
397
398 def OutputMarshalDecl(self, out_file, declared_types, typemap):
399 """Writes marshal declarations for ConstantType to |out_file|.
400
401 Args:
402 out_file: The output file.
403 declared_types: A set of types for which marshal and unmarshal function
404 declarations have already been generated.
405 typemap: A dict mapping type names to the corresponding object.
406 """
407 self._OutputTypedefMarshalDecl(out_file, declared_types, typemap)
408
409class AttributeStructure(TPMType):
410 """Represents a TPM attribute structure type definition.
411
412 Attributes:
413 old_type: The base type of the constant (e.g. 'int').
414 new_type: The name of the type (e.g. 'TPMA_OBJECT').
415 reserved: The list of bit bounds where bits must be 0 (e.g. ['10_2','3']).
416 """
417 # Attribute structures need an explicit cast to the base type.
418 _ATTRIBUTE_MARSHAL_FUNCTION = """
419UINT16 %(new_type)s_Marshal(
420 %(new_type)s *source,
421 BYTE **buffer,
422 INT32 *size) {
423 return %(old_type)s_Marshal((%(old_type)s*)source, buffer, size);
424}
425"""
426 _ATTRIBUTE_UNMARSHAL_START = """
427TPM_RC %(new_type)s_Unmarshal(
428 %(new_type)s *target,
429 BYTE **buffer,
430 INT32 *size) {
431 TPM_RC result;
432 result = %(old_type)s_Unmarshal((%(old_type)s*)target, buffer, size);
433 if (result != TPM_RC_SUCCESS) {
434 return result;
435 }"""
436 _CHECK_RESERVED = """
437 if (target->reserved%(bits)s != 0) {
438 return TPM_RC_RESERVED_BITS;
439 }"""
440
441 def __init__(self, old_type, new_type):
442 """Initializes an AttributeStructure instance.
443
444 Values may be added to reserved attribute during parsing.
445
446 Args:
447 old_type: The base type of the attribute structure.
448 new_type: The name of the type.
449 """
450 self.old_type = old_type
451 self.new_type = new_type
452 self.reserved = []
453
454 def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
455 """Writes marshal implementations for AttributStructure to |out_file|.
456
457 Args:
458 out_file: The output file.
459 marshalled_types: A set of types for which marshal and unmarshal functions
460 have already been generated.
461 typemap: A dict mapping type names to the corresponding object.
462 """
463 if self.new_type in marshalled_types:
464 return
465 if self.old_type not in marshalled_types:
466 typemap[self.old_type].OutputMarshalImpl(
467 out_file, marshalled_types, typemap)
468 out_file.write(self._ATTRIBUTE_MARSHAL_FUNCTION %
469 {'old_type': self.old_type,
470 'new_type': self.new_type})
471 out_file.write(self._ATTRIBUTE_UNMARSHAL_START %
472 {'old_type': self.old_type,
473 'new_type': self.new_type})
474 for bits in self.reserved:
475 out_file.write(self._CHECK_RESERVED % {'bits': bits})
476 out_file.write(self._UNMARSHAL_END)
477 marshalled_types.add(self.new_type)
478
479 def OutputMarshalDecl(self, out_file, declared_types, typemap):
480 """Writes marshal declarations for AttributeStructure to |out_file|.
481
482 Args:
483 out_file: The output file.
484 declared_types: A set of types for which marshal and unmarshal function
485 declarations have already been generated.
486 typemap: A dict mapping type names to the corresponding object.
487 """
488 self._OutputTypedefMarshalDecl(out_file, declared_types, typemap)
489
490class Interface(TPMType):
491 """Represents a TPM interface type definition.
492
493 Attributes:
494 old_type: The base type of the interface (e.g. 'TPM_HANDLE').
495 new_type: The name of the type (e.g. 'TPMI_DH_OBJECT').
496 valid_values: List of valid values for new_type. If this is not empty,
497 valid values for new_type is explicitly defined in the spec.
498 bounds: List of pairs representing bounds. If nonempty, target must fall
499 between one of these bounds.
500 conditional_value: Name of conditionally allowed value. If there is no
501 such value, this variable will be None.
502 supported_values: String literal indicating the name of a list of supported
503 values to be substituted at compile time (e.g. 'AES_KEY_SIZES_BITS').
504 If this is not None, valid values for new_type depends on the
505 implementation.
506 error_code: Return code when an unmarshalling error occurs.
507 """
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700508 _INTERFACE_CONDITIONAL_UNMARSHAL_START = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700509TPM_RC %(new_type)s_Unmarshal(
510 %(new_type)s *target,
511 BYTE **buffer,
512 INT32 *size,
513 BOOL allow_conditional_value) {
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700514 TPM_RC result;"""
515 _INTERFACE_UNMARSHAL_START = """
516TPM_RC %(new_type)s_Unmarshal(
517 %(new_type)s *target,
518 BYTE **buffer,
519 INT32 *size) {
520 TPM_RC result;"""
521 _UNMARSHAL_VALUE = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700522 result = %(old_type)s_Unmarshal(target, buffer, size);
523 if (result != TPM_RC_SUCCESS) {
524 return result;
525 }"""
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700526 _SETUP_CHECK_SUPPORTED_VALUES = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700527 uint16_t supported_values[] = %(supported_values)s;
528 size_t length = sizeof(supported_values)/sizeof(supported_values[0]);
529 size_t i;
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700530 BOOL is_supported_value = FALSE;"""
531 _CHECK_SUPPORTED_VALUES = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700532 for (i = 0; i < length; ++i) {
533 if (*target == supported_values[i]) {
534 is_supported_value = TRUE;
535 break;
536 }
537 }
538 if (!is_supported_value) {
539 return %(error_code)s;
540 }"""
541 _CHECK_CONDITIONAL = """
542 if (*target == %(name)s) {
543 return allow_conditional_value ? TPM_RC_SUCCESS : %(error_code)s;
544 }"""
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700545 _SETUP_CHECK_VALUES = '\n BOOL has_valid_value = FALSE;'
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700546 _VALUE_END_SWITCH = """
547 has_valid_value = TRUE;
548 break;
549 }"""
550 _CHECK_BOUND = """
551 if((*target >= %(lower)s) && (*target <= %(upper)s)) {
552 has_valid_value = TRUE;
553 }"""
554 _CHECK_VALUES_END = """
555 if (!has_valid_value) {
556 return %(error_code)s;
557 }"""
558 _CONDITIONAL_MARSHAL_DECLARATION = """
559UINT16 %(type)s_Marshal(
560 %(type)s *source,
561 BYTE **buffer,
562 INT32 *size);
563
564TPM_RC %(type)s_Unmarshal(
565 %(type)s *target,
566 BYTE **buffer,
567 INT32 *size,
568 BOOL allow_conditioanl_value);
569"""
570 _CONDITIONAL_UNMARSHAL_CALL = """
571 result = %(type)s_Unmarshal(
572 &target->%(name)s, buffer, size, %(flag)s);
573 if (result != TPM_RC_SUCCESS) {
574 return result;
575 }"""
576 _IFDEF_TYPE_RE = re.compile(r'^TPMI_(ALG|ECC)_.*')
577
578 def __init__(self, old_type, new_type):
579 """Initializes an Interface instance.
580
581 Values may be added/assigned to valid_values, bounds, conditional_value,
582 supported_values, and error_code attributes new values during parsing.
583
584 Args:
585 old_type: The base type of the interface.
586 new_type: The name of the type.
587 """
588 self.old_type = old_type
589 self.new_type = new_type
590 self.valid_values = []
591 self.bounds = []
592 self.conditional_value = None
593 self.supported_values = None
594 self.error_code = 'TPM_RC_VALUE'
595
596 def HasConditional(self):
597 """Returns true if Interface has a valid conditional_value."""
598 return self.conditional_value != None
599
600 def _NeedsIfdef(self):
601 """Returns True if new_type is a type which needs ifdef enclosing."""
602 return self._IFDEF_TYPE_RE.search(self.new_type)
603
604 def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
605 """Writes marshal implementation for Interface to |out_file|.
606
607 Args:
608 out_file: The output file.
609 marshalled_types: A set of types for which marshal and unmarshal functions
610 have already been generated.
611 typemap: A dict mapping type names to the corresponding object.
612 """
613 if self.new_type in marshalled_types:
614 return
615 if self.old_type not in marshalled_types:
616 typemap[self.old_type].OutputMarshalImpl(
617 out_file, marshalled_types, typemap)
618 out_file.write(self._TYPEDEF_MARSHAL_FUNCTION % {'old_type': self.old_type,
619 'new_type': self.new_type})
620 if self.conditional_value:
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700621 out_file.write(self._INTERFACE_CONDITIONAL_UNMARSHAL_START %
622 {'old_type': self.old_type,
623 'new_type': self.new_type})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700624 else:
625 out_file.write(
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700626 self._INTERFACE_UNMARSHAL_START % {'old_type': self.old_type,
627 'new_type': self.new_type})
628 # Creating necessary local variables.
629 if self.supported_values:
630 out_file.write(self._SETUP_CHECK_SUPPORTED_VALUES %
631 {'supported_values': self.supported_values})
632 if len(self.valid_values)+len(self.bounds) > 0:
633 out_file.write(self._SETUP_CHECK_VALUES)
634
635 out_file.write(self._UNMARSHAL_VALUE % {'old_type': self.old_type})
636
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700637 if self.supported_values:
638 out_file.write(self._CHECK_SUPPORTED_VALUES %
639 {'supported_values': self.supported_values,
640 'error_code': self.error_code})
641 if self.conditional_value:
642 out_file.write(
643 self._CHECK_CONDITIONAL % {'name': self.conditional_value,
644 'error_code': self.error_code})
645 # Checking for valid values.
646 if len(self.valid_values)+len(self.bounds) > 0:
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700647 if len(self.valid_values) > 0:
648 out_file.write(self._VALUE_START_SWITCH % {'name': '*target'})
649 for value in self.valid_values:
650 if self._NeedsIfdef():
651 out_file.write(self._VALUE_CASE_IFDEF % {'value': value})
652 else:
653 out_file.write(self._VALUE_CASE % {'value': value})
654 out_file.write(self._VALUE_END_SWITCH)
655 for (lower, upper) in self.bounds:
656 out_file.write(
657 self._CHECK_BOUND % {'lower': lower, 'upper': upper})
658 out_file.write(self._CHECK_VALUES_END % {'error_code': self.error_code})
659
660 out_file.write(self._UNMARSHAL_END)
661 marshalled_types.add(self.new_type)
662
663 def OutputMarshalDecl(self, out_file, declared_types, typemap):
664 """Writes marshal declarations for Interface to |out_file|.
665
666 Outputted declaration depends on whether Interface type has a
667 conditionally valid value.
668
669 Args:
670 out_file: The output file.
671 declared_types: A set of types for which marshal and unmarshal function
672 declarations have already been generated.
673 typemap: A dict mapping type names to the corresponding object.
674 """
675 if self.new_type in declared_types:
676 return
677 if self.old_type not in declared_types:
678 typemap[self.old_type].OutputMarshalDecl(
679 out_file, declared_types, typemap)
680 if self.HasConditional():
681 out_file.write(
682 self._CONDITIONAL_MARSHAL_DECLARATION % {'type': self.new_type})
683 else:
684 out_file.write(self._MARSHAL_DECLARATION % {'type': self.new_type})
685 declared_types.add(self.new_type)
686
687 def OutputUnmarshalCall(
688 self, out_file, field_type, field_name, conditional_valid):
689 """Write a call to Unmarshal function for Interface type to |out_file|.
690
691 Override TPMType OutputUnmarshalCall because when an Interface type has
692 a conditionally valid value, a BOOL value (|conditional_valid|) is passed
693 as a parameter.
694
695 Args:
696 out_file: The output file.
697 field_type: The type of the field in 'target' struct to be unmarshalled.
698 field_name: The name of the field in 'target' struct to be unmarshalled.
699 conditional_valid: BOOL value passed to function call indicating if
700 Interface conditional_value is valid.
701 """
702 if self.conditional_value:
703 out_file.write(
704 self._CONDITIONAL_UNMARSHAL_CALL % {'type': field_type,
705 'name': field_name,
706 'flag': conditional_valid})
707 else:
708 out_file.write(self._UNMARSHAL_CALL % {'type': field_type,
709 'name': field_name})
710
711class Structure(TPMType):
712 """Represents a TPM structure.
713
714 Attributes:
715 name: The name of the structure.
716 fields: A list of Field objects representing struct fields.
717 upper_bounds: A dictionary of (name, val) tuples mapping name to max val.
718 lower_bounds: A dictionary of (name, val) tuples mapping name to min val.
719 size_check: Set if TPM2B structure must be size checked (triggered by size=)
720 valid_tag_values: A list of values field tag is allowed to take.
721 error_code: The return code to be returned if an error occurs
722 """
723 _STRUCTURE_MARSHAL_START = """
724UINT16 %(name)s_Marshal(
725 %(name)s *source,
726 BYTE **buffer,
727 INT32 *size) {
728 UINT16 total_size = 0;"""
729 _STRUCTURE_UNMARSHAL_START = """
730TPM_RC %(name)s_Unmarshal(
731 %(name)s *target,
732 BYTE **buffer,
733 INT32 *size) {
734 TPM_RC result;"""
735 _MARSHAL_END = '\n return total_size;\n}\n'
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700736 _SETUP_ARRAY_FIELD = '\n INT32 i;'
737 _CHECK_SIZE_START = """
738 UINT32 start_size = *size;
739 UINT32 struct_size;"""
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700740 _CHECK_SIZE_END = """
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700741 struct_size = start_size - *size - sizeof(target->t.size);
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700742 if (struct_size != target->t.size) {
743 return TPM_RC_SIZE;
744 }"""
745 _TPM2B_ZERO_SIZE = """
746 if (target->t.size == 0) {
747 return %(return_value)s;
748 }"""
749 _CHECK_BOUND = """
750 if (target->%(name)s %(operator)s %(bound_value)s) {
751 return %(error_code)s;
752 }"""
753
754 def __init__(self, name):
755 """Initializes a Structure instance.
756
757 Initially the instance will have no fields, upper_bounds, lower_bounds, or
758 valid_tag_values. Those can be added with AddField(), AddUpperBound(),
759 AddLowerBound(), and AddTagVal() methods.
760
761 Args:
762 name: The name of the structure.
763 """
764 self.name = name
765 self.fields = []
766 self.upper_bounds = {}
767 self.lower_bounds = {}
768 self.size_check = False
769 self.valid_tag_values = []
770 self.error_code = 'TPM_RC_VALUE'
771
772 class Field(object):
773 """Represents a field in TPM structure
774
775 Attributes:
776 field_type: The type of field.
777 field_name: The name of the field.
778 extra_argument: Argument passed to OutputMarshalCall. Value represents a
779 BOOL value, selector value, or array length depending on context.
780 is_array: Boolean indicating whether field is an array.
781 """
782 _MARSHAL_FIELD_ARRAY = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700783 for (i = 0; i < source->%(array_length)s; ++i) {
784 total_size += %(type)s_Marshal(
785 &source->%(name)s[i], buffer, size);
786 }"""
787 _UNMARSHAL_FIELD_ARRAY = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700788 for (i = 0; i < target->%(array_length)s; ++i) {
789 result = %(type)s_Unmarshal(
790 &target->%(name)s[i], buffer, size);
791 if (result != TPM_RC_SUCCESS) {
792 return result;
793 }
794 }"""
795 def __init__(self, field_type, field_name, extra_argument, is_array):
796 """Initializes a Structure.Field instance.
797
798 Initially the instance will have no fields, upper_bounds, lower_bounds, or
799 valid_tag_values. Those can be added with AddField(), AddUpperBound(),
800 AddLowerBound(), and AddTagVal() methods.
801
802 Args:
803 field_type: The type of field.
804 field_name: The name of the field.
805 extra_argument: Argument passed to OutputMarshalCall. Value represents a
806 BOOL value, selector value, or array length depending on context.
807 is_array: Boolean indicating whether field is an array.
808 """
809 self.field_type = field_type
810 self.field_name = field_name
811 self.extra_argument = extra_argument
812 self.is_array = is_array
813
814 def OutputMarshal(self, out_file, typemap):
815 """Write a call to marshal the field this instance represents.
816
817 Args:
818 out_file: The output file.
819 typemap: A dict mapping type names to the corresponding object.
820 """
821 if self.is_array:
822 out_file.write(
823 self._MARSHAL_FIELD_ARRAY % {'type': self.field_type,
824 'name': self.field_name,
825 'array_length': self.extra_argument})
826 else:
827 typemap[self.field_type].OutputMarshalCall(
828 out_file, self.field_type, self.field_name, self.extra_argument)
829
830 def OutputUnmarshal(self, out_file, typemap):
831 """Write a call to unmarshal the field this instance represents.
832
833 Args:
834 out_file: The output file.
835 typemap: A dict mapping type names to the corresponding object.
836 """
837 if self.is_array:
838 out_file.write(
839 self._UNMARSHAL_FIELD_ARRAY % {'type': self.field_type,
840 'name': self.field_name,
841 'array_length': self.extra_argument})
842 else:
843 typemap[self.field_type].OutputUnmarshalCall(
844 out_file, self.field_type, self.field_name, self.extra_argument)
845
846 def AddField(self, field_type, field_name, extra_argument, is_array):
847 """Adds a field to fields attribute in Structure.
848
849 Args:
850 field_name: The name of the field.
851 field_type: The type of field.
852 extra_argument: Argument passed to OutputMarshalCall. Value represents a
853 BOOL value, selector value, or array length depending on context.
854 is_array: Boolean indicating whether field is an array.
855 """
856 # Each TPM2B is a union of two sized buffers, one which is type specific
857 # (the 't' element) and the other is a generic value (the 'b' element). For
858 # this reason a 't.' is prepended for fields in a TPM2B type. See section
859 # 9.11.6 in TCG TPM2.0 Library Specification, Part 2: Structures for more
860 # details.
861 if IsTPM2B(self.name):
862 field_name = 't.' + field_name
863 if is_array:
864 extra_argument = 't.' + extra_argument
865 self.fields.append(
866 self.Field(field_type, field_name, extra_argument, is_array))
867
868 def AddUpperBound(self, field_name, value):
869 """Adds an upper bound for a field.
870
871 Args:
872 field_name: Name of field with bound.
873 value: Value of upper bound.
874 """
875 if IsTPM2B(self.name):
876 field_name = 't.' + field_name
877 self.upper_bounds[field_name] = value
878
879 def AddLowerBound(self, field_name, value):
880 """Adds a lower bound for a field.
881
882 Args:
883 field_name: Name of field with bound.
884 value: Value of lower bound.
885 """
886 if IsTPM2B(self.name):
887 field_name = 't.' + field_name
888 self.lower_bounds[field_name] = value
889
890 def AddTagValue(self, value):
891 """Adds a valid value for tag field.
892
893 Args:
894 value: Valid value for tag field.
895 """
896 self.valid_tag_values.append(value)
897
898 def _GetFieldTypes(self):
899 """Creates a set which holds all current field types.
900
901 Returns:
902 A set of field types.
903 """
904 return set([field.field_type for field in self.fields])
905
906 def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
907 """Writes marshal implementations for Structure to |out_file|.
908
909 Args:
910 out_file: The output file.
911 marshalled_types: A set of types for which marshal and unmarshal functions
912 have already been generated.
913 typemap: A dict mapping type names to the corresponding object.
914 """
915 if self.name in marshalled_types:
916 return
917 # Make sure any dependencies already have marshal functions defined.
918 for field_type in self._GetFieldTypes():
919 if field_type not in marshalled_types:
920 typemap[field_type].OutputMarshalImpl(
921 out_file, marshalled_types, typemap)
922 marshalled_types.add(field_type)
923
924 out_file.write(self._STRUCTURE_MARSHAL_START % {'name': self.name})
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700925 # If any field is an array, create local variable INT32 i.
926 for field in self.fields:
927 if field.is_array:
928 out_file.write(self._SETUP_ARRAY_FIELD)
929 break
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700930 for field in self.fields:
931 field.OutputMarshal(out_file, typemap)
932 out_file.write(self._MARSHAL_END)
933
934 out_file.write(self._STRUCTURE_UNMARSHAL_START % {'name': self.name})
935 if self.size_check:
936 out_file.write(self._CHECK_SIZE_START)
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700937 # If any field is an array, create local variable INT32 i.
938 for field in self.fields:
939 if field.is_array:
940 out_file.write(self._SETUP_ARRAY_FIELD)
941 break
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700942 for field in self.fields:
943 field.OutputUnmarshal(out_file, typemap)
944 return_value = self.error_code
945 if field.field_name == 't.size' and self.size_check:
946 out_file.write(self._TPM2B_ZERO_SIZE % {'return_value': 'TPM_RC_SIZE'})
947 if field.field_name == 't.size' and not self.size_check:
948 out_file.write(
949 self._TPM2B_ZERO_SIZE % {'return_value': 'TPM_RC_SUCCESS'})
950 if field.field_name in self.upper_bounds:
951 if (field.field_name == 'count' or
952 field.field_name == 't.size' or
953 field.field_name == 'size'):
954 return_value = 'TPM_RC_SIZE'
955 out_file.write(self._CHECK_BOUND %
956 {'name': field.field_name,
957 'operator': '>',
958 'bound_value': self.upper_bounds[field.field_name],
959 'error_code': return_value})
960 if field.field_name in self.lower_bounds:
961 if (field.field_name == 'count' or
962 field.field_name == 't.size' or
963 field.field_name == 'size'):
964 return_value = 'TPM_RC_SIZE'
965 out_file.write(self._CHECK_BOUND %
966 {'name': field.field_name,
967 'operator': '<',
968 'bound_value': self.lower_bounds[field.field_name],
969 'error_code': return_value})
970 if field.field_name == 'tag' and len(self.valid_tag_values) != 0:
971 out_file.write(self._VALUE_START_SWITCH % {'name': 'target->tag'})
972 for value in self.valid_tag_values:
973 out_file.write(self._VALUE_CASE % {'value': value})
974 out_file.write(self._VALUE_END_SWITCH % {'error_code': 'TPM_RC_TAG'})
975 if self.size_check:
976 out_file.write(self._CHECK_SIZE_END)
977 out_file.write(self._UNMARSHAL_END)
978
979 marshalled_types.add(self.name)
980
981 def OutputMarshalDecl(self, out_file, declared_types, typemap):
982 """Writes marshal declarations for Structure to |out_file|.
983
984 Args:
985 out_file: The output file.
986 declared_types: A set of types for which marshal and unmarshal function
987 declarations have already been generated.
988 typemap: A dict mapping type names to the corresponding object.
989 """
990 self._OutputStructOrUnionMarshalDecl(out_file, declared_types, typemap)
991
992class Union(TPMType):
993 """Represents a TPM union.
994
995 Attributes:
996 name: The name of the union.
997 fields: A list of Field objects representing union fields.
998 """
999
1000 _UNION_MARSHAL_START = """
1001UINT16 %(name)s_Marshal(
1002 %(name)s *source,
1003 BYTE **buffer,
1004 INT32 *size,
1005 UINT32 selector) {
1006 switch(selector) {"""
1007 _UNION_UNMARSHAL_START = """
1008TPM_RC %(name)s_Unmarshal(
1009 %(name)s *target,
1010 BYTE **buffer,
1011 INT32 *size,
1012 UINT32 selector) {
1013 switch(selector) {"""
1014 _MARSHAL_END = '\n }\n return 0;\n}\n'
1015 _UNMARSHAL_END = '\n }\n return TPM_RC_SELECTOR;\n}\n'
1016 _MARSHAL_DECLARATION = """
1017UINT16 %(type)s_Marshal(
1018 %(type)s *source,
1019 BYTE **buffer,
1020 INT32 *size,
1021 UINT32 selector);
1022
1023TPM_RC %(type)s_Unmarshal(
1024 %(type)s *target,
1025 BYTE **buffer,
1026 INT32 *size,
1027 UINT32 selector);
1028"""
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001029 _CASE_SELECTOR = """
1030 case %(selector)s:"""
1031 _MARSHAL_EMPTY = """
1032 return 0;"""
1033 _UNMARSHAL_EMPTY = """
1034 return TPM_RC_SUCCESS;"""
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001035 _MARSHAL_FIELD = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001036 return %(type)s_Marshal(
1037 (%(type)s*)&source->%(name)s, buffer, size);"""
1038 _UNMARSHAL_FIELD = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001039 return %(type)s_Unmarshal(
1040 (%(type)s*)&target->%(name)s, buffer, size);"""
1041 _SETUP_MARSHAL_FIELD_ARRAY = """
1042 INT32 i;
1043 UINT16 total_size = 0;"""
1044 _SETUP_UNMARSHAL_FIELD_ARRAY = """
1045 INT32 i;
1046 TPM_RC result = TPM_RC_SUCCESS;"""
1047 _MARSHAL_FIELD_ARRAY = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001048 for (i = 0; i < %(array_length)s; ++i) {
1049 total_size += %(type)s_Marshal(
1050 &source->%(name)s[i], buffer, size);
1051 }
1052 return total_size;"""
1053 _UNMARSHAL_FIELD_ARRAY = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001054 for (i = 0; i < %(array_length)s; ++i) {
1055 result = %(type)s_Unmarshal(
1056 &target->%(name)s[i], buffer, size);
1057 if (result != TPM_RC_SUCCESS) {
1058 return result;
1059 }
1060 }
1061 return TPM_RC_SUCCESS;"""
1062 _UNMARSHAL_FIELD_CONDITIONAL = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001063 return %(type)s_Unmarshal(
1064 &target->%(name)s, buffer, size, FALSE);"""
1065 _UNION_MARSHAL_CALL = """
1066 total_size += %(type)s_Marshal(
1067 &source->%(name)s, buffer, size, source->%(selector)s);"""
1068 _UNION_UNMARSHAL_CALL = """
1069 result = %(type)s_Unmarshal(
1070 &target->%(name)s, buffer, size, target->%(selector)s);
1071 if (result != TPM_RC_SUCCESS) {
1072 return result;
1073 }"""
1074 _IFDEF = '\n#ifdef %(type)s'
1075 _ENDIF = '\n#endif'
1076 _IFDEF_TYPE_RE = re.compile(r'^TPM_(ALG|CC).*')
1077 # Represents a field in a TPM union.
1078 Field = collections.namedtuple(
1079 'Field', ['field_type', 'field_name', 'array_length'])
1080
1081 def __init__(self, name):
1082 """Initializes a Union instance.
1083
1084 Initially the instance will have no fields. Fields are added with the
1085 AddField() method.
1086
1087 Args:
1088 name: The name of the structure.
1089 """
1090 self.name = name
1091 self.fields = []
1092
1093 def _NeedsIfdef(self, selector):
1094 """Returns True if selector is a type which needs ifdef enclosing."""
1095 return self._IFDEF_TYPE_RE.search(selector)
1096
1097 def AddField(self, field_type, field_name, array_length):
1098 """Adds a field to fields attribute in Union.
1099
1100 Args:
1101 field_name: The name of the field.
1102 field_type: The type of field.
1103 array_length: Length of array if field is an array type. None if not an
1104 array type.
1105 """
Jocelyn Bohr7cba2332015-08-10 16:28:31 -07001106 # xor is a C++ keyword and must be fixed.
1107 if field_name == 'xor':
1108 field_name = 'xor_'
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001109 self.fields.append(self.Field(field_type, field_name, array_length))
1110
1111 def _OutputMarshalField(
1112 self, out_file, field_type, field_name, array_length, selector, typemap):
1113 """Write a call to marshal a field in this union.
1114
1115 Args:
1116 out_file: The output file.
1117 field_name: The name of the field.
1118 field_type: The type of field.
1119 array_length: Variable indicating length of array, None if field is not
1120 an array.
1121 selector: Selector value associated with field.
1122 typemap: A dict mapping type names to the corresponding object.
1123 """
1124 if array_length:
1125 out_file.write(self._MARSHAL_FIELD_ARRAY % {'type': field_type,
1126 'name': field_name,
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001127 'array_length': array_length})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001128 else:
1129 out_file.write(self._MARSHAL_FIELD % {'type': field_type,
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001130 'name': field_name})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001131
1132 def _OutputUnmarshalField(
1133 self, out_file, field_type, field_name, array_length, selector, typemap):
1134 """Write a call to unmarshal a field in this union.
1135
1136 Args:
1137 out_file: The output file.
1138 field_name: The name of the field.
1139 field_type: The type of field.
1140 array_length: Variable indicating length of array, None if field is not
1141 an array.
1142 selector: Selector value associated with field.
1143 typemap: A dict mapping type names to the corresponding object.
1144 """
1145 if array_length:
1146 out_file.write(
1147 self._UNMARSHAL_FIELD_ARRAY % {'type': field_type,
1148 'name': field_name,
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001149 'array_length': array_length})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001150 elif typemap[field_type].HasConditional():
1151 out_file.write(
1152 self._UNMARSHAL_FIELD_CONDITIONAL % {'type': field_type,
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001153 'name': field_name})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001154 else:
1155 out_file.write(self._UNMARSHAL_FIELD % {'type': field_type,
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001156 'name': field_name})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001157
1158 def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
1159 """Writes marshal implementations for Union to |out_file|.
1160
1161 Args:
1162 out_file: The output file.
1163 marshalled_types: A set of types for which marshal and unmarshal functions
1164 have already been generated.
1165 typemap: A dict mapping type names to the corresponding object.
1166 """
1167 if (self.name in marshalled_types or
1168 self.name == 'TPMU_NAME' or
1169 self.name == 'TPMU_ENCRYPTED_SECRET'):
1170 return
1171 selector_values = union_selectors.GetUnionSelectorValues(self.name)
1172 field_types = {f.field_name: f.field_type for f in self.fields}
1173 array_lengths = {f.field_name: f.array_length for f in self.fields}
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001174 # Make sure any dependencies already have marshal functions defined.
1175 for field_name in field_types:
1176 field_type = field_types[field_name]
1177 if field_type not in marshalled_types:
1178 typemap[field_type].OutputMarshalImpl(
1179 out_file, marshalled_types, typemap)
1180 marshalled_types.add(field_type)
Vadim Bendeburye6c58e42015-09-08 12:55:42 -07001181 out_file.write(self._UNION_MARSHAL_START % {'name': self.name})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001182 # Set up variables if Union is an array type.
1183 if self.fields[0].array_length:
1184 out_file.write(self._SETUP_MARSHAL_FIELD_ARRAY)
1185 for selector in selector_values:
1186 field_name = union_selectors.GetUnionSelectorField(self.name, selector)
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001187 if self._NeedsIfdef(selector):
1188 out_file.write(self._IFDEF % {'type': selector})
1189 out_file.write(self._CASE_SELECTOR % {'selector':selector})
1190 # Selector is not associated with a name, so no marshaling occurs.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001191 if not field_name:
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001192 out_file.write(self._MARSHAL_EMPTY)
1193 if self._NeedsIfdef(selector):
1194 out_file.write(self._ENDIF)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001195 continue
1196 field_type = field_types[field_name]
1197 array_length = array_lengths[field_name]
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001198 self._OutputMarshalField(
1199 out_file, field_type, field_name, array_length, selector, typemap)
1200 if self._NeedsIfdef(selector):
1201 out_file.write(self._ENDIF)
1202 out_file.write(self._MARSHAL_END)
1203 out_file.write(self._UNION_UNMARSHAL_START % {'name': self.name})
1204 # Set up variables if Union is an array type.
1205 if self.fields[0].array_length:
1206 out_file.write(self._SETUP_UNMARSHAL_FIELD_ARRAY)
1207 for selector in selector_values:
1208 field_name = union_selectors.GetUnionSelectorField(self.name, selector)
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001209 if self._NeedsIfdef(selector):
1210 out_file.write(self._IFDEF % {'type': selector})
1211 out_file.write(self._CASE_SELECTOR % {'selector': selector})
1212 # Selector is not associated with a name, so no unmarshaling occurs.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001213 if not field_name:
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001214 out_file.write(self._UNMARSHAL_EMPTY)
1215 if self._NeedsIfdef(selector):
1216 out_file.write(self._ENDIF)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001217 continue
1218 field_type = field_types[field_name]
1219 array_length = array_lengths[field_name]
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001220 self._OutputUnmarshalField(
1221 out_file, field_type, field_name, array_length, selector, typemap)
1222 if self._NeedsIfdef(selector):
1223 out_file.write(self._ENDIF)
1224 out_file.write(self._UNMARSHAL_END)
1225 marshalled_types.add(self.name)
1226
1227 def OutputMarshalDecl(self, out_file, declared_types, typemap):
1228 """Writes marshal declarations for Union to |out_file|.
1229
1230 Args:
1231 out_file: The output file.
1232 declared_types: A set of types for which marshal and unmarshal function
1233 declarations have already been generated.
1234 typemap: A dict mapping type names to the corresponding object.
1235 """
1236 self._OutputStructOrUnionMarshalDecl(out_file, declared_types, typemap)
1237
1238 def OutputMarshalCall(self, out_file, field_type, field_name, selector):
1239 """Write a call to marshal function for Union type to |out_file|.
1240
1241 Override TPMType OutputMarshalCall to pass in selector value.
1242
1243 Args:
1244 out_file: The output file.
1245 field_type: The type of the field in 'target' struct to be unmarshalled.
1246 field_name: The name of the field in 'target' struct to be unmarshalled.
1247 selector: The name of the selector value.
1248 """
1249 out_file.write(self._UNION_MARSHAL_CALL % {'type': field_type,
1250 'name': field_name,
1251 'selector': selector})
1252
1253 def OutputUnmarshalCall(self, out_file, field_type, field_name, selector):
1254 """Write a call to unmarshal function for Union type to |out_file|.
1255
1256 Override TPMType OutputUnmashalCall to pass in selector value.
1257
1258 Args:
1259 out_file: The output file.
1260 field_type: The type of the field in 'target' struct to be unmarshalled.
1261 field_name: The name of the field in 'target' struct to be unmarshalled.
1262 selector: The name of the selector value.
1263 """
1264 out_file.write(self._UNION_UNMARSHAL_CALL % {'type': field_type,
1265 'name': field_name,
1266 'selector': selector})
1267
1268class StructureParser(object):
1269 """Structure definition parser.
1270
1271 The input text file is extracted from the PDF file containing the TPM
1272 structures specification from the Trusted Computing Group. The syntax
1273 of the text file is defined by extract_structures.sh.
1274
1275 - Parses typedefs to a list of Typedef objects.
1276 - Parses constants to a list of ConstantType objects.
1277 - Parses attribute structures to a list of AttributeStruct objects.
1278 - Parses interfaces to a list of Interface objects.
1279 - Parses structs to a list of Structure objects.
1280 - Parses unions to a list of Union objects
1281
1282 The parser also creates 'typemap' dict which maps every type to its generator
1283 object. This typemap helps manage type dependencies.
1284
1285 Example usage:
1286 parser = StructureParser(open('myfile'))
1287 types, typemap = parser.Parse()
1288 """
1289
1290 # Compile regular expressions.
1291 _BEGIN_TYPES_TOKEN = '_BEGIN_TYPES'
1292 _BEGIN_CONSTANTS_TOKEN = '_BEGIN_CONSTANTS'
1293 _BEGIN_ATTRIBUTE_STRUCTS_TOKEN = '_BEGIN_ATTRIBUTE_STRUCTS'
1294 _BEGIN_INTERFACES_TOKEN = '_BEGIN_INTERFACES'
1295 _BEGIN_STRUCTURES_TOKEN = '_BEGIN_STRUCTURES'
1296 _BEGIN_UNIONS_TOKEN = '_BEGIN_UNIONS'
1297 _BEGIN_DEFINES_TOKEN = '_BEGIN_DEFINES'
1298 _END_TOKEN = '_END'
1299 _OLD_TYPE_RE = re.compile(r'^_OLD_TYPE\s+(\w+)$')
1300 _NEW_TYPE_RE = re.compile(r'^_NEW_TYPE\s+(\w+)$')
1301 _STRUCTURE_RE = re.compile(r'^_STRUCTURE\s+(\w+)$')
1302 _UNION_RE = re.compile(r'^_UNION\s+(\w+)$')
1303 _TYPE_RE = re.compile(r'^_TYPE\s+(\w+)$')
1304 _NAME = r'[a-zA-Z0-9_()\[\]/\*\+\-]+'
1305 _NAME_RE = re.compile(r'^_NAME\s+([a-zA-Z0-9_()/]+)$')
1306 _SUBSTITUTE_RE = re.compile(r'^_SUBSTITUTE\s+([a-zA-Z0-9_()/]+)$')
1307 _CONDITIONAL_RE = re.compile(r'^_CONDITIONAL\s+([a-zA-Z0-9_()/]+)$')
1308 _MIN_RE = re.compile(r'^_MIN\s+([a-zA-Z0-9_()/]+)$')
1309 _MAX_RE = re.compile(r'^_MAX\s+([a-zA-Z0-9_()/]+)$')
1310 _RETURN_RE = re.compile(r'^_RETURN\s+([a-zA-Z0-9_()/]+)$')
1311 _RESERVED_RE = re.compile(r'^_RESERVED\s+([a-zA-Z0-9_()/]+)$')
1312
1313 # Regular expressions for structures.
1314 _NAME_UNION_RE = re.compile(
1315 r'^_NAME\s+([a-zA-Z0-9_()/]+)\s+_UNION\s+([a-zA-Z0-9_()/]+)$')
1316 _NAME_ARRAY_RE = re.compile(
1317 r'^_NAME\s+([a-zA-Z0-9_()/]+)\s+_ARRAY\s+([a-zA-Z0-9_()/]+)$')
1318 _NAME_PLUS_RE = re.compile(r'^_NAME\s+([a-zA-Z0-9_()\[\]/\*\+\-]+)\s+_PLUS$')
1319 _VALID_RE = re.compile(r'^_VALID\s+([a-zA-Z0-9_()\[\]/\*\+\-]+)$')
1320 _FIELD_MAX_RE = re.compile(
1321 r'^_MAX\s+([a-zA-Z0-9_()/]+)\s+([a-zA-Z0-9_()/]+)$')
1322 _FIELD_MIN_RE = re.compile(
1323 r'^_MIN\s+([a-zA-Z0-9_()/]+)\s+([a-zA-Z0-9_()/]+)$')
1324 _NAME_SIZE_CHECK_RE = re.compile(r'^_NAME size _CHECK$')
1325
1326 def __init__(self, in_file):
1327 """Initializes a StructureParser instance.
1328
1329 Args:
1330 in_file: A file as returned by open() which has been opened for reading.
1331 """
1332 self._line = None
1333 self._in_file = in_file
1334
1335 def _NextLine(self):
1336 """Gets the next input line.
1337
1338 Returns:
1339 # The next input line if another line is available, None otherwise.
1340 """
1341 try:
1342 self._line = self._in_file.next()
1343 except StopIteration:
1344 self._line = None
1345
1346 def Parse(self):
1347 """Parse everything in a structures file.
1348
1349 Returns:
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001350 A type-map as described in the class documentation.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001351 """
1352 self._NextLine()
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001353 typemap = {}
1354 # maps types to valid constants
1355 while self._line:
1356 if self._BEGIN_TYPES_TOKEN == self._line.rstrip():
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001357 self._ParseTypes(typemap)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001358 elif self._BEGIN_CONSTANTS_TOKEN == self._line.rstrip():
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001359 self._ParseConstants(typemap)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001360 elif self._BEGIN_ATTRIBUTE_STRUCTS_TOKEN == self._line.rstrip():
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001361 self._ParseAttributeStructs(typemap)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001362 elif self._BEGIN_INTERFACES_TOKEN == self._line.rstrip():
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001363 self._ParseInterfaces(typemap)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001364 elif self._BEGIN_STRUCTURES_TOKEN == self._line.rstrip():
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001365 self._ParseStructures(typemap)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001366 elif self._BEGIN_UNIONS_TOKEN == self._line.rstrip():
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001367 self._ParseUnions(typemap)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001368 else:
1369 print('Invalid file format: %s' % self._line)
1370 break
1371 self._NextLine()
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001372 return typemap
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001373
1374 def _ParseTypes(self, typemap):
1375 """Parses a typedefs section.
1376
1377 The current line should be _BEGIN_TYPES and the method will stop parsing
1378 when an _END line is found.
1379
1380 Args:
1381 typemap: A dictionary to which parsed types are added.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001382 """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001383 self._NextLine()
1384 while self._END_TOKEN != self._line.rstrip():
1385 match = self._OLD_TYPE_RE.search(self._line)
1386 if not match:
1387 print('Invalid old type: %s' % self._line)
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001388 return
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001389 old_type = match.group(1)
1390 self._NextLine()
1391 match = self._NEW_TYPE_RE.search(self._line)
1392 if not match:
1393 print('Invalid new type: %s' % self._line)
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001394 return
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001395 new_type = match.group(1)
1396 self._NextLine()
1397 # We don't need code for BOOL type to be generated.
1398 if new_type == 'BOOL':
1399 continue
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001400 typemap[new_type] = Typedef(old_type, new_type)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001401
1402 def _ParseConstants(self, typemap):
1403 """Parses a constants section.
1404
1405 The current line should be _BEGIN_CONSTANTS and the method will stop parsing
1406 when an _END line is found. Each group of constants has an associated type
1407 alias.
1408
1409 Args:
1410 typemap: A dictionary to which parsed types are added.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001411 """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001412 self._NextLine()
1413 while self._END_TOKEN != self._line.rstrip():
1414 match_old = self._OLD_TYPE_RE.search(self._line)
1415 if not match_old:
1416 print('Invalid constants section, expected OLD_TYPE: %s' % self._line)
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001417 return
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001418 old_type = match_old.group(1)
1419 self._NextLine()
1420 match_new = self._NEW_TYPE_RE.search(self._line)
1421 if not match_new:
1422 print('Invalid constants section, expected NEW_TYPE: %s' % self._line)
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001423 return
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001424 new_type = match_new.group(1)
1425 self._NextLine()
1426 current_constant_type = ConstantType(old_type, new_type)
1427 match_name = self._NAME_RE.search(self._line)
1428 if not match_name:
1429 print('Invalid constant name: %s' % self._line)
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001430 return
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001431 while match_name:
1432 name = match_name.group(1)
1433 current_constant_type.valid_values.append(name)
1434 self._NextLine()
1435 match_name = self._NAME_RE.search(self._line)
1436 match_return = self._RETURN_RE.search(self._line)
1437 if not match_return:
1438 print('Invalid constants section, expected RETURN: %s' % self._line)
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001439 return
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001440 current_constant_type.error_code = match_return.group(1)
1441 self._NextLine()
1442 # We don't need code for TPM_PS type to be generated.
1443 if new_type == 'TPM_PS':
1444 continue
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001445 typemap[new_type] = current_constant_type
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001446
1447 def _ParseAttributeStructs(self, typemap):
1448 """Parses an attribute structs section.
1449
1450 The current line should be _BEGIN_ATTRIBUTE_STRUCTS and the method will
1451 stop parsing when an _END line is found. Each attribute structure has an
1452 associated type alias.
1453
1454 Args:
1455 typemap: A dictionary to which parsed types are added.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001456 """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001457 self._NextLine()
1458 while self._END_TOKEN != self._line.rstrip():
1459 match_old = self._OLD_TYPE_RE.search(self._line)
1460 if not match_old:
1461 print('Invalid attributes section, expected OLD_TYPE: %s' % self._line)
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001462 return
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001463 old_type = match_old.group(1)
1464 self._NextLine()
1465 match_new = self._NEW_TYPE_RE.search(self._line)
1466 if not match_new:
1467 print('Invalid attributes section, expected NEW_TYPE: %s' % self._line)
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001468 return
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001469 new_type = match_new.group(1)
1470 self._NextLine()
1471 current_attribute_struct = AttributeStructure(old_type, new_type)
1472 match_reserved = self._RESERVED_RE.search(self._line)
1473 while match_reserved:
1474 bits = match_reserved.group(1)
1475 current_attribute_struct.reserved.append(bits)
1476 self._NextLine()
1477 match_reserved = self._RESERVED_RE.search(self._line)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001478 typemap[new_type] = current_attribute_struct
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001479
1480 def _ParseInterfaces(self, typemap):
1481 """Parses an interface types section.
1482
1483 The current line should be _BEGIN_INTERFACES and the method will stop
1484 parsing when an _END line is found. Each interface type has an associated
1485 type alias.
1486
1487 Args:
1488 typemap: A dictionary to which parsed types are added.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001489 """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001490 self._NextLine()
1491 while self._END_TOKEN != self._line.rstrip():
1492 match_old = self._OLD_TYPE_RE.search(self._line)
1493 if not match_old:
1494 print('Invalid interfaces section, expected OLD_TYPE: %s' % self._line)
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001495 return
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001496 old_type = match_old.group(1)
1497 self._NextLine()
1498 match_new = self._NEW_TYPE_RE.search(self._line)
1499 if not match_new:
1500 print('Invalid interfaces section, expected NEW_TYPE: %s' % self._line)
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001501 return
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001502 new_type = match_new.group(1)
1503 self._NextLine()
1504 current_interface = Interface(old_type, new_type)
1505 while True:
1506 match_name = self._NAME_RE.search(self._line)
1507 match_conditional_value = self._CONDITIONAL_RE.search(self._line)
1508 match_min = self._MIN_RE.search(self._line)
1509 match_return = self._RETURN_RE.search(self._line)
1510 match_supported_values = self._SUBSTITUTE_RE.search(self._line)
1511 if match_name:
1512 current_interface.valid_values.append(match_name.group(1))
1513 elif match_supported_values:
1514 current_interface.supported_values = match_supported_values.group(1)
1515 elif match_min:
1516 lower = match_min.group(1)
1517 self._NextLine()
1518 match_max = self._MAX_RE.search(self._line)
1519 if not match_max:
1520 print('Invalid interfaces section, expected _MAX: %s' % self._line)
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001521 return
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001522 upper = match_max.group(1)
1523 current_interface.bounds.append((lower, upper))
1524 elif match_conditional_value:
1525 current_interface.conditional_value = match_conditional_value.group(1)
1526 elif match_return:
1527 current_interface.error_code = match_return.group(1)
1528 self._NextLine()
1529 break
1530 else:
1531 print('Invalid interfaces section: %s' % self._line)
1532 break
1533 self._NextLine()
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001534 typemap[new_type] = current_interface
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001535
1536 def _ParseStructures(self, typemap):
1537 """Parses a structures section.
1538
1539 The current line should be _BEGIN_STRUCTURES and the method will stop
1540 parsing when an _END line is found.
1541
1542 Args:
1543 typemap: A dictionary to which parsed types are added.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001544 """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001545 self._NextLine()
1546 while self._END_TOKEN != self._line.rstrip():
1547 match_structure = self._STRUCTURE_RE.search(self._line)
1548 if not match_structure:
1549 print('Invalid structure section, expected _STRUCTURE: %s' % self._line)
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001550 return
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001551 structure_name = match_structure.group(1)
1552 current_structure = Structure(structure_name)
1553 self._NextLine()
1554 match_type = self._TYPE_RE.search(self._line)
1555 if not match_type:
1556 print('Invalid field type: %s' % self._line)
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001557 return
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001558 while match_type:
1559 field_type = match_type.group(1)
1560 self._NextLine()
1561 match_name = self._NAME_RE.search(self._line)
1562 match_name_union = self._NAME_UNION_RE.search(self._line)
1563 match_name_array = self._NAME_ARRAY_RE.search(self._line)
1564 match_name_plus = self._NAME_PLUS_RE.search(self._line)
1565 match_name_size_check = self._NAME_SIZE_CHECK_RE.search(self._line)
1566 if match_name:
1567 field_name = match_name.group(1)
1568 current_structure.AddField(
1569 field_type, field_name, 'FALSE', False)
1570 self._NextLine()
1571 # Check for extra lines after tag field.
1572 if field_name == 'tag':
1573 match_valid = self._VALID_RE.search(self._line)
1574 if match_valid:
1575 while True:
1576 match_valid = self._VALID_RE.search(self._line)
1577 if match_valid:
1578 current_structure.AddTagValue(match_valid.group(1))
1579 self._NextLine()
1580 else:
1581 self._NextLine()
1582 break
1583 # Check for bounds.
1584 else:
1585 match_field_max = self._FIELD_MAX_RE.search(self._line)
1586 match_field_min = self._FIELD_MIN_RE.search(self._line)
1587 if match_field_max:
1588 current_structure.AddUpperBound(
1589 match_field_max.group(1), match_field_max.group(2))
1590 self._NextLine()
1591 elif match_field_min:
1592 current_structure.AddLowerBound(
1593 match_field_min.group(1), match_field_min.group(2))
1594 self._NextLine()
1595 elif match_name_union:
1596 field_name = match_name_union.group(1)
1597 selector = match_name_union.group(2)
1598 current_structure.AddField(
1599 field_type, field_name, selector, False)
1600 self._NextLine()
1601 elif match_name_array:
1602 field_name = match_name_array.group(1)
1603 array_length = match_name_array.group(2)
1604 current_structure.AddField(
1605 field_type, field_name, array_length, True)
1606 self._NextLine()
1607 # Check for bounds.
1608 match_field_max = self._FIELD_MAX_RE.search(self._line)
1609 match_field_min = self._FIELD_MIN_RE.search(self._line)
1610 if match_field_max:
1611 current_structure.AddUpperBound(
1612 match_field_max.group(1), match_field_max.group(2))
1613 self._NextLine()
1614 elif match_field_min:
1615 current_structure.AddLowerBound(
1616 match_field_min.group(1), match_field_min.group(2))
1617 self._NextLine()
1618 elif match_name_plus:
1619 field_name = match_name_plus.group(1)
1620 current_structure.AddField(
1621 field_type, field_name, 'TRUE', False)
1622 self._NextLine()
1623 elif match_name_size_check:
1624 field_name = 'size'
1625 current_structure.AddField(
1626 field_type, field_name, 'FALSE', False)
1627 current_structure.size_check = True
1628 self._NextLine()
1629 else:
1630 print('Invalid field name: %s' % self._line)
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001631 return
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001632 match_type = self._TYPE_RE.search(self._line)
1633 match_return = self._RETURN_RE.search(self._line)
1634 if match_return:
1635 current_structure.error_code = match_return.group(1)
1636 self._NextLine()
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001637 typemap[structure_name] = current_structure
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001638
1639 def _ParseUnions(self, typemap):
1640 """Parses a unions section.
1641
1642 The current line should be _BEGIN_UNIONS and the method will stop parsing
1643 when an _END line is found.
1644
1645 Args:
1646 typemap: A dictionary to which parsed types are added.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001647 """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001648 self._NextLine()
1649 while self._END_TOKEN != self._line.rstrip():
1650 match_union = self._UNION_RE.search(self._line)
1651 if not match_union:
1652 print('Invalid structure section, expected _STRUCTURE: %s' % self._line)
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001653 return
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001654 union_name = match_union.group(1)
1655 current_union = Union(union_name)
1656 self._NextLine()
1657 match_type = self._TYPE_RE.search(self._line)
1658 if not match_type:
1659 print('Invalid field type: %s' % self._line)
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001660 return
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001661 while match_type:
1662 field_type = match_type.group(1)
1663 self._NextLine()
1664 match_name = self._NAME_RE.search(self._line)
1665 match_name_array = self._NAME_ARRAY_RE.search(self._line)
1666 if match_name:
1667 field_name = match_name.group(1)
1668 # Field could be interface type with conditional value
1669 current_union.AddField(field_type, field_name, None)
1670 self._NextLine()
1671 elif match_name_array:
1672 field_name = match_name_array.group(1)
1673 array_length = match_name_array.group(2)
1674 current_union.AddField(field_type, field_name, array_length)
1675 self._NextLine()
1676 else:
1677 print('Invalid field name: %s' % self._line)
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001678 return
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001679 match_type = self._TYPE_RE.search(self._line)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001680 typemap[union_name] = current_union
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001681
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001682def GenerateHeader(typemap):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001683 """Generates a header file with declarations for all given generator objects.
1684
1685 Args:
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001686 typemap: A dict mapping type names to the corresponding object.
1687 """
1688 out_file = open(_OUTPUT_FILE_H, 'w')
1689 out_file.write(_COPYRIGHT_HEADER)
1690 guard_name = 'TPM2_%s_' % _OUTPUT_FILE_H.upper().replace('.', '_')
1691 out_file.write(_HEADER_FILE_GUARD_HEADER % {'name': guard_name})
1692 out_file.write(_HEADER_FILE_INCLUDES)
1693 # These types are built-in or defined by <stdint.h>; they serve as base cases
1694 # when defining type dependencies.
1695 declared_types = set(_BASIC_TYPES)
1696 # Generate serialize / parse function declarations.
1697 for basic_type in _BASIC_TYPES:
1698 out_file.write(_STANDARD_MARSHAL_DECLARATION % {'type': basic_type})
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001699 for tpm_type in [typemap[x] for x in sorted(typemap.keys())]:
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001700 tpm_type.OutputMarshalDecl(out_file, declared_types, typemap)
1701 out_file.write(_HEADER_FILE_GUARD_FOOTER % {'name': guard_name})
1702 out_file.close()
1703 call(['clang-format', '-i', '-style=Chromium', 'tpm_generated.h'])
1704
1705
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001706def GenerateImplementation(typemap):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001707 """Generates implementation code for each type.
1708
1709 Args:
1710 types: A list of Typedef objects.
1711 typemap: A dict mapping type names to the corresponding object.
1712 """
1713 out_file = open(_OUTPUT_FILE_CC, 'w')
1714 out_file.write(_COPYRIGHT_HEADER)
1715 out_file.write(_IMPLEMENTATION_FILE_INCLUDES)
1716 marshalled_types = set(_BASIC_TYPES)
1717 for basic_type in _BASIC_TYPES:
1718 out_file.write(_MARSHAL_BASIC_TYPE % {'type': basic_type})
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001719 for tpm_type in [typemap[x] for x in sorted(typemap.keys())]:
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001720 tpm_type.OutputMarshalImpl(out_file, marshalled_types, typemap)
1721 out_file.close()
1722 call(['clang-format', '-i', '-style=Chromium', 'tpm_generated.c'])