blob: 570b33811333c25951751f553d4dca44ad4e0fbb [file] [log] [blame]
# 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 2015 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' )
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"""
_CHECK_COMMAND_IFDEF = """
#if IS_CC_ENABLED(%(command_name)s)
if (*target == TPM_CC_%(command_name)s) {
return TPM_RC_SUCCESS;
}
#endif"""
_UNMARSHAL_END = """
return %(error_code)s;
}
"""
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 re.search('^TPM_ALG', 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:
# Commands below aren't real TPM commands, but opcode placeholders.
if value in ['TPM_CC_FIRST', 'TPM_CC_PP_FIRST',
'TPM_CC_LAST', 'TPM_CC_PP_LAST']: continue
if self._NeedsIfdef():
out_file.write(self._CHECK_VALUE_IFDEF % {'value': value})
elif self.new_type == 'TPM_CC':
out_file.write(self._CHECK_COMMAND_IFDEF % {'command_name': value.replace('TPM_CC_', '')})
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;"""
_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'])