1393 lines
48 KiB
Python
Executable file
1393 lines
48 KiB
Python
Executable file
# Copyright 2015 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
"""A code generator for TPM 2.0 structures.
|
|
|
|
The structure generator provides classes to create various objects
|
|
(structures, unions, constants, etc.) and then convert the set of generated
|
|
objects into valid C files named tpm_generated.{h,c}.
|
|
|
|
"""
|
|
|
|
from __future__ import print_function
|
|
|
|
import datetime
|
|
import re
|
|
|
|
from subprocess import call
|
|
|
|
_BASIC_TYPES = ['uint8_t', 'int8_t', 'uint16_t', 'int16_t', 'uint32_t',
|
|
'int32_t', 'uint64_t', 'int64_t']
|
|
_OUTPUT_FILE_H = 'tpm_generated.h'
|
|
_OUTPUT_FILE_CC = 'tpm_generated.c'
|
|
COPYRIGHT_HEADER = (
|
|
'// Copyright %d The Chromium OS Authors. All rights reserved.\n'
|
|
'// Use of this source code is governed by a BSD-style license that can '
|
|
'be\n'
|
|
'// found in the LICENSE file.\n'
|
|
'\n'
|
|
'// THIS CODE IS GENERATED - DO NOT MODIFY!\n' %
|
|
datetime.datetime.now().year)
|
|
HEADER_FILE_GUARD_HEADER = """
|
|
#ifndef %(name)s
|
|
#define %(name)s
|
|
"""
|
|
HEADER_FILE_GUARD_FOOTER = """
|
|
#endif // %(name)s
|
|
"""
|
|
_HEADER_FILE_INCLUDES = """
|
|
#include <endian.h>
|
|
#include <string.h>
|
|
|
|
#include "TPM_Types.h"
|
|
#include "Tpm.h"
|
|
"""
|
|
_IMPLEMENTATION_FILE_INCLUDES = """
|
|
#include "tpm_generated.h"
|
|
"""
|
|
# Function signatures for generated marshaling code are specified in TCG TPM2.0
|
|
# Library Specification, Part 4: Supporting Routines, sections 4.2.2 and 4.2.3.
|
|
_MARSHAL_BASIC_TYPE = """
|
|
UINT16 %(type)s_Marshal(%(type)s *source, BYTE **buffer, INT32 *size) {
|
|
%(type)s value_net = *source;
|
|
if (!size || *size < sizeof(%(type)s)) {
|
|
return 0; // Nothing has been marshaled.
|
|
}
|
|
switch (sizeof(%(type)s)) {
|
|
case 2:
|
|
value_net = htobe16(*source);
|
|
break;
|
|
case 4:
|
|
value_net = htobe32(*source);
|
|
break;
|
|
case 8:
|
|
value_net = htobe64(*source);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
memcpy(*buffer, &value_net, sizeof(%(type)s));
|
|
*buffer += sizeof(%(type)s);
|
|
*size -= sizeof(%(type)s);
|
|
return sizeof(%(type)s);
|
|
}
|
|
|
|
TPM_RC %(type)s_Unmarshal(%(type)s *target, BYTE **buffer, INT32 *size) {
|
|
%(type)s value_net = 0;
|
|
if (!size || *size < sizeof(%(type)s)) {
|
|
return TPM_RC_INSUFFICIENT;
|
|
}
|
|
memcpy(&value_net, *buffer, sizeof(%(type)s));
|
|
switch (sizeof(%(type)s)) {
|
|
case 2:
|
|
*target = be16toh(value_net);
|
|
break;
|
|
case 4:
|
|
*target = be32toh(value_net);
|
|
break;
|
|
case 8:
|
|
*target = be64toh(value_net);
|
|
break;
|
|
default:
|
|
*target = value_net;
|
|
}
|
|
*buffer += sizeof(%(type)s);
|
|
*size -= sizeof(%(type)s);
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
"""
|
|
_STANDARD_MARSHAL_DECLARATION = """
|
|
UINT16 %(type)s_Marshal(
|
|
%(type)s *source,
|
|
BYTE **buffer,
|
|
INT32 *size);
|
|
|
|
TPM_RC %(type)s_Unmarshal(
|
|
%(type)s *target,
|
|
BYTE **buffer,
|
|
INT32 *size);
|
|
"""
|
|
|
|
|
|
def _IsTPM2B(name):
|
|
return name.startswith('TPM2B_')
|
|
|
|
|
|
class Field(object):
|
|
"""Represents a field in TPM structure or union.
|
|
|
|
This object is used in several not fully overlapping cases, not all
|
|
attributes apply to all use cases.
|
|
|
|
The 'array_size' and 'run_time_size' attributes below are related to the
|
|
following code example:
|
|
|
|
struct {
|
|
int size;
|
|
byte array[MAX_SIZE]
|
|
} object.
|
|
|
|
In this structure the actual number of bytes in the array could be anything
|
|
from zero to MAX_SIZE. The field 'size' denotes the actual number of
|
|
elements at run time. So, when this object is constructed, array_size is
|
|
'MAX_SIZE' and run_time_size is 'size'.
|
|
|
|
The 'selector_value' attribute is used to associate union fields with
|
|
certain object types. For instance
|
|
|
|
typedef union {
|
|
TPM2B_PUBLIC_KEY_RSA rsa;
|
|
TPMS_ECC_POINT ecc;
|
|
} TPMU_PUBLIC_ID;
|
|
|
|
the field named 'rsa' will have its 'selector_value' set to 'TPM_ALG_RSA'.
|
|
|
|
Attributes:
|
|
field_type: a string, the type of field.
|
|
field_name: a string, the name of the field.
|
|
array_size: a string, see example above
|
|
run_time_size: a string, see example above
|
|
selector_value: a string, see example above
|
|
conditional_value: a string, necessary for validation when unmarshaling.
|
|
Some types have a value that is allowed for some
|
|
commands but not others. E.g. 'TPM_RS_PW' is a
|
|
conditional value for the 'TPMI_SH_AUTH_SESSION' type
|
|
and TPM_ALG_NULL is a conditional value for the
|
|
TPMI_ALG_HASH type.
|
|
"""
|
|
_MARSHAL_FIELD_ARRAY = """
|
|
for (i = 0; i < source->%(array_length)s; ++i) {
|
|
total_size += %(type)s_Marshal(&source->%(name)s[i], buffer, size);
|
|
}"""
|
|
_UNMARSHAL_FIELD_ARRAY = """
|
|
for (i = 0; i < target->%(array_length)s; ++i) {
|
|
result = %(type)s_Unmarshal(&target->%(name)s[i], buffer, size);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
return result;
|
|
}
|
|
}"""
|
|
|
|
def __init__(self, field_type, field_name,
|
|
selector=None, array_size='',
|
|
conditional_value='FALSE',
|
|
run_time_size=None):
|
|
"""Initializes a Field instance.
|
|
|
|
Args:
|
|
field_type: Initial value for the field type attribute.
|
|
field_name: Initial value for the field name attribute.
|
|
selector: Initial value for the selector attribute.
|
|
array_size: Initial value for the array_size attribute.
|
|
conditional_value: Initial value of the conditional_value attribute.
|
|
run_time_size: Initial value of the run_time_size attribute
|
|
"""
|
|
if not field_type:
|
|
# Some tables include rows without data type, for instance 'Table 70 -
|
|
# Definition of TPMU_HA Union' in part 2. These rows are supposed to
|
|
# cause another case added to the switch in the marshaling function
|
|
# (processing of TPM_ALG_NULL in this example). Setting field name to ''
|
|
# makes sure that the actual generated structure/union does not have an
|
|
# entry for this field, setting type of such field to some value
|
|
# simplifies functions generating the marshaling code.
|
|
self.field_type = 'BYTE'
|
|
self.field_name = ''
|
|
else:
|
|
self.field_type = field_type
|
|
self.field_name = field_name
|
|
self.array_size = array_size
|
|
self.selector_value = selector
|
|
self.conditional_value = conditional_value
|
|
self.run_time_size = run_time_size
|
|
|
|
def OutputMarshal(self, out_file, typemap):
|
|
"""Write a call to marshal the field this instance represents.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
typemap: A dict mapping type names to the corresponding object.
|
|
"""
|
|
if self.array_size:
|
|
if self.run_time_size:
|
|
real_size = self.run_time_size
|
|
else:
|
|
real_size = self.array_size
|
|
out_file.write(
|
|
self._MARSHAL_FIELD_ARRAY % {'type': self.field_type,
|
|
'name': self.field_name,
|
|
'array_length': real_size})
|
|
else:
|
|
typemap[self.field_type].OutputMarshalCall(out_file, self)
|
|
|
|
def OutputUnmarshal(self, out_file, typemap):
|
|
"""Write a call to unmarshal the field this instance represents.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
typemap: A dict mapping type names to the corresponding object.
|
|
"""
|
|
if self.array_size:
|
|
if self.run_time_size:
|
|
real_size = self.run_time_size
|
|
else:
|
|
real_size = self.array_size
|
|
out_file.write(
|
|
self._UNMARSHAL_FIELD_ARRAY % {'type': self.field_type,
|
|
'name': self.field_name,
|
|
'array_length': real_size})
|
|
else:
|
|
typemap[self.field_type].OutputUnmarshalCall(out_file, self)
|
|
|
|
|
|
class TPMType(object):
|
|
"""Base type for all TPMTypes.
|
|
|
|
Contains functions and string literals common to all TPM types.
|
|
|
|
Attributes:
|
|
_base_type: a string, when set - the very basic type this type is
|
|
derived from (should be used for marshaling/unmarshaling to
|
|
shortcut multiple nested invocations).
|
|
"""
|
|
# A function to marshal a TPM typedef.
|
|
_TYPEDEF_MARSHAL_FUNCTION = """
|
|
UINT16 %(new_type)s_Marshal(
|
|
%(new_type)s *source,
|
|
BYTE **buffer,
|
|
INT32 *size) {
|
|
return %(old_type)s_Marshal(source, buffer, size);
|
|
}
|
|
"""
|
|
# The function signature and unmarshaling call to the base type of a TPM
|
|
# typedef. After the value is unmarshaled, additional validation code is
|
|
# generated based on tables in TCG TPM2.0 Library Specification, Part 2:
|
|
# Structures.
|
|
_TYPEDEF_UNMARSHAL_START = """
|
|
TPM_RC %(new_type)s_Unmarshal(
|
|
%(new_type)s *target,
|
|
BYTE **buffer,
|
|
INT32 *size) {
|
|
TPM_RC result;
|
|
result = %(old_type)s_Unmarshal(target, buffer, size);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
return result;
|
|
}"""
|
|
_UNMARSHAL_END = '\n return TPM_RC_SUCCESS;\n}\n'
|
|
# Snippets of code for value validation.
|
|
_VALUE_START_SWITCH = '\n switch (%(name)s) {'
|
|
_VALUE_CASE = '\n case %(value)s:'
|
|
_VALUE_CASE_IFDEF = '\n#ifdef %(value)s\n case %(value)s:\n#endif'
|
|
_VALUE_END_SWITCH = """
|
|
break;
|
|
default:
|
|
return %(error_code)s;
|
|
}"""
|
|
# A declaration for marshaling and unmarshaling functions for a TPM type.
|
|
_MARSHAL_DECLARATION = _STANDARD_MARSHAL_DECLARATION
|
|
# Snippets of code which make calls to marshaling functions. Marshals a value
|
|
# of type 'type' into a field 'name' within a structure. This is used in
|
|
# generation of structure and command marshaling code.
|
|
_MARSHAL_CALL = """
|
|
total_size += %(type)s_Marshal(
|
|
&source->%(name)s, buffer, size);"""
|
|
_UNMARSHAL_CALL = """
|
|
result = %(type)s_Unmarshal(
|
|
&target->%(name)s, buffer, size);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
return result;
|
|
}"""
|
|
|
|
def __init__(self):
|
|
self._base_type = None
|
|
|
|
def SetBaseType(self, base_type):
|
|
self._base_type = base_type
|
|
|
|
def _GetBaseType(self, out_file, marshalled_types, typemap):
|
|
'''Return base type for this object.
|
|
|
|
The base type is used for shortcutting marshaling/unmarshaling code.
|
|
|
|
If _base_type is not set, return the old_type value as the base type.
|
|
|
|
If the base type's marshaling/unmarshaling code has not been generated
|
|
yet, issue it before continuing processing.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
marshalled_types: A set of types for which marshal and unmarshal functions
|
|
have already been generated.
|
|
typemap: A dict mapping type names to the corresponding object.
|
|
|
|
Returns:
|
|
A string, the name of the type to use for marshaling/unmarshaling.
|
|
|
|
'''
|
|
if self._base_type:
|
|
base_type = self._base_type
|
|
else:
|
|
base_type = self.old_type
|
|
if base_type not in marshalled_types:
|
|
typemap[base_type].OutputMarshalImpl(
|
|
out_file, marshalled_types, typemap)
|
|
return base_type
|
|
|
|
def HasConditional(self):
|
|
"""Returns true if TPMType has a conditional value."""
|
|
return False
|
|
|
|
def OutputMarshalCall(self, out_file, field):
|
|
"""Write a call to Marshal function for TPMType to |out_file|.
|
|
|
|
Accumulates a variable 'total_size' with the result of marshaling
|
|
field |field_name| in structure 'source'.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
field: A Field object describing this type.
|
|
"""
|
|
out_file.write(self._MARSHAL_CALL % {'type': field.field_type,
|
|
'name': field.field_name})
|
|
|
|
def OutputUnmarshalCall(self, out_file, field):
|
|
"""Write a call to Unmarshal function for TPMType to |out_file|.
|
|
|
|
Assigns result of unmarshaling field |field_name| in structure 'source'
|
|
to variable 'result'. Returns if the unmarshalling was unsuccessful.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
field: A Field object describing this type.
|
|
"""
|
|
obj_type = field.field_type
|
|
if obj_type == 'TPM_CC':
|
|
obj_type = 'UINT32'
|
|
out_file.write(self._UNMARSHAL_CALL % {'type': obj_type,
|
|
'name': field.field_name})
|
|
|
|
def _OutputTypedefMarshalDecl(self, out_file, declared_types, typemap):
|
|
"""Write marshal declarations for TPM typedefs to |out_file|.
|
|
|
|
Can only be called on Typedef, ConstantType, AttributeStruct, and
|
|
Interface objects.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
declared_types: A set of types for which marshal and unmarshal function
|
|
declarations have already been generated.
|
|
typemap: A dict mapping type names to the corresponding object.
|
|
"""
|
|
if self.new_type in declared_types:
|
|
return
|
|
if self.old_type not in declared_types and self.old_type in typemap:
|
|
typemap[self.old_type].OutputMarshalDecl(
|
|
out_file, declared_types, typemap)
|
|
out_file.write(self._MARSHAL_DECLARATION % {'type': self.new_type})
|
|
declared_types.add(self.new_type)
|
|
|
|
def _OutputStructOrUnionMarshalDecl(self, out_file, declared_types):
|
|
"""Write marshal declarations for a TPM Structure or Union.
|
|
|
|
Can only be called on Structure and Union objects.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
declared_types: A set of types for which marshal and unmarshal function
|
|
declarations have already been generated.
|
|
"""
|
|
# TPMU_NAME and TPMU_ENCRYPTED_SECRET type are never used across the
|
|
# interface.
|
|
if (self.name in declared_types or
|
|
self.name == 'TPMU_NAME' or
|
|
self.name == 'TPMU_ENCRYPTED_SECRET'):
|
|
return
|
|
out_file.write(self._MARSHAL_DECLARATION % {'type': self.name})
|
|
declared_types.add(self.name)
|
|
|
|
|
|
class Typedef(TPMType):
|
|
"""Represents a TPM typedef.
|
|
|
|
Attributes:
|
|
old_type: The existing type in a typedef statement.
|
|
new_type: The new type in a typedef statement.
|
|
"""
|
|
# A function to unmarshal a TPM typedef with no extra validation.
|
|
_TYPEDEF_UNMARSHAL_FUNCTION = """
|
|
TPM_RC %(new_type)s_Unmarshal(
|
|
%(new_type)s *target,
|
|
BYTE **buffer,
|
|
INT32 *size) {
|
|
return %(old_type)s_Unmarshal(target, buffer, size);
|
|
}
|
|
"""
|
|
|
|
def __init__(self, old_type, new_type):
|
|
"""Initializes a Typedef instance.
|
|
|
|
Args:
|
|
old_type: The base type of the attribute structure.
|
|
new_type: The name of the type.
|
|
"""
|
|
super(Typedef, self).__init__()
|
|
self.old_type = old_type
|
|
self.new_type = new_type
|
|
|
|
def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
|
|
"""Writes marshal implementations for Typedef to |out_file|.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
marshalled_types: A set of types for which marshal and unmarshal functions
|
|
have already been generated.
|
|
typemap: A dict mapping type names to the corresponding object.
|
|
"""
|
|
if self.new_type in marshalled_types:
|
|
return
|
|
base_type = self._GetBaseType(out_file, marshalled_types, typemap)
|
|
out_file.write(self._TYPEDEF_MARSHAL_FUNCTION % {'old_type': base_type,
|
|
'new_type': self.new_type})
|
|
out_file.write(
|
|
self._TYPEDEF_UNMARSHAL_FUNCTION % {'old_type': base_type,
|
|
'new_type': self.new_type})
|
|
marshalled_types.add(self.new_type)
|
|
|
|
def OutputMarshalDecl(self, out_file, declared_types, typemap):
|
|
"""Writes marshal declarations for Typedef to |out_file|.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
declared_types: A set of types for which marshal and unmarshal function
|
|
declarations have already been generated.
|
|
typemap: A dict mapping type names to the corresponding object.
|
|
"""
|
|
self._OutputTypedefMarshalDecl(out_file, declared_types, typemap)
|
|
|
|
|
|
class ConstantType(TPMType):
|
|
"""Represents a TPM Constant type definition.
|
|
|
|
Attributes:
|
|
old_type: The base type of the constant (e.g. 'int').
|
|
new_type: The name of the type (e.g. 'TPM_RC').
|
|
valid_values: The list of valid values this type can take (e.g.
|
|
'TPM_RC_SUCCESS').
|
|
error_code: Error to be returned when unmarshalling is unsuccessful.
|
|
"""
|
|
_CHECK_VALUE = """
|
|
if (*target == %(value)s) {
|
|
return TPM_RC_SUCCESS;
|
|
}"""
|
|
_CHECK_VALUE_IFDEF = """
|
|
#ifdef %(value)s
|
|
if (*target == %(value)s) {
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
#endif"""
|
|
_UNMARSHAL_END = """
|
|
return %(error_code)s;
|
|
}
|
|
"""
|
|
_IFDEF_TYPE_RE = re.compile(r'^TPM_(ALG|CC).*')
|
|
|
|
def __init__(self, old_type, new_type):
|
|
"""Initializes a ConstantType instance.
|
|
|
|
Values are added to valid_values attribute during parsing.
|
|
|
|
Args:
|
|
old_type: The base type of the constant type.
|
|
new_type: The name of the type.
|
|
"""
|
|
super(ConstantType, self).__init__()
|
|
self.old_type = old_type
|
|
self.new_type = new_type
|
|
self.valid_values = []
|
|
self.error_code = 'TPM_RC_VALUE'
|
|
|
|
def _NeedsIfdef(self):
|
|
"""Returns True if new_type is a type which needs ifdef enclosing."""
|
|
return self._IFDEF_TYPE_RE.search(self.new_type)
|
|
|
|
def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
|
|
"""Writes marshal implementations for ConstantType to |out_file|.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
marshalled_types: A set of types for which marshal and unmarshal functions
|
|
have already been generated.
|
|
typemap: A dict mapping type names to the corresponding object.
|
|
"""
|
|
if self.new_type in marshalled_types:
|
|
return
|
|
base_type = self._GetBaseType(out_file, marshalled_types, typemap)
|
|
out_file.write(self._TYPEDEF_MARSHAL_FUNCTION % {'old_type': base_type,
|
|
'new_type': self.new_type})
|
|
out_file.write(self._TYPEDEF_UNMARSHAL_START % {'old_type': base_type,
|
|
'new_type': self.new_type})
|
|
for value in self.valid_values:
|
|
if self._NeedsIfdef():
|
|
out_file.write(self._CHECK_VALUE_IFDEF % {'value': value})
|
|
else:
|
|
out_file.write(self._CHECK_VALUE % {'value': value})
|
|
out_file.write(self._UNMARSHAL_END % {'error_code': self.error_code})
|
|
marshalled_types.add(self.new_type)
|
|
|
|
def OutputMarshalDecl(self, out_file, declared_types, typemap):
|
|
"""Writes marshal declarations for ConstantType to |out_file|.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
declared_types: A set of types for which marshal and unmarshal function
|
|
declarations have already been generated.
|
|
typemap: A dict mapping type names to the corresponding object.
|
|
"""
|
|
self._OutputTypedefMarshalDecl(out_file, declared_types, typemap)
|
|
|
|
|
|
class AttributeStructure(TPMType):
|
|
"""Represents a TPM attribute structure type definition.
|
|
|
|
Attributes:
|
|
old_type: The base type of the constant (e.g. 'int').
|
|
new_type: The name of the type (e.g. 'TPMA_OBJECT').
|
|
reserved: The list of bit bounds where bits must be 0 (e.g. ['10_2','3']).
|
|
"""
|
|
# Attribute structures need an explicit cast to the base type.
|
|
_ATTRIBUTE_MARSHAL_FUNCTION = """
|
|
UINT16 %(new_type)s_Marshal(
|
|
%(new_type)s *source,
|
|
BYTE **buffer,
|
|
INT32 *size) {
|
|
return %(old_type)s_Marshal((%(old_type)s*)source, buffer, size);
|
|
}
|
|
"""
|
|
_ATTRIBUTE_UNMARSHAL_START = """
|
|
TPM_RC %(new_type)s_Unmarshal(
|
|
%(new_type)s *target,
|
|
BYTE **buffer,
|
|
INT32 *size) {
|
|
TPM_RC result;
|
|
result = %(old_type)s_Unmarshal((%(old_type)s*)target, buffer, size);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
return result;
|
|
}"""
|
|
_CHECK_RESERVED = """
|
|
if (target->reserved%(bits)s != 0) {
|
|
return TPM_RC_RESERVED_BITS;
|
|
}"""
|
|
|
|
def __init__(self, old_type, new_type):
|
|
"""Initializes an AttributeStructure instance.
|
|
|
|
Values may be added to reserved attribute during parsing.
|
|
|
|
Args:
|
|
old_type: The base type of the attribute structure.
|
|
new_type: The name of the type.
|
|
"""
|
|
super(AttributeStructure, self).__init__()
|
|
self.old_type = old_type
|
|
self.new_type = new_type
|
|
self.reserved = []
|
|
|
|
def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
|
|
"""Writes marshal implementations for AttributStructure to |out_file|.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
marshalled_types: A set of types for which marshal and unmarshal functions
|
|
have already been generated.
|
|
typemap: A dict mapping type names to the corresponding object.
|
|
"""
|
|
if self.new_type in marshalled_types:
|
|
return
|
|
base_type = self._GetBaseType(out_file, marshalled_types, typemap)
|
|
out_file.write(self._ATTRIBUTE_MARSHAL_FUNCTION %
|
|
{'old_type': base_type,
|
|
'new_type': self.new_type})
|
|
out_file.write(self._ATTRIBUTE_UNMARSHAL_START %
|
|
{'old_type': base_type,
|
|
'new_type': self.new_type})
|
|
for bits in self.reserved:
|
|
out_file.write(self._CHECK_RESERVED % {'bits': bits})
|
|
out_file.write(self._UNMARSHAL_END)
|
|
marshalled_types.add(self.new_type)
|
|
|
|
def OutputMarshalDecl(self, out_file, declared_types, typemap):
|
|
"""Writes marshal declarations for AttributeStructure to |out_file|.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
declared_types: A set of types for which marshal and unmarshal function
|
|
declarations have already been generated.
|
|
typemap: A dict mapping type names to the corresponding object.
|
|
"""
|
|
self._OutputTypedefMarshalDecl(out_file, declared_types, typemap)
|
|
|
|
|
|
class Interface(TPMType):
|
|
"""Represents a TPM interface type definition.
|
|
|
|
Attributes:
|
|
old_type: The base type of the interface (e.g. 'TPM_HANDLE').
|
|
new_type: The name of the type (e.g. 'TPMI_DH_OBJECT').
|
|
valid_values: List of valid values for new_type. If this is not empty,
|
|
valid values for new_type is explicitly defined in the spec.
|
|
bounds: List of pairs representing bounds. If nonempty, target must fall
|
|
between one of these bounds.
|
|
conditional_value: Name of conditionally allowed value. If there is no
|
|
such value, this variable will be None.
|
|
supported_values: String literal indicating the name of a list of supported
|
|
values to be substituted at compile time (e.g. 'AES_KEY_SIZES_BITS').
|
|
If this is not None, valid values for new_type depends on the
|
|
implementation.
|
|
error_code: Return code when an unmarshalling error occurs.
|
|
"""
|
|
_INTERFACE_CONDITIONAL_UNMARSHAL_START = """
|
|
TPM_RC %(new_type)s_Unmarshal(
|
|
%(new_type)s *target,
|
|
BYTE **buffer,
|
|
INT32 *size,
|
|
BOOL allow_conditional_value) {
|
|
TPM_RC result;"""
|
|
_INTERFACE_UNMARSHAL_START = """
|
|
TPM_RC %(new_type)s_Unmarshal(
|
|
%(new_type)s *target,
|
|
BYTE **buffer,
|
|
INT32 *size) {
|
|
TPM_RC result;"""
|
|
_UNMARSHAL_VALUE = """
|
|
result = %(old_type)s_Unmarshal(target, buffer, size);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
return result;
|
|
}"""
|
|
_UNMARSHAL_VALUE_ALLOW_RC_VALUE = """
|
|
result = %(old_type)s_Unmarshal(target, buffer, size);
|
|
if ((result != TPM_RC_VALUE) && (result != TPM_RC_SUCCESS)) {
|
|
return result;
|
|
}"""
|
|
_SETUP_CHECK_SUPPORTED_VALUES = """
|
|
uint16_t supported_values[] = %(supported_values)s;
|
|
size_t length = sizeof(supported_values)/sizeof(supported_values[0]);
|
|
size_t i;
|
|
BOOL is_supported_value = FALSE;"""
|
|
_CHECK_SUPPORTED_VALUES = """
|
|
for (i = 0; i < length; ++i) {
|
|
if (*target == supported_values[i]) {
|
|
is_supported_value = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (!is_supported_value) {
|
|
return %(error_code)s;
|
|
}"""
|
|
_CHECK_CONDITIONAL = """
|
|
if (*target == %(name)s) {
|
|
return allow_conditional_value ? TPM_RC_SUCCESS : %(error_code)s;
|
|
}"""
|
|
_SETUP_CHECK_VALUES = '\n BOOL has_valid_value = FALSE;'
|
|
_VALUE_END_SWITCH = """
|
|
has_valid_value = TRUE;
|
|
break;
|
|
}"""
|
|
_CHECK_BOUND = """
|
|
if((*target >= %(lower)s) && (*target <= %(upper)s)) {
|
|
has_valid_value = TRUE;
|
|
}"""
|
|
_CHECK_VALUES_END = """
|
|
if (!has_valid_value) {
|
|
return %(error_code)s;
|
|
}"""
|
|
_CONDITIONAL_MARSHAL_DECLARATION = """
|
|
UINT16 %(type)s_Marshal(
|
|
%(type)s *source,
|
|
BYTE **buffer,
|
|
INT32 *size);
|
|
|
|
TPM_RC %(type)s_Unmarshal(
|
|
%(type)s *target,
|
|
BYTE **buffer,
|
|
INT32 *size,
|
|
BOOL allow_conditioanl_value);
|
|
"""
|
|
_CONDITIONAL_UNMARSHAL_CALL = """
|
|
result = %(type)s_Unmarshal(
|
|
&target->%(name)s, buffer, size, %(flag)s);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
return result;
|
|
}"""
|
|
_IFDEF_TYPE_RE = re.compile(r'^TPMI_(ALG|ECC)_.*')
|
|
|
|
def __init__(self, old_type, new_type):
|
|
"""Initializes an Interface instance.
|
|
|
|
Values may be added/assigned to valid_values, bounds, conditional_value,
|
|
supported_values, and error_code attributes new values during parsing.
|
|
|
|
Args:
|
|
old_type: The base type of the interface.
|
|
new_type: The name of the type.
|
|
"""
|
|
super(Interface, self).__init__()
|
|
self.old_type = old_type
|
|
self.new_type = new_type
|
|
self.valid_values = []
|
|
self.bounds = []
|
|
self.conditional_value = None
|
|
self.supported_values = None
|
|
self.error_code = 'TPM_RC_VALUE'
|
|
|
|
def HasConditional(self):
|
|
"""Returns true if Interface has a valid conditional_value."""
|
|
return self.conditional_value is not None
|
|
|
|
def _NeedsIfdef(self):
|
|
"""Returns True if new_type is a type which needs ifdef enclosing."""
|
|
return self._IFDEF_TYPE_RE.search(self.new_type)
|
|
|
|
def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
|
|
"""Writes marshal implementation for Interface to |out_file|.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
marshalled_types: A set of types for which marshal and unmarshal functions
|
|
have already been generated.
|
|
typemap: A dict mapping type names to the corresponding object.
|
|
"""
|
|
if self.new_type in marshalled_types:
|
|
return
|
|
base_type = self._GetBaseType(out_file, marshalled_types, typemap)
|
|
out_file.write(self._TYPEDEF_MARSHAL_FUNCTION % {'old_type': base_type,
|
|
'new_type': self.new_type})
|
|
if self.conditional_value:
|
|
out_file.write(self._INTERFACE_CONDITIONAL_UNMARSHAL_START %
|
|
{'old_type': base_type,
|
|
'new_type': self.new_type})
|
|
else:
|
|
out_file.write(
|
|
self._INTERFACE_UNMARSHAL_START % {'old_type': base_type,
|
|
'new_type': self.new_type})
|
|
# Creating necessary local variables.
|
|
if self.supported_values:
|
|
out_file.write(self._SETUP_CHECK_SUPPORTED_VALUES %
|
|
{'supported_values': self.supported_values})
|
|
if len(self.valid_values)+len(self.bounds) > 0:
|
|
out_file.write(self._SETUP_CHECK_VALUES)
|
|
out_file.write(self._UNMARSHAL_VALUE_ALLOW_RC_VALUE %
|
|
{'old_type': base_type})
|
|
else:
|
|
out_file.write(self._UNMARSHAL_VALUE % {'old_type': base_type})
|
|
|
|
if self.supported_values:
|
|
out_file.write(self._CHECK_SUPPORTED_VALUES %
|
|
{'supported_values': self.supported_values,
|
|
'error_code': self.error_code})
|
|
if self.conditional_value:
|
|
out_file.write(
|
|
self._CHECK_CONDITIONAL % {'name': self.conditional_value,
|
|
'error_code': self.error_code})
|
|
# Checking for valid values.
|
|
if len(self.valid_values)+len(self.bounds) > 0:
|
|
if self.valid_values:
|
|
out_file.write(self._VALUE_START_SWITCH % {'name': '*target'})
|
|
for value in self.valid_values:
|
|
if self._NeedsIfdef():
|
|
out_file.write(self._VALUE_CASE_IFDEF % {'value': value})
|
|
else:
|
|
out_file.write(self._VALUE_CASE % {'value': value})
|
|
out_file.write(self._VALUE_END_SWITCH)
|
|
for (lower, upper) in self.bounds:
|
|
out_file.write(
|
|
self._CHECK_BOUND % {'lower': lower, 'upper': upper})
|
|
out_file.write(self._CHECK_VALUES_END % {'error_code': self.error_code})
|
|
|
|
out_file.write(self._UNMARSHAL_END)
|
|
marshalled_types.add(self.new_type)
|
|
|
|
def OutputMarshalDecl(self, out_file, declared_types, typemap):
|
|
"""Writes marshal declarations for Interface to |out_file|.
|
|
|
|
Outputted declaration depends on whether Interface type has a
|
|
conditionally valid value.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
declared_types: A set of types for which marshal and unmarshal function
|
|
declarations have already been generated.
|
|
typemap: A dict mapping type names to the corresponding object.
|
|
"""
|
|
if self.new_type in declared_types:
|
|
return
|
|
if self.old_type not in declared_types:
|
|
typemap[self.old_type].OutputMarshalDecl(
|
|
out_file, declared_types, typemap)
|
|
if self.HasConditional():
|
|
out_file.write(
|
|
self._CONDITIONAL_MARSHAL_DECLARATION % {'type': self.new_type})
|
|
else:
|
|
out_file.write(self._MARSHAL_DECLARATION % {'type': self.new_type})
|
|
declared_types.add(self.new_type)
|
|
|
|
def OutputUnmarshalCall(
|
|
self, out_file, field):
|
|
"""Write a call to Unmarshal function for Interface type to |out_file|.
|
|
|
|
Override TPMType OutputUnmarshalCall because when an Interface type has
|
|
a conditionally valid value, a BOOL value (|conditional_valid|) is passed
|
|
as a parameter.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
field: A Field object representing an element of this interface.
|
|
"""
|
|
if self.conditional_value:
|
|
out_file.write(
|
|
self._CONDITIONAL_UNMARSHAL_CALL % {'type': field.field_type,
|
|
'name': field.field_name,
|
|
'flag': field.conditional_value})
|
|
else:
|
|
out_file.write(self._UNMARSHAL_CALL % {'type': field.field_type,
|
|
'name': field.field_name})
|
|
|
|
|
|
class Structure(TPMType):
|
|
"""Represents a TPM structure.
|
|
|
|
Attributes:
|
|
name: The name of the structure.
|
|
fields: A list of Field objects representing struct fields.
|
|
upper_bounds: A dictionary of (name, val) tuples mapping name to max val.
|
|
lower_bounds: A dictionary of (name, val) tuples mapping name to min val.
|
|
size_check: Set if TPM2B structure must be size checked (triggered by size=)
|
|
valid_tag_values: A list of values field tag is allowed to take.
|
|
error_code: The return code to be returned if an error occurs
|
|
"""
|
|
_STRUCTURE_MARSHAL_START = """
|
|
UINT16 %(name)s_Marshal(
|
|
%(name)s *source,
|
|
BYTE **buffer,
|
|
INT32 *size) {
|
|
UINT16 total_size = 0;"""
|
|
_STRUCTURE_UNMARSHAL_START = """
|
|
TPM_RC %(name)s_Unmarshal(
|
|
%(name)s *target,
|
|
BYTE **buffer,
|
|
INT32 *size) {
|
|
TPM_RC result;"""
|
|
_MARSHAL_END = '\n return total_size;\n}\n'
|
|
_SETUP_ARRAY_FIELD = '\n INT32 i;'
|
|
_CHECK_SIZE_START = """
|
|
UINT32 start_size = *size;
|
|
UINT32 struct_size;"""
|
|
_CHECK_SIZE_END = """
|
|
struct_size = start_size - *size - sizeof(target->t.size);
|
|
if (struct_size != target->t.size) {
|
|
return TPM_RC_SIZE;
|
|
}"""
|
|
_TPM2B_ZERO_SIZE = """
|
|
if (target->t.size == 0) {
|
|
return %(return_value)s;
|
|
}"""
|
|
_CHECK_BOUND = """
|
|
if (target->%(name)s %(operator)s %(bound_value)s) {
|
|
return %(error_code)s;
|
|
}"""
|
|
_FIX_SIZE_FIELD = """
|
|
{
|
|
BYTE *size_location = *buffer - total_size;
|
|
INT32 size_field_size = sizeof(%(size_field_type)s);
|
|
UINT16 payload_size = total_size - (UINT16)size_field_size;
|
|
%(size_field_type)s_Marshal(&payload_size,
|
|
&size_location, &size_field_size);
|
|
}"""
|
|
|
|
def __init__(self, name):
|
|
"""Initializes a Structure instance.
|
|
|
|
Initially the instance will have no fields, upper_bounds, lower_bounds, or
|
|
valid_tag_values. Those can be added with AddField(), AddUpperBound(),
|
|
AddLowerBound(), and AddTagVal() methods.
|
|
|
|
Args:
|
|
name: The name of the structure.
|
|
"""
|
|
super(Structure, self).__init__()
|
|
self.name = name
|
|
self.fields = []
|
|
self.upper_bounds = {}
|
|
self.lower_bounds = {}
|
|
self.size_check = False
|
|
self.valid_tag_values = []
|
|
self.error_code = 'TPM_RC_VALUE'
|
|
|
|
def AddField(self, field):
|
|
"""Adds a field to fields attribute in Structure.
|
|
|
|
Args:
|
|
field: Instance of Field
|
|
"""
|
|
self.fields.append(field)
|
|
|
|
def AddUpperBound(self, field_name, value):
|
|
"""Adds an upper bound for a field.
|
|
|
|
Args:
|
|
field_name: Name of field with bound.
|
|
value: Value of upper bound.
|
|
"""
|
|
if _IsTPM2B(self.name):
|
|
field_name = 't.' + field_name
|
|
self.upper_bounds[field_name] = value
|
|
|
|
def AddLowerBound(self, field_name, value):
|
|
"""Adds a lower bound for a field.
|
|
|
|
Args:
|
|
field_name: Name of field with bound.
|
|
value: Value of lower bound.
|
|
"""
|
|
if _IsTPM2B(self.name):
|
|
field_name = 't.' + field_name
|
|
self.lower_bounds[field_name] = value
|
|
|
|
def _AddTagValue(self, value):
|
|
"""Adds a valid value for tag field.
|
|
|
|
Args:
|
|
value: Valid value for tag field.
|
|
"""
|
|
self.valid_tag_values.append(value)
|
|
|
|
def _GetFieldTypes(self):
|
|
"""Creates a set which holds all current field types.
|
|
|
|
Returns:
|
|
A set of field types.
|
|
"""
|
|
return set([field.field_type for field in self.fields])
|
|
|
|
def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
|
|
"""Writes marshal implementations for Structure to |out_file|.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
marshalled_types: A set of types for which marshal and unmarshal functions
|
|
have already been generated.
|
|
typemap: A dict mapping type names to the corresponding object.
|
|
"""
|
|
if self.name in marshalled_types:
|
|
return
|
|
|
|
# Make sure any dependencies already have marshal functions defined.
|
|
for field_type in self._GetFieldTypes():
|
|
if field_type not in marshalled_types:
|
|
typemap[field_type].OutputMarshalImpl(
|
|
out_file, marshalled_types, typemap)
|
|
marshalled_types.add(field_type)
|
|
|
|
out_file.write(self._STRUCTURE_MARSHAL_START % {'name': self.name})
|
|
# If any field is an array, create local variable INT32 i.
|
|
for field in self.fields:
|
|
if field.array_size:
|
|
out_file.write(self._SETUP_ARRAY_FIELD)
|
|
break
|
|
for field in self.fields:
|
|
# Each TPM2B is a union of two sized buffers, one which is type specific
|
|
# (the 't' element) and the other is a generic value (the 'b' element).
|
|
# For this reason a 't.' is prepended for fields in a TPM2B type. See
|
|
# section 9.11.6 in TCG TPM2.0 Library Specification, Part 2: Structures
|
|
# for more details.
|
|
if _IsTPM2B(self.name):
|
|
field.field_name = 't.' + field.field_name
|
|
if field.run_time_size:
|
|
field.run_time_size = 't.' + field.run_time_size
|
|
field.OutputMarshal(out_file, typemap)
|
|
if self.size_check:
|
|
out_file.write(self._FIX_SIZE_FIELD % {'size_field_type': self.fields[0].field_type})
|
|
out_file.write(self._MARSHAL_END)
|
|
|
|
out_file.write(self._STRUCTURE_UNMARSHAL_START % {'name': self.name})
|
|
if self.size_check:
|
|
out_file.write(self._CHECK_SIZE_START)
|
|
# If any field is an array, create local variable INT32 i.
|
|
for field in self.fields:
|
|
if field.array_size:
|
|
out_file.write(self._SETUP_ARRAY_FIELD)
|
|
break
|
|
for field in self.fields:
|
|
field.OutputUnmarshal(out_file, typemap)
|
|
return_value = self.error_code
|
|
if field.field_name == 't.size' and self.size_check:
|
|
out_file.write(self._TPM2B_ZERO_SIZE % {'return_value': 'TPM_RC_SIZE'})
|
|
if field.field_name == 't.size' and not self.size_check:
|
|
out_file.write(
|
|
self._TPM2B_ZERO_SIZE % {'return_value': 'TPM_RC_SUCCESS'})
|
|
if field.field_name in self.upper_bounds:
|
|
if (field.field_name == 'count' or
|
|
field.field_name == 't.size' or
|
|
field.field_name == 'size'):
|
|
return_value = 'TPM_RC_SIZE'
|
|
out_file.write(self._CHECK_BOUND %
|
|
{'name': field.field_name,
|
|
'operator': '>',
|
|
'bound_value': self.upper_bounds[field.field_name],
|
|
'error_code': return_value})
|
|
if field.field_name in self.lower_bounds:
|
|
if (field.field_name == 'count' or
|
|
field.field_name == 't.size' or
|
|
field.field_name == 'size'):
|
|
return_value = 'TPM_RC_SIZE'
|
|
out_file.write(self._CHECK_BOUND %
|
|
{'name': field.field_name,
|
|
'operator': '<',
|
|
'bound_value': self.lower_bounds[field.field_name],
|
|
'error_code': return_value})
|
|
if field.field_name == 'tag' and self.valid_tag_values:
|
|
out_file.write(self._VALUE_START_SWITCH % {'name': 'target->tag'})
|
|
for value in self.valid_tag_values:
|
|
out_file.write(self._VALUE_CASE % {'value': value})
|
|
out_file.write(self._VALUE_END_SWITCH % {'error_code': 'TPM_RC_TAG'})
|
|
if self.size_check:
|
|
out_file.write(self._CHECK_SIZE_END)
|
|
if not self.fields:
|
|
# The spec includes a definition of an empty structure, as a side effect
|
|
# the marshaling/unmarshaling functions become empty, the compiler
|
|
# warning is suppressed by the below statement.
|
|
out_file.write(' (void)result;\n')
|
|
out_file.write(self._UNMARSHAL_END)
|
|
|
|
marshalled_types.add(self.name)
|
|
|
|
def OutputMarshalDecl(self, out_file, declared_types, _):
|
|
"""Writes marshal declarations for Structure to |out_file|.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
declared_types: A set of types for which marshal and unmarshal function
|
|
declarations have already been generated.
|
|
"""
|
|
self._OutputStructOrUnionMarshalDecl(out_file, declared_types)
|
|
|
|
|
|
class Union(TPMType):
|
|
"""Represents a TPM union.
|
|
|
|
Attributes:
|
|
name: The name of the union.
|
|
fields: A list of Field objects representing union fields.
|
|
"""
|
|
|
|
_UNION_MARSHAL_START = """
|
|
UINT16 %(name)s_Marshal(
|
|
%(name)s *source,
|
|
BYTE **buffer,
|
|
INT32 *size,
|
|
UINT32 selector) {
|
|
%(array_extras)s
|
|
switch(selector) {"""
|
|
_UNION_UNMARSHAL_START = """
|
|
TPM_RC %(name)s_Unmarshal(
|
|
%(name)s *target,
|
|
BYTE **buffer,
|
|
INT32 *size,
|
|
UINT32 selector) {
|
|
switch(selector) {"""
|
|
_MARSHAL_END = '\n }\n return 0;\n}\n'
|
|
_UNMARSHAL_END = '\n }\n return TPM_RC_SELECTOR;\n}\n'
|
|
_MARSHAL_DECLARATION = """
|
|
UINT16 %(type)s_Marshal(
|
|
%(type)s *source,
|
|
BYTE **buffer,
|
|
INT32 *size,
|
|
UINT32 selector);
|
|
|
|
TPM_RC %(type)s_Unmarshal(
|
|
%(type)s *target,
|
|
BYTE **buffer,
|
|
INT32 *size,
|
|
UINT32 selector);
|
|
"""
|
|
_CASE_SELECTOR = """
|
|
case %(selector)s:"""
|
|
_MARSHAL_EMPTY = """
|
|
return 0;"""
|
|
_UNMARSHAL_EMPTY = """
|
|
return TPM_RC_SUCCESS;"""
|
|
_MARSHAL_FIELD = """
|
|
return %(type)s_Marshal(
|
|
(%(type)s*)&source->%(name)s, buffer, size);"""
|
|
_UNMARSHAL_FIELD = """
|
|
return %(type)s_Unmarshal(
|
|
(%(type)s*)&target->%(name)s, buffer, size);"""
|
|
_SETUP_MARSHAL_FIELD_ARRAY = """
|
|
INT32 i;
|
|
UINT16 total_size = 0;"""
|
|
_SETUP_UNMARSHAL_FIELD_ARRAY = """
|
|
INT32 i;
|
|
TPM_RC result = TPM_RC_SUCCESS;"""
|
|
_MARSHAL_FIELD_ARRAY = """
|
|
for (i = 0; i < %(array_length)s; ++i) {
|
|
total_size += %(type)s_Marshal(
|
|
&source->%(name)s[i], buffer, size);
|
|
}
|
|
return total_size;"""
|
|
_UNMARSHAL_FIELD_ARRAY = """
|
|
for (i = 0; i < %(array_length)s; ++i) {
|
|
result = %(type)s_Unmarshal(
|
|
&target->%(name)s[i], buffer, size);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
return result;
|
|
}
|
|
}
|
|
return TPM_RC_SUCCESS;"""
|
|
_UNMARSHAL_FIELD_CONDITIONAL = """
|
|
return %(type)s_Unmarshal(
|
|
&target->%(name)s, buffer, size, FALSE);"""
|
|
_UNION_MARSHAL_CALL = """
|
|
total_size += %(type)s_Marshal(
|
|
&source->%(name)s, buffer, size, source->%(selector)s);"""
|
|
_UNION_UNMARSHAL_CALL = """
|
|
result = %(type)s_Unmarshal(
|
|
&target->%(name)s, buffer, size, target->%(selector)s);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
return result;
|
|
}"""
|
|
_IFDEF = '\n#ifdef %(type)s'
|
|
_ENDIF = '\n#endif'
|
|
_IFDEF_TYPE_RE = re.compile(r'^TPM_(ALG|CC).*')
|
|
|
|
def __init__(self, name):
|
|
"""Initializes a Union instance.
|
|
|
|
Initially the instance will have no fields. Fields are added with the
|
|
AddField() method.
|
|
|
|
Args:
|
|
name: The name of the structure.
|
|
"""
|
|
super(Union, self).__init__()
|
|
self.name = name
|
|
self.fields = []
|
|
|
|
def _NeedsIfdef(self, selector):
|
|
"""Returns True if selector is a type which needs ifdef enclosing."""
|
|
return self._IFDEF_TYPE_RE.search(selector)
|
|
|
|
def AddField(self, field):
|
|
"""Adds a field to fields attribute in Union.
|
|
|
|
Args:
|
|
field: instance of Field
|
|
"""
|
|
# xor is a C++ keyword and must be fixed.
|
|
if field.field_name == 'xor':
|
|
field.field_name = 'xor_'
|
|
self.fields.append(field)
|
|
|
|
def _OutputMarshalField(
|
|
self, out_file, field_type, field_name, array_length):
|
|
"""Write a call to marshal a field in this union.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
field_type: The type of field.
|
|
field_name: The name of the field.
|
|
array_length: Variable indicating length of array, None if field is not
|
|
an array.
|
|
"""
|
|
if array_length:
|
|
out_file.write(self._MARSHAL_FIELD_ARRAY % {'type': field_type,
|
|
'name': field_name,
|
|
'array_length': array_length})
|
|
else:
|
|
out_file.write(self._MARSHAL_FIELD % {'type': field_type,
|
|
'name': field_name})
|
|
|
|
def _OutputUnmarshalField(
|
|
self, out_file, field_type, field_name, array_length, typemap):
|
|
"""Write a call to unmarshal a field in this union.
|
|
|
|
Args:
|
|
out_file: The output file object.
|
|
field_type: The type of field.
|
|
field_name: The name of the field.
|
|
array_length: Variable indicating length of array, None if field is not
|
|
an array.
|
|
typemap: A dict mapping type names to the corresponding object.
|
|
"""
|
|
if array_length:
|
|
out_file.write(
|
|
self._UNMARSHAL_FIELD_ARRAY % {'type': field_type,
|
|
'name': field_name,
|
|
'array_length': array_length})
|
|
elif typemap[field_type].HasConditional():
|
|
out_file.write(
|
|
self._UNMARSHAL_FIELD_CONDITIONAL % {'type': field_type,
|
|
'name': field_name})
|
|
else:
|
|
out_file.write(self._UNMARSHAL_FIELD % {'type': field_type,
|
|
'name': field_name})
|
|
|
|
def OutputMarshalImpl(self, out_file, marshalled_types, typemap):
|
|
"""Writes marshal implementations for Union to |out_file|.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
marshalled_types: A set of types for which marshal and unmarshal functions
|
|
have already been generated.
|
|
typemap: A dict mapping type names to the corresponding object.
|
|
"""
|
|
if (self.name in marshalled_types or
|
|
self.name == 'TPMU_NAME' or
|
|
self.name == 'TPMU_ENCRYPTED_SECRET' or
|
|
not self.fields):
|
|
return
|
|
|
|
field_types = {f.field_name: f.field_type for f in self.fields}
|
|
array_lengths = {}
|
|
for f in self.fields:
|
|
if f.array_size:
|
|
array_lengths[f.field_name] = f.array_size
|
|
else:
|
|
array_lengths[f.field_name] = None
|
|
|
|
# Make sure any dependencies already have marshal functions defined.
|
|
for field_type in field_types.itervalues():
|
|
if field_type not in marshalled_types:
|
|
typemap[field_type].OutputMarshalImpl(
|
|
out_file, marshalled_types, typemap)
|
|
marshalled_types.add(field_type)
|
|
if self.fields[0].array_size:
|
|
array_extras = self._SETUP_MARSHAL_FIELD_ARRAY
|
|
else:
|
|
array_extras = ''
|
|
out_file.write(self._UNION_MARSHAL_START % {'name': self.name,
|
|
'array_extras': array_extras})
|
|
# Set up variables if Union is an array type.
|
|
for field in self.fields:
|
|
selector = field.selector_value
|
|
if not selector:
|
|
continue
|
|
field_name = field.field_name
|
|
if self._NeedsIfdef(selector):
|
|
out_file.write(self._IFDEF % {'type': selector})
|
|
out_file.write(self._CASE_SELECTOR % {'selector': selector})
|
|
# Selector is not associated with a name, so no marshaling occurs.
|
|
if not field_name:
|
|
out_file.write(self._MARSHAL_EMPTY)
|
|
if self._NeedsIfdef(selector):
|
|
out_file.write(self._ENDIF)
|
|
continue
|
|
field_type = field_types[field_name]
|
|
array_length = array_lengths[field_name]
|
|
self._OutputMarshalField(out_file, field_type, field_name, array_length)
|
|
if self._NeedsIfdef(selector):
|
|
out_file.write(self._ENDIF)
|
|
out_file.write(self._MARSHAL_END)
|
|
out_file.write(self._UNION_UNMARSHAL_START % {'name': self.name})
|
|
# Set up variables if Union is an array type.
|
|
if self.fields[0].array_size:
|
|
out_file.write(self._SETUP_UNMARSHAL_FIELD_ARRAY)
|
|
for field in self.fields:
|
|
selector = field.selector_value
|
|
if not selector:
|
|
continue
|
|
field_name = field.field_name
|
|
if self._NeedsIfdef(selector):
|
|
out_file.write(self._IFDEF % {'type': selector})
|
|
out_file.write(self._CASE_SELECTOR % {'selector': selector})
|
|
# Selector is not associated with a name, so no unmarshaling occurs.
|
|
if not field_name:
|
|
out_file.write(self._UNMARSHAL_EMPTY)
|
|
if self._NeedsIfdef(selector):
|
|
out_file.write(self._ENDIF)
|
|
continue
|
|
field_type = field_types[field_name]
|
|
array_length = array_lengths[field_name]
|
|
self._OutputUnmarshalField(
|
|
out_file, field_type, field_name, array_length, typemap)
|
|
if self._NeedsIfdef(selector):
|
|
out_file.write(self._ENDIF)
|
|
out_file.write(self._UNMARSHAL_END)
|
|
marshalled_types.add(self.name)
|
|
|
|
def OutputMarshalDecl(self, out_file, declared_types, _):
|
|
"""Writes marshal declarations for Union to |out_file|.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
declared_types: A set of types for which marshal and unmarshal function
|
|
declarations have already been generated.
|
|
"""
|
|
self._OutputStructOrUnionMarshalDecl(out_file, declared_types)
|
|
|
|
def OutputMarshalCall(self, out_file, field):
|
|
"""Write a call to marshal function for Union type to |out_file|.
|
|
|
|
Override TPMType OutputMarshalCall to pass in selector value.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
field: A Field object representing a member of this union
|
|
"""
|
|
out_file.write(self._UNION_MARSHAL_CALL %
|
|
{'type': field.field_type,
|
|
'name': field.field_name,
|
|
'selector': field.selector_value})
|
|
|
|
def OutputUnmarshalCall(self, out_file, field):
|
|
"""Write a call to unmarshal function for Union type to |out_file|.
|
|
|
|
Override TPMType OutputUnmashalCall to pass in selector value.
|
|
|
|
Args:
|
|
out_file: The output file.
|
|
field: A Field object representing a member of this union
|
|
"""
|
|
out_file.write(self._UNION_UNMARSHAL_CALL %
|
|
{'type': field.field_type,
|
|
'name': field.field_name,
|
|
'selector': field.selector_value})
|
|
|
|
|
|
def GenerateHeader(typemap):
|
|
"""Generates a header file with declarations for all given generator objects.
|
|
|
|
Args:
|
|
typemap: A dict mapping type names to the corresponding object.
|
|
"""
|
|
out_file = open(_OUTPUT_FILE_H, 'w')
|
|
out_file.write(COPYRIGHT_HEADER)
|
|
guard_name = 'TPM2_%s_' % _OUTPUT_FILE_H.upper().replace('.', '_')
|
|
out_file.write(HEADER_FILE_GUARD_HEADER % {'name': guard_name})
|
|
out_file.write(_HEADER_FILE_INCLUDES)
|
|
# These types are built-in or defined by <stdint.h>; they serve as base cases
|
|
# when defining type dependencies.
|
|
declared_types = set(_BASIC_TYPES)
|
|
# Generate serialize / parse function declarations.
|
|
for basic_type in _BASIC_TYPES:
|
|
out_file.write(_STANDARD_MARSHAL_DECLARATION % {'type': basic_type})
|
|
for tpm_type in [typemap[x] for x in sorted(typemap.keys())]:
|
|
tpm_type.OutputMarshalDecl(out_file, declared_types, typemap)
|
|
out_file.write(HEADER_FILE_GUARD_FOOTER % {'name': guard_name})
|
|
out_file.close()
|
|
call(['clang-format', '-i', '-style=Chromium', 'tpm_generated.h'])
|
|
|
|
|
|
def GenerateImplementation(typemap):
|
|
"""Generates implementation code for each type.
|
|
|
|
Args:
|
|
typemap: A dict mapping string type names to the corresponding object.
|
|
"""
|
|
out_file = open(_OUTPUT_FILE_CC, 'w')
|
|
out_file.write(COPYRIGHT_HEADER)
|
|
out_file.write(_IMPLEMENTATION_FILE_INCLUDES)
|
|
marshalled_types = set(_BASIC_TYPES)
|
|
for basic_type in _BASIC_TYPES:
|
|
out_file.write(_MARSHAL_BASIC_TYPE % {'type': basic_type})
|
|
for tpm_type in [typemap[x] for x in sorted(typemap.keys())]:
|
|
tpm_type.OutputMarshalImpl(out_file, marshalled_types, typemap)
|
|
out_file.close()
|
|
call(['clang-format', '-i', '-style=Chromium', 'tpm_generated.c'])
|