blob: 2224d9a1c36af3e839f810d3516ea585c83bfec1 [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)) {
Vadim Bendebury69289282015-10-22 12:13:15 -070055 return 0; // Nothing has been marshaled.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -070056 }
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.
Vadim Bendeburyf5af8592015-10-14 17:15:04 -0700246
247 Attributes:
248 _base_type: a string, when set - the very basic type this type is
249 derived from (should be used for marshaling/unmarshaling to
250 shortcut multiple nested invocations).
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700251 """
252 # A function to marshal a TPM typedef.
253 _TYPEDEF_MARSHAL_FUNCTION = """
254UINT16 %(new_type)s_Marshal(
255 %(new_type)s *source,
256 BYTE **buffer,
257 INT32 *size) {
258 return %(old_type)s_Marshal(source, buffer, size);
259}
260"""
261 # The function signature and unmarshaling call to the base type of a TPM
262 # typedef. After the value is unmarshaled, additional validation code is
263 # generated based on tables in TCG TPM2.0 Library Specification, Part 2:
264 # Structures.
265 _TYPEDEF_UNMARSHAL_START = """
266TPM_RC %(new_type)s_Unmarshal(
267 %(new_type)s *target,
268 BYTE **buffer,
269 INT32 *size) {
270 TPM_RC result;
271 result = %(old_type)s_Unmarshal(target, buffer, size);
272 if (result != TPM_RC_SUCCESS) {
273 return result;
274 }"""
275 _UNMARSHAL_END = '\n return TPM_RC_SUCCESS;\n}\n'
276 # Snippets of code for value validation.
277 _VALUE_START_SWITCH = '\n switch (%(name)s) {'
278 _VALUE_CASE = '\n case %(value)s:'
279 _VALUE_CASE_IFDEF = '\n#ifdef %(value)s\n case %(value)s:\n#endif'
280 _VALUE_END_SWITCH = """
281 break;
282 default:
283 return %(error_code)s;
284 }"""
285 # A declaration for marshaling and unmarshaling functions for a TPM type.
286 _MARSHAL_DECLARATION = _STANDARD_MARSHAL_DECLARATION
287 # Snippets of code which make calls to marshaling functions. Marshals a value
288 # of type 'type' into a field 'name' within a structure. This is used in
289 # generation of structure and command marshaling code.
290 _MARSHAL_CALL = """
291 total_size += %(type)s_Marshal(
292 &source->%(name)s, buffer, size);"""
293 _UNMARSHAL_CALL = """
294 result = %(type)s_Unmarshal(
295 &target->%(name)s, buffer, size);
296 if (result != TPM_RC_SUCCESS) {
297 return result;
298 }"""
299
Vadim Bendeburyf5af8592015-10-14 17:15:04 -0700300 def __init__(self):
301 self._base_type = None
302
303 def SetBaseType(self, base_type):
304 self._base_type = base_type
305
306 def _GetBaseType(self, out_file, marshalled_types, typemap):
307 '''Return base type for this object.
308
309 The base type is used for shortcutting marshaling/unmarshaling code.
310
311 If _base_type is not set, return the old_type value as the base type.
312
313 If the base type's marshaling/unmarshaling code has not been generated
314 yet, issue it before continuing processing.
315
316 Args:
317 out_file: The output file.
318 marshalled_types: A set of types for which marshal and unmarshal functions
319 have already been generated.
320 typemap: A dict mapping type names to the corresponding object.
321
322 Returns:
323 A string, the name of the type to use for marshaling/unmarshaling.
324
325 '''
326 if self._base_type:
327 base_type = self._base_type
328 else:
329 base_type = self.old_type
330 if base_type not in marshalled_types:
331 typemap[base_type].OutputMarshalImpl(
332 out_file, marshalled_types, typemap)
333 return base_type
334
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700335 def HasConditional(self):
336 """Returns true if TPMType has a conditional value."""
337 return False
338
Vadim Bendebury595736f2015-09-17 17:19:18 -0700339 def OutputMarshalCall(self, out_file, field):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700340 """Write a call to Marshal function for TPMType to |out_file|.
341
342 Accumulates a variable 'total_size' with the result of marshaling
343 field |field_name| in structure 'source'.
344
345 Args:
346 out_file: The output file.
Vadim Bendebury595736f2015-09-17 17:19:18 -0700347 field: A Field object describing this type.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700348 """
Vadim Bendebury595736f2015-09-17 17:19:18 -0700349 out_file.write(self._MARSHAL_CALL % {'type': field.field_type,
350 'name': field.field_name})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700351
Vadim Bendebury595736f2015-09-17 17:19:18 -0700352 def OutputUnmarshalCall(self, out_file, field):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700353 """Write a call to Unmarshal function for TPMType to |out_file|.
354
355 Assigns result of unmarshaling field |field_name| in structure 'source'
356 to variable 'result'. Returns if the unmarshalling was unsuccessful.
357
358 Args:
359 out_file: The output file.
Vadim Bendebury595736f2015-09-17 17:19:18 -0700360 field: A Field object describing this type.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700361 """
Vadim Bendebury907fc8f2015-10-06 13:15:15 -0700362 obj_type = field.field_type
363 if obj_type == 'TPM_CC':
364 obj_type = 'UINT32'
365 out_file.write(self._UNMARSHAL_CALL % {'type': obj_type,
Vadim Bendebury595736f2015-09-17 17:19:18 -0700366 'name': field.field_name})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700367
368 def _OutputTypedefMarshalDecl(self, out_file, declared_types, typemap):
369 """Write marshal declarations for TPM typedefs to |out_file|.
370
371 Can only be called on Typedef, ConstantType, AttributeStruct, and
372 Interface objects.
373
374 Args:
375 out_file: The output file.
376 declared_types: A set of types for which marshal and unmarshal function
377 declarations have already been generated.
378 typemap: A dict mapping type names to the corresponding object.
379 """
380 if self.new_type in declared_types:
381 return
Vadim Bendebury595736f2015-09-17 17:19:18 -0700382 if self.old_type not in declared_types and self.old_type in typemap:
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700383 typemap[self.old_type].OutputMarshalDecl(
384 out_file, declared_types, typemap)
385 out_file.write(self._MARSHAL_DECLARATION % {'type': self.new_type})
386 declared_types.add(self.new_type)
387
Vadim Bendeburyb85286c2015-09-15 14:25:48 -0700388 def _OutputStructOrUnionMarshalDecl(self, out_file, declared_types):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700389 """Write marshal declarations for a TPM Structure or Union.
390
391 Can only be called on Structure and Union objects.
392
393 Args:
394 out_file: The output file.
395 declared_types: A set of types for which marshal and unmarshal function
396 declarations have already been generated.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700397 """
398 # TPMU_NAME and TPMU_ENCRYPTED_SECRET type are never used across the
399 # interface.
400 if (self.name in declared_types or
401 self.name == 'TPMU_NAME' or
402 self.name == 'TPMU_ENCRYPTED_SECRET'):
403 return
404 out_file.write(self._MARSHAL_DECLARATION % {'type': self.name})
405 declared_types.add(self.name)
406
Vadim Bendebury595736f2015-09-17 17:19:18 -0700407
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700408class Typedef(TPMType):
409 """Represents a TPM typedef.
410
411 Attributes:
412 old_type: The existing type in a typedef statement.
413 new_type: The new type in a typedef statement.
414 """
415 # A function to unmarshal a TPM typedef with no extra validation.
416 _TYPEDEF_UNMARSHAL_FUNCTION = """
417TPM_RC %(new_type)s_Unmarshal(
418 %(new_type)s *target,
419 BYTE **buffer,
420 INT32 *size) {
421 return %(old_type)s_Unmarshal(target, buffer, size);
422}
423"""
Vadim Bendebury595736f2015-09-17 17:19:18 -0700424
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700425 def __init__(self, old_type, new_type):
426 """Initializes a Typedef instance.
427
428 Args:
429 old_type: The base type of the attribute structure.
430 new_type: The name of the type.
431 """
Vadim Bendeburyf5af8592015-10-14 17:15:04 -0700432 super(Typedef, self).__init__()
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700433 self.old_type = old_type
434 self.new_type = new_type
435
436 def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
437 """Writes marshal implementations for Typedef to |out_file|.
438
439 Args:
440 out_file: The output file.
441 marshalled_types: A set of types for which marshal and unmarshal functions
442 have already been generated.
443 typemap: A dict mapping type names to the corresponding object.
444 """
445 if self.new_type in marshalled_types:
446 return
Vadim Bendeburyf5af8592015-10-14 17:15:04 -0700447 base_type = self._GetBaseType(out_file, marshalled_types, typemap)
448 out_file.write(self._TYPEDEF_MARSHAL_FUNCTION % {'old_type': base_type,
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700449 'new_type': self.new_type})
450 out_file.write(
Vadim Bendeburyf5af8592015-10-14 17:15:04 -0700451 self._TYPEDEF_UNMARSHAL_FUNCTION % {'old_type': base_type,
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700452 'new_type': self.new_type})
453 marshalled_types.add(self.new_type)
454
455 def OutputMarshalDecl(self, out_file, declared_types, typemap):
456 """Writes marshal declarations for Typedef to |out_file|.
457
458 Args:
459 out_file: The output file.
460 declared_types: A set of types for which marshal and unmarshal function
461 declarations have already been generated.
462 typemap: A dict mapping type names to the corresponding object.
463 """
464 self._OutputTypedefMarshalDecl(out_file, declared_types, typemap)
465
Vadim Bendebury595736f2015-09-17 17:19:18 -0700466
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700467class ConstantType(TPMType):
468 """Represents a TPM Constant type definition.
469
470 Attributes:
471 old_type: The base type of the constant (e.g. 'int').
472 new_type: The name of the type (e.g. 'TPM_RC').
473 valid_values: The list of valid values this type can take (e.g.
474 'TPM_RC_SUCCESS').
475 error_code: Error to be returned when unmarshalling is unsuccessful.
476 """
477 _CHECK_VALUE = """
478 if (*target == %(value)s) {
479 return TPM_RC_SUCCESS;
480 }"""
481 _CHECK_VALUE_IFDEF = """
482#ifdef %(value)s
483 if (*target == %(value)s) {
484 return TPM_RC_SUCCESS;
485 }
486#endif"""
487 _UNMARSHAL_END = """
488 return %(error_code)s;
489}
490"""
491 _IFDEF_TYPE_RE = re.compile(r'^TPM_(ALG|CC).*')
492
493 def __init__(self, old_type, new_type):
494 """Initializes a ConstantType instance.
495
496 Values are added to valid_values attribute during parsing.
497
498 Args:
499 old_type: The base type of the constant type.
500 new_type: The name of the type.
501 """
Vadim Bendeburyf5af8592015-10-14 17:15:04 -0700502 super(ConstantType, self).__init__()
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700503 self.old_type = old_type
504 self.new_type = new_type
505 self.valid_values = []
506 self.error_code = 'TPM_RC_VALUE'
507
508 def _NeedsIfdef(self):
509 """Returns True if new_type is a type which needs ifdef enclosing."""
510 return self._IFDEF_TYPE_RE.search(self.new_type)
511
512 def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
513 """Writes marshal implementations for ConstantType to |out_file|.
514
515 Args:
516 out_file: The output file.
517 marshalled_types: A set of types for which marshal and unmarshal functions
518 have already been generated.
519 typemap: A dict mapping type names to the corresponding object.
520 """
521 if self.new_type in marshalled_types:
522 return
Vadim Bendeburyf5af8592015-10-14 17:15:04 -0700523 base_type = self._GetBaseType(out_file, marshalled_types, typemap)
524 out_file.write(self._TYPEDEF_MARSHAL_FUNCTION % {'old_type': base_type,
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700525 'new_type': self.new_type})
Vadim Bendeburyf5af8592015-10-14 17:15:04 -0700526 out_file.write(self._TYPEDEF_UNMARSHAL_START % {'old_type': base_type,
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700527 'new_type': self.new_type})
528 for value in self.valid_values:
529 if self._NeedsIfdef():
530 out_file.write(self._CHECK_VALUE_IFDEF % {'value': value})
531 else:
532 out_file.write(self._CHECK_VALUE % {'value': value})
533 out_file.write(self._UNMARSHAL_END % {'error_code': self.error_code})
534 marshalled_types.add(self.new_type)
535
536 def OutputMarshalDecl(self, out_file, declared_types, typemap):
537 """Writes marshal declarations for ConstantType to |out_file|.
538
539 Args:
540 out_file: The output file.
541 declared_types: A set of types for which marshal and unmarshal function
542 declarations have already been generated.
543 typemap: A dict mapping type names to the corresponding object.
544 """
545 self._OutputTypedefMarshalDecl(out_file, declared_types, typemap)
546
Vadim Bendebury595736f2015-09-17 17:19:18 -0700547
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700548class AttributeStructure(TPMType):
549 """Represents a TPM attribute structure type definition.
550
551 Attributes:
552 old_type: The base type of the constant (e.g. 'int').
553 new_type: The name of the type (e.g. 'TPMA_OBJECT').
554 reserved: The list of bit bounds where bits must be 0 (e.g. ['10_2','3']).
555 """
556 # Attribute structures need an explicit cast to the base type.
557 _ATTRIBUTE_MARSHAL_FUNCTION = """
558UINT16 %(new_type)s_Marshal(
559 %(new_type)s *source,
560 BYTE **buffer,
561 INT32 *size) {
562 return %(old_type)s_Marshal((%(old_type)s*)source, buffer, size);
563}
564"""
565 _ATTRIBUTE_UNMARSHAL_START = """
566TPM_RC %(new_type)s_Unmarshal(
567 %(new_type)s *target,
568 BYTE **buffer,
569 INT32 *size) {
570 TPM_RC result;
571 result = %(old_type)s_Unmarshal((%(old_type)s*)target, buffer, size);
572 if (result != TPM_RC_SUCCESS) {
573 return result;
574 }"""
575 _CHECK_RESERVED = """
576 if (target->reserved%(bits)s != 0) {
577 return TPM_RC_RESERVED_BITS;
578 }"""
579
580 def __init__(self, old_type, new_type):
581 """Initializes an AttributeStructure instance.
582
583 Values may be added to reserved attribute during parsing.
584
585 Args:
586 old_type: The base type of the attribute structure.
587 new_type: The name of the type.
588 """
Vadim Bendeburyf5af8592015-10-14 17:15:04 -0700589 super(AttributeStructure, self).__init__()
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700590 self.old_type = old_type
591 self.new_type = new_type
592 self.reserved = []
593
594 def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
595 """Writes marshal implementations for AttributStructure to |out_file|.
596
597 Args:
598 out_file: The output file.
599 marshalled_types: A set of types for which marshal and unmarshal functions
600 have already been generated.
601 typemap: A dict mapping type names to the corresponding object.
602 """
603 if self.new_type in marshalled_types:
604 return
Vadim Bendeburyf5af8592015-10-14 17:15:04 -0700605 base_type = self._GetBaseType(out_file, marshalled_types, typemap)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700606 out_file.write(self._ATTRIBUTE_MARSHAL_FUNCTION %
Vadim Bendeburyf5af8592015-10-14 17:15:04 -0700607 {'old_type': base_type,
Vadim Bendeburyb85286c2015-09-15 14:25:48 -0700608 'new_type': self.new_type})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700609 out_file.write(self._ATTRIBUTE_UNMARSHAL_START %
Vadim Bendeburyf5af8592015-10-14 17:15:04 -0700610 {'old_type': base_type,
Vadim Bendeburyb85286c2015-09-15 14:25:48 -0700611 'new_type': self.new_type})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700612 for bits in self.reserved:
613 out_file.write(self._CHECK_RESERVED % {'bits': bits})
614 out_file.write(self._UNMARSHAL_END)
615 marshalled_types.add(self.new_type)
616
617 def OutputMarshalDecl(self, out_file, declared_types, typemap):
618 """Writes marshal declarations for AttributeStructure to |out_file|.
619
620 Args:
621 out_file: The output file.
622 declared_types: A set of types for which marshal and unmarshal function
623 declarations have already been generated.
624 typemap: A dict mapping type names to the corresponding object.
625 """
626 self._OutputTypedefMarshalDecl(out_file, declared_types, typemap)
627
Vadim Bendebury595736f2015-09-17 17:19:18 -0700628
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700629class Interface(TPMType):
630 """Represents a TPM interface type definition.
631
632 Attributes:
633 old_type: The base type of the interface (e.g. 'TPM_HANDLE').
634 new_type: The name of the type (e.g. 'TPMI_DH_OBJECT').
635 valid_values: List of valid values for new_type. If this is not empty,
636 valid values for new_type is explicitly defined in the spec.
637 bounds: List of pairs representing bounds. If nonempty, target must fall
638 between one of these bounds.
639 conditional_value: Name of conditionally allowed value. If there is no
640 such value, this variable will be None.
641 supported_values: String literal indicating the name of a list of supported
642 values to be substituted at compile time (e.g. 'AES_KEY_SIZES_BITS').
643 If this is not None, valid values for new_type depends on the
644 implementation.
645 error_code: Return code when an unmarshalling error occurs.
646 """
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700647 _INTERFACE_CONDITIONAL_UNMARSHAL_START = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700648TPM_RC %(new_type)s_Unmarshal(
649 %(new_type)s *target,
650 BYTE **buffer,
651 INT32 *size,
652 BOOL allow_conditional_value) {
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700653 TPM_RC result;"""
654 _INTERFACE_UNMARSHAL_START = """
655TPM_RC %(new_type)s_Unmarshal(
656 %(new_type)s *target,
657 BYTE **buffer,
658 INT32 *size) {
659 TPM_RC result;"""
660 _UNMARSHAL_VALUE = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700661 result = %(old_type)s_Unmarshal(target, buffer, size);
662 if (result != TPM_RC_SUCCESS) {
663 return result;
664 }"""
Vadim Bendebury907fc8f2015-10-06 13:15:15 -0700665 _UNMARSHAL_VALUE_ALLOW_RC_VALUE = """
666 result = %(old_type)s_Unmarshal(target, buffer, size);
667 if ((result != TPM_RC_VALUE) && (result != TPM_RC_SUCCESS)) {
668 return result;
669 }"""
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700670 _SETUP_CHECK_SUPPORTED_VALUES = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700671 uint16_t supported_values[] = %(supported_values)s;
672 size_t length = sizeof(supported_values)/sizeof(supported_values[0]);
673 size_t i;
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700674 BOOL is_supported_value = FALSE;"""
675 _CHECK_SUPPORTED_VALUES = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700676 for (i = 0; i < length; ++i) {
677 if (*target == supported_values[i]) {
678 is_supported_value = TRUE;
679 break;
680 }
681 }
682 if (!is_supported_value) {
683 return %(error_code)s;
684 }"""
685 _CHECK_CONDITIONAL = """
686 if (*target == %(name)s) {
687 return allow_conditional_value ? TPM_RC_SUCCESS : %(error_code)s;
688 }"""
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700689 _SETUP_CHECK_VALUES = '\n BOOL has_valid_value = FALSE;'
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700690 _VALUE_END_SWITCH = """
691 has_valid_value = TRUE;
692 break;
693 }"""
694 _CHECK_BOUND = """
695 if((*target >= %(lower)s) && (*target <= %(upper)s)) {
696 has_valid_value = TRUE;
697 }"""
698 _CHECK_VALUES_END = """
699 if (!has_valid_value) {
700 return %(error_code)s;
701 }"""
702 _CONDITIONAL_MARSHAL_DECLARATION = """
703UINT16 %(type)s_Marshal(
704 %(type)s *source,
705 BYTE **buffer,
706 INT32 *size);
707
708TPM_RC %(type)s_Unmarshal(
709 %(type)s *target,
710 BYTE **buffer,
711 INT32 *size,
712 BOOL allow_conditioanl_value);
713"""
714 _CONDITIONAL_UNMARSHAL_CALL = """
715 result = %(type)s_Unmarshal(
716 &target->%(name)s, buffer, size, %(flag)s);
717 if (result != TPM_RC_SUCCESS) {
718 return result;
719 }"""
720 _IFDEF_TYPE_RE = re.compile(r'^TPMI_(ALG|ECC)_.*')
721
722 def __init__(self, old_type, new_type):
723 """Initializes an Interface instance.
724
725 Values may be added/assigned to valid_values, bounds, conditional_value,
726 supported_values, and error_code attributes new values during parsing.
727
728 Args:
729 old_type: The base type of the interface.
730 new_type: The name of the type.
731 """
Vadim Bendeburyf5af8592015-10-14 17:15:04 -0700732 super(Interface, self).__init__()
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700733 self.old_type = old_type
734 self.new_type = new_type
735 self.valid_values = []
736 self.bounds = []
737 self.conditional_value = None
738 self.supported_values = None
739 self.error_code = 'TPM_RC_VALUE'
740
741 def HasConditional(self):
742 """Returns true if Interface has a valid conditional_value."""
Vadim Bendebury595736f2015-09-17 17:19:18 -0700743 return self.conditional_value is not None
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700744
745 def _NeedsIfdef(self):
746 """Returns True if new_type is a type which needs ifdef enclosing."""
747 return self._IFDEF_TYPE_RE.search(self.new_type)
748
749 def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
750 """Writes marshal implementation for Interface to |out_file|.
751
752 Args:
753 out_file: The output file.
754 marshalled_types: A set of types for which marshal and unmarshal functions
755 have already been generated.
756 typemap: A dict mapping type names to the corresponding object.
757 """
758 if self.new_type in marshalled_types:
759 return
Vadim Bendeburyf5af8592015-10-14 17:15:04 -0700760 base_type = self._GetBaseType(out_file, marshalled_types, typemap)
761 out_file.write(self._TYPEDEF_MARSHAL_FUNCTION % {'old_type': base_type,
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700762 'new_type': self.new_type})
763 if self.conditional_value:
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700764 out_file.write(self._INTERFACE_CONDITIONAL_UNMARSHAL_START %
Vadim Bendeburyf5af8592015-10-14 17:15:04 -0700765 {'old_type': base_type,
Vadim Bendeburyb85286c2015-09-15 14:25:48 -0700766 'new_type': self.new_type})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700767 else:
768 out_file.write(
Vadim Bendeburyf5af8592015-10-14 17:15:04 -0700769 self._INTERFACE_UNMARSHAL_START % {'old_type': base_type,
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700770 'new_type': self.new_type})
771 # Creating necessary local variables.
772 if self.supported_values:
773 out_file.write(self._SETUP_CHECK_SUPPORTED_VALUES %
Vadim Bendeburyb85286c2015-09-15 14:25:48 -0700774 {'supported_values': self.supported_values})
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700775 if len(self.valid_values)+len(self.bounds) > 0:
776 out_file.write(self._SETUP_CHECK_VALUES)
Vadim Bendebury907fc8f2015-10-06 13:15:15 -0700777 out_file.write(self._UNMARSHAL_VALUE_ALLOW_RC_VALUE %
Vadim Bendeburyf5af8592015-10-14 17:15:04 -0700778 {'old_type': base_type})
Vadim Bendebury907fc8f2015-10-06 13:15:15 -0700779 else:
Vadim Bendeburyf5af8592015-10-14 17:15:04 -0700780 out_file.write(self._UNMARSHAL_VALUE % {'old_type': base_type})
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700781
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700782 if self.supported_values:
783 out_file.write(self._CHECK_SUPPORTED_VALUES %
Vadim Bendeburyb85286c2015-09-15 14:25:48 -0700784 {'supported_values': self.supported_values,
785 'error_code': self.error_code})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700786 if self.conditional_value:
787 out_file.write(
788 self._CHECK_CONDITIONAL % {'name': self.conditional_value,
789 'error_code': self.error_code})
790 # Checking for valid values.
791 if len(self.valid_values)+len(self.bounds) > 0:
Vadim Bendebury595736f2015-09-17 17:19:18 -0700792 if self.valid_values:
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700793 out_file.write(self._VALUE_START_SWITCH % {'name': '*target'})
794 for value in self.valid_values:
795 if self._NeedsIfdef():
796 out_file.write(self._VALUE_CASE_IFDEF % {'value': value})
797 else:
798 out_file.write(self._VALUE_CASE % {'value': value})
799 out_file.write(self._VALUE_END_SWITCH)
800 for (lower, upper) in self.bounds:
801 out_file.write(
802 self._CHECK_BOUND % {'lower': lower, 'upper': upper})
803 out_file.write(self._CHECK_VALUES_END % {'error_code': self.error_code})
804
805 out_file.write(self._UNMARSHAL_END)
806 marshalled_types.add(self.new_type)
807
808 def OutputMarshalDecl(self, out_file, declared_types, typemap):
809 """Writes marshal declarations for Interface to |out_file|.
810
811 Outputted declaration depends on whether Interface type has a
812 conditionally valid value.
813
814 Args:
815 out_file: The output file.
816 declared_types: A set of types for which marshal and unmarshal function
817 declarations have already been generated.
818 typemap: A dict mapping type names to the corresponding object.
819 """
820 if self.new_type in declared_types:
821 return
822 if self.old_type not in declared_types:
823 typemap[self.old_type].OutputMarshalDecl(
824 out_file, declared_types, typemap)
825 if self.HasConditional():
826 out_file.write(
827 self._CONDITIONAL_MARSHAL_DECLARATION % {'type': self.new_type})
828 else:
829 out_file.write(self._MARSHAL_DECLARATION % {'type': self.new_type})
830 declared_types.add(self.new_type)
831
832 def OutputUnmarshalCall(
Vadim Bendebury595736f2015-09-17 17:19:18 -0700833 self, out_file, field):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700834 """Write a call to Unmarshal function for Interface type to |out_file|.
835
836 Override TPMType OutputUnmarshalCall because when an Interface type has
837 a conditionally valid value, a BOOL value (|conditional_valid|) is passed
838 as a parameter.
839
840 Args:
841 out_file: The output file.
Vadim Bendebury595736f2015-09-17 17:19:18 -0700842 field: A Field object representing an element of this interface.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700843 """
844 if self.conditional_value:
845 out_file.write(
Vadim Bendebury595736f2015-09-17 17:19:18 -0700846 self._CONDITIONAL_UNMARSHAL_CALL % {'type': field.field_type,
847 'name': field.field_name,
848 'flag': field.conditional_value})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700849 else:
Vadim Bendebury595736f2015-09-17 17:19:18 -0700850 out_file.write(self._UNMARSHAL_CALL % {'type': field.field_type,
851 'name': field.field_name})
852
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700853
854class Structure(TPMType):
855 """Represents a TPM structure.
856
857 Attributes:
858 name: The name of the structure.
859 fields: A list of Field objects representing struct fields.
860 upper_bounds: A dictionary of (name, val) tuples mapping name to max val.
861 lower_bounds: A dictionary of (name, val) tuples mapping name to min val.
862 size_check: Set if TPM2B structure must be size checked (triggered by size=)
863 valid_tag_values: A list of values field tag is allowed to take.
864 error_code: The return code to be returned if an error occurs
865 """
866 _STRUCTURE_MARSHAL_START = """
867UINT16 %(name)s_Marshal(
868 %(name)s *source,
869 BYTE **buffer,
870 INT32 *size) {
871 UINT16 total_size = 0;"""
872 _STRUCTURE_UNMARSHAL_START = """
873TPM_RC %(name)s_Unmarshal(
874 %(name)s *target,
875 BYTE **buffer,
876 INT32 *size) {
877 TPM_RC result;"""
878 _MARSHAL_END = '\n return total_size;\n}\n'
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700879 _SETUP_ARRAY_FIELD = '\n INT32 i;'
880 _CHECK_SIZE_START = """
881 UINT32 start_size = *size;
882 UINT32 struct_size;"""
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700883 _CHECK_SIZE_END = """
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700884 struct_size = start_size - *size - sizeof(target->t.size);
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700885 if (struct_size != target->t.size) {
886 return TPM_RC_SIZE;
887 }"""
888 _TPM2B_ZERO_SIZE = """
889 if (target->t.size == 0) {
890 return %(return_value)s;
891 }"""
892 _CHECK_BOUND = """
893 if (target->%(name)s %(operator)s %(bound_value)s) {
894 return %(error_code)s;
895 }"""
Vadim Bendeburyb8c5ecc2015-10-05 14:43:25 -0700896 _FIX_SIZE_FIELD = """
897 {
898 BYTE *size_location = *buffer - total_size;
899 INT32 size_field_size = sizeof(%(size_field_type)s);
900 UINT16 payload_size = total_size - (UINT16)size_field_size;
901 %(size_field_type)s_Marshal(&payload_size,
902 &size_location, &size_field_size);
903 }"""
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700904
905 def __init__(self, name):
906 """Initializes a Structure instance.
907
908 Initially the instance will have no fields, upper_bounds, lower_bounds, or
909 valid_tag_values. Those can be added with AddField(), AddUpperBound(),
910 AddLowerBound(), and AddTagVal() methods.
911
912 Args:
913 name: The name of the structure.
914 """
Vadim Bendeburyf5af8592015-10-14 17:15:04 -0700915 super(Structure, self).__init__()
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700916 self.name = name
917 self.fields = []
918 self.upper_bounds = {}
919 self.lower_bounds = {}
920 self.size_check = False
921 self.valid_tag_values = []
922 self.error_code = 'TPM_RC_VALUE'
923
Vadim Bendebury595736f2015-09-17 17:19:18 -0700924 def AddField(self, field):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700925 """Adds a field to fields attribute in Structure.
926
927 Args:
Vadim Bendebury595736f2015-09-17 17:19:18 -0700928 field: Instance of Field
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700929 """
Vadim Bendebury595736f2015-09-17 17:19:18 -0700930 self.fields.append(field)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700931
932 def AddUpperBound(self, field_name, value):
933 """Adds an upper bound for a field.
934
935 Args:
936 field_name: Name of field with bound.
937 value: Value of upper bound.
938 """
Vadim Bendebury595736f2015-09-17 17:19:18 -0700939 if _IsTPM2B(self.name):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700940 field_name = 't.' + field_name
941 self.upper_bounds[field_name] = value
942
943 def AddLowerBound(self, field_name, value):
944 """Adds a lower bound for a field.
945
946 Args:
947 field_name: Name of field with bound.
948 value: Value of lower bound.
949 """
Vadim Bendebury595736f2015-09-17 17:19:18 -0700950 if _IsTPM2B(self.name):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700951 field_name = 't.' + field_name
952 self.lower_bounds[field_name] = value
953
Vadim Bendebury595736f2015-09-17 17:19:18 -0700954 def _AddTagValue(self, value):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700955 """Adds a valid value for tag field.
956
957 Args:
958 value: Valid value for tag field.
959 """
960 self.valid_tag_values.append(value)
961
962 def _GetFieldTypes(self):
963 """Creates a set which holds all current field types.
964
965 Returns:
966 A set of field types.
967 """
968 return set([field.field_type for field in self.fields])
969
970 def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
971 """Writes marshal implementations for Structure to |out_file|.
972
973 Args:
974 out_file: The output file.
975 marshalled_types: A set of types for which marshal and unmarshal functions
976 have already been generated.
977 typemap: A dict mapping type names to the corresponding object.
978 """
979 if self.name in marshalled_types:
980 return
Vadim Bendebury595736f2015-09-17 17:19:18 -0700981
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700982 # Make sure any dependencies already have marshal functions defined.
983 for field_type in self._GetFieldTypes():
984 if field_type not in marshalled_types:
985 typemap[field_type].OutputMarshalImpl(
986 out_file, marshalled_types, typemap)
987 marshalled_types.add(field_type)
988
989 out_file.write(self._STRUCTURE_MARSHAL_START % {'name': self.name})
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700990 # If any field is an array, create local variable INT32 i.
991 for field in self.fields:
Vadim Bendebury595736f2015-09-17 17:19:18 -0700992 if field.array_size:
Jocelyn Bohrfb668122015-07-30 10:17:56 -0700993 out_file.write(self._SETUP_ARRAY_FIELD)
994 break
ChromeOS Developer9edfbac2015-07-17 16:33:16 -0700995 for field in self.fields:
Vadim Bendebury595736f2015-09-17 17:19:18 -0700996 # Each TPM2B is a union of two sized buffers, one which is type specific
997 # (the 't' element) and the other is a generic value (the 'b' element).
998 # For this reason a 't.' is prepended for fields in a TPM2B type. See
999 # section 9.11.6 in TCG TPM2.0 Library Specification, Part 2: Structures
1000 # for more details.
1001 if _IsTPM2B(self.name):
1002 field.field_name = 't.' + field.field_name
1003 if field.run_time_size:
1004 field.run_time_size = 't.' + field.run_time_size
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001005 field.OutputMarshal(out_file, typemap)
Vadim Bendeburyb8c5ecc2015-10-05 14:43:25 -07001006 if self.size_check:
1007 out_file.write(self._FIX_SIZE_FIELD % {'size_field_type': self.fields[0].field_type})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001008 out_file.write(self._MARSHAL_END)
1009
1010 out_file.write(self._STRUCTURE_UNMARSHAL_START % {'name': self.name})
1011 if self.size_check:
1012 out_file.write(self._CHECK_SIZE_START)
Jocelyn Bohrfb668122015-07-30 10:17:56 -07001013 # If any field is an array, create local variable INT32 i.
1014 for field in self.fields:
Vadim Bendebury595736f2015-09-17 17:19:18 -07001015 if field.array_size:
Jocelyn Bohrfb668122015-07-30 10:17:56 -07001016 out_file.write(self._SETUP_ARRAY_FIELD)
1017 break
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001018 for field in self.fields:
1019 field.OutputUnmarshal(out_file, typemap)
1020 return_value = self.error_code
1021 if field.field_name == 't.size' and self.size_check:
1022 out_file.write(self._TPM2B_ZERO_SIZE % {'return_value': 'TPM_RC_SIZE'})
1023 if field.field_name == 't.size' and not self.size_check:
1024 out_file.write(
1025 self._TPM2B_ZERO_SIZE % {'return_value': 'TPM_RC_SUCCESS'})
1026 if field.field_name in self.upper_bounds:
1027 if (field.field_name == 'count' or
1028 field.field_name == 't.size' or
1029 field.field_name == 'size'):
1030 return_value = 'TPM_RC_SIZE'
1031 out_file.write(self._CHECK_BOUND %
Vadim Bendeburyb85286c2015-09-15 14:25:48 -07001032 {'name': field.field_name,
1033 'operator': '>',
1034 'bound_value': self.upper_bounds[field.field_name],
1035 'error_code': return_value})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001036 if field.field_name in self.lower_bounds:
1037 if (field.field_name == 'count' or
1038 field.field_name == 't.size' or
1039 field.field_name == 'size'):
1040 return_value = 'TPM_RC_SIZE'
1041 out_file.write(self._CHECK_BOUND %
Vadim Bendeburyb85286c2015-09-15 14:25:48 -07001042 {'name': field.field_name,
1043 'operator': '<',
1044 'bound_value': self.lower_bounds[field.field_name],
1045 'error_code': return_value})
Vadim Bendebury595736f2015-09-17 17:19:18 -07001046 if field.field_name == 'tag' and self.valid_tag_values:
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001047 out_file.write(self._VALUE_START_SWITCH % {'name': 'target->tag'})
1048 for value in self.valid_tag_values:
1049 out_file.write(self._VALUE_CASE % {'value': value})
1050 out_file.write(self._VALUE_END_SWITCH % {'error_code': 'TPM_RC_TAG'})
1051 if self.size_check:
1052 out_file.write(self._CHECK_SIZE_END)
Vadim Bendebury595736f2015-09-17 17:19:18 -07001053 if not self.fields:
1054 # The spec includes a definition of an empty structure, as a side effect
1055 # the marshaling/unmarshaling functions become empty, the compiler
1056 # warning is suppressed by the below statement.
1057 out_file.write(' (void)result;\n')
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001058 out_file.write(self._UNMARSHAL_END)
1059
1060 marshalled_types.add(self.name)
1061
Vadim Bendeburyb85286c2015-09-15 14:25:48 -07001062 def OutputMarshalDecl(self, out_file, declared_types, _):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001063 """Writes marshal declarations for Structure to |out_file|.
1064
1065 Args:
1066 out_file: The output file.
1067 declared_types: A set of types for which marshal and unmarshal function
1068 declarations have already been generated.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001069 """
Vadim Bendeburyb85286c2015-09-15 14:25:48 -07001070 self._OutputStructOrUnionMarshalDecl(out_file, declared_types)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001071
Vadim Bendebury595736f2015-09-17 17:19:18 -07001072
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001073class Union(TPMType):
1074 """Represents a TPM union.
1075
1076 Attributes:
1077 name: The name of the union.
1078 fields: A list of Field objects representing union fields.
1079 """
1080
1081 _UNION_MARSHAL_START = """
1082UINT16 %(name)s_Marshal(
1083 %(name)s *source,
1084 BYTE **buffer,
1085 INT32 *size,
1086 UINT32 selector) {
Vadim Bendebury1f2ef972015-10-07 17:45:48 -07001087 %(array_extras)s
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001088 switch(selector) {"""
1089 _UNION_UNMARSHAL_START = """
1090TPM_RC %(name)s_Unmarshal(
1091 %(name)s *target,
1092 BYTE **buffer,
1093 INT32 *size,
1094 UINT32 selector) {
1095 switch(selector) {"""
1096 _MARSHAL_END = '\n }\n return 0;\n}\n'
1097 _UNMARSHAL_END = '\n }\n return TPM_RC_SELECTOR;\n}\n'
1098 _MARSHAL_DECLARATION = """
1099UINT16 %(type)s_Marshal(
1100 %(type)s *source,
1101 BYTE **buffer,
1102 INT32 *size,
1103 UINT32 selector);
1104
1105TPM_RC %(type)s_Unmarshal(
1106 %(type)s *target,
1107 BYTE **buffer,
1108 INT32 *size,
1109 UINT32 selector);
1110"""
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001111 _CASE_SELECTOR = """
1112 case %(selector)s:"""
1113 _MARSHAL_EMPTY = """
1114 return 0;"""
1115 _UNMARSHAL_EMPTY = """
1116 return TPM_RC_SUCCESS;"""
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001117 _MARSHAL_FIELD = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001118 return %(type)s_Marshal(
1119 (%(type)s*)&source->%(name)s, buffer, size);"""
1120 _UNMARSHAL_FIELD = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001121 return %(type)s_Unmarshal(
1122 (%(type)s*)&target->%(name)s, buffer, size);"""
1123 _SETUP_MARSHAL_FIELD_ARRAY = """
1124 INT32 i;
1125 UINT16 total_size = 0;"""
1126 _SETUP_UNMARSHAL_FIELD_ARRAY = """
1127 INT32 i;
1128 TPM_RC result = TPM_RC_SUCCESS;"""
1129 _MARSHAL_FIELD_ARRAY = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001130 for (i = 0; i < %(array_length)s; ++i) {
1131 total_size += %(type)s_Marshal(
1132 &source->%(name)s[i], buffer, size);
1133 }
1134 return total_size;"""
1135 _UNMARSHAL_FIELD_ARRAY = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001136 for (i = 0; i < %(array_length)s; ++i) {
1137 result = %(type)s_Unmarshal(
1138 &target->%(name)s[i], buffer, size);
1139 if (result != TPM_RC_SUCCESS) {
1140 return result;
1141 }
1142 }
1143 return TPM_RC_SUCCESS;"""
1144 _UNMARSHAL_FIELD_CONDITIONAL = """
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001145 return %(type)s_Unmarshal(
1146 &target->%(name)s, buffer, size, FALSE);"""
1147 _UNION_MARSHAL_CALL = """
1148 total_size += %(type)s_Marshal(
1149 &source->%(name)s, buffer, size, source->%(selector)s);"""
1150 _UNION_UNMARSHAL_CALL = """
1151 result = %(type)s_Unmarshal(
1152 &target->%(name)s, buffer, size, target->%(selector)s);
1153 if (result != TPM_RC_SUCCESS) {
1154 return result;
1155 }"""
1156 _IFDEF = '\n#ifdef %(type)s'
1157 _ENDIF = '\n#endif'
1158 _IFDEF_TYPE_RE = re.compile(r'^TPM_(ALG|CC).*')
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001159
1160 def __init__(self, name):
1161 """Initializes a Union instance.
1162
1163 Initially the instance will have no fields. Fields are added with the
1164 AddField() method.
1165
1166 Args:
1167 name: The name of the structure.
1168 """
Vadim Bendeburyf5af8592015-10-14 17:15:04 -07001169 super(Union, self).__init__()
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001170 self.name = name
1171 self.fields = []
1172
1173 def _NeedsIfdef(self, selector):
1174 """Returns True if selector is a type which needs ifdef enclosing."""
1175 return self._IFDEF_TYPE_RE.search(selector)
1176
Vadim Bendebury595736f2015-09-17 17:19:18 -07001177 def AddField(self, field):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001178 """Adds a field to fields attribute in Union.
1179
1180 Args:
Vadim Bendebury595736f2015-09-17 17:19:18 -07001181 field: instance of Field
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001182 """
Jocelyn Bohr7cba2332015-08-10 16:28:31 -07001183 # xor is a C++ keyword and must be fixed.
Vadim Bendebury595736f2015-09-17 17:19:18 -07001184 if field.field_name == 'xor':
1185 field.field_name = 'xor_'
1186 self.fields.append(field)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001187
1188 def _OutputMarshalField(
Vadim Bendeburyb85286c2015-09-15 14:25:48 -07001189 self, out_file, field_type, field_name, array_length):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001190 """Write a call to marshal a field in this union.
1191
1192 Args:
1193 out_file: The output file.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001194 field_type: The type of field.
Vadim Bendebury595736f2015-09-17 17:19:18 -07001195 field_name: The name of the field.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001196 array_length: Variable indicating length of array, None if field is not
1197 an array.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001198 """
1199 if array_length:
1200 out_file.write(self._MARSHAL_FIELD_ARRAY % {'type': field_type,
1201 'name': field_name,
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001202 'array_length': array_length})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001203 else:
1204 out_file.write(self._MARSHAL_FIELD % {'type': field_type,
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001205 'name': field_name})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001206
1207 def _OutputUnmarshalField(
Vadim Bendeburyb85286c2015-09-15 14:25:48 -07001208 self, out_file, field_type, field_name, array_length, typemap):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001209 """Write a call to unmarshal a field in this union.
1210
1211 Args:
Vadim Bendebury595736f2015-09-17 17:19:18 -07001212 out_file: The output file object.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001213 field_type: The type of field.
Vadim Bendebury595736f2015-09-17 17:19:18 -07001214 field_name: The name of the field.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001215 array_length: Variable indicating length of array, None if field is not
1216 an array.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001217 typemap: A dict mapping type names to the corresponding object.
1218 """
1219 if array_length:
1220 out_file.write(
1221 self._UNMARSHAL_FIELD_ARRAY % {'type': field_type,
1222 'name': field_name,
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001223 'array_length': array_length})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001224 elif typemap[field_type].HasConditional():
1225 out_file.write(
1226 self._UNMARSHAL_FIELD_CONDITIONAL % {'type': field_type,
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001227 'name': field_name})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001228 else:
1229 out_file.write(self._UNMARSHAL_FIELD % {'type': field_type,
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001230 'name': field_name})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001231
1232 def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
1233 """Writes marshal implementations for Union to |out_file|.
1234
1235 Args:
1236 out_file: The output file.
1237 marshalled_types: A set of types for which marshal and unmarshal functions
1238 have already been generated.
1239 typemap: A dict mapping type names to the corresponding object.
1240 """
1241 if (self.name in marshalled_types or
1242 self.name == 'TPMU_NAME' or
Vadim Bendebury595736f2015-09-17 17:19:18 -07001243 self.name == 'TPMU_ENCRYPTED_SECRET' or
1244 not self.fields):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001245 return
Vadim Bendebury595736f2015-09-17 17:19:18 -07001246
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001247 field_types = {f.field_name: f.field_type for f in self.fields}
Vadim Bendebury595736f2015-09-17 17:19:18 -07001248 array_lengths = {}
1249 for f in self.fields:
1250 if f.array_size:
1251 array_lengths[f.field_name] = f.array_size
1252 else:
1253 array_lengths[f.field_name] = None
1254
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001255 # Make sure any dependencies already have marshal functions defined.
Vadim Bendebury595736f2015-09-17 17:19:18 -07001256 for field_type in field_types.itervalues():
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001257 if field_type not in marshalled_types:
1258 typemap[field_type].OutputMarshalImpl(
1259 out_file, marshalled_types, typemap)
1260 marshalled_types.add(field_type)
Vadim Bendebury595736f2015-09-17 17:19:18 -07001261 if self.fields[0].array_size:
Vadim Bendebury1f2ef972015-10-07 17:45:48 -07001262 array_extras = self._SETUP_MARSHAL_FIELD_ARRAY
1263 else:
1264 array_extras = ''
1265 out_file.write(self._UNION_MARSHAL_START % {'name': self.name,
1266 'array_extras': array_extras})
1267 # Set up variables if Union is an array type.
Vadim Bendebury595736f2015-09-17 17:19:18 -07001268 for field in self.fields:
1269 selector = field.selector_value
1270 if not selector:
1271 continue
1272 field_name = field.field_name
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001273 if self._NeedsIfdef(selector):
1274 out_file.write(self._IFDEF % {'type': selector})
Vadim Bendebury595736f2015-09-17 17:19:18 -07001275 out_file.write(self._CASE_SELECTOR % {'selector': selector})
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001276 # Selector is not associated with a name, so no marshaling occurs.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001277 if not field_name:
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001278 out_file.write(self._MARSHAL_EMPTY)
1279 if self._NeedsIfdef(selector):
1280 out_file.write(self._ENDIF)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001281 continue
1282 field_type = field_types[field_name]
1283 array_length = array_lengths[field_name]
Vadim Bendeburyb85286c2015-09-15 14:25:48 -07001284 self._OutputMarshalField(out_file, field_type, field_name, array_length)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001285 if self._NeedsIfdef(selector):
1286 out_file.write(self._ENDIF)
1287 out_file.write(self._MARSHAL_END)
1288 out_file.write(self._UNION_UNMARSHAL_START % {'name': self.name})
1289 # Set up variables if Union is an array type.
Vadim Bendebury595736f2015-09-17 17:19:18 -07001290 if self.fields[0].array_size:
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001291 out_file.write(self._SETUP_UNMARSHAL_FIELD_ARRAY)
Vadim Bendebury595736f2015-09-17 17:19:18 -07001292 for field in self.fields:
1293 selector = field.selector_value
1294 if not selector:
1295 continue
1296 field_name = field.field_name
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001297 if self._NeedsIfdef(selector):
1298 out_file.write(self._IFDEF % {'type': selector})
1299 out_file.write(self._CASE_SELECTOR % {'selector': selector})
1300 # Selector is not associated with a name, so no unmarshaling occurs.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001301 if not field_name:
Jocelyn Bohr5aef9c62015-08-11 12:46:22 -07001302 out_file.write(self._UNMARSHAL_EMPTY)
1303 if self._NeedsIfdef(selector):
1304 out_file.write(self._ENDIF)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001305 continue
1306 field_type = field_types[field_name]
1307 array_length = array_lengths[field_name]
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001308 self._OutputUnmarshalField(
Vadim Bendeburyb85286c2015-09-15 14:25:48 -07001309 out_file, field_type, field_name, array_length, typemap)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001310 if self._NeedsIfdef(selector):
1311 out_file.write(self._ENDIF)
1312 out_file.write(self._UNMARSHAL_END)
1313 marshalled_types.add(self.name)
1314
Vadim Bendeburyb85286c2015-09-15 14:25:48 -07001315 def OutputMarshalDecl(self, out_file, declared_types, _):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001316 """Writes marshal declarations for Union to |out_file|.
1317
1318 Args:
1319 out_file: The output file.
1320 declared_types: A set of types for which marshal and unmarshal function
1321 declarations have already been generated.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001322 """
Vadim Bendeburyb85286c2015-09-15 14:25:48 -07001323 self._OutputStructOrUnionMarshalDecl(out_file, declared_types)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001324
Vadim Bendebury595736f2015-09-17 17:19:18 -07001325 def OutputMarshalCall(self, out_file, field):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001326 """Write a call to marshal function for Union type to |out_file|.
1327
1328 Override TPMType OutputMarshalCall to pass in selector value.
1329
1330 Args:
1331 out_file: The output file.
Vadim Bendebury595736f2015-09-17 17:19:18 -07001332 field: A Field object representing a member of this union
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001333 """
Vadim Bendebury595736f2015-09-17 17:19:18 -07001334 out_file.write(self._UNION_MARSHAL_CALL %
1335 {'type': field.field_type,
1336 'name': field.field_name,
1337 'selector': field.selector_value})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001338
Vadim Bendebury595736f2015-09-17 17:19:18 -07001339 def OutputUnmarshalCall(self, out_file, field):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001340 """Write a call to unmarshal function for Union type to |out_file|.
1341
1342 Override TPMType OutputUnmashalCall to pass in selector value.
1343
1344 Args:
1345 out_file: The output file.
Vadim Bendebury595736f2015-09-17 17:19:18 -07001346 field: A Field object representing a member of this union
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001347 """
Vadim Bendebury595736f2015-09-17 17:19:18 -07001348 out_file.write(self._UNION_UNMARSHAL_CALL %
1349 {'type': field.field_type,
1350 'name': field.field_name,
1351 'selector': field.selector_value})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001352
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001353
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001354def GenerateHeader(typemap):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001355 """Generates a header file with declarations for all given generator objects.
1356
1357 Args:
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001358 typemap: A dict mapping type names to the corresponding object.
1359 """
1360 out_file = open(_OUTPUT_FILE_H, 'w')
Vadim Bendebury595736f2015-09-17 17:19:18 -07001361 out_file.write(COPYRIGHT_HEADER)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001362 guard_name = 'TPM2_%s_' % _OUTPUT_FILE_H.upper().replace('.', '_')
Vadim Bendebury595736f2015-09-17 17:19:18 -07001363 out_file.write(HEADER_FILE_GUARD_HEADER % {'name': guard_name})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001364 out_file.write(_HEADER_FILE_INCLUDES)
1365 # These types are built-in or defined by <stdint.h>; they serve as base cases
1366 # when defining type dependencies.
1367 declared_types = set(_BASIC_TYPES)
1368 # Generate serialize / parse function declarations.
1369 for basic_type in _BASIC_TYPES:
1370 out_file.write(_STANDARD_MARSHAL_DECLARATION % {'type': basic_type})
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001371 for tpm_type in [typemap[x] for x in sorted(typemap.keys())]:
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001372 tpm_type.OutputMarshalDecl(out_file, declared_types, typemap)
Vadim Bendebury595736f2015-09-17 17:19:18 -07001373 out_file.write(HEADER_FILE_GUARD_FOOTER % {'name': guard_name})
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001374 out_file.close()
1375 call(['clang-format', '-i', '-style=Chromium', 'tpm_generated.h'])
1376
1377
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001378def GenerateImplementation(typemap):
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001379 """Generates implementation code for each type.
1380
1381 Args:
Vadim Bendebury595736f2015-09-17 17:19:18 -07001382 typemap: A dict mapping string type names to the corresponding object.
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001383 """
1384 out_file = open(_OUTPUT_FILE_CC, 'w')
Vadim Bendebury595736f2015-09-17 17:19:18 -07001385 out_file.write(COPYRIGHT_HEADER)
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001386 out_file.write(_IMPLEMENTATION_FILE_INCLUDES)
1387 marshalled_types = set(_BASIC_TYPES)
1388 for basic_type in _BASIC_TYPES:
1389 out_file.write(_MARSHAL_BASIC_TYPE % {'type': basic_type})
Vadim Bendebury3cd85262015-09-04 17:01:40 -07001390 for tpm_type in [typemap[x] for x in sorted(typemap.keys())]:
ChromeOS Developer9edfbac2015-07-17 16:33:16 -07001391 tpm_type.OutputMarshalImpl(out_file, marshalled_types, typemap)
1392 out_file.close()
1393 call(['clang-format', '-i', '-style=Chromium', 'tpm_generated.c'])