tpm2: remove generator
This CL removes generator scripts from tpm2 repository. Future
re-generation of the code is not expected, Python 2 support is being
dropped.
BUG=chromium:1031755
TEST=build cr50
Change-Id: I3640633bee54e62f997c06d988432b2b1307a6e4
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/tpm2/+/2140074
Tested-by: Andrey Pronin <apronin@chromium.org>
Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
Commit-Queue: Andrey Pronin <apronin@chromium.org>
diff --git a/generator/README b/generator/README
deleted file mode 100644
index ca8753f..0000000
--- a/generator/README
+++ /dev/null
@@ -1,33 +0,0 @@
-********************
-TPM2 CODE GENERATION
-********************
-
-Code generation scripts for libtpm2 process TCG TPM2 library specification in
-HTML form and generate the appropriate type definitions and interface code.
-
-
-====================
- TPM SPECIFICATION
-====================
-
-See http://www.trustedcomputinggroup.org. This version of libtpm2 is based on
-Family TPM 2.0 Level 00 Revision 01.16.
-
-Parts 2,3 and 4 of the specification were converted from PDF into HTML using
-Adobe Acrobat editor, and tarred and zipped into TPM2_Parts_2_3_4.tgz.
-
-Note that presently the scripts still do not process part4, and ignore all
-source code included in part 3.
-
-=========================================
- REGENERATING TPM2 SOURCE CODE
-=========================================
-
-Run this command in the root tpm2 directory:
-
-$ generator/generator.py generator/TPM2_Parts_2_3_4.tgz
-
-The generator can also be invoked with separate html files as command line
-arguments:
-
-$ generator/generator.py <part2>.html <part3>.html
diff --git a/generator/TPM2_Parts_2_3_4.tgz b/generator/TPM2_Parts_2_3_4.tgz
deleted file mode 100644
index 620a24e..0000000
--- a/generator/TPM2_Parts_2_3_4.tgz
+++ /dev/null
Binary files differ
diff --git a/generator/command_generator.py b/generator/command_generator.py
deleted file mode 100755
index dd1e7a8..0000000
--- a/generator/command_generator.py
+++ /dev/null
@@ -1,646 +0,0 @@
-# Copyright 2014 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 commands.
-
-The command generator takes as input a list of command objects generated by
-parsing the TCG specification and outputs valid C code to marshal command
-input and output structures, and also generates functions ParseHandleBuffer
-and CommandDispatcher defined by the TCG TPM2.0 Library Specification.
-
-"""
-
-from __future__ import print_function
-
-import re
-from subprocess import call
-
-from structure_generator import COPYRIGHT_HEADER
-from structure_generator import Field
-
-_HEADER_FILE_GUARD_HEADER = """
-#ifndef TPM2_%(name)s_FP_H_
-#define TPM2_%(name)s_FP_H_
-"""
-_HEADER_FILE_GUARD_FOOTER = """
-#endif // TPM2_%(name)s_FP_H
-"""
-_HEADER_FILE_INCLUDES = """
-#include "tpm_generated.h"
-"""
-_IMPLEMENTATION_FILE_INCLUDES = """
-#include "MemoryLib_fp.h"
-#include "%(command_name)s_fp.h"
-"""
-_COMMAND_DISPATCHER_INCLUDES = '#include "%(command_name)s_fp.h"\n'
-_COMMAND_DISPATCHER_START = """
-#include "Implementation.h"
-#include "CommandDispatcher_fp.h"
-
-TPM_RC CommandDispatcher(
- TPMI_ST_COMMAND_TAG tag,
- TPM_CC command_code,
- INT32 *request_parameter_buffer_size,
- BYTE *request_parameter_buffer_start,
- TPM_HANDLE request_handles[],
- UINT32 *response_handle_buffer_size,
- UINT32 *response_parameter_buffer_size) {
- BYTE *request_parameter_buffer = request_parameter_buffer_start;
- switch(command_code) {"""
-_COMMAND_DISPATCHER_CASE = """
-#if IS_CC_ENABLED(%(command_name)s)
- case TPM_CC_%(command_name)s:
- return Exec_%(command_name)s(tag, &request_parameter_buffer,
- request_parameter_buffer_size, request_handles,
- response_handle_buffer_size, response_parameter_buffer_size);
-#endif"""
-_COMMAND_DISPATCHER_END = """
- default:
- return TPM_RC_COMMAND_CODE;
- }
-}"""
-_HANDLE_PROCESS_START = """
-#include "tpm_generated.h"
-#include "HandleProcess_fp.h"
-#include "Implementation.h"
-#include "TPM_Types.h"
-
-TPM_RC ParseHandleBuffer(
- TPM_CC command_code,
- BYTE **request_handle_buffer_start,
- INT32 *request_buffer_remaining_size,
- TPM_HANDLE request_handles[],
- UINT32 *num_request_handles) {
- TPM_RC result = TPM_RC_SUCCESS;
- *num_request_handles = 0;
- switch(command_code) {
-"""
-_HANDLE_PROCESS_CASE_START = """
-#if IS_CC_ENABLED(%(command_code)s)
- case TPM_CC_%(command_code)s:"""
-_HANDLE_PROCESS_CASE_UNMARSHAL = """
- result = %(handle_type)s_Unmarshal(
- (%(handle_type)s*)&request_handles[*num_request_handles],
- request_handle_buffer_start,
- request_buffer_remaining_size);"""
-_HANDLE_PROCESS_CASE_UNMARSHAL_FLAG = """
- result = %(handle_type)s_Unmarshal(
- (%(handle_type)s*)&request_handles[*num_request_handles],
- request_handle_buffer_start,
- request_buffer_remaining_size,
- %(flag_val)s);"""
-_HANDLE_PROCESS_CASE_CHECK = """
- if (result != TPM_RC_SUCCESS) {
- return result;
- }
- ++(*num_request_handles);"""
-_HANDLE_PROCESS_CASE_END = """
- return TPM_RC_SUCCESS;
-#endif"""
-_HANDLE_PROCESS_END = """
- default:
- return TPM_RC_COMMAND_CODE;
- }
-}"""
-_GET_COMMAND_CODE_STRING_HEADER = """
-#ifndef TPM2_GET_COMMAND_CODE_STRING_FP_H_
-#define TPM2_GET_COMMAND_CODE_STRING_FP_H_
-
-#include "TPM_Types.h"
-
-const char* GetCommandCodeString(TPM_CC command_code);
-
-#endif // TPM2_GET_COMMAND_CODE_STRING_FP_H_"""
-_GET_COMMAND_CODE_STRING_START = """
-#include "GetCommandCodeString_fp.h"
-
-const char* GetCommandCodeString(TPM_CC command_code) {
- switch(command_code) {"""
-_GET_COMMAND_CODE_STRING_CASE = """
-#if IS_CC_ENABLED(%(command_name)s)
- case TPM_CC_%(command_name)s:
- return "%(command_name)s";
-#endif"""
-_GET_COMMAND_CODE_STRING_END = """
- default:
- return "Unknown command";
- }
-}"""
-
-
-class Command(object):
- """Represents a TPM command.
-
- Attributes:
- name: The command name (e.g. 'TPM2_Startup').
- command_code: The name of the command code constant (e.g. TPM2_CC_Startup).
- request_args: A list to hold command input arguments. Each element is a dict
- and has these keys:
- 'type': The argument type.
- 'name': The argument name.
- 'command_code': The optional value of the command code constant.
- 'description': Optional descriptive text for the argument.
- 'has_conditional': String literal 'TRUE' or 'FALSE' indicating
- whether 'type' is allowed to have a conditional value.
- response_args: A list identical in form to request_args but to hold command
- output arguments.
- """
-
- _HANDLE_RE = re.compile(r'TPMI_.H_.*')
- _STRUCT_DECL_START = """
-typedef struct {"""
- _STRUCT_DECL_FIELD = """
- %(type)s %(name)s;"""
- _STRUCT_DECL_END = """
-} %(command_name)s_%(direction)s;
-"""
- _FUNCTION_DECL_IN_OUT = """
-// Executes %(command_name)s with request handles and parameters from
-// |in| and computes response handles and parameters to |out|.
-TPM_RC TPM2_%(command_name)s(
- %(command_name)s_In *in,
- %(command_name)s_Out *out);
-"""
- _FUNCTION_DECL_IN = """
-// Executes %(command_name)s with request handles and parameters from |in|.
-TPM_RC TPM2_%(command_name)s(
- %(command_name)s_In *in);
-"""
- _FUNCTION_DECL_OUT = """
-// Executes %(command_name)s and computes response handles and parameters
-// to |out|.
-TPM_RC TPM2_%(command_name)s(
- %(command_name)s_Out *out);
-"""
- _EXEC_DECL = """
-// Unmarshals any request parameters starting at |request_parameter_buffer|.
-// Executes command. Marshals any response handles and parameters to the
-// global response buffer and computes |*response_handle_buffer_size| and
-// |*response_parameter_buffer_size|. If |tag| == TPM_ST_SESSIONS, marshals
-// parameter_size indicating the size of the parameter area. parameter_size
-// field is located between the handle area and parameter area.
-TPM_RC Exec_%(command_name)s(
- TPMI_ST_COMMAND_TAG tag,
- BYTE **request_parameter_buffer,
- INT32 *request_parameter_buffer_size,
- TPM_HANDLE request_handles[],
- UINT32 *response_handle_buffer_size,
- UINT32 *response_parameter_buffer_size);
-"""
- _EXEC_COMMAND_IMPL_START = """
-TPM_RC Exec_%(command_name)s(
- TPMI_ST_COMMAND_TAG tag,
- BYTE **request_parameter_buffer,
- INT32 *request_parameter_buffer_size,
- TPM_HANDLE request_handles[],
- UINT32 *response_handle_buffer_size,
- UINT32 *response_parameter_buffer_size) {
- TPM_RC result = TPM_RC_SUCCESS;"""
- _EXEC_COMMAND_IMPL_IN_OUT = """
- %(command_name)s_In in;
- %(command_name)s_Out out;
-#if IS_CC_ENABLED(%(command_name)s)
- BYTE *response_buffer;
- INT32 response_buffer_size;
- UINT16 bytes_marshalled;
- UINT16 num_response_handles = %(num_response_handles)s;
-#endif
- *response_handle_buffer_size = 0;
- *response_parameter_buffer_size = 0;
- // Unmarshal request parameters to input structure.
- result = %(command_name)s_In_Unmarshal(&in, request_handles,
- request_parameter_buffer, request_parameter_buffer_size);
- if (result != TPM_RC_SUCCESS) {
- return result;
- }
- // Execute command.
- result = TPM2_%(command_name)s(&in, &out);
- if (result != TPM_RC_SUCCESS) {
- return result;
- }
-// Marshal output structure to global response buffer.
-#if IS_CC_ENABLED(%(command_name)s)
- response_buffer = MemoryGetResponseBuffer(TPM_CC_%(command_name)s) + 10;
- response_buffer_size = MAX_RESPONSE_SIZE - 10;
- bytes_marshalled = %(command_name)s_Out_Marshal(
- &out, tag, &response_buffer, &response_buffer_size);
- *response_handle_buffer_size = num_response_handles*sizeof(TPM_HANDLE);
- *response_parameter_buffer_size =
- bytes_marshalled - *response_handle_buffer_size;
- return TPM_RC_SUCCESS;
-#endif
- return TPM_RC_COMMAND_CODE;
-}
-"""
- _EXEC_COMMAND_IMPL_IN = """
- %(command_name)s_In in;
-#if IS_CC_ENABLED(%(command_name)s)
- BYTE *response_buffer;
- INT32 response_buffer_size;
-#endif
- *response_handle_buffer_size = 0;
- *response_parameter_buffer_size = 0;
- // Unmarshal request parameters to input structure.
- result = %(command_name)s_In_Unmarshal(&in, request_handles,
- request_parameter_buffer, request_parameter_buffer_size);
- if (result != TPM_RC_SUCCESS) {
- return result;
- }
- // Execute command.
- result = TPM2_%(command_name)s(&in);
- if (result != TPM_RC_SUCCESS) {
- return result;
- }
-#if IS_CC_ENABLED(%(command_name)s)
- response_buffer = MemoryGetResponseBuffer(TPM_CC_%(command_name)s) + 10;
- response_buffer_size = MAX_RESPONSE_SIZE - 10;
- // Add parameter_size field, always equal to 0 here.
- if (tag == TPM_ST_SESSIONS) {
- UINT32_Marshal(response_parameter_buffer_size, &response_buffer,
- &response_buffer_size);
- }
- return TPM_RC_SUCCESS;
-#endif
- return TPM_RC_COMMAND_CODE;
-}
-"""
- _EXEC_COMMAND_IMPL_OUT = """
- %(command_name)s_Out out;
-#if IS_CC_ENABLED(%(command_name)s)
- BYTE *response_buffer;
- INT32 response_buffer_size;
- UINT16 bytes_marshalled;
- UINT16 num_response_handles = %(num_response_handles)s;
-#endif
- *response_handle_buffer_size = 0;
- *response_parameter_buffer_size = 0;
- // Execute command.
- result = TPM2_%(command_name)s(&out);
- if (result != TPM_RC_SUCCESS) {
- return result;
- }
-// Marshal output structure containing response handles and parameters to
-// response buffer.
-#if IS_CC_ENABLED(%(command_name)s)
- response_buffer = MemoryGetResponseBuffer(TPM_CC_%(command_name)s) + 10;
- response_buffer_size = MAX_RESPONSE_SIZE - 10;
- bytes_marshalled = %(command_name)s_Out_Marshal(
- &out, tag, &response_buffer, &response_buffer_size);
- *response_handle_buffer_size = num_response_handles*sizeof(TPM_HANDLE);
- *response_parameter_buffer_size =
- bytes_marshalled - *response_handle_buffer_size;
- return TPM_RC_SUCCESS;
-#endif
- return TPM_RC_COMMAND_CODE;
-}
-"""
- _UNMARSHAL_COMMAND_START = """
-static TPM_RC %(command_name)s_In_Unmarshal(
- %(command_name)s_In *target,
- TPM_HANDLE request_handles[],
- BYTE **buffer,
- INT32 *size) {
- TPM_RC result = TPM_RC_SUCCESS;"""
- _MARSHAL_COMMAND_START = """
-#if IS_CC_ENABLED(%(command_name)s)
-static UINT16 %(command_name)s_Out_Marshal(
- %(command_name)s_Out *source,
- TPMI_ST_COMMAND_TAG tag,
- BYTE **buffer,
- INT32 *size) {
- UINT16 total_size = 0;
- UINT32 parameter_size = 0;
- BYTE *parameter_size_location;
- INT32 parameter_size_size = sizeof(UINT32);
- UINT32 num_response_handles = %(num_response_handles)s;"""
- _UNMARSHAL_END = """
- if ((result == TPM_RC_SUCCESS) && *size) {
- result = TPM_RC_SIZE;
- }
- return result;
-}
-"""
- _MARSHAL_END = """
- // Compute actual parameter_size. Don't add result to total_size.
- if (tag == TPM_ST_SESSIONS) {
- parameter_size = total_size - num_response_handles*sizeof(TPM_HANDLE);
- UINT32_Marshal(
- ¶meter_size, ¶meter_size_location, ¶meter_size_size);
- }
- return total_size;
-}
-#endif
-"""
- _SET_COMMAND_HANDLE = """
- target->%(field_name)s = request_handles[%(num)s];"""
- _PARAMETERSIZE_CHECK = """
- // Add parameter_size=0 to indicate size of the parameter area. Will be
- // replaced later by computed parameter_size.
- if (tag == TPM_ST_SESSIONS) {
- parameter_size_location = *buffer;
- // Don't add to total_size, but increment *buffer and decrement *size.
- UINT32_Marshal(¶meter_size, buffer, size);
- }"""
-
- def __init__(self, name):
- """Initializes a Command instance.
-
- Initially the request_args and response_args attributes are not set.
-
- Args:
- name: The command name (e.g. 'TPM2_Startup').
- """
- self.name = name
- self.request_args = None
- self.response_args = None
- if name.startswith('TPM2_'):
- self.command_code = name.replace('TPM2_', 'TPM_CC_')
- else:
- self.command_code = ''
-
- def __str__(self):
- s = ['%s:' % self.name,]
- if self.request_args:
- s.append(' req:')
- for r in self.request_args:
- s.append(' %s: %s' % (r['type'], r['name']))
- if self.response_args:
- s.append(' resp:')
- for r in self.response_args:
- s.append(' %s: %s' % (r['type'], r['name']))
- s.append('')
- return '\n'.join(s)
-
- def OutputMarshalFunction(self, out_file, typemap):
- """Generates a marshal function for the command output structure.
-
- Args:
- out_file: File to be written to opened by the caller.
- typemap: A dict mapping type names to the corresponding object.
- Generated by structure_generator.
- """
- if not self.response_args:
- return
- # Categorize arguments as either handles or parameters.
- handles, parameters = self._SplitArgs(self.response_args)
- out_file.write(self._MARSHAL_COMMAND_START % {
- 'command_name': self.MethodName(),
- 'num_response_handles': self._GetNumberOfResponseHandles()})
- if handles:
- out_file.write('\n // Marshal response handles.')
- for handle in handles:
- typemap[handle['type']].OutputMarshalCall(
- out_file, Field(handle['type'],
- handle['name'],
- conditional_value=handle['has_conditional']))
- out_file.write(self._PARAMETERSIZE_CHECK)
- if parameters:
- out_file.write('\n // Marshal response parameters.')
- for parameter in parameters:
- typemap[parameter['type']].OutputMarshalCall(
- out_file, Field(parameter['type'], parameter['name'],
- conditional_value=parameter['has_conditional']))
- out_file.write(self._MARSHAL_END)
-
- def OutputUnmarshalFunction(self, out_file, typemap):
- """Generates a unmarshal function for the command input structure.
-
- Args:
- out_file: File to be written to opened by the caller.
- typemap: A dict mapping type names to the corresponding object.
- Generated by structure_generator.
- """
- if not self.request_args:
- return
- # Categorize arguments as either handles or parameters.
- handles, parameters = self._SplitArgs(self.request_args)
- out_file.write(self._UNMARSHAL_COMMAND_START % {
- 'command_name': self.MethodName()})
- if handles:
- out_file.write('\n // Get request handles from request_handles array.')
- for index, handle in enumerate(handles):
- out_file.write(self._SET_COMMAND_HANDLE % {'field_name': handle['name'],
- 'num': index})
- if parameters:
- out_file.write('\n // Unmarshal request parameters.')
- for parameter in parameters:
- typemap[parameter['type']].OutputUnmarshalCall(
- out_file, Field(parameter['type'],
- parameter['name'],
- conditional_value=parameter['has_conditional']))
- out_file.write(self._UNMARSHAL_END)
-
- def OutputExecFunction(self, out_file):
- """Generates an exec function for the command.
-
- Args:
- out_file: File to be written to opened by the caller.
- """
- out_file.write(
- self._EXEC_COMMAND_IMPL_START % {'command_name': self.MethodName()})
- if self.request_args and self.response_args:
- out_file.write(self._EXEC_COMMAND_IMPL_IN_OUT % {
- 'command_name': self.MethodName(),
- 'num_response_handles': self._GetNumberOfResponseHandles()})
- elif self.request_args:
- out_file.write(self._EXEC_COMMAND_IMPL_IN % {
- 'command_name': self.MethodName()})
- elif self.response_args:
- out_file.write(self._EXEC_COMMAND_IMPL_OUT % {
- 'command_name': self.MethodName(),
- 'num_response_handles': self._GetNumberOfResponseHandles()})
-
- def OutputDecl(self, out_file):
- """Generates a TPM object declaration."""
- if self.request_args:
- out_file.write(self._STRUCT_DECL_START)
- for arg in self.request_args:
- out_file.write(self._STRUCT_DECL_FIELD % {'type': arg['type'],
- 'name': arg['name']})
- out_file.write(self._STRUCT_DECL_END % {'command_name': self.MethodName(),
- 'direction': 'In'})
- if self.response_args:
- out_file.write(self._STRUCT_DECL_START)
- for arg in self.response_args:
- out_file.write(self._STRUCT_DECL_FIELD % {'type': arg['type'],
- 'name': arg['name']})
- out_file.write(self._STRUCT_DECL_END % {'command_name': self.MethodName(),
- 'direction': 'Out'})
- if len(self.response_args) and len(self.request_args):
- out_file.write(
- self._FUNCTION_DECL_IN_OUT % {'command_name': self.MethodName()})
- elif self.response_args:
- out_file.write(
- self._FUNCTION_DECL_OUT % {'command_name': self.MethodName()})
- elif self.request_args:
- out_file.write(
- self._FUNCTION_DECL_IN % {'command_name': self.MethodName()})
- out_file.write(self._EXEC_DECL % {'command_name': self.MethodName()})
-
- def _GetNumberOfRequestHandles(self):
- """Returns the number of input handles for this command."""
- return len(self._SplitArgs(self.request_args)[0])
-
- def _GetNumberOfResponseHandles(self):
- """Returns the number of output handles for this command."""
- return len(self._SplitArgs(self.response_args)[0])
-
- def MethodName(self):
- """Creates an appropriate generated method name for the command.
-
- We use the command name without the TPM2_ prefix.
-
- Returns:
- The method name.
- """
- if not self.name.startswith('TPM2_'):
- return self.name
- return self.name[5:]
-
- def GetRequestHandles(self):
- """Returns a list of input handles for this command."""
- return self._SplitArgs(self.request_args)[0]
-
- def _SplitArgs(self, args):
- """Splits a list of args into handles and parameters."""
- always_params = {
- 'TPM_CC_FlushContext': 'TPMI_DH_CONTEXT',
- 'TPM_CC_Hash': 'TPMI_RH_HIERARCHY',
- 'TPM_CC_LoadExternal': 'TPMI_RH_HIERARCHY',
- 'TPM_CC_SequenceComplete': 'TPMI_RH_HIERARCHY',
- }
- handles = []
- parameters = []
- always_handle = set(['TPM_HANDLE'])
- # Handle types that appear as command parameters.
- always_parameter = set(['TPMI_RH_ENABLES', 'TPMI_DH_PERSISTENT'])
- if self.command_code in always_params:
- always_parameter.add(always_params[self.command_code])
- for arg in args:
- if (arg['type'] in always_handle or
- (self._HANDLE_RE.search(arg['type']) and
- arg['type'] not in always_parameter)):
- handles.append(arg)
- else:
- parameters.append(arg)
- return handles, parameters
-
-
-def _OutputCommandDispatcher(commands):
- """Generates implementation file for CommandDispatcher function.
-
- Args:
- commands: A list of Command objects.
- """
- with open('CommandDispatcher.c', 'w') as out_file:
- out_file.write(COPYRIGHT_HEADER)
- for command in commands:
- out_file.write(_COMMAND_DISPATCHER_INCLUDES %
- {'command_name': command.MethodName()})
- out_file.write(_COMMAND_DISPATCHER_START)
- for command in commands:
- out_file.write(_COMMAND_DISPATCHER_CASE %
- {'command_name': command.MethodName()})
- out_file.write(_COMMAND_DISPATCHER_END)
- _ProcessClangFormat('CommandDispatcher.c')
-
-
-def _OutputHandleProcess(commands, typemap):
- """Generates implementation file for ParseHandleBuffer function.
-
- Args:
- commands: A list of Command objects.
- typemap: A dict mapping type names to the corresponding object.
- Generated by structure_generator.
- """
- with open('HandleProcess.c', 'w') as out_file:
- out_file.write(COPYRIGHT_HEADER)
- out_file.write(_HANDLE_PROCESS_START)
- for command in commands:
- out_file.write(_HANDLE_PROCESS_CASE_START %
- {'command_code': command.MethodName()})
- for handle in command.GetRequestHandles():
- if typemap[handle['type']].HasConditional():
- out_file.write(_HANDLE_PROCESS_CASE_UNMARSHAL_FLAG %
- {'handle_type': handle['type'],
- 'flag_val': handle['has_conditional']})
- else:
- out_file.write(_HANDLE_PROCESS_CASE_UNMARSHAL %
- {'handle_type': handle['type']})
- out_file.write(_HANDLE_PROCESS_CASE_CHECK)
- out_file.write(_HANDLE_PROCESS_CASE_END)
- out_file.write(_HANDLE_PROCESS_END)
- _ProcessClangFormat('HandleProcess.c')
-
-
-def _OutputGetCommandCodeString(commands):
- """Generates header and implementation files for GetCommandCodeString.
-
- Args:
- commands: A list of Command objects.
- """
- with open('GetCommandCodeString_fp.h', 'w') as out_file:
- out_file.write(COPYRIGHT_HEADER)
- out_file.write(_GET_COMMAND_CODE_STRING_HEADER)
- _ProcessClangFormat('GetCommandCodeString_fp.h')
- with open('GetCommandCodeString.c', 'w') as out_file:
- out_file.write(COPYRIGHT_HEADER)
- out_file.write(_GET_COMMAND_CODE_STRING_START)
- for command in commands:
- out_file.write(_GET_COMMAND_CODE_STRING_CASE %
- {'command_name': command.MethodName()})
- out_file.write(_GET_COMMAND_CODE_STRING_END)
- _ProcessClangFormat('GetCommandCodeString.c')
-
-
-def GenerateHeader(commands):
- """Generates a header file with declarations for all given generator objects.
-
- Args:
- commands: A list of Command objects.
- """
- for command in commands:
- command_header_file = command.MethodName()+'_fp.h'
- with open(command_header_file, 'w') as out_file:
- out_file.write(COPYRIGHT_HEADER)
- out_file.write(
- _HEADER_FILE_GUARD_HEADER % {'name': command.MethodName().upper()})
- out_file.write(_HEADER_FILE_INCLUDES)
- command.OutputDecl(out_file)
- out_file.write(
- _HEADER_FILE_GUARD_FOOTER % {'name': command.MethodName().upper()})
- _ProcessClangFormat(command_header_file)
-
-
-def GenerateImplementation(commands, typemap):
- """Generates implementation code for each command.
-
- Args:
- commands: A list of Command objects.
- typemap: A dict mapping type names to the corresponding object.
- Generated by structure_generator.
- """
- for command in commands:
- marshal_command_file = 'Marshal_'+command.MethodName()+'.c'
- with open(marshal_command_file, 'w') as out_file:
- out_file.write(COPYRIGHT_HEADER)
- out_file.write(_IMPLEMENTATION_FILE_INCLUDES %
- {'command_name': command.MethodName()})
- command.OutputMarshalFunction(out_file, typemap)
- command.OutputUnmarshalFunction(out_file, typemap)
- command.OutputExecFunction(out_file)
- _ProcessClangFormat(marshal_command_file)
- _OutputHandleProcess(commands, typemap)
- _OutputCommandDispatcher(commands)
- _OutputGetCommandCodeString(commands)
-
-
-def _ProcessClangFormat(file_name):
- """Call clang-format on the given file name.
-
- Args:
- file_name: A file name to apply clang-format.
- """
- call(['clang-format', '-i', '-style=Chromium', '-sort-includes=false',
- file_name])
diff --git a/generator/cros.patch b/generator/cros.patch
deleted file mode 100644
index 9ad34a9..0000000
--- a/generator/cros.patch
+++ /dev/null
@@ -1,68 +0,0 @@
-diff --git b/tpm_generated.c a/tpm_generated.c
-index b6bd839..954bff3 100644
---- b/tpm_generated.c
-+++ a/tpm_generated.c
-@@ -2349,7 +2349,11 @@ UINT16 TPMS_SIG_SCHEME_RSASSA_Marshal(TPMS_SIG_SCHEME_RSASSA* source,
- TPM_RC TPMS_SIG_SCHEME_RSASSA_Unmarshal(TPMS_SIG_SCHEME_RSASSA* target,
- BYTE** buffer,
- INT32* size) {
-+#if defined(SUPPORT_PADDING_ONLY_RSASSA) && SUPPORT_PADDING_ONLY_RSASSA == YES
-+ return TPMI_ALG_HASH_Unmarshal(&target->hashAlg, buffer, size, TRUE);
-+#else
- return TPMS_SCHEME_HASH_Unmarshal(target, buffer, size);
-+#endif
- }
-
- UINT16 TPMS_ENC_SCHEME_OAEP_Marshal(TPMS_ENC_SCHEME_OAEP* source,
-diff --git b/tpm_types.h a/tpm_types.h
-index eec5e48..9528c36 100644
---- b/tpm_types.h
-+++ a/tpm_types.h
-@@ -370,6 +370,7 @@ typedef UINT8 TPM_HT;
- #define TPM_HT_PERMANENT 0x40
- #define TPM_HT_TRANSIENT 0x80
- #define TPM_HT_PERSISTENT 0x81
-+#define TPM_HT_HIDDEN 0xfe
-
- // Table 29 Definition of TPM_RH Constants < S>
- typedef TPM_HANDLE TPM_RH;
-@@ -404,6 +405,7 @@ typedef TPM_HANDLE TPM_HC;
- #define HR_PERSISTENT (TPM_HT_PERSISTENT << HR_SHIFT)
- #define HR_NV_INDEX (TPM_HT_NV_INDEX << HR_SHIFT)
- #define HR_PERMANENT (TPM_HT_PERMANENT << HR_SHIFT)
-+#define HR_HIDDEN (TPM_HT_HIDDEN << HR_SHIFT)
- #define PCR_FIRST (HR_PCR + 0)
- #define PCR_LAST (PCR_FIRST + IMPLEMENTATION_PCR-1)
- #define HMAC_SESSION_FIRST (HR_HMAC_SESSION + 0)
-@@ -1119,9 +1121,12 @@ typedef union {
- #ifdef TPM_ALG_ECDSA
- TPMS_SIG_SCHEME_ECDSA ecdsa;
- #endif
--#ifdef TPM_ALG_ECDAA
-+// TODO(ngm): ECDAA is not currently supported
-+// on CR50, but this field has unguarded references
-+// in CryptUtil.c, so allow its inclusion.
-+// #ifdef TPM_ALG_ECDAA
- TPMS_SIG_SCHEME_ECDAA ecdaa;
--#endif
-+// #endif
- #ifdef TPM_ALG_SM2
- TPMS_SIG_SCHEME_SM2 sm2;
- #endif
-diff --git a/tpm_types.h b/tpm_types.h
-index 9528c36..822e5bd 100644
---- a/tpm_types.h
-+++ b/tpm_types.h
-@@ -368,9 +368,9 @@ typedef UINT8 TPM_HT;
- #define TPM_HT_POLICY_SESSION 0x03
- #define TPM_HT_ACTIVE_SESSION 0x03
- #define TPM_HT_PERMANENT 0x40
--#define TPM_HT_TRANSIENT 0x80
--#define TPM_HT_PERSISTENT 0x81
--#define TPM_HT_HIDDEN 0xfe
-+#define TPM_HT_TRANSIENT ((TPM_HT)0x80)
-+#define TPM_HT_PERSISTENT ((TPM_HT)0x81)
-+#define TPM_HT_HIDDEN ((TPM_HT)0xfe)
-
- // Table 29 Definition of TPM_RH Constants < S>
- typedef TPM_HANDLE TPM_RH;
diff --git a/generator/extract_structures.py b/generator/extract_structures.py
deleted file mode 100755
index 24a2ff5..0000000
--- a/generator/extract_structures.py
+++ /dev/null
@@ -1,189 +0,0 @@
-#!/usr/bin/python
-# 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.
-
-"""Module for parsing TCG TPM2 library specification in HTML format.
-
-This module processes parts 2 and 3 of the specification, extracting
-information related to tables defined in the documents, feeding the
-information into the Table object for further processing and creating the
-appropriate TPM2 objects.
-"""
-
-from __future__ import print_function
-
-import HTMLParser
-import os
-import re
-import sys
-
-import tpm_table
-
-table_name = re.compile(r'^\s*Table\s+[0-9]+')
-
-
-class SpecParser(HTMLParser.HTMLParser):
- """A class for parsing TCG specifications in html format."""
-
- # The state machine of the parser could be in one of the following states.
- ANCHOR = 0 # Look for table title anchor
- TABLE_NAME = 1 # Look for table title in the data stream
- TABLE_BODY = 2 # Scraping the actual table body
- MAYBE_DONE = 3 # Could be over, unless a single spec table is split in
- # multiple HTML tables (to continue on the next page)
- SKIP_HEADER = 4 # Ignore the header of the split tables
-
- def __init__(self):
- """Initialize a parser object to default state."""
- HTMLParser.HTMLParser.__init__(self)
- self._state = self.ANCHOR
- self._title = ''
- self._table = tpm_table.Table()
- self._previous_table_number = 0 # Used to check if there are skipped tables
-
- def _Normalize(self, data):
- """Normalize HTML data.
-
- HTML files generated from TCG specifications sometimes include utf8
- characters (like long dashes), which appear only in comments/table titles
- and can be safely ignored.
-
- Args:
- data: a string representing portion of data from the HTML being parsed.
-
- Returns:
- a string, the input data with characters above ASCII printable range
- excluded.
- """
- return ' ' + ''.join(x for x in self.unescape(data) if ord(x) < 128)
-
- def GetTable(self):
- """Return the Table object containing all information parsed so far."""
- return self._table
-
- def _SetState(self, new_state):
- if self._state != new_state:
- self._state = new_state
- if new_state == self.TABLE_NAME:
- self._title = ''
-
- def handle_starttag(self, tag, attrs):
- """Invoked each time a new HTML tag is opened.
-
- This method drives changes in the parser FSM states, its heuristics are
- derived from the format of the HTML files the TCG specs get converted to.
-
- Each specification table is preceded with a tittle. The title is wrapped
- in an anchor tag with a property 'name' set to 'bookmark#xxx. The title
- text starts with ' Table [0-9]+ '. Once the table title is detected,
- the state machine switches to looking for the actual HTML table, i.e. tags
- 'table', 'tr' and 'td' (the generated specs do not use the 'th' tags).
-
- Large specification tables can be split into multiple HTML tables (so that
- they fit in a page). This is why the presence of the closing 'table' tag
- is not enough to close the parsing of the current specification table.
-
- In some cases the next table is defined in the spec immediately after the
- current one - this is when the new anchor tag is used as a signal that the
- previous table has been completely consumed.
-
- Args:
- tag: a string, the HTML tag
- attrs: a tuple of zero or more two-string tuples, the first element -
- the HTML tag's attribute, the second element - the attribute
- value.
- """
- if tag == 'a':
- if [x for x in attrs if x[0] == 'name' and x[1].startswith('bookmark')]:
- if self._state == self.ANCHOR:
- self._SetState(self.TABLE_NAME)
- elif self._state == self.MAYBE_DONE:
- # Done indeed
- self._table.ProcessTable()
- self._table.Init()
- self._SetState(self.TABLE_NAME)
- elif self._state == self.TABLE_NAME:
- self._title = ''
- elif tag == 'p' and self._state == self.TABLE_NAME and not self._title:
- # This was not a valid table start, back to looking for the right anchor.
- self._SetState(self.ANCHOR)
- elif self._state == self.TABLE_NAME and tag == 'table':
- if not table_name.search(self._title):
- # Table title does not match the expected format - back to square one.
- self._SetState(self.ANCHOR)
- return # will have to start over
- table_number = int(self._title.split()[1])
- self._previous_table_number += 1
- if table_number > self._previous_table_number:
- print('Table(s) %s missing' % ' '.join(
- '%d' % x for x in
- range(self._previous_table_number, table_number)), file=sys.stderr)
- self._previous_table_number = table_number
- self._table.Init(self._title)
- self._SetState(self.TABLE_BODY)
- elif self._state == self.MAYBE_DONE and tag == 'tr':
- self._SetState(self.SKIP_HEADER)
- elif self._state == self.SKIP_HEADER and tag == 'tr':
- self._SetState(self.TABLE_BODY)
- self._table.NewRow()
- elif self._state == self.TABLE_BODY:
- if tag == 'tr':
- self._table.NewRow()
- elif tag == 'td':
- self._table.NewCell()
-
- def handle_endtag(self, tag):
- """Invoked each time an HTML tag is closed."""
- if tag == 'table' and self._table.InProgress():
- self._SetState(self.MAYBE_DONE)
-
- def handle_data(self, data):
- """Process data outside HTML tags."""
- if self._state == self.TABLE_NAME:
- self._title += ' %s' % self._Normalize(data)
- elif self._state == self.TABLE_BODY:
- self._table.AddData(self._Normalize(data))
- elif self._state == self.MAYBE_DONE:
- # Done indeed
- self._table.ProcessTable()
- self._table.Init()
- self._SetState(self.ANCHOR)
-
- def close(self):
- """Finish processing of the HTML buffer."""
- if self._state in (self.TABLE_BODY, self.MAYBE_DONE):
- self._table.ProcessTable()
- self._state = self.ANCHOR
-
- def handle_entityref(self, name):
- """Process HTML escape sequence."""
- entmap = {
- 'amp': '&',
- 'gt': '>',
- 'lt': '<',
- 'quot': '"',
- }
- if name in entmap:
- if self._state == self.TABLE_BODY:
- self._table.AddData(entmap[name])
- elif self._state == self.TABLE_NAME:
- self._title += entmap[name]
-
-
-def main(structs_html_file_name):
- """When invoked standalone - dump .h file on the console."""
- parser = SpecParser()
- with open(structs_html_file_name) as input_file:
- html_content = input_file.read()
- parser.feed(html_content)
- parser.close()
- print(parser.GetTable().GetHFile())
-
-if __name__ == '__main__':
- if len(sys.argv) != 2:
- print('%s: One parameter is required, the name of the html file '
- 'which is the TPM2 library Part 2 specification' %
- os.path.basename(sys.argv[0]), file=sys.stderr)
- sys.exit(1)
- main(sys.argv[1])
diff --git a/generator/generator.py b/generator/generator.py
deleted file mode 100755
index aa1027f..0000000
--- a/generator/generator.py
+++ /dev/null
@@ -1,181 +0,0 @@
-#!/usr/bin/python
-
-# 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 Main file for command and structure generators.
-
-Takes in structures.txt and commands.txt as outputted by extract_*.sh, then
-passes files as input to structure_generator and command_generator objects.
-"""
-
-from __future__ import print_function
-
-import os
-import re
-import subprocess
-import sys
-
-import command_generator
-import extract_structures
-import structure_generator
-
-TMP_DIR = '/tmp'
-TYPES_FILE = 'tpm_types.h'
-
-
-class GeneratorException(Exception):
- """Generator error, a convenience class."""
- pass
-
-usage = ('''
-usage: %s [-h|[tar_archive|part2.html part3.html]]
-
- -h show this message and exit
-
- tar_archive - a tarred archive consisting of at least two HTML files,
- parts 2 and 3 of the TCG TPM2 library specification. File
- names must include 'part2' and 'part3'. The extracted files
- could be found in %s after this script finished processing.
-
- part{23}.html - parts 2 and 3 of the TCG TPM2 library specification in
- html format.
-''' % (os.path.basename(__file__), TMP_DIR))
-
-
-def _TryUntarring(tar_file_name):
- """Try retrieving parts 2 and 3 from the passed in archive.
-
- Args:
- tar_file_name: a string, file name of the tar file which is supposed to
- contain parts 2 and 3 of the specification.
-
- Returns:
- A tuple of strings, two file names in case they were found in the archive
- and successfully extracted.
- """
- part2 = None
- part3 = None
- tar_extract_base = ['tar', '-C', TMP_DIR, '-f']
-
- components = subprocess.check_output(['tar', 'tf', tar_file_name],
- stderr=subprocess.STDOUT)
- for name in components.splitlines():
- if re.search('part2', name, re.IGNORECASE):
- subprocess.check_output(tar_extract_base + [tar_file_name, '-x', name],
- stderr=subprocess.STDOUT)
- part2 = os.path.join(TMP_DIR, name)
- if re.search('part3', name, re.IGNORECASE):
- subprocess.check_output(tar_extract_base + [tar_file_name, '-x', name],
- stderr=subprocess.STDOUT)
- part3 = os.path.join(TMP_DIR, name)
- return part2, part3
-
-
-def _ParseCommandLine(args):
-
- """Process command line and determine input file names.
-
- Input files could be supplied by two different ways - as part of a tar
- archive (in which case only one command line parameter is expected), or as
- two separate file names, one for part 2 and one for part 3.
-
- If a single command line parameter is supplied, and it is not '-h', tar
- extraction is attempted and if successful, two separate files are created in
- TMP_DIR.
-
- Args:
- args: a list of string, command line parameters retrieved from sys.argv
-
- Returns:
- A tuple of two strings, two html files to process, part 2 and part 3 of
- the spec.
-
- Raises:
- GeneratorException: on input errors.
- """
- if len(args) == 1:
- if args[0] == '-h':
- print(usage)
- sys.exit(0)
- try:
- structures_file, commands_file = _TryUntarring(args[0])
- except subprocess.CalledProcessError as e:
- raise GeneratorException("command '%s' failed:\n%s\n%s" %
- (' '.join(e.cmd), e.output, usage))
-
- elif len(args) == 2:
- structures_file = args[0]
- commands_file = args[1]
- else:
- raise GeneratorException(usage)
- return structures_file, commands_file
-
-def _PatchCrosChanges():
- """After generation is completed add Chrome OS specific patches."""
-
- # A single fixed name patch file is included in the repository, use it to
- # update generated files with Chrome Os specific changes.
- subprocess.call(['patch', '-i', 'generator/cros.patch'])
-
-def main(argv):
- """A Main function.
-
- TPM structures and commands files are parsed and C header and C implementation
- files are generated.
-
- Args:
- argv: a list of strings, command line parameters.
- """
-
- structures_file, commands_file = _ParseCommandLine(argv[1:])
- print('parse part2...')
- html_parser = extract_structures.SpecParser()
- tpm_table = html_parser.GetTable()
- # The tables included in the below tuple are defined twice in the
- # specification, once in part 2 and once in part 4. Let's ignore the part 2
- # definitions to avoid collisions.
- tpm_table.SetSkipTables((2, 6, 9, 10, 13))
- html_parser.feed(open(structures_file).read())
- html_parser.close()
- tpm_defines = tpm_table.GetHFile()
-
- print('parse part3...')
- tpm_table.SetSkipTables(())
- html_parser.feed(open(commands_file).read())
- html_parser.close()
-
- # Move to the root directory, which is one level above the script.
- os.chdir(os.path.join(os.path.dirname(argv[0]), '..'))
-
- # Save types include file.
- print('generate output...')
- types_file = open(TYPES_FILE, 'w')
- guard_name = TYPES_FILE.upper()
- guard_name = guard_name.replace('.', '_')
- guard_name = 'TPM2_' + guard_name + '_'
- types_file.write((structure_generator.COPYRIGHT_HEADER +
- structure_generator.HEADER_FILE_GUARD_HEADER) %
- {'name': guard_name})
- types_file.write(tpm_defines)
- types_file.write((structure_generator.HEADER_FILE_GUARD_FOOTER) %
- {'name': guard_name})
- types_file.close()
- typemap = tpm_table.GetTypeMap()
- structure_generator.GenerateHeader(typemap)
- structure_generator.GenerateImplementation(typemap)
- commands = tpm_table.GetCommandList()
- command_generator.GenerateHeader(commands)
- command_generator.GenerateImplementation(commands, typemap)
- _PatchCrosChanges()
- print('Processed %d TPM types.' % len(typemap))
- print('Processed %d commands.' % len(commands))
-
-if __name__ == '__main__':
- try:
- main(sys.argv)
- except GeneratorException as e:
- if e.message:
- print(e, file=sys.stderr)
- sys.exit(1)
diff --git a/generator/structure_generator.py b/generator/structure_generator.py
deleted file mode 100755
index 570b338..0000000
--- a/generator/structure_generator.py
+++ /dev/null
@@ -1,1402 +0,0 @@
-# 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'])
diff --git a/generator/structure_generator_test.py b/generator/structure_generator_test.py
deleted file mode 100755
index fcff891..0000000
--- a/generator/structure_generator_test.py
+++ /dev/null
@@ -1,194 +0,0 @@
-#!/usr/bin/python2
-
-# 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.
-
-"""Unit tests for the libtpm2 structure_generator."""
-
-from __future__ import print_function
-
-import StringIO
-import os
-import unittest
-
-import extract_structures
-import structure_generator
-
-
-class TestGenerators(unittest.TestCase):
- """Test structure_generator classes."""
-
- def testTypedefMarshal(self):
- """Test generation of marshaling code for typedefs."""
- marshalled_types = set(['int'])
- typedef = structure_generator.Typedef('int', 'INT')
- typedef2 = structure_generator.Typedef('INT', 'INT2')
- typemap = {'INT': typedef}
- out_file = StringIO.StringIO()
- typedef2.OutputMarshalImpl(out_file, marshalled_types, typemap)
- self.assertIn('INT', marshalled_types)
- self.assertIn('INT2', marshalled_types)
- out_file.close()
-
- def testConstantTypeMarshal(self):
- """Test generation of marshaling code for constant types."""
- marshalled_types = set(['int'])
- typedef = structure_generator.Typedef('int', 'UINT16')
- constant = structure_generator.ConstantType('UINT16', 'TPM_TYPE')
- constant.valid_values.append('VALUE0')
- constant.valid_values.append('VALUE1')
- typemap = {'UINT16': typedef}
- out_file = StringIO.StringIO()
- constant.OutputMarshalImpl(out_file, marshalled_types, typemap)
- self.assertIn('UINT16', marshalled_types)
- self.assertIn('TPM_TYPE', marshalled_types)
- out_file.close()
-
- def testAttributeStructureMarshal(self):
- """Test generation of marshaling code for attribute structures."""
- marshalled_types = set(['int'])
- typedef = structure_generator.Typedef('int', 'UINT16')
- attributeStruct = structure_generator.AttributeStructure(
- 'UINT16', 'TPM_TYPE')
- attributeStruct.reserved.append('4_7')
- attributeStruct.reserved.append('1')
- typemap = {'UINT16': typedef}
- out_file = StringIO.StringIO()
- attributeStruct.OutputMarshalImpl(out_file, marshalled_types, typemap)
- self.assertIn('UINT16', marshalled_types)
- self.assertIn('TPM_TYPE', marshalled_types)
- out_file.close()
-
- def testInterfacemarshal(self):
- """test generation of marshaling code for interfaces."""
- marshalled_types = set(['int'])
- typedef = structure_generator.Typedef('int', 'UINT16')
- interface = structure_generator.Interface('UINT16', 'TPM_TYPE')
- interface.conditional = 'TPM_VALUE_NULL'
- interface.bounds.append(('TPM_MIN', 'TPM_MAX'))
- interface.valid_values.append('VALUE0')
- interface.valid_values.append('VALUE1')
- typemap = {'UINT16': typedef}
- out_file = StringIO.StringIO()
- interface.OutputMarshalImpl(out_file, marshalled_types, typemap)
- self.assertIn('UINT16', marshalled_types)
- self.assertIn('TPM_TYPE', marshalled_types)
- out_file.close()
-
- def testStructMarshal(self):
- """Test generation of marshaling code for structures."""
- marshalled_types = set(['int'])
- struct = structure_generator.Structure('TEST_STRUCT')
- struct.AddField(structure_generator.Field('UINT16', 'type', None, False))
- struct.AddField(structure_generator.Field('TPMI_TYPE', 'interfaceField0',
- 'TRUE', False))
- struct.AddField(structure_generator.Field('TPMI_TYPE', 'interfaceField1',
- 'FALSE', False))
- struct.AddField(structure_generator.Field('TPMU_SYM_MODE', 'unionField',
- 'type', False))
- struct.AddField(structure_generator.Field('UINT16', 'arrayField',
- 'MAX_VALUE', True))
- typedef = structure_generator.Typedef('int', 'UINT16')
- interface = structure_generator.Interface('UINT16', 'TPMI_TYPE')
- # Choose TPMU_SYM_MODE because it exists in selectors definition and it
- # has few fields.
- union = structure_generator.Union('TPMU_SYM_MODE')
- union.AddField(structure_generator.Field('UINT16', 'aes', None))
- union.AddField(structure_generator.Field('UINT16', 'SM4', None))
- typemap = {
- 'UINT16': typedef,
- 'TPMI_TYPE': interface,
- 'TPMU_SYM_MODE': union
- }
- out_file = StringIO.StringIO()
- struct.OutputMarshalImpl(out_file, marshalled_types, typemap)
- self.assertIn('UINT16', marshalled_types)
- self.assertIn('TPMI_TYPE', marshalled_types)
- self.assertIn('TPMU_SYM_MODE', marshalled_types)
- self.assertIn('TEST_STRUCT', marshalled_types)
- out_file.close()
-
- def testUnionMarshal(self):
- """Test generation of marshaling code for unions."""
- marshalled_types = set(['int'])
- union = structure_generator.Union('TPMU_SYM_MODE')
- union.AddField(structure_generator.Field('UINT16', 'aes', None))
- union.AddField(structure_generator.Field('UINT16', 'SM4', None))
- typedef = structure_generator.Typedef('int', 'UINT16')
- typemap = {'UINT16': typedef}
- out_file = StringIO.StringIO()
- union.OutputMarshalImpl(out_file, marshalled_types, typemap)
- self.assertIn('UINT16', marshalled_types)
- self.assertIn('TPMU_SYM_MODE', marshalled_types)
- out_file.close()
-
- def _MakeArg(self, arg_type, arg_name):
- return {'type': arg_type,
- 'name': arg_name,
- 'command_code': None,
- 'description': None}
-
-
-class TestParser(unittest.TestCase):
- """Test structure parser."""
-
- def testStructureParser(self):
- """Test the structure parser with valid data.
-
- One of each typedef, constant type, attribute structure, interface,
- structure, and union. Should appear in types array in that order.
- """
- html_parser = extract_structures.SpecParser()
- html_file_name = os.path.join(os.path.dirname(__file__),
- 'test_structure_generator.html')
- html_parser.feed(open(html_file_name).read())
- html_parser.close()
- types = html_parser.GetTable().GetTypeMap()
- self.assertEqual(len(types), 6)
- tpm_obj = types['UINT16']
- self.assertEqual(tpm_obj.old_type, 'uint16_t')
- self.assertEqual(tpm_obj.new_type, 'UINT16')
- tpm_obj = types['TPMA_LOCALITY']
- self.assertEqual(tpm_obj.old_type, 'base_type')
- self.assertEqual(tpm_obj.new_type, 'TPMA_LOCALITY')
- self.assertEqual(tpm_obj.reserved[0], '4_7')
- self.assertEqual(tpm_obj.reserved[1], '9')
- tpm_obj = types['const_type']
- self.assertEqual(tpm_obj.old_type, 'base_type')
- self.assertEqual(tpm_obj.new_type, 'const_type')
- self.assertEqual(tpm_obj.valid_values[0], 'const_name')
- self.assertEqual(tpm_obj.error_code, 'return_name')
- tpm_obj = types['TPMI_DH_OBJECT']
- self.assertEqual(tpm_obj.old_type, 'base_type')
- self.assertEqual(tpm_obj.new_type, 'TPMI_DH_OBJECT')
- self.assertEqual(tpm_obj.bounds[0][0], 'min_name')
- self.assertEqual(tpm_obj.bounds[0][1], 'max_name')
- self.assertEqual(tpm_obj.valid_values[0], 'const_name')
- self.assertEqual(tpm_obj.conditional_value, 'null_name')
- self.assertEqual(tpm_obj.error_code, 'return_name')
- tpm_obj = types['struct_type']
- self.assertEqual(tpm_obj.name, 'struct_type')
- self.assertEqual(tpm_obj.fields[0].field_type, 'UINT16')
- self.assertEqual(tpm_obj.fields[0].field_name, 'field1')
- self.assertEqual(tpm_obj.fields[1].field_type, 'UINT16')
- self.assertEqual(tpm_obj.fields[1].field_name, 'field2')
- self.assertEqual(tpm_obj.fields[2].field_type, 'UINT16')
- self.assertEqual(tpm_obj.fields[2].field_name, 'field3')
- self.assertEqual(tpm_obj.fields[2].run_time_size, 'field1')
- self.assertEqual(tpm_obj.fields[3].field_type, 'UINT16')
- self.assertEqual(tpm_obj.fields[3].field_name, 'field4')
- self.assertEqual(tpm_obj.fields[3].selector_value, 'field2')
- self.assertEqual(tpm_obj.fields[4].field_type, 'interface_type')
- self.assertEqual(tpm_obj.fields[4].field_name, 'field5')
- self.assertEqual(tpm_obj.upper_bounds['field1'], 'max')
- self.assertEqual(tpm_obj.lower_bounds['field1'], 'min')
- tpm_obj = types['union_type']
- self.assertEqual(tpm_obj.name, 'union_type')
- self.assertEqual(tpm_obj.fields[0].field_type, 'field1_type')
- self.assertEqual(tpm_obj.fields[0].field_name, 'field1')
- self.assertEqual(tpm_obj.fields[1].field_type, 'field2_type')
- self.assertEqual(tpm_obj.fields[1].field_name, 'field2')
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/generator/test_structure_generator.html b/generator/test_structure_generator.html
deleted file mode 100644
index 6f645ed..0000000
--- a/generator/test_structure_generator.html
+++ /dev/null
@@ -1,70 +0,0 @@
-<!--
-
- 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.
-
-This file contains HTML code which defines a few TPM objects following the
-format of the HTML files generated by pdf=>html converting of TCG TPM2 library
-specification.
--->
-
-<html>
-<head></head>
-<body>
-Some arbitrary text
-<a name="bookmark273"> Table 1 Definition of Types for ints</a>
-<table>
-<tr><td> Type </td><td> Name </td><td> Description </td></tr>
-<tr><td> uint16_t </td><td> UINT16 </td><td> </td></tr>
-</table>
-<p>more arbitrary text
-<a name="bookmark219">Table 2 Definition of (base_type) TPMA_LOCALITY Bits
-</a>
-<table>
-<tr><td> Bit </td><td> Name </td> <td> Definition </td></tr>
-<tr><td> 3:0 </td><td> TPM_LOC_ZERO </td><td></td></tr>
-<tr><td> 7:4 </td><td> Reserved </td><td></td></tr>
-<tr><td> 8 </td><td> TPM_LOC_ONE </td><td></td></tr>
-<tr><td> 9 </td><td> Reserved </td><td></td></tr>
-<tr><td> 10 </td><td> TPM_LOC_TWO </td><td></td></tr>
-</table>
-<p>more arbitrary text
-<a name="bookmark219">
-</a>
-<a name=bookmark99>Table 3 Definition of (base_type) const_type Constants </a>
-<table>
-<tr><td> Name </td> <td> Value </td><td> Comments </td></tr>
-<tr><td> const_name </td><td> 0x322E3000 </td><td> terrminator </td></tr>
-<tr><td> TPM_SPEC_LEVEL </td><td> 00 </td> <td> the level number </td> </tr>
-<tr><td> #return_name </td><td> </td> <td> </td></tr>
-</table>
-<p>more arbitrary text
-<a name=bookmark274>Table 4 Definition of (base_type) TPMI_DH_OBJECT Type</a>
-<table>
-<tr><td> Values </td> <td> Comments </td> </tr>
-<tr><td> const_name </td><td> one of valid values </td> </tr>
-<tr><td> {min_name:max_name} </td><td> allowed range </td> </tr>
-<tr><td> {PERSISTENT_FIRST:PERSISTENT_LAST}</td><td> allowed range </td> </tr>
-<tr><td> +null_name </td> <td> the conditional value </td> </tr>
-<tr><td> #return_name </td><td> </td></tr>
-</table>
-<p>more arbitrary text
-<a name=bookmark274>Table 5 Definition of struct_type Structure <OUT>
-<table>
-<tr><td> Values </td> <td> Comments </td> </tr>
-<tr><td> field1 </td><td> UINT16 </td> </tr>
-<tr><td> field2 </td><td> UINT16 </td> </tr>
-<tr><td> field3[field1]{min:max} </td><td> UINT16 </td> </tr>
-<tr><td> [field2]field4 </td><td> UINT16 </td> </tr>
-<tr><td> field5= </td><td> interface_type </td> </tr>
-</table>
-<p>more arbitrary text
-<a name=bookmark781>Table 6 Definition of union_type Union</a>
-<table>
-<tr><td> Parameter </td><td> Type </td><td> Selector </td><td> Description </td></tr>
-<tr><td> field1 </td><td> field1_type </td><td> field1_selector </td><td> a prime factor of the public key </td> </tr>
-<tr><td> field2 </td><td> field2_type </td><td> field2_selector </td><td> the integer private key </td> </tr>
-</table>
-<p>more arbitrary text
-</body>
diff --git a/generator/tpm_table.py b/generator/tpm_table.py
deleted file mode 100644
index 97eaf90..0000000
--- a/generator/tpm_table.py
+++ /dev/null
@@ -1,831 +0,0 @@
-"""Module for processing TCG TPM2 library object descriptions.
-
-The descriptions are scraped from the tables of parts 2 and 3 of the
-specification by a different module and fed through this module for
-processing.
-"""
-
-from __future__ import print_function
-
-import re
-import sys
-
-from command_generator import Command
-from structure_generator import AttributeStructure
-from structure_generator import ConstantType
-from structure_generator import Field
-from structure_generator import Interface
-from structure_generator import Structure
-from structure_generator import Typedef
-from structure_generator import Union
-
-
-def _DebugLog(*args, **kwargs):
- """When used - sends its inputs to stderr.
-
- This function can be used when debugging this module. Its footprint is
- similar to print(), but the default destination is sys.stderr, which is
- handy when the script generates stdio output redirected into a file.
-
- Args:
- *args: a list of items of various types to print. Printed space separated,
- each one converted to str before being printed.
- **kwargs: a dictionary of variables to pass to print(), if any. In fact the
- only key this function cares about is 'endl', which allows to
- suppress adding a newline to the printed string.
- """
- endl = kwargs.get('endl', '\n')
- print(' '.join(str(x) for x in args), end=endl, file=sys.stderr)
-
-
-class Table(object):
- """Representation of TCG TPM2 library specification tables.
-
- The purpose of this class is to both generate new TPM2 objects and to keep
- track of the previously generated objects for post processing (generating C
- code).
-
- The HTML scraper finds tables in the specifications and builds up the
- tables' contents in this object, one at a time. This object's table
- representation includes table title, table header and one or more then table
- rows.
-
- The table title must start with 'Table ### xxx', where ### is monotonously
- increasing table number and xxx is some description allowing to deduce the
- type of the object defined by this table.
-
- The cells of the table include names and types of the components, various
- decorations are used to convey additional information: array boundaries,
- values' limits, return values, selectors, etc, etc.
-
- Once the entire table is scraped, the scraper invokes a method to process it
- (ProcessTable). The title of the table is examined by this module and the
- appropriate processing method is invoked to actually convert the internal
- table representation into a TPM2 object.
-
- Two maps are maintained persistently over the life time of this object, the
- map of types (keyed by the type name scraped from part 2) and map of
- commands (keyed by the command name, scraped from part 3).
-
- One other thing this module produces is the text for the .h file defining
- all structures and types this module encountered.
-
- Attributes:
-
- _alg_id_table: actual table of various TPM2 algorithms, a copy of Table 9
- from part 2. It is used to convert encoded algorithm specs
- used in other tables into a list of matching algorithms.
- _h_file: a multiline string, the accumulated .h file defining all TPM
- objects processed so far.
- _type_map: a dictionary of various TPM types, keyed by the string - the
- type name
- _command_map: a dictionary of command_generator.Command objects, keyed by
- the string, the command name
- skip_tables: a tuple of integers, the numbers of tables which should not
- be included in the .h file, as the same information was
- derived from part 4 earlier.
- _title: a string, title of the currently being processed specification
- table
- _title_type: a string, base type of the object defined by the currently
- being processed specification table
- _alg_type: a string, in some tables included in the title in curly
- brackets, to indicate what type of the algorithm this table
- deals with (usually RSA or ECC)
- _body: a list of strings, rows of the currently being processed
- specification table
- _has_selector_column: a Boolean, set to True if the third column of the
- table is the selector to be used to process this row (as in
- picking the object type when the table represents a union)
- _skip_printing: a Boolean, set to True if the table contents should not be
- included on tpm_types.h - some tables are also defined in
- files extracted from Part 4 of the specification.
-
- """
-
- # Match table titles with processing routines.
- TABLE_ROUTER = (
- (re.compile('(Constants|Defines for Logic Values)'), '_ProcessConstants'),
- (re.compile('(of Types for|Base Types)'), '_ProcessTypes'),
- (re.compile('Definition of .* Type'), '_ProcessInterfaceOrType'),
- (re.compile('Unmarshaling Errors'), '_ProcessEnum'),
- (re.compile(r'Definition of [\S]+ (Structure|Union)'),
- '_ProcessStructureOrUnion'),
- (re.compile('Definition of .* Bits'), '_ProcessBits'),
- (re.compile(r' TPM2_\S+ (Command|Response)'), '_ProcessCommand'),
- )
-
-
- # The TCG spec in some cases uses so called 'Algorithm macros' to describe
- # all algorithms a type should apply to. The macros are described in details
- # in section 4.12 of part 2 of the spec.
- #
- # Basically, the macro consists of the prefix '!ALG' followed by dot
- # separated descriptions of algorithm types this marco applies to.
- #
- # The algorithm types are expressed as sequences or lower or upper case
- # letters, and should match the third column of Table 9 either inclusively
- # (in case the type letters are in upper case, or exclusively, in case the
- # type letters are in lower case.
- _alg_macro = re.compile(r'!ALG\.([a-z\.]+)', re.IGNORECASE)
-
- def __init__(self):
- """Create a Table class instance."""
- self._alg_id_table = []
- # Allow re-initializing attributes outside __init__() (in Init())
- self.Init()
- self._h_file = ''
- self._type_map = {}
- self._command_map = {}
- self.skip_tables = ()
-
- def Init(self, title=''):
- """Initialize a new table.
-
- This function is invoked each time a new table is encountered in the spec.
-
- A typical table header could look like this:
-
- 'Table 10 - Definition of (UINT16) {ECC} TPM_ECC_CURVE Constants'
-
- The algorithm type in curly brackets, if present, is redundant, it is
- stripped off before the table header comment is generated for the .h file.
-
- Some titles include the parenthesized base type the defined object should
- be typedef'ed from.
-
- Args:
- title: a string, the title of the table as included in the TCG spec.
- """
- title_bracket_filter = re.compile(r'({.*?}) ?')
- title_type_filter = re.compile(r'(\(.*?\)) ?')
- # Retrieve base type, if present in the table title.
- m = title_type_filter.search(title)
- if m:
- # the header shown in the docstring above would result in the match of
- # '(UINT16)', remove the parenthesis and save the base type.
- self._title_type = m.groups()[0][1:-1]
- self._title = title_type_filter.sub('', title).strip()
- else:
- self._title_type = ''
- self._title = title.strip()
- # Now retrieve algorithm type, if present in the table title.
- m = title_bracket_filter.search(self._title)
- self._alg_type = ''
- if m:
- self._title = title_bracket_filter.sub('', self._title).strip()
- alg_type = m.groups()[0][1:-1].strip()
- if not alg_type.startswith('!'):
- self._alg_type = alg_type
- self._body = []
- self._has_selector_column = False
- self._skip_printing = False
-
- def _SplitByAlg(self, word):
- """Split the passed in word by the regex used to pick TPM algorithms.
-
- The TPM algorithm regex is used all over the spec in situations where
- similar code needs to be generated for different algorithms of a certain
- type.
-
- A string in the spec might look like one of the following:
- TPMI_!ALG.S_KEY_BITS or !ALG.S_KEY_SIZES_BITS.
-
- The split would result in a three element list: the part before !ALG
- (could be empty), the letters between '!ALG.' and _ or end of the string,
- and the part after the letters included in the algorithm regex.
-
- TPMI_!ALG.S_KEY_BITS => ['TPMI_', 'S', '_KEY_BITS']
- !ALG.S_KEY_SIZES_BITS => ['', 'S', '_KEY_SIZES_BITS']
-
- The first and last elements of the split are used as the prefix and suffix
- of the type names included in the generated file.
-
- In some cases there is no regex suffix present, only the !ALG string, as
- in the selector column in table 127 (TPM_ALG_!ALG) In this case the split
- by the !ALG string is attempted, and the generated list has just two
- elements.
-
- In yet some other cases, say in Table 126 where the type field does not
- change at all set to TPMI_ALG_SYM_MODE for all fields. In such cases the
- split returns a single element list, the second element set to None is
- added to the list.
-
- Args:
- word: a string, the encoded algorithm string to be split.
-
- Returns:
- a tuple of two strings, first and last elements of the split, either one
- could be empty.
-
- """
- parts = self._alg_macro.split(word)
- if len(parts) == 1:
- parts = word.split('!ALG')
- if len(parts) == 1:
- return word, None
- return parts[0].strip('_'), parts[-1].strip('_')
-
- def SetSkipTables(self, skip_tables):
- """Set the tuple of table numbers to be ignored by the parser."""
- self.skip_tables = skip_tables
-
- def _AddToHfile(self, text=''):
- self._h_file += text + '\n'
-
- def _SetBaseType(self, old_type, tpm_obj):
- """Set the base type for a new object.
-
- Many TPM objects are typedefed hierarchically, for instance
-
- uint16_t => UINT16 => TPM_ALG_ID_Marshal => TPMI_ALG_HASH_Marshal
-
- This causes excessive nesting when marshaling and unmarshaling, which is
- bad from both performance and stack size requirements point of view.
-
- This function will discover the 'basest' type and set it in the tpm
- object, this would help to generate direct marshaling/unmarshaling
- functions.
-
- Args:
- old_type: a string, name of the immediate type this tpm object typedefed
- from.
- tpm_obj: a tpm object, derived from TPMType
- """
- base_type = old_type
- while base_type in self._type_map:
- try:
- base_type = self._type_map[base_type].old_type
- except AttributeError:
- break # The underlying type is not a typedef
- tpm_obj.SetBaseType(base_type)
-
- def _AddTypedef(self, old_type, new_type):
- if not self._skip_printing:
- self._AddToHfile('typedef %s %s;' % (old_type, new_type))
- # No need to generate marshaling/unmarshaling code for BOOL type.
- if new_type != 'BOOL':
- self._type_map[new_type] = Typedef(old_type, new_type)
- self._SetBaseType(old_type, self._type_map[new_type])
-
- def InProgress(self):
- """Return True when the parser is in the middle of a table."""
- return self._title
-
- def _GetMaxLengths(self, table):
- """Find out maximum lengths of the table columns.
-
- This function helps to generate nicely aligned definitions in the output
- .h file, by making sure that each field's name starts in the same column,
- far enough for all fields' types to fit.
-
- Args:
- table: a list of string lists. Each component consists of at least two
- elements, the first one the field or constant type, the
- second one the field name or constant value.
-
- Returns:
- a tuple of two integers, the first one - the length of the longest
- string in the first colume, the second one - the length of the
- longest string in the second column.
- """
- lengths = [0, 0]
- for row in table:
- for i in range(len(lengths)):
- if len(row[i]) > lengths[i]:
- lengths[i] = len(row[i])
- return tuple(lengths)
-
- def NewRow(self):
- """Start a new row in the internal table representation."""
- self._body.append([])
-
- def NewCell(self):
- """Start a new cell in the last row."""
- self._body[-1].append('')
-
- def AddData(self, data):
- """Add data to the last cell of the last row."""
- if not self._body:
- return # Ignore end of line and whitespace formatting.
- self._body[-1][-1] += data
-
- def ProcessTable(self):
- """Process accumulated table contents.
-
- This function is invoked when the parser state machine detects that the
- entire HTML table has been processed. The received contents is handled
- based on the table title by finding the matching entry in TABLE_ROUTER
- tuple.
-
- The result of processing is adding a new TPM type to the _type_map
- dictionary, or a new command descriptor to the _command_map dictionary.
- """
-
- # The table has a selector column if it has at least three columns, and
- # the third column is titled 'Selector'.
- self._has_selector_column = (len(self._body[0]) >= 3 and
- self._body[0][2].strip() == 'Selector')
- # Preprocess representation of the table scraped from the spec. Namely,
- # remove the header row, and strip all other cells before adding them to
- # self._body[], which becomes a list including all scraped table cells,
- # stripped.
- self._body = [[cell.strip() for cell in row] for row in self._body[1:]]
- if 'TPM_ALG_ID Constants' in self._title:
- self._alg_id_table = [[x[0], x[2].replace(' ', ''), x[3]]
- for x in self._body]
-
- # The name of the type defined in the table, when present, is always the
- # fifth element in the stripped header, for instance:
- # 'Table 10 - Definition of TPM_ECC_CURVE Constants'
- try:
- type_name = self._title.split()[4]
- except IndexError:
- type_name = ''
-
- # Based on the table title, find the function to process the table and
- # generate a TPM specification object of a certain type.
- table_func = ''
- for regex, func in self.TABLE_ROUTER:
- if regex.search(self._title):
- table_func = func
- break
- else:
- self._AddToHfile('// Unprocessed: %s' % self._title)
- return
-
- if int(self._title.split()[1]) in self.skip_tables:
- self._skip_printing = True
- self._AddToHfile('// Skipped: %s' % self._title)
- else:
- self._AddToHfile('// %s' % self._title)
-
- # Invoke a TPM type specific processing function.
- getattr(self, table_func)(type_name)
-
- def _ProcessCommand(self, _):
- """Process command description table from part 3.
-
- Each TPM command has two tables associated with it, one describing the
- request structure, and another one describing the response structure. The
- first time a TPM command is encountered, a Command object is created and
- its 'request_args' property is set, the second time it is encountered -
- the existing object's 'response_args' property is set.
- """
- command_name = self._title.split()[2]
- if command_name not in self._command_map:
- command = Command(command_name)
- self._command_map[command_name] = command
- else:
- command = self._command_map[command_name]
- params = []
- # The first three fields in each request and response are always the same
- # and are not included in the generated structures. Let's iterate over the
- # rest of the fields.
- for row in self._body[3:]:
- # A dictionary describing a request or response structure field.
- field = {}
- # Ignore the '@' decoration for now.
- field_type, field['name'] = row[0], row[1].lstrip('@')
- # The '+' decoration means this field can be conditional.
- if field_type.endswith('+'):
- field_type = field_type[:-1]
- field['has_conditional'] = 'TRUE'
- else:
- field['has_conditional'] = 'FALSE'
- field['type'] = field_type
- if len(row) > 2:
- field['description'] = row[2]
- else:
- field['description'] = ''
- # Add the new field to the list of request or response fields.
- params.append(field)
- if ' Command' in self._title:
- command.request_args = params
- else:
- command.response_args = params
-
- def _PickAlgEntries(self, alg_type_str):
- """Process algorithm id table and find all matching entries.
-
- See comments to _alg_macro above.
-
- Args:
- alg_type_str: a string, one or more dot separated encoded algorithm types.
-
- Returns:
- A table of alg_type (Table 9 of part 2) entries matching the passed in
- encoded type string.
- """
- filtered_table = []
- for alg_type in alg_type_str.split('.'):
- if re.match('^[A-Z]+$', alg_type):
- # Exclusive selection, must exactly match algorithm type from table 9
- # (which is in the second column). Add to the return value all
- # matching rows of table 9.
- extension = []
- for row in self._alg_id_table:
- if row[1] == alg_type:
- if self._alg_type and self._alg_type != row[2]:
- continue
- extension.append(row)
- filtered_table.extend(extension)
- elif re.match('^[a-z]+$', alg_type):
- # Inclusive selection. All type letters must be present in the type
- # column, but no exact match is required.
- for row in self._alg_id_table:
- for char in alg_type.upper():
- if char not in row[1]:
- break
- else:
- if not self._alg_type or self._alg_type == row[2]:
- filtered_table.append(row)
- return filtered_table
-
- def _ParseAlgorithmRegex(self, token):
- """Process a token as an algorithm regex.
-
- This function tries to interpret the passed in token as an encoded
- algorithm specification.
-
- In case the encoded algorithm regex matches, the function splits the token
- into prefix, algorithm description and suffix, and then retrieves the list
- of all algorithms matching the algorithm description.
-
- Args:
- token: a string, potentially including the algorithm regex.
-
- Returns:
- in case the regex matched returns a tri-tuple of two strings (prefix and
- suffix, either one could be empty) and a list of matching algorithms
- from the algorithm descriptors table. If there has been no match -
- returns None.
- """
- elements = self._alg_macro.split(token)
- if len(elements) == 3:
- # The token matched the algorithm regex, Find out prefix and suffix to
- # be used on the generated type names, and the algorithm regex suffix to
- # use to find matching entries in the algorithm table.
- name_prefix, alg_suffix, name_suffix = tuple(elements)
- name_prefix = name_prefix.strip('_')
- name_suffix = name_suffix.strip('_')
- return name_prefix, name_suffix, self._PickAlgEntries(alg_suffix)
-
- def _ProcessInterface(self, type_name):
- """Processes spec tables describing interfaces."""
- result = self._ParseAlgorithmRegex(type_name)
- if result:
- name_prefix, name_suffix, alg_list = tuple(result)
- # Process all matching algorithm types
- for alg_desc in alg_list:
- alg_base = alg_desc[0].replace('TPM_ALG_', '')
- new_name = '_'.join([name_prefix,
- alg_base, name_suffix]).strip('_')
- new_if = Interface(self._title_type, new_name)
- self._AddTypedef(self._title_type, new_name)
- for row in self._body:
- new_value = row[0]
- if new_value.startswith('$!ALG'):
- new_if.supported_values = alg_base + '_' + '_'.join(
- new_value.split('_')[1:])
- elif new_value.startswith('$'):
- new_if.supported_values = new_value[1:]
- elif new_value.startswith('#'):
- new_if.error_code = new_value[1:]
- self._type_map[new_name] = new_if
- self._AddToHfile('\n')
- return
- new_if = Interface(self._title_type, type_name)
- self._AddTypedef(self._title_type, type_name)
- self._type_map[type_name] = new_if
- self._SetBaseType(type_name, new_if)
- for row in self._body:
- new_value = row[0]
- result = self._ParseAlgorithmRegex(new_value)
- if result:
- # The field is described using the algorithm regex. The above comment
- # applies.
- name_prefix, name_suffix, alg_list = tuple(result)
- for alg_desc in alg_list:
- alg_base = alg_desc[0].replace('TPM_ALG_', '')
- new_if.valid_values.append('_'.join(
- [name_prefix, alg_base, name_suffix]).strip('_'))
- else:
- if new_value.startswith('{'):
- bounds = tuple(
- [x.strip() for x in new_value[1:-1].strip().split(':')])
- new_if.bounds.append(bounds)
- elif new_value.startswith('+'):
- new_if.conditional_value = new_value[1:]
- elif new_value.startswith('#'):
- new_if.error_code = new_value[1:]
- elif new_value.startswith('$'):
- new_if.supported_values = new_value[1:]
- else:
- new_if.valid_values.append(new_value)
- return
-
- def _ProcessTypedefs(self, type_name):
- """Processes spec tables defining new types."""
- result = self._ParseAlgorithmRegex(type_name)
- if result:
- name_prefix, name_suffix, alg_list = tuple(result)
- for alg_desc in alg_list:
- alg_base = alg_desc[0].replace('TPM_ALG_', '')
- new_type = '%s_%s_%s' % (name_prefix, alg_base, name_suffix)
- self._AddTypedef(self._title_type, new_type)
- self._AddToHfile('\n')
- else:
- self._AddTypedef(self._title_type, type_name)
-
- def _ProcessBits(self, type_name):
- """Processes spec tables describing attributes (bit fields)."""
- bits_lines = []
- base_bit = 0
- tpm_obj = AttributeStructure(self._title_type, type_name)
- self._type_map[type_name] = tpm_obj
- self._SetBaseType(self._title_type, tpm_obj)
- for bits_line in self._body:
- field, name = tuple(bits_line[:2])
- if not field:
- continue
- if name.startswith('TPM_'):
- # Spec inconsistency fix.
- name_pieces = [x.lower() for x in name.split('_')[1:]]
- name = name_pieces[0]
- for piece in name_pieces[1:]:
- name += piece[0].upper() + piece[1:]
- bit_range = [x.replace(' ', '') for x in field.split(':')]
- field_base = int(bit_range[-1])
- if field_base != base_bit:
- field_name = 'reserved%d' % base_bit
- field_width = field_base - base_bit
- if field_width > 1:
- field_name += '_%d' % (field_base - 1)
- bits_lines.append(['%s : %d' % (field_name, field_width)])
- tpm_obj.reserved.append(field_name.replace('reserved', ''))
- if len(bit_range) > 1:
- field_width = int(bit_range[0]) - field_base + 1
- else:
- field_width = 1
- if re.match('reserved', name, re.IGNORECASE):
- name = 'reserved%d' % field_base
- if field_width > 1:
- name += '_%d' % (field_base + field_width - 1)
- tpm_obj.reserved.append(name.replace('reserved', ''))
- bits_lines.append([name, ': %d' % field_width])
- base_bit = field_base + field_width
- max_type_len, _ = self._GetMaxLengths(bits_lines)
- self._AddToHfile('typedef struct {')
- for bits_line in bits_lines:
- self._AddToHfile(' %s %-*s %s;' % (self._title_type, max_type_len,
- bits_line[0], bits_line[1]))
- self._AddToHfile('} %s;\n' % type_name)
-
- def _ExpandAlgs(self, row):
- """Find all algorithms encoded in the variable name.
-
- Args:
- row: a list of strings, a row of a structure or union table scraped from
- part 2.
-
- Returns:
- A list for structure_generator.Field objects, one per expanded
- algorithm.
-
- """
- alg_spec = row[0].split()
- expansion = []
- m = self._alg_macro.search(alg_spec[0])
- if m:
- alg_type = m.groups()[0]
- # Find all algorithms of this type in the alg id table
- alg_entries = self._PickAlgEntries(alg_type)
- if len(alg_spec) == 2 and alg_spec[1][0] == '[':
- # This is the case of a union of arrays.
- raw_size_parts = self._alg_macro.split(alg_spec[1][1:-1])
- size_prefix = raw_size_parts[0].strip('_')
- size_suffix = raw_size_parts[2].strip('_')
- for alg_desc in alg_entries:
- alg_base = alg_desc[0].replace('TPM_ALG_', '')
- size = '_'.join([size_prefix, alg_base, size_suffix]).strip('_')
- if self._has_selector_column:
- selector_parts = self._alg_macro.split(row[2])
- selector_prefix = selector_parts[0].strip('_')
- selector_suffix = selector_parts[2].strip('_')
- selector = '_'.join([selector_prefix,
- alg_base, selector_suffix]).strip('_')
- else:
- selector = ''
- expansion.append(Field(row[1], alg_base.lower(),
- selector=selector, array_size=size))
- else:
- type_prefix, type_suffix = self._SplitByAlg(row[1])
- if self._has_selector_column:
- selector_prefix, selector_suffix = self._SplitByAlg(row[2])
- else:
- selector = ''
- for alg_desc in alg_entries:
- alg_base = alg_desc[0].replace('TPM_ALG_', '')
- if type_suffix is not None:
- var_type = '_'.join([type_prefix, alg_base, type_suffix]).strip('_')
- else:
- var_type = type_prefix
- if self._has_selector_column:
- selector = '_'.join([selector_prefix, alg_base,
- selector_suffix]).strip('_')
- expansion.append(Field(var_type, alg_base.lower(),
- selector=selector))
- return expansion
-
- def _ProcessInterfaceOrType(self, type_name):
- if type_name.startswith('TPMI_'):
- self._ProcessInterface(type_name)
- else:
- self._ProcessTypedefs(type_name)
-
- def _StructOrUnionToHfile(self, body_fields, type_name, union_mode, tpm_obj):
- body_lines = []
- for field in body_fields:
- tpm_obj.AddField(field)
- body_lines.append([field.field_type, field.field_name])
- if field.array_size:
- body_lines[-1][-1] += '[%s]' % field.array_size
- if field.selector_value:
- body_lines[-1].append(field.selector_value)
- max_type_len, _ = self._GetMaxLengths(body_lines)
- tpm2b_mode = type_name.startswith('TPM2B_')
- space_prefix = ''
- if union_mode:
- self._AddToHfile('typedef union {')
- else:
- if tpm2b_mode:
- self._AddToHfile('typedef union {')
- space_prefix = ' '
- self._AddToHfile(' struct {')
- else:
- self._AddToHfile('typedef struct {')
- for line in body_lines:
- guard_required = len(line) > 2 and line[2].startswith('TPM_ALG_')
- if not line[1]:
- continue
- if guard_required:
- self._AddToHfile('#ifdef %s' % line[2])
- self._AddToHfile(space_prefix + ' %-*s %s;' % (
- max_type_len, line[0], line[1]))
- if guard_required:
- self._AddToHfile('#endif')
- if tpm2b_mode:
- self._AddToHfile(' } t;')
- self._AddToHfile(' TPM2B b;')
- self._AddToHfile('} %s;\n' % type_name)
- self._type_map[type_name] = tpm_obj
-
-
- def _ProcessStructureOrUnion(self, type_name):
- """Processes spec tables describing structure and unions.
-
- Both of these object types share a lot of similarities. Union types have
- the word 'Union' in the table title.
-
- Args:
- type_name: a string, name of the TPM object type
- """
- union_mode = 'Union' in self._title
- if union_mode:
- tpm_obj = Union(type_name)
- else:
- tpm_obj = Structure(type_name)
- body_fields = []
- for row in self._body:
- if row[0].startswith('#'):
- tpm_obj.error_code = row[0][1:]
- continue
- if (len(row) < 2 or
- row[1].startswith('#') or
- row[0].startswith('//')):
- continue
- value = row[0]
- if value.endswith('='):
- value = value[:-1]
- tpm_obj.size_check = True
- if self._alg_macro.search(value):
- body_fields.extend(self._ExpandAlgs(row))
- continue
- array_size = None
- run_time_size = None
- vm = re.search(r'^(\S+)\s*\[(\S+)\]\s*\{(.*:*)\}', value)
- selector = ''
- if vm:
- value, run_time_size, bounds = vm.groups()
- lower, upper = [x.strip() for x in bounds.split(':')]
- if upper:
- array_size = upper
- tpm_obj.AddUpperBound(run_time_size, upper)
- else:
- array_size = run_time_size
- if lower:
- tpm_obj.AddLowerBound(run_time_size, lower)
- else:
- vm = re.search(r'^\[(\S+)\]\s*(\S+)', value)
- if vm:
- selector, value = vm.groups()
- else:
- vm = re.search(r'^(\S+)\s*\{(.+)\}', value)
- if vm:
- value, bounds = vm.groups()
- if ':' in bounds:
- lower, upper = [x.strip() for x in bounds.split(':')]
- if upper:
- tpm_obj.AddUpperBound(value, upper)
- if lower:
- tpm_obj.AddLowerBound(value, lower)
- if self._has_selector_column:
- selector = row[2]
- field_type = row[1]
- if field_type.startswith('+') or field_type.endswith('+'):
- field_type = field_type.strip('+')
- conditional = 'TRUE'
- else:
- conditional = 'FALSE'
- if field_type or value:
- body_fields.append(Field(field_type,
- value,
- array_size=array_size,
- run_time_size=run_time_size,
- selector=selector,
- conditional_value=conditional))
-
- self._StructOrUnionToHfile(body_fields, type_name, union_mode, tpm_obj)
-
- def _ProcessEnum(self, _):
- """Processes spec tables describing enums."""
- if self._skip_printing:
- return
- self._AddToHfile('enum {')
- for value, row in enumerate(self._body):
- self._AddToHfile(' %s = %d,' % (row[0], value + 1))
- self._AddToHfile('};\n')
-
- def _ProcessTypes(self, _):
- """Processes spec tables describing new types."""
- for type_, name_, _ in self._body:
- m = self._alg_macro.search(name_)
- if not m:
- self._AddTypedef(type_, name_)
- continue
- qualifier = [x for x in ('ECC', 'RSA') if x == type_.split('_')[-1]]
- alg_suffix = m.groups()[0]
- type_base = self._alg_macro.split(name_)[0]
- for alg_desc in self._PickAlgEntries(alg_suffix):
- if qualifier and alg_desc[2] != qualifier[0]:
- continue
- self._AddTypedef(type_, alg_desc[0].replace('TPM_ALG_', type_base))
- self._AddToHfile()
-
- def _ProcessConstants(self, type_name):
- """Processes spec tables describing constants."""
- if self._title_type:
- self._AddTypedef(self._title_type, type_name)
- constant_defs = []
- tpm_obj = ConstantType(self._title_type, type_name)
- for row in self._body:
- name = row[0].strip()
- if not name:
- continue
- if name.startswith('#'):
- tpm_obj.error_code = name[1:]
- continue
- if name == 'reserved' or len(row) < 2:
- continue
- value = row[1].strip()
- rm = re.match(r'^(\(.*?\))', value)
- if rm:
- value = '%s' % rm.groups()[0]
- else:
- v_list = value.split()
- if len(v_list) > 2 and v_list[1] == '+':
- value = '((%s)(%s))' % (type_name, ' '.join(v_list[:3]))
- if ' ' in value and not value.startswith('('):
- value = '(%s)' % value
- constant_defs.append([name, value])
- tpm_obj.valid_values.append(name)
- if self._title_type:
- self._type_map[type_name] = tpm_obj
- self._SetBaseType(self._title_type, tpm_obj)
- if self._skip_printing:
- return
- max_name_len, max_value_len = self._GetMaxLengths(constant_defs)
- for row in constant_defs:
- self._AddToHfile('#define %-*s %*s' % (max_name_len, row[0],
- max_value_len, row[1]))
- self._AddToHfile()
-
- def GetHFile(self):
- return self._h_file
-
- def GetCommandList(self):
- return sorted(self._command_map.values(),
- cmp=lambda x, y: cmp(x.name, y.name))
-
- def GetTypeMap(self):
- return self._type_map