blob: 48ffe36425ebdb0e8df219ea7cf9b55ee5ceb983 [file] [log] [blame]
#!/usr/bin/python
# Copyright (c) 2011 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.
#
# Originally written by Mario and Luigi at Google.
"""A code generator for TPM utility functions.
The generator inputs the Trousers header file "tpm.h" (here renamed
"tss_tpm_h") as well as massaged representation of TPM commands from
the TPM specs, and outputs marshalling/unmarshalling functions and
type declarations for the TPM structures and commands.
"""
import re, sys, os
# Global copyright header.
_COPYRIGHT_HEADER = """\
/* Copyright (c) 2011 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.
*/
"""
# Header file include guards.
_HEADER_FILE_GUARD_HEADER = """
#ifndef %(name)s
#define %(name)s
"""
_HEADER_FILE_GUARD_FOOTER = """
#endif /* %(name)s */
"""
# The tag name for the following structures does not follow the convention.
_STRUCTURE_TAG_EXCEPTIONS = dict(
TPM_SIGN_INFO="TPM_TAG_SIGNINFO",
TPM_CONTEXT_BLOB="TPM_TAG_CONTEXTBLOB",
TPM_DELEGATE_KEY_BLOB="TPM_TAG_DELG_KEY_BLOB")
# A dictionary of commands that are ignored.
IGNORED_COMMANDS = set(["TPM_FieldUpgrade", "TPM_CertifySelfTest"])
# A set of struct declarations that are ignored.
IGNORED_STRUCTS = set([
"TPM_VERSION_BYTE",
"TPM_NV_DATA_SENSITIVE",
"TPM_KEY_HANDLE_LIST"])
# Bytecodes
BC_INT8 = "BC_INT8"
BC_INT16 = "BC_INT16"
BC_INT32 = "BC_INT32"
BC_REF = "BC_REF"
BC_ARRAY = "BC_ARRAY"
BC_RECORD = "BC_RECORD"
BC_FIELD_KIND_NORMAL = "BC_FIELD_KIND_NORMAL"
BC_FIELD_KIND_VARIABLE = "BC_FIELD_KIND_VARIABLE"
# This variable keeps track of bytecode positions
BYTECODE_OFFSET = 0
# Structures whose bytecode offset is required in hand-written C code.
MANUALLY_MARSHALLED_STRUCTS = set([
"TPM_NONCE",
"TPM_NV_DATA_PUBLIC",
"TPM_PUBKEY",
"TPM_RSA_KEY_PARMS",
])
# Variable-length integers (varints) are encoded as 7-bit digits, most
# significant first (big endian, for readability). Each digit is stored in a
# byte. The most significant bit is 1 when there are more digits, 0 otherwise.
# For instance:
#
# 4 -> 0x04
# 257 -> 0x81, 0x01
#
# We can use varints only for known integer values, for instance bytecode
# offsets. A bunch of values are only known at C compilation time.
def IntToByteCode(x):
return IntToByteCode1(x / 128) + [x % 128]
def IntToByteCode1(x):
if x == 0:
return []
else:
return IntToByteCode1(x / 128) + [x % 128 + 128]
def OutputVarInt(x, file):
global BYTECODE_OFFSET
file.write("/* (%04d) varint: %d */" % (BYTECODE_OFFSET, x))
bytes = IntToByteCode(x)
file.write("".join(map(lambda x: " %d," % x, bytes)))
BYTECODE_OFFSET += len(bytes)
file.write("\n")
def OutputByte(byte, file):
global BYTECODE_OFFSET
file.write("/* (%04d) */ %s,\n" % (BYTECODE_OFFSET, str(byte)))
BYTECODE_OFFSET += 1
def OutputTwoBytes(x, file):
global BYTECODE_OFFSET
file.write("/* (%04d) */ TWO_BYTES_INT(%s),\n" % (BYTECODE_OFFSET, str(x)))
BYTECODE_OFFSET += 2
def OutputOffsetOf(field_name, record_name, file):
global BYTECODE_OFFSET
file.write("/* (%04d) */ OFFSETOF_TWO_BYTES(%s, %s),\n" %
(BYTECODE_OFFSET, field_name, record_name))
BYTECODE_OFFSET += 2
# We parse a C header file (MIDL, actually) and produce descriptors for each
# type defined by the header file. Then we use the descriptors to output
# useful code.
#
# (Before we go any further: confusion may arise in the uninitiated from the
# use of Python objects to describe C types. The Python objects have types
# themselves. To reduce the confusion we try to call them "classes" and
# "subclasses" since, luckily, that's what they are. We reserve the words
# "struct", "record", and "type" for the C types.)
#
# Every named type has a descriptor. Each kind of type (struct, typedef, etc)
# has an associated class, which is a subclass of TypeDesc. Other classes are
# used internally to type descriptors, as described below.
#
# There are four kinds of types: built-in types, types defined by typedef,
# types defined by a struct declaration, and pointers.
class TypeDesc(object):
"""Generic type desriptor."""
def __init__(self):
self.bytecode_offset = -1
def OutputByteCodeOffset(self, file):
OutputVarInt(self.bytecode_offset, file)
def OutputByteCodeRef(self, file):
assert self.bytecode_offset >= 0
OutputByte(BC_REF, file)
self.OutputByteCodeOffset(file)
class NamedTypeDesc(TypeDesc):
"""Desriptor for named types."""
def __init__(self, name):
super(NamedTypeDesc, self).__init__()
self.name = name
def Format(self):
return self.name
class BuiltInTypeDesc(NamedTypeDesc):
"""Desriptor for built-in types."""
def __init__(self, name, bytecode):
super(BuiltInTypeDesc, self).__init__(name)
self.bytecode = bytecode
def BaseType(self):
return self
def OutputByteCodeRef(self, file):
OutputByte(self.bytecode, file)
class TypedefDesc(NamedTypeDesc):
"""Types defined by another type (i.e. aliases)."""
def __init__(self, name, definition):
super(TypedefDesc, self).__init__(name)
self.definition = definition
def BaseType(self):
return self.definition.BaseType()
def OutputDeclarations(self, out_file):
# Type declaration only
out_file.write("typedef %s %s;\n" % (self.definition.name, self.name))
def OutputDefinitions(self, out_file):
pass
def OutputByteCode(self, out_file):
pass
def OutputByteCodeRef(self, out_file):
self.definition.OutputByteCodeRef(out_file)
class RecordDesc(NamedTypeDesc):
"""Descriptor for structs (also typedefs of structs, for simplicity)."""
def BaseType(self):
return self
def OutputByteCode(self, out_file):
if self.fields:
bytecode_offset = BYTECODE_OFFSET
out_file.write("/* Record: %s */\n" % self.name)
OutputByte(BC_RECORD, out_file)
OutputByte(len(self.fields), out_file)
for field in self.fields:
field.OutputByteCode(out_file)
self.bytecode_offset = bytecode_offset
def OutputDeclarations(self, out_file):
if self.fields:
self.OutputTypeDeclaration(out_file)
def OutputTypeDeclaration(self, out_file):
out_file.write("\ntypedef struct %s {\n" % self.name)
for field in self.fields:
field.OutputFieldDeclaration(out_file)
out_file.write("} %s;\n\n" % self.name)
def TagName(self):
if self.name in _STRUCTURE_TAG_EXCEPTIONS:
return _STRUCTURE_TAG_EXCEPTIONS[self.name]
else:
return "TPM_TAG_" + self.name[4:]
class FieldDesc(object):
"""A RecordDesc has a list of fields.
Each field is described by either a FieldDesc, a VarFieldDesc (for
variable-length fields), or an ImplicitVarFieldDesc (special case of
variable-length field where the length is defined implicitly by a
payload type).
"""
def __init__(self, record, index):
# RECORD is the containing record descriptor, used to emit code that lets
# the C compiler compute field offsets. INDEX is the position of the field
# in the record, used to find the size field for variable-length fields.
self.record = record
self.index = index
self.size_field = None
def OutputByteCode(self, out_file):
out_file.write("/* Field: %s */\n" % self.name)
OutputByte(BC_FIELD_KIND_NORMAL, out_file)
OutputOffsetOf(self.name, self.record.name, out_file)
self.type.OutputByteCodeRef(out_file)
def OutputFieldDeclaration(self, out_file):
out_file.write(" %s %s;\n" % (self.type.name, self.name))
class VarFieldDesc(FieldDesc):
"""Descriptor for variable-length fields."""
def OutputByteCode(self, out_file):
out_file.write("/* Variable-length field: %s */\n" % self.name)
OutputByte(BC_FIELD_KIND_VARIABLE, out_file)
OutputOffsetOf(self.name, self.record.name, out_file)
OutputByte(self.size_field.index, out_file)
self.type.OutputByteCodeRef(out_file)
def OutputFieldDeclaration(self, out_file):
out_file.write(" %s* %s;\n" % (self.type.name, self.name))
class ImplicitVarFieldDesc(VarFieldDesc):
"""Descriptor for implicit variable-length fields."""
pass
class ArrayFieldDesc(FieldDesc):
"""Descriptor for fixed-length array (e.g. TPM_SaveContext, TPM_NONCE)."""
def OutputFieldDeclaration(self, out_file):
out_file.write(" %s %s[%s];\n" % (self.element_type.name,
self.name,
self.length))
def OutputByteCode(self, out_file):
out_file.write("/* Array field: %s */\n" % self.name)
OutputByte(BC_ARRAY, out_file)
OutputTwoBytes(self.length, out_file)
self.element_type.OutputByteCodeRef(out_file)
class ArgDesc(object):
"""Descriptor for formal argument of a function."""
def __init__(self, argtype, name):
self.type = argtype
self.name = name
class PointerDesc(TypeDesc):
"""Pointer type (used in argument lists)."""
def __init__(self, base_type):
super(PointerDesc, self).__init__()
self.base_type = base_type
def Format(self):
return self.base_type.Format() + "*"
# The symbol table, i.e. a dictionary mapping type names to type descriptors.
# It is initialized here with the predefined types.
TYPES_DICT = dict(
BYTE=BuiltInTypeDesc("uint8_t", "BC_INT8"),
TSS_BOOL=BuiltInTypeDesc("uint8_t", "BC_INT8"),
BOOL=BuiltInTypeDesc("uint8_t", "BC_INT8"),
UINT16=BuiltInTypeDesc("uint16_t", "BC_INT16"),
UINT32=BuiltInTypeDesc("uint32_t", "BC_INT32"),
UINT64=BuiltInTypeDesc("uint64_t", "BC_INT64"),
APSession=BuiltInTypeDesc("APSession", "BC_APSESSION"),
TPM_RESULT=BuiltInTypeDesc("TPM_RESULT", "BC_INT32"),
int=BuiltInTypeDesc("int", "BC_INT32"),
)
class StructureParser(object):
"""Type structure parser.
"Doing It Right (TM)" would be overkill here. To parse the header file
"the right way" we would need a full C parser (MIDL, actually). So instead
we make heavy assumptions on the file format and the types we need to deal
with. Since the input is quite stable (no changes are expected), this
works well enough.
"""
# compile regular expressions
_STRUCT_RE = re.compile("^typedef\s+struct\s+td(\w+)")
_ENDSTRUCT_RE = re.compile("^}")
_TYPEDEF_RE = re.compile("^typedef\s+(\w+)\s+(\w+)")
# "type name" or "type name[...]" or "type *name"
_FIELD_RE = re.compile("^\s+(\w+(?:\s*[*])?)\s*(\w+)((?:[[].*[]])?)")
_SIZEIS_RE = re.compile("^\s+SIZEIS.(\w+)")
def Parse(self, filename):
"""Parses the TPM header file to extract structure information.
Args:
filename: Name of the TPM header file
Returns:
List of extracted type descriptors.
"""
types = []
header_file = open(filename)
for line in header_file:
match = self._STRUCT_RE.search(line)
if match:
name = match.group(1)
if name in IGNORED_STRUCTS:
continue
desc = RecordDesc(name)
TYPES_DICT[name] = desc
self.ParseRecord(header_file, desc)
types.append(desc)
continue
match = self._TYPEDEF_RE.search(line)
if match:
old_name = match.group(1)
new_name = match.group(2)
old_desc = TYPES_DICT[old_name]
desc = TypedefDesc(new_name, old_desc)
TYPES_DICT[new_name] = desc
types.append(desc)
continue
return types
def ParseRecord(self, in_file, record_desc):
"""Parses the body of a TPM struct declaration (all but the first line)."""
fields_list = []
i = 0
size_field_name = None
line = in_file.next() # skip open brace
while True:
line = in_file.next()
match = self._SIZEIS_RE.search(line)
if match:
size_field_name = match.group(1)
continue
match = self._FIELD_RE.search(line)
if match:
type_name = match.group(1) + match.group(3)
field_name = match.group(2)
field_desc = FieldDesc(record_desc, i)
field_desc.name = field_name
field_desc.type = type_name
if size_field_name:
size_field_index = next((f for f in xrange(len(fields_list))
if fields_list[f].name == size_field_name))
field_desc.size_field_index = size_field_index
size_field_name = None
fields_list.append(field_desc)
i = i + 1
continue
match = self._ENDSTRUCT_RE.search(line)
if match:
record_desc.fields = fields_list
return
class StructureGenerator(object):
"""TPM structure types and marshaling code generator."""
def Generate(self, types, filename_h, filename_c):
"""Generates the .c and .h file for the given types."""
# Declarations (.h file)
h = open(filename_h, "w")
h.write(_COPYRIGHT_HEADER)
guard_name = "TRUNKS_%s_" % filename_h.upper().replace(".", "_")
h.write(_HEADER_FILE_GUARD_HEADER % {"name": guard_name})
h.write("""
#include <stdint.h>
#include <string.h>
#include "trunks_tpm.h"
""")
for t in types:
t.OutputDeclarations(h)
h.write(_HEADER_FILE_GUARD_FOOTER % {"name": guard_name})
h.close()
# Bytecodes (.c file)
c = open(filename_c, "w")
c.write(_COPYRIGHT_HEADER)
c.write("""
#include <stdint.h>
#include <string.h>
#include "%s"
#include "trunks_internal.h"
#include "g_tpm_commands.h"
uint8_t StructureByteCodes[] = {
""" % filename_h)
for t in types:
t.OutputByteCode(c)
c.close()
class Command(object):
"""Descriptor for a TPM command."""
def __init__(self, name):
self.name = name
self.has_auth1 = False
self.has_auth2 = False
self.has_ins = False
self.has_outs = False
def OutputDeclarations(self, out_file):
self.request.OutputDeclarations(out_file)
self.response.OutputDeclarations(out_file)
out_file.write("\n")
self.OutputFunctionHeader(out_file, ";\n")
def OutputByteCode(self, out_file):
self.request.OutputByteCode(out_file)
self.response.OutputByteCode(out_file)
def OutputDefinitions(self, out_file):
self.OutputFunctionHeader(out_file, " {")
self.OutputFunctionBody(out_file)
def OutputFunctionHeader(self, out_file, suffix):
"""Outputs the function header for this command."""
out_file.write("""\
/* Sends a %s command to the TPM and reads the response. */
uint32_t Ttl_%s(%s)%s""" % (self.name, self.name, self.ArgList(), suffix))
def ArgList(self):
if self.args:
arg_list = map(lambda a: "%s %s" % (a.type.Format(), a.name), self.args)
return ", ".join(arg_list)
else:
return "void"
def OutputFunctionBody(self, out_file):
"""Outputs the function body for this command."""
body_template = """
%(initializers)s RETURN_ON_FAILURE(TtlRunCommand(%(ordinal)s,
%(rqu_bytecode)s, %(rsp_bytecode)s, in_parameters, out_parameters,
auth1, auth2, buffer, buffer_size));
return TPM_SUCCESS;
}
"""
initializers = ""
if not self.has_ins:
initializers += " void* in_parameters = NULL;\n"
if not self.has_outs:
initializers += " void* out_parameters = NULL;\n"
initializers += " uint8_t buffer[TPM_MAX_COMMAND_LENGTH];\n"
initializers += " int buffer_size = sizeof(buffer);\n"
if not self.has_auth1:
initializers += " void* auth1 = NULL;\n"
if not self.has_auth2:
initializers += " void* auth2 = NULL;\n"
# write function body
out_file.write(body_template % {
"initializers": initializers,
"ordinal": self.ordinal,
"rqu_bytecode": self.request.bytecode_offset,
"rsp_bytecode": self.response.bytecode_offset,
})
class CommandParser(object):
"""Command definition parser.
The text file is extracted from the PDF file containing the TPM
command specification from the Trusted Computing Group. The syntax
of the text file is ad-hoc.
"""
_LINE_SKIP_RE = re.compile("^(\s*$)|(^_COMMENT)")
_TYPE_RE = "(\w+(?:\s*[[].*[]])?)"
_COMMAND_RE = re.compile("^_TPM_COMMAND\s+(\w+)$")
_IN_PARAM_RE = re.compile("^_IN_PARAM\s+%s\s+(\w+)\s+(.*)$" % _TYPE_RE)
_OUT_PARAM_RE = re.compile("^_OUT_PARAM\s+%s\s+(\w+)\s+(.*)$" % _TYPE_RE)
# One line of lookahead
_line = None
def NextLine(self, in_file):
try:
while True:
self._line = in_file.next()
if not self._LINE_SKIP_RE.search(self._line):
break
except StopIteration:
self._line = None
def Parse(self, filename):
"""Parses a text version of the TPM command specification.
Args:
filename: Name of the TPM command specification file.
Returns:
List of extracted command descriptors.
"""
commands = []
f = open(filename)
self.NextLine(f)
while True:
cmd = self.ParseCommand(f)
if not cmd:
return commands
if cmd.name not in IGNORED_COMMANDS:
commands.append(cmd)
def ParseCommand(self, f):
"""Parses a TPM command structure."""
if not self._line:
return None
match = self._COMMAND_RE.search(self._line)
if not match:
print "cannot match command from line: %s\n" % self._line
name = match.group(1)
cmd = Command(name)
self.NextLine(f)
cmd.request = self.ParseCommandRR(f, self._IN_PARAM_RE, name + "_rqu")
cmd.response = self.ParseCommandRR(f, self._OUT_PARAM_RE, name + "_rsp")
assert ((cmd.request.fields and cmd.response.fields) or
cmd.name in IGNORED_COMMANDS)
return cmd
def ParseCommandRR(self, f, regexp, name):
"""Parses a request or response structure."""
fields = []
i = 0
record = RecordDesc(name)
while self._line:
match = regexp.search(self._line)
if not match:
break
field = FieldDesc(record, i)
field.name = match.group(2)
# For now assign the type name, not the descriptor, and resolve later.
# The type resolution also includes transforming a FIELD into a VARFIELD
# or ARRAYFIELD when applicable.
field.type = match.group(1)
field.description = match.group(3)
field.size_field_name = None
fields.append(field)
i = i + 1
self.NextLine(f)
record.fields = fields
return record
class Rewriter(object):
"""TPM type and command rewriter."""
_POINTER_RE = re.compile("^(\w+)\s*[*]$")
_ARRAY_RE = re.compile("^(\w+)\s*[[]\s*[]]$")
_FIXARRAY_RE = re.compile("^(\w+)\s*[[]\s*(\w+)\s*[]]$")
_TAG_RE = re.compile("^\s*(\w+)\s*$")
_ORD_RE = re.compile("^.*((TPM|TSC)_ORD_\w+).*$")
def Rewrite(self, commands):
for command in commands:
self.FixTypes(command.request)
self.FixTypes(command.response)
self.ExtractConstants(command)
self.FixRequestHeaderAndTrailer(command)
self.FixResponseHeaderAndTrailer(command)
self.ComputeCommandArgs(command)
def FixTypes(self, record):
"""Fixes the given command structures.
Args:
record: structure to be fixed.
The following modifications are applied:
1. Replace type names in fields with their type descriptors
2. Change Fields into VarFields as applicable.
3. Change Fields into ArrayFields as applicable.
"""
if not isinstance(record, RecordDesc):
return
new_fields = []
previous_old_field = None
previous_new_field = None
for field in record.fields:
match = Rewriter._POINTER_RE.match(field.type)
if not match:
match = Rewriter._ARRAY_RE.match(field.type)
if match:
new_field = VarFieldDesc(record, field.index)
new_field.name = field.name
new_field.type = TYPES_DICT[match.group(1)]
new_field.size_field = previous_new_field
else:
match = Rewriter._FIXARRAY_RE.match(field.type)
if match:
new_field = ArrayFieldDesc(record, field.index)
element_type = TYPES_DICT[match.group(1)]
new_field.element_type = element_type
new_field.name = field.name
new_field.length = match.group(2)
else:
new_field = field # recycle
new_field.type = TYPES_DICT[field.type]
new_fields.append(new_field)
previous_old_field = field
previous_new_field = new_field
record.fields = new_fields
def ExtractConstants(self, cmd):
"""Extracts the command tag and ordinal."""
match = Rewriter._TAG_RE.search(cmd.request.fields[0].description)
if match:
cmd.tag = match.group(1)
match = Rewriter._ORD_RE.search(cmd.request.fields[2].description)
if match:
cmd.ordinal = match.group(1)
if not cmd.tag or not cmd.ordinal:
print "Could not extract tag or ordinal for command %s" % cmd.name
def FixFields(self, fields, len):
fields = fields[3:len]
for field in fields:
field.index -= 3
return fields
def FixRequestHeaderAndTrailer(self, cmd):
"""Fixes the request header and trailer according to the command type."""
req_params_len = len(cmd.request.fields)
if cmd.tag == "TPM_TAG_RQU_AUTH2_COMMAND":
req_params_len -= 10
cmd.has_auth1 = True
cmd.has_auth2 = True
elif cmd.tag == "TPM_TAG_RQU_AUTH1_COMMAND":
req_params_len -= 5
cmd.has_auth1 = True
# remove first three fields
cmd.request.fields = self.FixFields(cmd.request.fields, req_params_len)
cmd.has_ins = len(cmd.request.fields) > 0
def FixResponseHeaderAndTrailer(self, cmd):
"""Fixes the response header and trailer according to the command type."""
rsp_params_len = len(cmd.response.fields)
if cmd.tag == "TPM_TAG_RQU_AUTH2_COMMAND":
rsp_params_len -= 6
elif cmd.tag == "TPM_TAG_RQU_AUTH1_COMMAND":
rsp_params_len -= 3
cmd.response.fields = self.FixFields(cmd.response.fields, rsp_params_len)
cmd.has_outs = len(cmd.response.fields) > 0
def ComputeCommandArgs(self, cmd):
"""Generates the argument list for the given command."""
cmd.args = []
if cmd.has_ins:
cmd.args.append(ArgDesc(PointerDesc(cmd.request), "in_parameters"))
if cmd.has_outs:
cmd.args.append(ArgDesc(PointerDesc(cmd.response), "out_parameters"))
cmd.args.append(ArgDesc(PointerDesc(TYPES_DICT["BYTE"]), "buffer"))
cmd.args.append(ArgDesc(TYPES_DICT["int"], "buffer_size"))
if cmd.has_auth1:
cmd.args.append(ArgDesc(PointerDesc(TYPES_DICT["APSession"]), "auth1"))
if cmd.has_auth2:
cmd.args.append(ArgDesc(PointerDesc(TYPES_DICT["APSession"]), "auth2"))
class CommandGenerator(object):
"""TPM command types and marshaling code generator."""
def Generate(self, commands, filename_h, filename_b, filename_c):
"""Generates the .c and .h file for the given commands."""
h = open(filename_h, "w")
h.write(_COPYRIGHT_HEADER)
guard_name = "TRUNKS_%s_" % filename_h.upper().replace(".", "_")
h.write(_HEADER_FILE_GUARD_HEADER % {"name": guard_name})
h.write("""
#include "g_tpm_structures.h"
#include "trunks_internal.h"
""")
b = open(filename_b, "a")
b.write("\n\n/* Command Structures (request and response) */\n\n")
c = open(filename_c, "w")
c.write(_COPYRIGHT_HEADER)
c.write("""
#include "%s"
""" % filename_h)
# Output addresses of bytecodes for some struct types.
for name in MANUALLY_MARSHALLED_STRUCTS:
struct = TYPES_DICT[name]
h.write("#define TTL_%s_BYTECODE_OFFSET %d\n" %
(name, struct.bytecode_offset))
h.write("\n")
# Output commands.
for command in commands:
command.OutputDeclarations(h)
command.OutputByteCode(b)
command.OutputDefinitions(c)
h.write(_HEADER_FILE_GUARD_FOOTER % {"name": guard_name})
h.close()
b.write("};\n")
b.close()
c.close()
def Run():
tpm_structures = StructureParser().Parse("tss_tpm_h")
for structure in tpm_structures:
Rewriter().FixTypes(structure)
StructureGenerator().Generate(
tpm_structures, "g_tpm_structures.h", "g_tpm_structures.c")
tpm_commands = CommandParser().Parse("g_tpm_commands_structure.txt")
Rewriter().Rewrite(tpm_commands)
CommandGenerator().Generate(tpm_commands, "g_tpm_commands.h",
"g_tpm_structures.c", "g_tpm_commands.c")
def Test():
print "no tests yet"
exit(1)
# main program
if __name__ == "__main__":
if len(sys.argv) == 1:
Run()
elif len(sys.argv) == 2 and sys.argv[1] == "test":
Test()
else:
sys.stderr.write("usage: %s [test]\n" % sys.argv[0])
exit(1)