blob: 2e5ed8e1d5a0847e14c038f0c3cdce3ee3979838 [file] [log] [blame]
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001# Copyright 2015 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""A code generator for TPM 2.0 structures.
6
Vadim Bendebury595736f2015-09-17 17:19:18 -07007The structure generator provides classes to create various objects
8(structures, unions, constants, etc.) and then convert the set of generated
9objects into valid C files named tpm_generated.{h,c}.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -070010
ChromeOS Developer9edfbac2015-07-17 16:33:16 -070011"""
12
13from __future__ import print_function
14
Vadim Bendebury595736f2015-09-17 17:19:18 -070015import datetime
ChromeOS Developer9edfbac2015-07-17 16:33:16 -070016import re
ChromeOS Developer9edfbac2015-07-17 16:33:16 -070017
Vadim Bendebury595736f2015-09-17 17:19:18 -070018from subprocess import call
ChromeOS Developer9edfbac2015-07-17 16:33:16 -070019
20_BASIC_TYPES = ['uint8_t', 'int8_t', 'uint16_t', 'int16_t', 'uint32_t',
21 'int32_t', 'uint64_t', 'int64_t']
22_OUTPUT_FILE_H = 'tpm_generated.h'
23_OUTPUT_FILE_CC = 'tpm_generated.c'
Vadim Bendebury595736f2015-09-17 17:19:18 -070024COPYRIGHT_HEADER = (
25 '// Copyright %d The Chromium OS Authors. All rights reserved.\n'
ChromeOS Developer9edfbac2015-07-17 16:33:16 -070026 '// Use of this source code is governed by a BSD-style license that can '
27 'be\n'
28 '// found in the LICENSE file.\n'
29 '\n'
Vadim Bendebury595736f2015-09-17 17:19:18 -070030 '// THIS CODE IS GENERATED - DO NOT MODIFY!\n' %
31 datetime.datetime.now().year)
32HEADER_FILE_GUARD_HEADER = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -070033#ifndef %(name)s
34#define %(name)s
35"""
Vadim Bendebury595736f2015-09-17 17:19:18 -070036HEADER_FILE_GUARD_FOOTER = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -070037#endif // %(name)s
38"""
39_HEADER_FILE_INCLUDES = """
40#include <endian.h>
41#include <string.h>
42
43#include "TPM_Types.h"
44#include "Tpm.h"
45"""
46_IMPLEMENTATION_FILE_INCLUDES = """
47#include "tpm_generated.h"
48"""
49# Function signatures for generated marshaling code are specified in TCG TPM2.0
50# Library Specification, Part 4: Supporting Routines, sections 4.2.2 and 4.2.3.
51_MARSHAL_BASIC_TYPE = """
52UINT16 %(type)s_Marshal(%(type)s *source, BYTE **buffer, INT32 *size) {
Jocelyn Bohrfb668122015-07-30 10:17:56 -070053 %(type)s value_net = *source;
ChromeOS Developer9edfbac2015-07-17 16:33:16 -070054 if (!size || *size < sizeof(%(type)s)) {
55 return sizeof(%(type)s);
56 }
ChromeOS Developer9edfbac2015-07-17 16:33:16 -070057 switch (sizeof(%(type)s)) {
58 case 2:
59 value_net = htobe16(*source);
60 break;
61 case 4:
62 value_net = htobe32(*source);
63 break;
64 case 8:
65 value_net = htobe64(*source);
66 break;
67 default:
68 break;
69 }
70 memcpy(*buffer, &value_net, sizeof(%(type)s));
71 *buffer += sizeof(%(type)s);
72 *size -= sizeof(%(type)s);
73 return sizeof(%(type)s);
74}
75
76TPM_RC %(type)s_Unmarshal(%(type)s *target, BYTE **buffer, INT32 *size) {
Jocelyn Bohrfb668122015-07-30 10:17:56 -070077 %(type)s value_net = 0;
ChromeOS Developer9edfbac2015-07-17 16:33:16 -070078 if (!size || *size < sizeof(%(type)s)) {
79 return TPM_RC_INSUFFICIENT;
80 }
ChromeOS Developer9edfbac2015-07-17 16:33:16 -070081 memcpy(&value_net, *buffer, sizeof(%(type)s));
82 switch (sizeof(%(type)s)) {
83 case 2:
84 *target = be16toh(value_net);
85 break;
86 case 4:
87 *target = be32toh(value_net);
88 break;
89 case 8:
90 *target = be64toh(value_net);
91 break;
92 default:
93 *target = value_net;
94 }
95 *buffer += sizeof(%(type)s);
96 *size -= sizeof(%(type)s);
97 return TPM_RC_SUCCESS;
98}
99"""
100_STANDARD_MARSHAL_DECLARATION = """
101UINT16 %(type)s_Marshal(
102 %(type)s *source,
103 BYTE **buffer,
104 INT32 *size);
105
106TPM_RC %(type)s_Unmarshal(
107 %(type)s *target,
108 BYTE **buffer,
109 INT32 *size);
110"""
111
Vadim Bendebury595736f2015-09-17 17:19:18 -0700112
113def _IsTPM2B(name):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700114 return name.startswith('TPM2B_')
115
116
Vadim Bendebury595736f2015-09-17 17:19:18 -0700117class Field(object):
118 """Represents a field in TPM structure or union.
119
120 This object is used in several not fully overlapping cases, not all
121 attributes apply to all use cases.
122
123 The 'array_size' and 'run_time_size' attributes below are related to the
124 following code example:
125
126 struct {
127 int size;
128 byte array[MAX_SIZE]
129 } object.
130
131 In this structure the actual number of bytes in the array could be anything
132 from zero to MAX_SIZE. The field 'size' denotes the actual number of
133 elements at run time. So, when this object is constructed, array_size is
134 'MAX_SIZE' and run_time_size is 'size'.
135
136 The 'selector_value' attribute is used to associate union fields with
137 certain object types. For instance
138
139 typedef union {
140 TPM2B_PUBLIC_KEY_RSA rsa;
141 TPMS_ECC_POINT ecc;
142 } TPMU_PUBLIC_ID;
143
144 the field named 'rsa' will have its 'selector_value' set to 'TPM_ALG_RSA'.
145
146 Attributes:
147 field_type: a string, the type of field.
148 field_name: a string, the name of the field.
149 array_size: a string, see example above
150 run_time_size: a string, see example above
151 selector_value: a string, see example above
152 conditional_value: a string, necessary for validation when unmarshaling.
153 Some types have a value that is allowed for some
154 commands but not others. E.g. 'TPM_RS_PW' is a
155 conditional value for the 'TPMI_SH_AUTH_SESSION' type
156 and TPM_ALG_NULL is a conditional value for the
157 TPMI_ALG_HASH type.
158 """
159 _MARSHAL_FIELD_ARRAY = """
160 for (i = 0; i < source->%(array_length)s; ++i) {
161 total_size += %(type)s_Marshal(&source->%(name)s[i], buffer, size);
162 }"""
163 _UNMARSHAL_FIELD_ARRAY = """
164 for (i = 0; i < target->%(array_length)s; ++i) {
165 result = %(type)s_Unmarshal(&target->%(name)s[i], buffer, size);
166 if (result != TPM_RC_SUCCESS) {
167 return result;
168 }
169 }"""
170
171 def __init__(self, field_type, field_name,
172 selector=None, array_size='',
173 conditional_value='FALSE',
174 run_time_size=None):
175 """Initializes a Field instance.
176
177 Args:
178 field_type: Initial value for the field type attribute.
179 field_name: Initial value for the field name attribute.
180 selector: Initial value for the selector attribute.
181 array_size: Initial value for the array_size attribute.
182 conditional_value: Initial value of the conditional_value attribute.
183 run_time_size: Initial value of the run_time_size attribute
184 """
185 if not field_type:
186 # Some tables include rows without data type, for instance 'Table 70 -
187 # Definition of TPMU_HA Union' in part 2. These rows are supposed to
188 # cause another case added to the switch in the marshaling function
189 # (processing of TPM_ALG_NULL in this example). Setting field name to ''
190 # makes sure that the actual generated structure/union does not have an
191 # entry for this field, setting type of such field to some value
192 # simplifies functions generating the marshaling code.
193 self.field_type = 'BYTE'
194 self.field_name = ''
195 else:
196 self.field_type = field_type
197 self.field_name = field_name
198 self.array_size = array_size
199 self.selector_value = selector
200 self.conditional_value = conditional_value
201 self.run_time_size = run_time_size
202
203 def OutputMarshal(self, out_file, typemap):
204 """Write a call to marshal the field this instance represents.
205
206 Args:
207 out_file: The output file.
208 typemap: A dict mapping type names to the corresponding object.
209 """
210 if self.array_size:
211 if self.run_time_size:
212 real_size = self.run_time_size
213 else:
214 real_size = self.array_size
215 out_file.write(
216 self._MARSHAL_FIELD_ARRAY % {'type': self.field_type,
217 'name': self.field_name,
218 'array_length': real_size})
219 else:
220 typemap[self.field_type].OutputMarshalCall(out_file, self)
221
222 def OutputUnmarshal(self, out_file, typemap):
223 """Write a call to unmarshal the field this instance represents.
224
225 Args:
226 out_file: The output file.
227 typemap: A dict mapping type names to the corresponding object.
228 """
229 if self.array_size:
230 if self.run_time_size:
231 real_size = self.run_time_size
232 else:
233 real_size = self.array_size
234 out_file.write(
235 self._UNMARSHAL_FIELD_ARRAY % {'type': self.field_type,
236 'name': self.field_name,
237 'array_length': real_size})
238 else:
239 typemap[self.field_type].OutputUnmarshalCall(out_file, self)
240
241
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700242class TPMType(object):
Vadim Bendebury595736f2015-09-17 17:19:18 -0700243 """Base type for all TPMTypes.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700244
245 Contains functions and string literals common to all TPM types.
246 """
247 # A function to marshal a TPM typedef.
248 _TYPEDEF_MARSHAL_FUNCTION = """
249UINT16 %(new_type)s_Marshal(
250 %(new_type)s *source,
251 BYTE **buffer,
252 INT32 *size) {
253 return %(old_type)s_Marshal(source, buffer, size);
254}
255"""
256 # The function signature and unmarshaling call to the base type of a TPM
257 # typedef. After the value is unmarshaled, additional validation code is
258 # generated based on tables in TCG TPM2.0 Library Specification, Part 2:
259 # Structures.
260 _TYPEDEF_UNMARSHAL_START = """
261TPM_RC %(new_type)s_Unmarshal(
262 %(new_type)s *target,
263 BYTE **buffer,
264 INT32 *size) {
265 TPM_RC result;
266 result = %(old_type)s_Unmarshal(target, buffer, size);
267 if (result != TPM_RC_SUCCESS) {
268 return result;
269 }"""
270 _UNMARSHAL_END = '\n return TPM_RC_SUCCESS;\n}\n'
271 # Snippets of code for value validation.
272 _VALUE_START_SWITCH = '\n switch (%(name)s) {'
273 _VALUE_CASE = '\n case %(value)s:'
274 _VALUE_CASE_IFDEF = '\n#ifdef %(value)s\n case %(value)s:\n#endif'
275 _VALUE_END_SWITCH = """
276 break;
277 default:
278 return %(error_code)s;
279 }"""
280 # A declaration for marshaling and unmarshaling functions for a TPM type.
281 _MARSHAL_DECLARATION = _STANDARD_MARSHAL_DECLARATION
282 # Snippets of code which make calls to marshaling functions. Marshals a value
283 # of type 'type' into a field 'name' within a structure. This is used in
284 # generation of structure and command marshaling code.
285 _MARSHAL_CALL = """
286 total_size += %(type)s_Marshal(
287 &source->%(name)s, buffer, size);"""
288 _UNMARSHAL_CALL = """
289 result = %(type)s_Unmarshal(
290 &target->%(name)s, buffer, size);
291 if (result != TPM_RC_SUCCESS) {
292 return result;
293 }"""
294
295 def HasConditional(self):
296 """Returns true if TPMType has a conditional value."""
297 return False
298
Vadim Bendebury595736f2015-09-17 17:19:18 -0700299 def OutputMarshalCall(self, out_file, field):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700300 """Write a call to Marshal function for TPMType to |out_file|.
301
302 Accumulates a variable 'total_size' with the result of marshaling
303 field |field_name| in structure 'source'.
304
305 Args:
306 out_file: The output file.
Vadim Bendebury595736f2015-09-17 17:19:18 -0700307 field: A Field object describing this type.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700308 """
Vadim Bendebury595736f2015-09-17 17:19:18 -0700309 out_file.write(self._MARSHAL_CALL % {'type': field.field_type,
310 'name': field.field_name})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700311
Vadim Bendebury595736f2015-09-17 17:19:18 -0700312 def OutputUnmarshalCall(self, out_file, field):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700313 """Write a call to Unmarshal function for TPMType to |out_file|.
314
315 Assigns result of unmarshaling field |field_name| in structure 'source'
316 to variable 'result'. Returns if the unmarshalling was unsuccessful.
317
318 Args:
319 out_file: The output file.
Vadim Bendebury595736f2015-09-17 17:19:18 -0700320 field: A Field object describing this type.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700321 """
Vadim Bendebury595736f2015-09-17 17:19:18 -0700322 out_file.write(self._UNMARSHAL_CALL % {'type': field.field_type,
323 'name': field.field_name})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700324
325 def _OutputTypedefMarshalDecl(self, out_file, declared_types, typemap):
326 """Write marshal declarations for TPM typedefs to |out_file|.
327
328 Can only be called on Typedef, ConstantType, AttributeStruct, and
329 Interface objects.
330
331 Args:
332 out_file: The output file.
333 declared_types: A set of types for which marshal and unmarshal function
334 declarations have already been generated.
335 typemap: A dict mapping type names to the corresponding object.
336 """
337 if self.new_type in declared_types:
338 return
Vadim Bendebury595736f2015-09-17 17:19:18 -0700339 if self.old_type not in declared_types and self.old_type in typemap:
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700340 typemap[self.old_type].OutputMarshalDecl(
341 out_file, declared_types, typemap)
342 out_file.write(self._MARSHAL_DECLARATION % {'type': self.new_type})
343 declared_types.add(self.new_type)
344
Vadim Bendeburyb85286c2015-09-15 14:25:48 -0700345 def _OutputStructOrUnionMarshalDecl(self, out_file, declared_types):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700346 """Write marshal declarations for a TPM Structure or Union.
347
348 Can only be called on Structure and Union objects.
349
350 Args:
351 out_file: The output file.
352 declared_types: A set of types for which marshal and unmarshal function
353 declarations have already been generated.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700354 """
355 # TPMU_NAME and TPMU_ENCRYPTED_SECRET type are never used across the
356 # interface.
357 if (self.name in declared_types or
358 self.name == 'TPMU_NAME' or
359 self.name == 'TPMU_ENCRYPTED_SECRET'):
360 return
361 out_file.write(self._MARSHAL_DECLARATION % {'type': self.name})
362 declared_types.add(self.name)
363
Vadim Bendebury595736f2015-09-17 17:19:18 -0700364
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700365class Typedef(TPMType):
366 """Represents a TPM typedef.
367
368 Attributes:
369 old_type: The existing type in a typedef statement.
370 new_type: The new type in a typedef statement.
371 """
372 # A function to unmarshal a TPM typedef with no extra validation.
373 _TYPEDEF_UNMARSHAL_FUNCTION = """
374TPM_RC %(new_type)s_Unmarshal(
375 %(new_type)s *target,
376 BYTE **buffer,
377 INT32 *size) {
378 return %(old_type)s_Unmarshal(target, buffer, size);
379}
380"""
Vadim Bendebury595736f2015-09-17 17:19:18 -0700381
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700382 def __init__(self, old_type, new_type):
383 """Initializes a Typedef instance.
384
385 Args:
386 old_type: The base type of the attribute structure.
387 new_type: The name of the type.
388 """
389 self.old_type = old_type
390 self.new_type = new_type
391
392 def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
393 """Writes marshal implementations for Typedef to |out_file|.
394
395 Args:
396 out_file: The output file.
397 marshalled_types: A set of types for which marshal and unmarshal functions
398 have already been generated.
399 typemap: A dict mapping type names to the corresponding object.
400 """
401 if self.new_type in marshalled_types:
402 return
403 if self.old_type not in marshalled_types:
404 typemap[self.old_type].OutputMarshalImpl(
405 out_file, marshalled_types, typemap)
406 out_file.write(self._TYPEDEF_MARSHAL_FUNCTION % {'old_type': self.old_type,
407 'new_type': self.new_type})
408 out_file.write(
409 self._TYPEDEF_UNMARSHAL_FUNCTION % {'old_type': self.old_type,
410 'new_type': self.new_type})
411 marshalled_types.add(self.new_type)
412
413 def OutputMarshalDecl(self, out_file, declared_types, typemap):
414 """Writes marshal declarations for Typedef to |out_file|.
415
416 Args:
417 out_file: The output file.
418 declared_types: A set of types for which marshal and unmarshal function
419 declarations have already been generated.
420 typemap: A dict mapping type names to the corresponding object.
421 """
422 self._OutputTypedefMarshalDecl(out_file, declared_types, typemap)
423
Vadim Bendebury595736f2015-09-17 17:19:18 -0700424
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700425class ConstantType(TPMType):
426 """Represents a TPM Constant type definition.
427
428 Attributes:
429 old_type: The base type of the constant (e.g. 'int').
430 new_type: The name of the type (e.g. 'TPM_RC').
431 valid_values: The list of valid values this type can take (e.g.
432 'TPM_RC_SUCCESS').
433 error_code: Error to be returned when unmarshalling is unsuccessful.
434 """
435 _CHECK_VALUE = """
436 if (*target == %(value)s) {
437 return TPM_RC_SUCCESS;
438 }"""
439 _CHECK_VALUE_IFDEF = """
440#ifdef %(value)s
441 if (*target == %(value)s) {
442 return TPM_RC_SUCCESS;
443 }
444#endif"""
445 _UNMARSHAL_END = """
446 return %(error_code)s;
447}
448"""
449 _IFDEF_TYPE_RE = re.compile(r'^TPM_(ALG|CC).*')
450
451 def __init__(self, old_type, new_type):
452 """Initializes a ConstantType instance.
453
454 Values are added to valid_values attribute during parsing.
455
456 Args:
457 old_type: The base type of the constant type.
458 new_type: The name of the type.
459 """
460 self.old_type = old_type
461 self.new_type = new_type
462 self.valid_values = []
463 self.error_code = 'TPM_RC_VALUE'
464
465 def _NeedsIfdef(self):
466 """Returns True if new_type is a type which needs ifdef enclosing."""
467 return self._IFDEF_TYPE_RE.search(self.new_type)
468
469 def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
470 """Writes marshal implementations for ConstantType to |out_file|.
471
472 Args:
473 out_file: The output file.
474 marshalled_types: A set of types for which marshal and unmarshal functions
475 have already been generated.
476 typemap: A dict mapping type names to the corresponding object.
477 """
478 if self.new_type in marshalled_types:
479 return
480 if self.old_type not in marshalled_types:
481 typemap[self.old_type].OutputMarshalImpl(
482 out_file, marshalled_types, typemap)
483 out_file.write(self._TYPEDEF_MARSHAL_FUNCTION % {'old_type': self.old_type,
484 'new_type': self.new_type})
485 out_file.write(self._TYPEDEF_UNMARSHAL_START % {'old_type': self.old_type,
486 'new_type': self.new_type})
487 for value in self.valid_values:
488 if self._NeedsIfdef():
489 out_file.write(self._CHECK_VALUE_IFDEF % {'value': value})
490 else:
491 out_file.write(self._CHECK_VALUE % {'value': value})
492 out_file.write(self._UNMARSHAL_END % {'error_code': self.error_code})
493 marshalled_types.add(self.new_type)
494
495 def OutputMarshalDecl(self, out_file, declared_types, typemap):
496 """Writes marshal declarations for ConstantType to |out_file|.
497
498 Args:
499 out_file: The output file.
500 declared_types: A set of types for which marshal and unmarshal function
501 declarations have already been generated.
502 typemap: A dict mapping type names to the corresponding object.
503 """
504 self._OutputTypedefMarshalDecl(out_file, declared_types, typemap)
505
Vadim Bendebury595736f2015-09-17 17:19:18 -0700506
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700507class AttributeStructure(TPMType):
508 """Represents a TPM attribute structure type definition.
509
510 Attributes:
511 old_type: The base type of the constant (e.g. 'int').
512 new_type: The name of the type (e.g. 'TPMA_OBJECT').
513 reserved: The list of bit bounds where bits must be 0 (e.g. ['10_2','3']).
514 """
515 # Attribute structures need an explicit cast to the base type.
516 _ATTRIBUTE_MARSHAL_FUNCTION = """
517UINT16 %(new_type)s_Marshal(
518 %(new_type)s *source,
519 BYTE **buffer,
520 INT32 *size) {
521 return %(old_type)s_Marshal((%(old_type)s*)source, buffer, size);
522}
523"""
524 _ATTRIBUTE_UNMARSHAL_START = """
525TPM_RC %(new_type)s_Unmarshal(
526 %(new_type)s *target,
527 BYTE **buffer,
528 INT32 *size) {
529 TPM_RC result;
530 result = %(old_type)s_Unmarshal((%(old_type)s*)target, buffer, size);
531 if (result != TPM_RC_SUCCESS) {
532 return result;
533 }"""
534 _CHECK_RESERVED = """
535 if (target->reserved%(bits)s != 0) {
536 return TPM_RC_RESERVED_BITS;
537 }"""
538
539 def __init__(self, old_type, new_type):
540 """Initializes an AttributeStructure instance.
541
542 Values may be added to reserved attribute during parsing.
543
544 Args:
545 old_type: The base type of the attribute structure.
546 new_type: The name of the type.
547 """
548 self.old_type = old_type
549 self.new_type = new_type
550 self.reserved = []
551
552 def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
553 """Writes marshal implementations for AttributStructure to |out_file|.
554
555 Args:
556 out_file: The output file.
557 marshalled_types: A set of types for which marshal and unmarshal functions
558 have already been generated.
559 typemap: A dict mapping type names to the corresponding object.
560 """
561 if self.new_type in marshalled_types:
562 return
563 if self.old_type not in marshalled_types:
564 typemap[self.old_type].OutputMarshalImpl(
565 out_file, marshalled_types, typemap)
566 out_file.write(self._ATTRIBUTE_MARSHAL_FUNCTION %
Vadim Bendeburyb85286c2015-09-15 14:25:48 -0700567 {'old_type': self.old_type,
568 'new_type': self.new_type})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700569 out_file.write(self._ATTRIBUTE_UNMARSHAL_START %
Vadim Bendeburyb85286c2015-09-15 14:25:48 -0700570 {'old_type': self.old_type,
571 'new_type': self.new_type})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700572 for bits in self.reserved:
573 out_file.write(self._CHECK_RESERVED % {'bits': bits})
574 out_file.write(self._UNMARSHAL_END)
575 marshalled_types.add(self.new_type)
576
577 def OutputMarshalDecl(self, out_file, declared_types, typemap):
578 """Writes marshal declarations for AttributeStructure to |out_file|.
579
580 Args:
581 out_file: The output file.
582 declared_types: A set of types for which marshal and unmarshal function
583 declarations have already been generated.
584 typemap: A dict mapping type names to the corresponding object.
585 """
586 self._OutputTypedefMarshalDecl(out_file, declared_types, typemap)
587
Vadim Bendebury595736f2015-09-17 17:19:18 -0700588
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700589class Interface(TPMType):
590 """Represents a TPM interface type definition.
591
592 Attributes:
593 old_type: The base type of the interface (e.g. 'TPM_HANDLE').
594 new_type: The name of the type (e.g. 'TPMI_DH_OBJECT').
595 valid_values: List of valid values for new_type. If this is not empty,
596 valid values for new_type is explicitly defined in the spec.
597 bounds: List of pairs representing bounds. If nonempty, target must fall
598 between one of these bounds.
599 conditional_value: Name of conditionally allowed value. If there is no
600 such value, this variable will be None.
601 supported_values: String literal indicating the name of a list of supported
602 values to be substituted at compile time (e.g. 'AES_KEY_SIZES_BITS').
603 If this is not None, valid values for new_type depends on the
604 implementation.
605 error_code: Return code when an unmarshalling error occurs.
606 """
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700607 _INTERFACE_CONDITIONAL_UNMARSHAL_START = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700608TPM_RC %(new_type)s_Unmarshal(
609 %(new_type)s *target,
610 BYTE **buffer,
611 INT32 *size,
612 BOOL allow_conditional_value) {
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700613 TPM_RC result;"""
614 _INTERFACE_UNMARSHAL_START = """
615TPM_RC %(new_type)s_Unmarshal(
616 %(new_type)s *target,
617 BYTE **buffer,
618 INT32 *size) {
619 TPM_RC result;"""
620 _UNMARSHAL_VALUE = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700621 result = %(old_type)s_Unmarshal(target, buffer, size);
622 if (result != TPM_RC_SUCCESS) {
623 return result;
624 }"""
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700625 _SETUP_CHECK_SUPPORTED_VALUES = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700626 uint16_t supported_values[] = %(supported_values)s;
627 size_t length = sizeof(supported_values)/sizeof(supported_values[0]);
628 size_t i;
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700629 BOOL is_supported_value = FALSE;"""
630 _CHECK_SUPPORTED_VALUES = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700631 for (i = 0; i < length; ++i) {
632 if (*target == supported_values[i]) {
633 is_supported_value = TRUE;
634 break;
635 }
636 }
637 if (!is_supported_value) {
638 return %(error_code)s;
639 }"""
640 _CHECK_CONDITIONAL = """
641 if (*target == %(name)s) {
642 return allow_conditional_value ? TPM_RC_SUCCESS : %(error_code)s;
643 }"""
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700644 _SETUP_CHECK_VALUES = '\n BOOL has_valid_value = FALSE;'
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700645 _VALUE_END_SWITCH = """
646 has_valid_value = TRUE;
647 break;
648 }"""
649 _CHECK_BOUND = """
650 if((*target >= %(lower)s) && (*target <= %(upper)s)) {
651 has_valid_value = TRUE;
652 }"""
653 _CHECK_VALUES_END = """
654 if (!has_valid_value) {
655 return %(error_code)s;
656 }"""
657 _CONDITIONAL_MARSHAL_DECLARATION = """
658UINT16 %(type)s_Marshal(
659 %(type)s *source,
660 BYTE **buffer,
661 INT32 *size);
662
663TPM_RC %(type)s_Unmarshal(
664 %(type)s *target,
665 BYTE **buffer,
666 INT32 *size,
667 BOOL allow_conditioanl_value);
668"""
669 _CONDITIONAL_UNMARSHAL_CALL = """
670 result = %(type)s_Unmarshal(
671 &target->%(name)s, buffer, size, %(flag)s);
672 if (result != TPM_RC_SUCCESS) {
673 return result;
674 }"""
675 _IFDEF_TYPE_RE = re.compile(r'^TPMI_(ALG|ECC)_.*')
676
677 def __init__(self, old_type, new_type):
678 """Initializes an Interface instance.
679
680 Values may be added/assigned to valid_values, bounds, conditional_value,
681 supported_values, and error_code attributes new values during parsing.
682
683 Args:
684 old_type: The base type of the interface.
685 new_type: The name of the type.
686 """
687 self.old_type = old_type
688 self.new_type = new_type
689 self.valid_values = []
690 self.bounds = []
691 self.conditional_value = None
692 self.supported_values = None
693 self.error_code = 'TPM_RC_VALUE'
694
695 def HasConditional(self):
696 """Returns true if Interface has a valid conditional_value."""
Vadim Bendebury595736f2015-09-17 17:19:18 -0700697 return self.conditional_value is not None
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700698
699 def _NeedsIfdef(self):
700 """Returns True if new_type is a type which needs ifdef enclosing."""
701 return self._IFDEF_TYPE_RE.search(self.new_type)
702
703 def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
704 """Writes marshal implementation for Interface to |out_file|.
705
706 Args:
707 out_file: The output file.
708 marshalled_types: A set of types for which marshal and unmarshal functions
709 have already been generated.
710 typemap: A dict mapping type names to the corresponding object.
711 """
712 if self.new_type in marshalled_types:
713 return
714 if self.old_type not in marshalled_types:
715 typemap[self.old_type].OutputMarshalImpl(
716 out_file, marshalled_types, typemap)
717 out_file.write(self._TYPEDEF_MARSHAL_FUNCTION % {'old_type': self.old_type,
718 'new_type': self.new_type})
719 if self.conditional_value:
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700720 out_file.write(self._INTERFACE_CONDITIONAL_UNMARSHAL_START %
Vadim Bendeburyb85286c2015-09-15 14:25:48 -0700721 {'old_type': self.old_type,
722 'new_type': self.new_type})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700723 else:
724 out_file.write(
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700725 self._INTERFACE_UNMARSHAL_START % {'old_type': self.old_type,
726 'new_type': self.new_type})
727 # Creating necessary local variables.
728 if self.supported_values:
729 out_file.write(self._SETUP_CHECK_SUPPORTED_VALUES %
Vadim Bendeburyb85286c2015-09-15 14:25:48 -0700730 {'supported_values': self.supported_values})
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700731 if len(self.valid_values)+len(self.bounds) > 0:
732 out_file.write(self._SETUP_CHECK_VALUES)
733
734 out_file.write(self._UNMARSHAL_VALUE % {'old_type': self.old_type})
735
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700736 if self.supported_values:
737 out_file.write(self._CHECK_SUPPORTED_VALUES %
Vadim Bendeburyb85286c2015-09-15 14:25:48 -0700738 {'supported_values': self.supported_values,
739 'error_code': self.error_code})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700740 if self.conditional_value:
741 out_file.write(
742 self._CHECK_CONDITIONAL % {'name': self.conditional_value,
743 'error_code': self.error_code})
744 # Checking for valid values.
745 if len(self.valid_values)+len(self.bounds) > 0:
Vadim Bendebury595736f2015-09-17 17:19:18 -0700746 if self.valid_values:
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700747 out_file.write(self._VALUE_START_SWITCH % {'name': '*target'})
748 for value in self.valid_values:
749 if self._NeedsIfdef():
750 out_file.write(self._VALUE_CASE_IFDEF % {'value': value})
751 else:
752 out_file.write(self._VALUE_CASE % {'value': value})
753 out_file.write(self._VALUE_END_SWITCH)
754 for (lower, upper) in self.bounds:
755 out_file.write(
756 self._CHECK_BOUND % {'lower': lower, 'upper': upper})
757 out_file.write(self._CHECK_VALUES_END % {'error_code': self.error_code})
758
759 out_file.write(self._UNMARSHAL_END)
760 marshalled_types.add(self.new_type)
761
762 def OutputMarshalDecl(self, out_file, declared_types, typemap):
763 """Writes marshal declarations for Interface to |out_file|.
764
765 Outputted declaration depends on whether Interface type has a
766 conditionally valid value.
767
768 Args:
769 out_file: The output file.
770 declared_types: A set of types for which marshal and unmarshal function
771 declarations have already been generated.
772 typemap: A dict mapping type names to the corresponding object.
773 """
774 if self.new_type in declared_types:
775 return
776 if self.old_type not in declared_types:
777 typemap[self.old_type].OutputMarshalDecl(
778 out_file, declared_types, typemap)
779 if self.HasConditional():
780 out_file.write(
781 self._CONDITIONAL_MARSHAL_DECLARATION % {'type': self.new_type})
782 else:
783 out_file.write(self._MARSHAL_DECLARATION % {'type': self.new_type})
784 declared_types.add(self.new_type)
785
786 def OutputUnmarshalCall(
Vadim Bendebury595736f2015-09-17 17:19:18 -0700787 self, out_file, field):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700788 """Write a call to Unmarshal function for Interface type to |out_file|.
789
790 Override TPMType OutputUnmarshalCall because when an Interface type has
791 a conditionally valid value, a BOOL value (|conditional_valid|) is passed
792 as a parameter.
793
794 Args:
795 out_file: The output file.
Vadim Bendebury595736f2015-09-17 17:19:18 -0700796 field: A Field object representing an element of this interface.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700797 """
798 if self.conditional_value:
799 out_file.write(
Vadim Bendebury595736f2015-09-17 17:19:18 -0700800 self._CONDITIONAL_UNMARSHAL_CALL % {'type': field.field_type,
801 'name': field.field_name,
802 'flag': field.conditional_value})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700803 else:
Vadim Bendebury595736f2015-09-17 17:19:18 -0700804 out_file.write(self._UNMARSHAL_CALL % {'type': field.field_type,
805 'name': field.field_name})
806
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700807
808class Structure(TPMType):
809 """Represents a TPM structure.
810
811 Attributes:
812 name: The name of the structure.
813 fields: A list of Field objects representing struct fields.
814 upper_bounds: A dictionary of (name, val) tuples mapping name to max val.
815 lower_bounds: A dictionary of (name, val) tuples mapping name to min val.
816 size_check: Set if TPM2B structure must be size checked (triggered by size=)
817 valid_tag_values: A list of values field tag is allowed to take.
818 error_code: The return code to be returned if an error occurs
819 """
820 _STRUCTURE_MARSHAL_START = """
821UINT16 %(name)s_Marshal(
822 %(name)s *source,
823 BYTE **buffer,
824 INT32 *size) {
825 UINT16 total_size = 0;"""
826 _STRUCTURE_UNMARSHAL_START = """
827TPM_RC %(name)s_Unmarshal(
828 %(name)s *target,
829 BYTE **buffer,
830 INT32 *size) {
831 TPM_RC result;"""
832 _MARSHAL_END = '\n return total_size;\n}\n'
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700833 _SETUP_ARRAY_FIELD = '\n INT32 i;'
834 _CHECK_SIZE_START = """
835 UINT32 start_size = *size;
836 UINT32 struct_size;"""
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700837 _CHECK_SIZE_END = """
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700838 struct_size = start_size - *size - sizeof(target->t.size);
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700839 if (struct_size != target->t.size) {
840 return TPM_RC_SIZE;
841 }"""
842 _TPM2B_ZERO_SIZE = """
843 if (target->t.size == 0) {
844 return %(return_value)s;
845 }"""
846 _CHECK_BOUND = """
847 if (target->%(name)s %(operator)s %(bound_value)s) {
848 return %(error_code)s;
849 }"""
850
851 def __init__(self, name):
852 """Initializes a Structure instance.
853
854 Initially the instance will have no fields, upper_bounds, lower_bounds, or
855 valid_tag_values. Those can be added with AddField(), AddUpperBound(),
856 AddLowerBound(), and AddTagVal() methods.
857
858 Args:
859 name: The name of the structure.
860 """
861 self.name = name
862 self.fields = []
863 self.upper_bounds = {}
864 self.lower_bounds = {}
865 self.size_check = False
866 self.valid_tag_values = []
867 self.error_code = 'TPM_RC_VALUE'
868
Vadim Bendebury595736f2015-09-17 17:19:18 -0700869 def AddField(self, field):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700870 """Adds a field to fields attribute in Structure.
871
872 Args:
Vadim Bendebury595736f2015-09-17 17:19:18 -0700873 field: Instance of Field
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700874 """
Vadim Bendebury595736f2015-09-17 17:19:18 -0700875 self.fields.append(field)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700876
877 def AddUpperBound(self, field_name, value):
878 """Adds an upper bound for a field.
879
880 Args:
881 field_name: Name of field with bound.
882 value: Value of upper bound.
883 """
Vadim Bendebury595736f2015-09-17 17:19:18 -0700884 if _IsTPM2B(self.name):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700885 field_name = 't.' + field_name
886 self.upper_bounds[field_name] = value
887
888 def AddLowerBound(self, field_name, value):
889 """Adds a lower bound for a field.
890
891 Args:
892 field_name: Name of field with bound.
893 value: Value of lower bound.
894 """
Vadim Bendebury595736f2015-09-17 17:19:18 -0700895 if _IsTPM2B(self.name):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700896 field_name = 't.' + field_name
897 self.lower_bounds[field_name] = value
898
Vadim Bendebury595736f2015-09-17 17:19:18 -0700899 def _AddTagValue(self, value):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700900 """Adds a valid value for tag field.
901
902 Args:
903 value: Valid value for tag field.
904 """
905 self.valid_tag_values.append(value)
906
907 def _GetFieldTypes(self):
908 """Creates a set which holds all current field types.
909
910 Returns:
911 A set of field types.
912 """
913 return set([field.field_type for field in self.fields])
914
915 def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
916 """Writes marshal implementations for Structure to |out_file|.
917
918 Args:
919 out_file: The output file.
920 marshalled_types: A set of types for which marshal and unmarshal functions
921 have already been generated.
922 typemap: A dict mapping type names to the corresponding object.
923 """
924 if self.name in marshalled_types:
925 return
Vadim Bendebury595736f2015-09-17 17:19:18 -0700926
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700927 # Make sure any dependencies already have marshal functions defined.
928 for field_type in self._GetFieldTypes():
929 if field_type not in marshalled_types:
930 typemap[field_type].OutputMarshalImpl(
931 out_file, marshalled_types, typemap)
932 marshalled_types.add(field_type)
933
934 out_file.write(self._STRUCTURE_MARSHAL_START % {'name': self.name})
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700935 # If any field is an array, create local variable INT32 i.
936 for field in self.fields:
Vadim Bendebury595736f2015-09-17 17:19:18 -0700937 if field.array_size:
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700938 out_file.write(self._SETUP_ARRAY_FIELD)
939 break
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700940 for field in self.fields:
Vadim Bendebury595736f2015-09-17 17:19:18 -0700941 # Each TPM2B is a union of two sized buffers, one which is type specific
942 # (the 't' element) and the other is a generic value (the 'b' element).
943 # For this reason a 't.' is prepended for fields in a TPM2B type. See
944 # section 9.11.6 in TCG TPM2.0 Library Specification, Part 2: Structures
945 # for more details.
946 if _IsTPM2B(self.name):
947 field.field_name = 't.' + field.field_name
948 if field.run_time_size:
949 field.run_time_size = 't.' + field.run_time_size
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700950 field.OutputMarshal(out_file, typemap)
951 out_file.write(self._MARSHAL_END)
952
953 out_file.write(self._STRUCTURE_UNMARSHAL_START % {'name': self.name})
954 if self.size_check:
955 out_file.write(self._CHECK_SIZE_START)
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700956 # If any field is an array, create local variable INT32 i.
957 for field in self.fields:
Vadim Bendebury595736f2015-09-17 17:19:18 -0700958 if field.array_size:
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700959 out_file.write(self._SETUP_ARRAY_FIELD)
960 break
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700961 for field in self.fields:
962 field.OutputUnmarshal(out_file, typemap)
963 return_value = self.error_code
964 if field.field_name == 't.size' and self.size_check:
965 out_file.write(self._TPM2B_ZERO_SIZE % {'return_value': 'TPM_RC_SIZE'})
966 if field.field_name == 't.size' and not self.size_check:
967 out_file.write(
968 self._TPM2B_ZERO_SIZE % {'return_value': 'TPM_RC_SUCCESS'})
969 if field.field_name in self.upper_bounds:
970 if (field.field_name == 'count' or
971 field.field_name == 't.size' or
972 field.field_name == 'size'):
973 return_value = 'TPM_RC_SIZE'
974 out_file.write(self._CHECK_BOUND %
Vadim Bendeburyb85286c2015-09-15 14:25:48 -0700975 {'name': field.field_name,
976 'operator': '>',
977 'bound_value': self.upper_bounds[field.field_name],
978 'error_code': return_value})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700979 if field.field_name in self.lower_bounds:
980 if (field.field_name == 'count' or
981 field.field_name == 't.size' or
982 field.field_name == 'size'):
983 return_value = 'TPM_RC_SIZE'
984 out_file.write(self._CHECK_BOUND %
Vadim Bendeburyb85286c2015-09-15 14:25:48 -0700985 {'name': field.field_name,
986 'operator': '<',
987 'bound_value': self.lower_bounds[field.field_name],
988 'error_code': return_value})
Vadim Bendebury595736f2015-09-17 17:19:18 -0700989 if field.field_name == 'tag' and self.valid_tag_values:
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700990 out_file.write(self._VALUE_START_SWITCH % {'name': 'target->tag'})
991 for value in self.valid_tag_values:
992 out_file.write(self._VALUE_CASE % {'value': value})
993 out_file.write(self._VALUE_END_SWITCH % {'error_code': 'TPM_RC_TAG'})
994 if self.size_check:
995 out_file.write(self._CHECK_SIZE_END)
Vadim Bendebury595736f2015-09-17 17:19:18 -0700996 if not self.fields:
997 # The spec includes a definition of an empty structure, as a side effect
998 # the marshaling/unmarshaling functions become empty, the compiler
999 # warning is suppressed by the below statement.
1000 out_file.write(' (void)result;\n')
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001001 out_file.write(self._UNMARSHAL_END)
1002
1003 marshalled_types.add(self.name)
1004
Vadim Bendeburyb85286c2015-09-15 14:25:48 -07001005 def OutputMarshalDecl(self, out_file, declared_types, _):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001006 """Writes marshal declarations for Structure to |out_file|.
1007
1008 Args:
1009 out_file: The output file.
1010 declared_types: A set of types for which marshal and unmarshal function
1011 declarations have already been generated.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001012 """
Vadim Bendeburyb85286c2015-09-15 14:25:48 -07001013 self._OutputStructOrUnionMarshalDecl(out_file, declared_types)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001014
Vadim Bendebury595736f2015-09-17 17:19:18 -07001015
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001016class Union(TPMType):
1017 """Represents a TPM union.
1018
1019 Attributes:
1020 name: The name of the union.
1021 fields: A list of Field objects representing union fields.
1022 """
1023
1024 _UNION_MARSHAL_START = """
1025UINT16 %(name)s_Marshal(
1026 %(name)s *source,
1027 BYTE **buffer,
1028 INT32 *size,
1029 UINT32 selector) {
1030 switch(selector) {"""
1031 _UNION_UNMARSHAL_START = """
1032TPM_RC %(name)s_Unmarshal(
1033 %(name)s *target,
1034 BYTE **buffer,
1035 INT32 *size,
1036 UINT32 selector) {
1037 switch(selector) {"""
1038 _MARSHAL_END = '\n }\n return 0;\n}\n'
1039 _UNMARSHAL_END = '\n }\n return TPM_RC_SELECTOR;\n}\n'
1040 _MARSHAL_DECLARATION = """
1041UINT16 %(type)s_Marshal(
1042 %(type)s *source,
1043 BYTE **buffer,
1044 INT32 *size,
1045 UINT32 selector);
1046
1047TPM_RC %(type)s_Unmarshal(
1048 %(type)s *target,
1049 BYTE **buffer,
1050 INT32 *size,
1051 UINT32 selector);
1052"""
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001053 _CASE_SELECTOR = """
1054 case %(selector)s:"""
1055 _MARSHAL_EMPTY = """
1056 return 0;"""
1057 _UNMARSHAL_EMPTY = """
1058 return TPM_RC_SUCCESS;"""
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001059 _MARSHAL_FIELD = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001060 return %(type)s_Marshal(
1061 (%(type)s*)&source->%(name)s, buffer, size);"""
1062 _UNMARSHAL_FIELD = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001063 return %(type)s_Unmarshal(
1064 (%(type)s*)&target->%(name)s, buffer, size);"""
1065 _SETUP_MARSHAL_FIELD_ARRAY = """
1066 INT32 i;
1067 UINT16 total_size = 0;"""
1068 _SETUP_UNMARSHAL_FIELD_ARRAY = """
1069 INT32 i;
1070 TPM_RC result = TPM_RC_SUCCESS;"""
1071 _MARSHAL_FIELD_ARRAY = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001072 for (i = 0; i < %(array_length)s; ++i) {
1073 total_size += %(type)s_Marshal(
1074 &source->%(name)s[i], buffer, size);
1075 }
1076 return total_size;"""
1077 _UNMARSHAL_FIELD_ARRAY = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001078 for (i = 0; i < %(array_length)s; ++i) {
1079 result = %(type)s_Unmarshal(
1080 &target->%(name)s[i], buffer, size);
1081 if (result != TPM_RC_SUCCESS) {
1082 return result;
1083 }
1084 }
1085 return TPM_RC_SUCCESS;"""
1086 _UNMARSHAL_FIELD_CONDITIONAL = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001087 return %(type)s_Unmarshal(
1088 &target->%(name)s, buffer, size, FALSE);"""
1089 _UNION_MARSHAL_CALL = """
1090 total_size += %(type)s_Marshal(
1091 &source->%(name)s, buffer, size, source->%(selector)s);"""
1092 _UNION_UNMARSHAL_CALL = """
1093 result = %(type)s_Unmarshal(
1094 &target->%(name)s, buffer, size, target->%(selector)s);
1095 if (result != TPM_RC_SUCCESS) {
1096 return result;
1097 }"""
1098 _IFDEF = '\n#ifdef %(type)s'
1099 _ENDIF = '\n#endif'
1100 _IFDEF_TYPE_RE = re.compile(r'^TPM_(ALG|CC).*')
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001101
1102 def __init__(self, name):
1103 """Initializes a Union instance.
1104
1105 Initially the instance will have no fields. Fields are added with the
1106 AddField() method.
1107
1108 Args:
1109 name: The name of the structure.
1110 """
1111 self.name = name
1112 self.fields = []
1113
1114 def _NeedsIfdef(self, selector):
1115 """Returns True if selector is a type which needs ifdef enclosing."""
1116 return self._IFDEF_TYPE_RE.search(selector)
1117
Vadim Bendebury595736f2015-09-17 17:19:18 -07001118 def AddField(self, field):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001119 """Adds a field to fields attribute in Union.
1120
1121 Args:
Vadim Bendebury595736f2015-09-17 17:19:18 -07001122 field: instance of Field
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001123 """
Jocelyn Bohr7cba2332015-08-10 16:28:31 -07001124 # xor is a C++ keyword and must be fixed.
Vadim Bendebury595736f2015-09-17 17:19:18 -07001125 if field.field_name == 'xor':
1126 field.field_name = 'xor_'
1127 self.fields.append(field)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001128
1129 def _OutputMarshalField(
Vadim Bendeburyb85286c2015-09-15 14:25:48 -07001130 self, out_file, field_type, field_name, array_length):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001131 """Write a call to marshal a field in this union.
1132
1133 Args:
1134 out_file: The output file.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001135 field_type: The type of field.
Vadim Bendebury595736f2015-09-17 17:19:18 -07001136 field_name: The name of the field.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001137 array_length: Variable indicating length of array, None if field is not
1138 an array.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001139 """
1140 if array_length:
1141 out_file.write(self._MARSHAL_FIELD_ARRAY % {'type': field_type,
1142 'name': field_name,
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001143 'array_length': array_length})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001144 else:
1145 out_file.write(self._MARSHAL_FIELD % {'type': field_type,
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001146 'name': field_name})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001147
1148 def _OutputUnmarshalField(
Vadim Bendeburyb85286c2015-09-15 14:25:48 -07001149 self, out_file, field_type, field_name, array_length, typemap):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001150 """Write a call to unmarshal a field in this union.
1151
1152 Args:
Vadim Bendebury595736f2015-09-17 17:19:18 -07001153 out_file: The output file object.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001154 field_type: The type of field.
Vadim Bendebury595736f2015-09-17 17:19:18 -07001155 field_name: The name of the field.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001156 array_length: Variable indicating length of array, None if field is not
1157 an array.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001158 typemap: A dict mapping type names to the corresponding object.
1159 """
1160 if array_length:
1161 out_file.write(
1162 self._UNMARSHAL_FIELD_ARRAY % {'type': field_type,
1163 'name': field_name,
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001164 'array_length': array_length})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001165 elif typemap[field_type].HasConditional():
1166 out_file.write(
1167 self._UNMARSHAL_FIELD_CONDITIONAL % {'type': field_type,
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001168 'name': field_name})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001169 else:
1170 out_file.write(self._UNMARSHAL_FIELD % {'type': field_type,
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001171 'name': field_name})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001172
1173 def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
1174 """Writes marshal implementations for Union to |out_file|.
1175
1176 Args:
1177 out_file: The output file.
1178 marshalled_types: A set of types for which marshal and unmarshal functions
1179 have already been generated.
1180 typemap: A dict mapping type names to the corresponding object.
1181 """
1182 if (self.name in marshalled_types or
1183 self.name == 'TPMU_NAME' or
Vadim Bendebury595736f2015-09-17 17:19:18 -07001184 self.name == 'TPMU_ENCRYPTED_SECRET' or
1185 not self.fields):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001186 return
Vadim Bendebury595736f2015-09-17 17:19:18 -07001187
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001188 field_types = {f.field_name: f.field_type for f in self.fields}
Vadim Bendebury595736f2015-09-17 17:19:18 -07001189 array_lengths = {}
1190 for f in self.fields:
1191 if f.array_size:
1192 array_lengths[f.field_name] = f.array_size
1193 else:
1194 array_lengths[f.field_name] = None
1195
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001196 # Make sure any dependencies already have marshal functions defined.
Vadim Bendebury595736f2015-09-17 17:19:18 -07001197 for field_type in field_types.itervalues():
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001198 if field_type not in marshalled_types:
1199 typemap[field_type].OutputMarshalImpl(
1200 out_file, marshalled_types, typemap)
1201 marshalled_types.add(field_type)
Vadim Bendeburye6c58e42015-09-08 12:55:42 -07001202 out_file.write(self._UNION_MARSHAL_START % {'name': self.name})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001203 # Set up variables if Union is an array type.
Vadim Bendebury595736f2015-09-17 17:19:18 -07001204 if self.fields[0].array_size:
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001205 out_file.write(self._SETUP_MARSHAL_FIELD_ARRAY)
Vadim Bendebury595736f2015-09-17 17:19:18 -07001206 for field in self.fields:
1207 selector = field.selector_value
1208 if not selector:
1209 continue
1210 field_name = field.field_name
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001211 if self._NeedsIfdef(selector):
1212 out_file.write(self._IFDEF % {'type': selector})
Vadim Bendebury595736f2015-09-17 17:19:18 -07001213 out_file.write(self._CASE_SELECTOR % {'selector': selector})
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001214 # Selector is not associated with a name, so no marshaling occurs.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001215 if not field_name:
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001216 out_file.write(self._MARSHAL_EMPTY)
1217 if self._NeedsIfdef(selector):
1218 out_file.write(self._ENDIF)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001219 continue
1220 field_type = field_types[field_name]
1221 array_length = array_lengths[field_name]
Vadim Bendeburyb85286c2015-09-15 14:25:48 -07001222 self._OutputMarshalField(out_file, field_type, field_name, array_length)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001223 if self._NeedsIfdef(selector):
1224 out_file.write(self._ENDIF)
1225 out_file.write(self._MARSHAL_END)
1226 out_file.write(self._UNION_UNMARSHAL_START % {'name': self.name})
1227 # Set up variables if Union is an array type.
Vadim Bendebury595736f2015-09-17 17:19:18 -07001228 if self.fields[0].array_size:
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001229 out_file.write(self._SETUP_UNMARSHAL_FIELD_ARRAY)
Vadim Bendebury595736f2015-09-17 17:19:18 -07001230 for field in self.fields:
1231 selector = field.selector_value
1232 if not selector:
1233 continue
1234 field_name = field.field_name
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001235 if self._NeedsIfdef(selector):
1236 out_file.write(self._IFDEF % {'type': selector})
1237 out_file.write(self._CASE_SELECTOR % {'selector': selector})
1238 # Selector is not associated with a name, so no unmarshaling occurs.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001239 if not field_name:
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001240 out_file.write(self._UNMARSHAL_EMPTY)
1241 if self._NeedsIfdef(selector):
1242 out_file.write(self._ENDIF)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001243 continue
1244 field_type = field_types[field_name]
1245 array_length = array_lengths[field_name]
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001246 self._OutputUnmarshalField(
Vadim Bendeburyb85286c2015-09-15 14:25:48 -07001247 out_file, field_type, field_name, array_length, typemap)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001248 if self._NeedsIfdef(selector):
1249 out_file.write(self._ENDIF)
1250 out_file.write(self._UNMARSHAL_END)
1251 marshalled_types.add(self.name)
1252
Vadim Bendeburyb85286c2015-09-15 14:25:48 -07001253 def OutputMarshalDecl(self, out_file, declared_types, _):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001254 """Writes marshal declarations for Union to |out_file|.
1255
1256 Args:
1257 out_file: The output file.
1258 declared_types: A set of types for which marshal and unmarshal function
1259 declarations have already been generated.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001260 """
Vadim Bendeburyb85286c2015-09-15 14:25:48 -07001261 self._OutputStructOrUnionMarshalDecl(out_file, declared_types)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001262
Vadim Bendebury595736f2015-09-17 17:19:18 -07001263 def OutputMarshalCall(self, out_file, field):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001264 """Write a call to marshal function for Union type to |out_file|.
1265
1266 Override TPMType OutputMarshalCall to pass in selector value.
1267
1268 Args:
1269 out_file: The output file.
Vadim Bendebury595736f2015-09-17 17:19:18 -07001270 field: A Field object representing a member of this union
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001271 """
Vadim Bendebury595736f2015-09-17 17:19:18 -07001272 out_file.write(self._UNION_MARSHAL_CALL %
1273 {'type': field.field_type,
1274 'name': field.field_name,
1275 'selector': field.selector_value})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001276
Vadim Bendebury595736f2015-09-17 17:19:18 -07001277 def OutputUnmarshalCall(self, out_file, field):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001278 """Write a call to unmarshal function for Union type to |out_file|.
1279
1280 Override TPMType OutputUnmashalCall to pass in selector value.
1281
1282 Args:
1283 out_file: The output file.
Vadim Bendebury595736f2015-09-17 17:19:18 -07001284 field: A Field object representing a member of this union
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001285 """
Vadim Bendebury595736f2015-09-17 17:19:18 -07001286 out_file.write(self._UNION_UNMARSHAL_CALL %
1287 {'type': field.field_type,
1288 'name': field.field_name,
1289 'selector': field.selector_value})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001290
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001291
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001292def GenerateHeader(typemap):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001293 """Generates a header file with declarations for all given generator objects.
1294
1295 Args:
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001296 typemap: A dict mapping type names to the corresponding object.
1297 """
1298 out_file = open(_OUTPUT_FILE_H, 'w')
Vadim Bendebury595736f2015-09-17 17:19:18 -07001299 out_file.write(COPYRIGHT_HEADER)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001300 guard_name = 'TPM2_%s_' % _OUTPUT_FILE_H.upper().replace('.', '_')
Vadim Bendebury595736f2015-09-17 17:19:18 -07001301 out_file.write(HEADER_FILE_GUARD_HEADER % {'name': guard_name})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001302 out_file.write(_HEADER_FILE_INCLUDES)
1303 # These types are built-in or defined by <stdint.h>; they serve as base cases
1304 # when defining type dependencies.
1305 declared_types = set(_BASIC_TYPES)
1306 # Generate serialize / parse function declarations.
1307 for basic_type in _BASIC_TYPES:
1308 out_file.write(_STANDARD_MARSHAL_DECLARATION % {'type': basic_type})
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001309 for tpm_type in [typemap[x] for x in sorted(typemap.keys())]:
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001310 tpm_type.OutputMarshalDecl(out_file, declared_types, typemap)
Vadim Bendebury595736f2015-09-17 17:19:18 -07001311 out_file.write(HEADER_FILE_GUARD_FOOTER % {'name': guard_name})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001312 out_file.close()
1313 call(['clang-format', '-i', '-style=Chromium', 'tpm_generated.h'])
1314
1315
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001316def GenerateImplementation(typemap):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001317 """Generates implementation code for each type.
1318
1319 Args:
Vadim Bendebury595736f2015-09-17 17:19:18 -07001320 typemap: A dict mapping string type names to the corresponding object.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001321 """
1322 out_file = open(_OUTPUT_FILE_CC, 'w')
Vadim Bendebury595736f2015-09-17 17:19:18 -07001323 out_file.write(COPYRIGHT_HEADER)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001324 out_file.write(_IMPLEMENTATION_FILE_INCLUDES)
1325 marshalled_types = set(_BASIC_TYPES)
1326 for basic_type in _BASIC_TYPES:
1327 out_file.write(_MARSHAL_BASIC_TYPE % {'type': basic_type})
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001328 for tpm_type in [typemap[x] for x in sorted(typemap.keys())]:
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001329 tpm_type.OutputMarshalImpl(out_file, marshalled_types, typemap)
1330 out_file.close()
1331 call(['clang-format', '-i', '-style=Chromium', 'tpm_generated.c'])