generator.py revision 4dc4629c415e7ca90ff146d7bb75b5646ecd8b17
1#!/usr/bin/python2 2 3# 4# Copyright (C) 2014 The Android Open Source Project 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18 19"""A code generator for TPM 2.0 structures and commands. 20 21The generator takes as input a structures file as emitted by the 22extract_structures.sh script and a commands file as emitted by the 23extract_commands.sh script. It outputs valid C++ into tpm_generated.{h,cc}. 24 25The input grammar is documented in the extract_* scripts. Sample input for 26structures looks like this: 27_BEGIN_TYPES 28_OLD_TYPE UINT32 29_NEW_TYPE TPM_HANDLE 30_END 31_BEGIN_CONSTANTS 32_CONSTANTS (UINT32) TPM_SPEC 33_TYPE UINT32 34_NAME TPM_SPEC_FAMILY 35_VALUE 0x322E3000 36_NAME TPM_SPEC_LEVEL 37_VALUE 00 38_END 39_BEGIN_STRUCTURES 40_STRUCTURE TPMS_TIME_INFO 41_TYPE UINT64 42_NAME time 43_TYPE TPMS_CLOCK_INFO 44_NAME clockInfo 45_END 46 47Sample input for commands looks like this: 48_BEGIN 49_INPUT_START TPM2_Startup 50_TYPE TPMI_ST_COMMAND_TAG 51_NAME tag 52_COMMENT TPM_ST_NO_SESSIONS 53_TYPE UINT32 54_NAME commandSize 55_TYPE TPM_CC 56_NAME commandCode 57_COMMENT TPM_CC_Startup {NV} 58_TYPE TPM_SU 59_NAME startupType 60_COMMENT TPM_SU_CLEAR or TPM_SU_STATE 61_OUTPUT_START TPM2_Startup 62_TYPE TPM_ST 63_NAME tag 64_COMMENT see clause 8 65_TYPE UINT32 66_NAME responseSize 67_TYPE TPM_RC 68_NAME responseCode 69_END 70""" 71 72from __future__ import print_function 73 74import argparse 75import re 76import subprocess 77 78import union_selectors 79 80_BASIC_TYPES = ['uint8_t', 'int8_t', 'int', 'uint16_t', 'int16_t', 81 'uint32_t', 'int32_t', 'uint64_t', 'int64_t'] 82_OUTPUT_FILE_H = 'tpm_generated.h' 83_OUTPUT_FILE_CC = 'tpm_generated.cc' 84_COPYRIGHT_HEADER = ( 85 '//\n' 86 '// Copyright (C) 2015 The Android Open Source Project\n' 87 '//\n' 88 '// Licensed under the Apache License, Version 2.0 (the "License");\n' 89 '// you may not use this file except in compliance with the License.\n' 90 '// You may obtain a copy of the License at\n' 91 '//\n' 92 '// http://www.apache.org/licenses/LICENSE-2.0\n' 93 '//\n' 94 '// Unless required by applicable law or agreed to in writing, software\n' 95 '// distributed under the License is distributed on an "AS IS" BASIS,\n' 96 '// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or ' 97 'implied.\n' 98 '// See the License for the specific language governing permissions and\n' 99 '// limitations under the License.\n' 100 '//\n\n' 101 '// THIS CODE IS GENERATED - DO NOT MODIFY!\n') 102_HEADER_FILE_GUARD_HEADER = """ 103#ifndef %(name)s 104#define %(name)s 105""" 106_HEADER_FILE_GUARD_FOOTER = """ 107#endif // %(name)s 108""" 109_HEADER_FILE_INCLUDES = """ 110#include <string> 111 112#include <base/callback_forward.h> 113#include <base/macros.h> 114 115#include "trunks/trunks_export.h" 116""" 117_IMPLEMENTATION_FILE_INCLUDES = """ 118#include <string> 119 120#include <base/bind.h> 121#include <base/callback.h> 122#include <base/logging.h> 123#include <base/macros.h> 124#include <base/stl_util.h> 125#include <base/strings/string_number_conversions.h> 126#include <base/sys_byteorder.h> 127#include <crypto/secure_hash.h> 128 129#include "trunks/authorization_delegate.h" 130#include "trunks/command_transceiver.h" 131#include "trunks/error_codes.h" 132 133""" 134_LOCAL_INCLUDE = """ 135#include "trunks/%(filename)s" 136""" 137_NAMESPACE_BEGIN = """ 138namespace trunks { 139""" 140_NAMESPACE_END = """ 141} // namespace trunks 142""" 143_FORWARD_DECLARATIONS = """ 144class AuthorizationDelegate; 145class CommandTransceiver; 146""" 147_FUNCTION_DECLARATIONS = """ 148TRUNKS_EXPORT size_t GetNumberOfRequestHandles(TPM_CC command_code); 149TRUNKS_EXPORT size_t GetNumberOfResponseHandles(TPM_CC command_code); 150""" 151_CLASS_BEGIN = """ 152class TRUNKS_EXPORT Tpm { 153 public: 154 // Does not take ownership of |transceiver|. 155 explicit Tpm(CommandTransceiver* transceiver) : transceiver_(transceiver) {} 156 virtual ~Tpm() {} 157 158""" 159_CLASS_END = """ 160 private: 161 CommandTransceiver* transceiver_; 162 163 DISALLOW_COPY_AND_ASSIGN(Tpm); 164}; 165""" 166_SERIALIZE_BASIC_TYPE = """ 167TPM_RC Serialize_%(type)s(const %(type)s& value, std::string* buffer) { 168 VLOG(3) << __func__; 169 %(type)s value_net = value; 170 switch (sizeof(%(type)s)) { 171 case 2: 172 value_net = base::HostToNet16(value); 173 break; 174 case 4: 175 value_net = base::HostToNet32(value); 176 break; 177 case 8: 178 value_net = base::HostToNet64(value); 179 break; 180 default: 181 break; 182 } 183 const char* value_bytes = reinterpret_cast<const char*>(&value_net); 184 buffer->append(value_bytes, sizeof(%(type)s)); 185 return TPM_RC_SUCCESS; 186} 187 188TPM_RC Parse_%(type)s( 189 std::string* buffer, 190 %(type)s* value, 191 std::string* value_bytes) { 192 VLOG(3) << __func__; 193 if (buffer->size() < sizeof(%(type)s)) 194 return TPM_RC_INSUFFICIENT; 195 %(type)s value_net = 0; 196 memcpy(&value_net, buffer->data(), sizeof(%(type)s)); 197 switch (sizeof(%(type)s)) { 198 case 2: 199 *value = base::NetToHost16(value_net); 200 break; 201 case 4: 202 *value = base::NetToHost32(value_net); 203 break; 204 case 8: 205 *value = base::NetToHost64(value_net); 206 break; 207 default: 208 *value = value_net; 209 } 210 if (value_bytes) { 211 value_bytes->append(buffer->substr(0, sizeof(%(type)s))); 212 } 213 buffer->erase(0, sizeof(%(type)s)); 214 return TPM_RC_SUCCESS; 215} 216""" 217_SERIALIZE_DECLARATION = """ 218TRUNKS_EXPORT TPM_RC Serialize_%(type)s( 219 const %(type)s& value, 220 std::string* buffer); 221 222TRUNKS_EXPORT TPM_RC Parse_%(type)s( 223 std::string* buffer, 224 %(type)s* value, 225 std::string* value_bytes); 226""" 227 228_SIMPLE_TPM2B_HELPERS_DECLARATION = """ 229TRUNKS_EXPORT %(type)s Make_%(type)s( 230 const std::string& bytes); 231TRUNKS_EXPORT std::string StringFrom_%(type)s( 232 const %(type)s& tpm2b); 233""" 234_COMPLEX_TPM2B_HELPERS_DECLARATION = """ 235TRUNKS_EXPORT %(type)s Make_%(type)s( 236 const %(inner_type)s& inner); 237""" 238 239_HANDLE_COUNT_FUNCTION_START = """ 240size_t GetNumberOf%(handle_type)sHandles(TPM_CC command_code) { 241 switch (command_code) {""" 242_HANDLE_COUNT_FUNCTION_CASE = """ 243 case %(command_code)s: return %(handle_count)s;""" 244_HANDLE_COUNT_FUNCTION_END = """ 245 default: LOG(WARNING) << "Unknown command code: " << command_code; 246 } 247 return 0; 248} 249""" 250 251def FixName(name): 252 """Fixes names to conform to Chromium style.""" 253 # Handle names with array notation. E.g. 'myVar[10]' is grouped as 'myVar' and 254 # '[10]'. 255 match = re.search(r'([^\[]*)(\[.*\])*', name) 256 # Transform the name to Chromium style. E.g. 'myVarAgain' becomes 257 # 'my_var_again'. 258 fixed_name = re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', match.group(1)).lower() 259 return fixed_name + match.group(2) if match.group(2) else fixed_name 260 261 262def IsTPM2B(name): 263 return name.startswith('TPM2B_') 264 265 266def GetCppBool(condition): 267 if condition: 268 return 'true' 269 return 'false' 270 271 272class Typedef(object): 273 """Represents a TPM typedef. 274 275 Attributes: 276 old_type: The existing type in a typedef statement. 277 new_type: The new type in a typedef statement. 278 """ 279 280 _TYPEDEF = 'typedef %(old_type)s %(new_type)s;\n' 281 _SERIALIZE_FUNCTION = """ 282TPM_RC Serialize_%(new)s( 283 const %(new)s& value, 284 std::string* buffer) { 285 VLOG(3) << __func__; 286 return Serialize_%(old)s(value, buffer); 287} 288""" 289 _PARSE_FUNCTION = """ 290TPM_RC Parse_%(new)s( 291 std::string* buffer, 292 %(new)s* value, 293 std::string* value_bytes) { 294 VLOG(3) << __func__; 295 return Parse_%(old)s(buffer, value, value_bytes); 296} 297""" 298 299 def __init__(self, old_type, new_type): 300 """Initializes a Typedef instance. 301 302 Args: 303 old_type: The existing type in a typedef statement. 304 new_type: The new type in a typedef statement. 305 """ 306 self.old_type = old_type 307 self.new_type = new_type 308 309 def OutputForward(self, out_file, defined_types, typemap): 310 """Writes a typedef definition to |out_file|. 311 312 Any outstanding dependencies will be forward declared. This method is the 313 same as Output() because forward declarations do not apply for typedefs. 314 315 Args: 316 out_file: The output file. 317 defined_types: A set of types for which definitions have already been 318 generated. 319 typemap: A dict mapping type names to the corresponding object. 320 """ 321 self.Output(out_file, defined_types, typemap) 322 323 def Output(self, out_file, defined_types, typemap): 324 """Writes a typedef definition to |out_file|. 325 326 Any outstanding dependencies will be forward declared. 327 328 Args: 329 out_file: The output file. 330 defined_types: A set of types for which definitions have already been 331 generated. 332 typemap: A dict mapping type names to the corresponding object. 333 """ 334 if self.new_type in defined_types: 335 return 336 # Make sure the dependency is already defined. 337 if self.old_type not in defined_types: 338 typemap[self.old_type].OutputForward(out_file, defined_types, typemap) 339 out_file.write(self._TYPEDEF % {'old_type': self.old_type, 340 'new_type': self.new_type}) 341 defined_types.add(self.new_type) 342 343 def OutputSerialize(self, out_file, serialized_types, typemap): 344 """Writes a serialize and parse function for the typedef to |out_file|. 345 346 Args: 347 out_file: The output file. 348 serialized_types: A set of types for which serialize and parse functions 349 have already been generated. 350 typemap: A dict mapping type names to the corresponding object. 351 """ 352 if self.new_type in serialized_types: 353 return 354 if self.old_type not in serialized_types: 355 typemap[self.old_type].OutputSerialize(out_file, serialized_types, 356 typemap) 357 out_file.write(self._SERIALIZE_FUNCTION % {'old': self.old_type, 358 'new': self.new_type}) 359 out_file.write(self._PARSE_FUNCTION % {'old': self.old_type, 360 'new': self.new_type}) 361 serialized_types.add(self.new_type) 362 363 364class Constant(object): 365 """Represents a TPM constant. 366 367 Attributes: 368 const_type: The type of the constant (e.g. 'int'). 369 name: The name of the constant (e.g. 'kMyConstant'). 370 value: The value of the constant (e.g. '7'). 371 """ 372 373 _CONSTANT = 'const %(type)s %(name)s = %(value)s;\n' 374 375 def __init__(self, const_type, name, value): 376 """Initializes a Constant instance. 377 378 Args: 379 const_type: The type of the constant (e.g. 'int'). 380 name: The name of the constant (e.g. 'kMyConstant'). 381 value: The value of the constant (e.g. '7'). 382 """ 383 self.const_type = const_type 384 self.name = name 385 self.value = value 386 387 def Output(self, out_file, defined_types, typemap): 388 """Writes a constant definition to |out_file|. 389 390 Any outstanding dependencies will be forward declared. 391 392 Args: 393 out_file: The output file. 394 defined_types: A set of types for which definitions have already been 395 generated. 396 typemap: A dict mapping type names to the corresponding object. 397 """ 398 # Make sure the dependency is already defined. 399 if self.const_type not in defined_types: 400 typemap[self.const_type].OutputForward(out_file, defined_types, typemap) 401 out_file.write(self._CONSTANT % {'type': self.const_type, 402 'name': self.name, 403 'value': self.value}) 404 405 406class Structure(object): 407 """Represents a TPM structure or union. 408 409 Attributes: 410 name: The name of the structure. 411 is_union: A boolean indicating whether this is a union. 412 fields: A list of (type, name) tuples representing the struct fields. 413 depends_on: A list of strings for types this struct depends on other than 414 field types. See AddDependency() for more details. 415 """ 416 417 _STRUCTURE = 'struct %(name)s {\n' 418 _STRUCTURE_FORWARD = 'struct %(name)s;\n' 419 _UNION = 'union %(name)s {\n' 420 _UNION_FORWARD = 'union %(name)s;\n' 421 _STRUCTURE_END = '};\n\n' 422 _STRUCTURE_FIELD = ' %(type)s %(name)s;\n' 423 _SERIALIZE_FUNCTION_START = """ 424TPM_RC Serialize_%(type)s( 425 const %(type)s& value, 426 std::string* buffer) { 427 TPM_RC result = TPM_RC_SUCCESS; 428 VLOG(3) << __func__; 429""" 430 _SERIALIZE_FIELD = """ 431 result = Serialize_%(type)s(value.%(name)s, buffer); 432 if (result) { 433 return result; 434 } 435""" 436 _SERIALIZE_FIELD_ARRAY = """ 437 if (arraysize(value.%(name)s) < value.%(count)s) { 438 return TPM_RC_INSUFFICIENT; 439 } 440 for (uint32_t i = 0; i < value.%(count)s; ++i) { 441 result = Serialize_%(type)s(value.%(name)s[i], buffer); 442 if (result) { 443 return result; 444 } 445 } 446""" 447 _SERIALIZE_FIELD_WITH_SELECTOR = """ 448 result = Serialize_%(type)s( 449 value.%(name)s, 450 value.%(selector_name)s, 451 buffer); 452 if (result) { 453 return result; 454 } 455""" 456 _SERIALIZE_COMPLEX_TPM2B = """ 457 std::string field_bytes; 458 result = Serialize_%(type)s(value.%(name)s, &field_bytes); 459 if (result) { 460 return result; 461 } 462 std::string size_bytes; 463 result = Serialize_UINT16(field_bytes.size(), &size_bytes); 464 if (result) { 465 return result; 466 } 467 buffer->append(size_bytes + field_bytes); 468""" 469 _PARSE_FUNCTION_START = """ 470TPM_RC Parse_%(type)s( 471 std::string* buffer, 472 %(type)s* value, 473 std::string* value_bytes) { 474 TPM_RC result = TPM_RC_SUCCESS; 475 VLOG(3) << __func__; 476""" 477 _PARSE_FIELD = """ 478 result = Parse_%(type)s( 479 buffer, 480 &value->%(name)s, 481 value_bytes); 482 if (result) { 483 return result; 484 } 485""" 486 _PARSE_FIELD_ARRAY = """ 487 if (arraysize(value->%(name)s) < value->%(count)s) { 488 return TPM_RC_INSUFFICIENT; 489 } 490 for (uint32_t i = 0; i < value->%(count)s; ++i) { 491 result = Parse_%(type)s( 492 buffer, 493 &value->%(name)s[i], 494 value_bytes); 495 if (result) { 496 return result; 497 } 498 } 499""" 500 _PARSE_FIELD_WITH_SELECTOR = """ 501 result = Parse_%(type)s( 502 buffer, 503 value->%(selector_name)s, 504 &value->%(name)s, 505 value_bytes); 506 if (result) { 507 return result; 508 } 509""" 510 _SERIALIZE_FUNCTION_END = ' return result;\n}\n' 511 _ARRAY_FIELD_RE = re.compile(r'(.*)\[(.*)\]') 512 _ARRAY_FIELD_SIZE_RE = re.compile(r'^(count|size)') 513 _UNION_TYPE_RE = re.compile(r'^TPMU_.*') 514 _SERIALIZE_UNION_FUNCTION_START = """ 515TPM_RC Serialize_%(union_type)s( 516 const %(union_type)s& value, 517 %(selector_type)s selector, 518 std::string* buffer) { 519 TPM_RC result = TPM_RC_SUCCESS; 520 VLOG(3) << __func__; 521""" 522 _SERIALIZE_UNION_FIELD = """ 523 if (selector == %(selector_value)s) { 524 result = Serialize_%(field_type)s(value.%(field_name)s, buffer); 525 if (result) { 526 return result; 527 } 528 } 529""" 530 _SERIALIZE_UNION_FIELD_ARRAY = """ 531 if (selector == %(selector_value)s) { 532 if (arraysize(value.%(field_name)s) < %(count)s) { 533 return TPM_RC_INSUFFICIENT; 534 } 535 for (uint32_t i = 0; i < %(count)s; ++i) { 536 result = Serialize_%(field_type)s(value.%(field_name)s[i], buffer); 537 if (result) { 538 return result; 539 } 540 } 541 } 542""" 543 _PARSE_UNION_FUNCTION_START = """ 544TPM_RC Parse_%(union_type)s( 545 std::string* buffer, 546 %(selector_type)s selector, 547 %(union_type)s* value, 548 std::string* value_bytes) { 549 TPM_RC result = TPM_RC_SUCCESS; 550 VLOG(3) << __func__; 551""" 552 _PARSE_UNION_FIELD = """ 553 if (selector == %(selector_value)s) { 554 result = Parse_%(field_type)s( 555 buffer, 556 &value->%(field_name)s, 557 value_bytes); 558 if (result) { 559 return result; 560 } 561 } 562""" 563 _PARSE_UNION_FIELD_ARRAY = """ 564 if (selector == %(selector_value)s) { 565 if (arraysize(value->%(field_name)s) < %(count)s) { 566 return TPM_RC_INSUFFICIENT; 567 } 568 for (uint32_t i = 0; i < %(count)s; ++i) { 569 result = Parse_%(field_type)s( 570 buffer, 571 &value->%(field_name)s[i], 572 value_bytes); 573 if (result) { 574 return result; 575 } 576 } 577 } 578""" 579 _EMPTY_UNION_CASE = """ 580 if (selector == %(selector_value)s) { 581 // Do nothing. 582 } 583""" 584 _SIMPLE_TPM2B_HELPERS = """ 585%(type)s Make_%(type)s( 586 const std::string& bytes) { 587 %(type)s tpm2b; 588 CHECK(bytes.size() <= sizeof(tpm2b.%(buffer_name)s)); 589 memset(&tpm2b, 0, sizeof(%(type)s)); 590 tpm2b.size = bytes.size(); 591 memcpy(tpm2b.%(buffer_name)s, bytes.data(), bytes.size()); 592 return tpm2b; 593} 594 595std::string StringFrom_%(type)s( 596 const %(type)s& tpm2b) { 597 const char* char_buffer = reinterpret_cast<const char*>( 598 tpm2b.%(buffer_name)s); 599 return std::string(char_buffer, tpm2b.size); 600} 601""" 602 _COMPLEX_TPM2B_HELPERS = """ 603%(type)s Make_%(type)s( 604 const %(inner_type)s& inner) { 605 %(type)s tpm2b; 606 tpm2b.size = sizeof(%(inner_type)s); 607 tpm2b.%(inner_name)s = inner; 608 return tpm2b; 609} 610""" 611 612 def __init__(self, name, is_union): 613 """Initializes a Structure instance. 614 615 Initially the instance will have no fields and no dependencies. Those can be 616 added with the AddField() and AddDependency() methods. 617 618 Args: 619 name: The name of the structure. 620 is_union: A boolean indicating whether this is a union. 621 """ 622 self.name = name 623 self.is_union = is_union 624 self.fields = [] 625 self.depends_on = [] 626 self._forwarded = False 627 628 def AddField(self, field_type, field_name): 629 """Adds a field for this struct. 630 631 Args: 632 field_type: The type of the field. 633 field_name: The name of the field. 634 """ 635 self.fields.append((field_type, FixName(field_name))) 636 637 def AddDependency(self, required_type): 638 """Adds an explicit dependency on another type. 639 640 This is used in cases where there is an additional dependency other than the 641 field types, which are implicit dependencies. For example, a field like 642 FIELD_TYPE value[sizeof(OTHER_TYPE)] would need OTHER_TYPE to be already 643 declared. 644 645 Args: 646 required_type: The type this structure depends on. 647 """ 648 self.depends_on.append(required_type) 649 650 def IsSimpleTPM2B(self): 651 """Returns whether this struct is a TPM2B structure with raw bytes.""" 652 return self.name.startswith('TPM2B_') and self.fields[1][0] == 'BYTE' 653 654 def IsComplexTPM2B(self): 655 """Returns whether this struct is a TPM2B structure with an inner struct.""" 656 return self.name.startswith('TPM2B_') and self.fields[1][0] != 'BYTE' 657 658 def _GetFieldTypes(self): 659 """Creates a set which holds all current field types. 660 661 Returns: 662 A set of field types. 663 """ 664 return set([field[0] for field in self.fields]) 665 666 def OutputForward(self, out_file, unused_defined_types, unused_typemap): 667 """Writes a structure forward declaration to |out_file|. 668 669 This method needs to match the OutputForward method in other type classes 670 (e.g. Typedef) which is why the unused_* args exist. 671 672 Args: 673 out_file: The output file. 674 unused_defined_types: Not used. 675 unused_typemap: Not used. 676 """ 677 if self._forwarded: 678 return 679 if self.is_union: 680 out_file.write(self._UNION_FORWARD % {'name': self.name}) 681 else: 682 out_file.write(self._STRUCTURE_FORWARD % {'name': self.name}) 683 self._forwarded = True 684 685 def Output(self, out_file, defined_types, typemap): 686 """Writes a structure definition to |out_file|. 687 688 Any outstanding dependencies will be defined. 689 690 Args: 691 out_file: The output file. 692 defined_types: A set of types for which definitions have already been 693 generated. 694 typemap: A dict mapping type names to the corresponding object. 695 """ 696 if self.name in defined_types: 697 return 698 # Make sure any dependencies are already defined. 699 for field_type in self._GetFieldTypes(): 700 if field_type not in defined_types: 701 typemap[field_type].Output(out_file, defined_types, typemap) 702 for required_type in self.depends_on: 703 if required_type not in defined_types: 704 typemap[required_type].Output(out_file, defined_types, typemap) 705 if self.is_union: 706 out_file.write(self._UNION % {'name': self.name}) 707 else: 708 out_file.write(self._STRUCTURE % {'name': self.name}) 709 for field in self.fields: 710 out_file.write(self._STRUCTURE_FIELD % {'type': field[0], 711 'name': field[1]}) 712 out_file.write(self._STRUCTURE_END) 713 defined_types.add(self.name) 714 715 def OutputSerialize(self, out_file, serialized_types, typemap): 716 """Writes serialize and parse functions for a structure to |out_file|. 717 718 Args: 719 out_file: The output file. 720 serialized_types: A set of types for which serialize and parse functions 721 have already been generated. This type name of this structure will be 722 added on success. 723 typemap: A dict mapping type names to the corresponding object. 724 """ 725 if (self.name in serialized_types or 726 self.name == 'TPMU_NAME' or 727 self.name == 'TPMU_ENCRYPTED_SECRET'): 728 return 729 # Make sure any dependencies already have serialize functions defined. 730 for field_type in self._GetFieldTypes(): 731 if field_type not in serialized_types: 732 typemap[field_type].OutputSerialize(out_file, serialized_types, typemap) 733 if self.is_union: 734 self._OutputUnionSerialize(out_file) 735 serialized_types.add(self.name) 736 return 737 out_file.write(self._SERIALIZE_FUNCTION_START % {'type': self.name}) 738 if self.IsComplexTPM2B(): 739 field_type = self.fields[1][0] 740 field_name = self.fields[1][1] 741 out_file.write(self._SERIALIZE_COMPLEX_TPM2B % {'type': field_type, 742 'name': field_name}) 743 else: 744 for field in self.fields: 745 if self._ARRAY_FIELD_RE.search(field[1]): 746 self._OutputArrayField(out_file, field, self._SERIALIZE_FIELD_ARRAY) 747 elif self._UNION_TYPE_RE.search(field[0]): 748 self._OutputUnionField(out_file, field, 749 self._SERIALIZE_FIELD_WITH_SELECTOR) 750 else: 751 out_file.write(self._SERIALIZE_FIELD % {'type': field[0], 752 'name': field[1]}) 753 out_file.write(self._SERIALIZE_FUNCTION_END) 754 out_file.write(self._PARSE_FUNCTION_START % {'type': self.name}) 755 for field in self.fields: 756 if self._ARRAY_FIELD_RE.search(field[1]): 757 self._OutputArrayField(out_file, field, self._PARSE_FIELD_ARRAY) 758 elif self._UNION_TYPE_RE.search(field[0]): 759 self._OutputUnionField(out_file, field, self._PARSE_FIELD_WITH_SELECTOR) 760 else: 761 out_file.write(self._PARSE_FIELD % {'type': field[0], 762 'name': field[1]}) 763 out_file.write(self._SERIALIZE_FUNCTION_END) 764 # If this is a TPM2B structure throw in a few convenience functions. 765 if self.IsSimpleTPM2B(): 766 field_name = self._ARRAY_FIELD_RE.search(self.fields[1][1]).group(1) 767 out_file.write(self._SIMPLE_TPM2B_HELPERS % {'type': self.name, 768 'buffer_name': field_name}) 769 elif self.IsComplexTPM2B(): 770 field_type = self.fields[1][0] 771 field_name = self.fields[1][1] 772 out_file.write(self._COMPLEX_TPM2B_HELPERS % {'type': self.name, 773 'inner_type': field_type, 774 'inner_name': field_name}) 775 serialized_types.add(self.name) 776 777 def _OutputUnionSerialize(self, out_file): 778 """Writes serialize and parse functions for a union to |out_file|. 779 780 This is more complex than the struct case because only one field of the 781 union is serialized / parsed based on the value of a selector. Arrays are 782 also handled differently: the full size of the array is serialized instead 783 of looking for a field which specifies the count. 784 785 Args: 786 out_file: The output file 787 """ 788 selector_type = union_selectors.GetUnionSelectorType(self.name) 789 selector_values = union_selectors.GetUnionSelectorValues(self.name) 790 field_types = {f[1]: f[0] for f in self.fields} 791 out_file.write(self._SERIALIZE_UNION_FUNCTION_START % 792 {'union_type': self.name, 'selector_type': selector_type}) 793 for selector in selector_values: 794 field_name = FixName(union_selectors.GetUnionSelectorField(self.name, 795 selector)) 796 if not field_name: 797 out_file.write(self._EMPTY_UNION_CASE % {'selector_value': selector}) 798 continue 799 field_type = field_types[field_name] 800 array_match = self._ARRAY_FIELD_RE.search(field_name) 801 if array_match: 802 field_name = array_match.group(1) 803 count = array_match.group(2) 804 out_file.write(self._SERIALIZE_UNION_FIELD_ARRAY % 805 {'selector_value': selector, 806 'count': count, 807 'field_type': field_type, 808 'field_name': field_name}) 809 else: 810 out_file.write(self._SERIALIZE_UNION_FIELD % 811 {'selector_value': selector, 812 'field_type': field_type, 813 'field_name': field_name}) 814 out_file.write(self._SERIALIZE_FUNCTION_END) 815 out_file.write(self._PARSE_UNION_FUNCTION_START % 816 {'union_type': self.name, 'selector_type': selector_type}) 817 for selector in selector_values: 818 field_name = FixName(union_selectors.GetUnionSelectorField(self.name, 819 selector)) 820 if not field_name: 821 out_file.write(self._EMPTY_UNION_CASE % {'selector_value': selector}) 822 continue 823 field_type = field_types[field_name] 824 array_match = self._ARRAY_FIELD_RE.search(field_name) 825 if array_match: 826 field_name = array_match.group(1) 827 count = array_match.group(2) 828 out_file.write(self._PARSE_UNION_FIELD_ARRAY % 829 {'selector_value': selector, 830 'count': count, 831 'field_type': field_type, 832 'field_name': field_name}) 833 else: 834 out_file.write(self._PARSE_UNION_FIELD % 835 {'selector_value': selector, 836 'field_type': field_type, 837 'field_name': field_name}) 838 out_file.write(self._SERIALIZE_FUNCTION_END) 839 840 def _OutputUnionField(self, out_file, field, code_format): 841 """Writes serialize / parse code for a union field. 842 843 In this case |self| may not necessarily represent a union but |field| does. 844 This requires that a field of an acceptable selector type appear somewhere 845 in the struct. The value of this field is used as the selector value when 846 calling the serialize / parse function for the union. 847 848 Args: 849 out_file: The output file. 850 field: The union field to be processed as a (type, name) tuple. 851 code_format: Must be (_SERIALIZE|_PARSE)_FIELD_WITH_SELECTOR 852 """ 853 selector_types = union_selectors.GetUnionSelectorTypes(field[0]) 854 selector_name = '' 855 for tmp in self.fields: 856 if tmp[0] in selector_types: 857 selector_name = tmp[1] 858 break 859 assert selector_name, 'Missing selector for %s in %s!' % (field[1], 860 self.name) 861 out_file.write(code_format % {'type': field[0], 862 'selector_name': selector_name, 863 'name': field[1]}) 864 865 def _OutputArrayField(self, out_file, field, code_format): 866 """Writes serialize / parse code for an array field. 867 868 The allocated size of the array is ignored and a field which holds the 869 actual count of items in the array must exist. Only the number of items 870 represented by the value of that count field are serialized / parsed. 871 872 Args: 873 out_file: The output file. 874 field: The array field to be processed as a (type, name) tuple. 875 code_format: Must be (_SERIALIZE|_PARSE)_FIELD_ARRAY 876 """ 877 field_name = self._ARRAY_FIELD_RE.search(field[1]).group(1) 878 for count_field in self.fields: 879 assert count_field != field, ('Missing count field for %s in %s!' % 880 (field[1], self.name)) 881 if self._ARRAY_FIELD_SIZE_RE.search(count_field[1]): 882 out_file.write(code_format % {'count': count_field[1], 883 'type': field[0], 884 'name': field_name}) 885 break 886 887 888class Define(object): 889 """Represents a preprocessor define. 890 891 Attributes: 892 name: The name being defined. 893 value: The value being assigned to the name. 894 """ 895 896 _DEFINE = '#if !defined(%(name)s)\n#define %(name)s %(value)s\n#endif\n' 897 898 def __init__(self, name, value): 899 """Initializes a Define instance. 900 901 Args: 902 name: The name being defined. 903 value: The value being assigned to the name. 904 """ 905 self.name = name 906 self.value = value 907 908 def Output(self, out_file): 909 """Writes a preprocessor define to |out_file|. 910 911 Args: 912 out_file: The output file. 913 """ 914 out_file.write(self._DEFINE % {'name': self.name, 'value': self.value}) 915 916 917class StructureParser(object): 918 """Structure definition parser. 919 920 The input text file is extracted from the PDF file containing the TPM 921 structures specification from the Trusted Computing Group. The syntax 922 of the text file is defined by extract_structures.sh. 923 924 - Parses typedefs to a list of Typedef objects. 925 - Parses constants to a list of Constant objects. 926 - Parses structs and unions to a list of Structure objects. 927 - Parses defines to a list of Define objects. 928 929 The parser also creates 'typemap' dict which maps every type to its generator 930 object. This typemap helps manage type dependencies. 931 932 Example usage: 933 parser = StructureParser(open('myfile')) 934 types, constants, structs, defines, typemap = parser.Parse() 935 """ 936 937 # Compile regular expressions. 938 _BEGIN_TYPES_TOKEN = '_BEGIN_TYPES' 939 _BEGIN_CONSTANTS_TOKEN = '_BEGIN_CONSTANTS' 940 _BEGIN_STRUCTURES_TOKEN = '_BEGIN_STRUCTURES' 941 _BEGIN_UNIONS_TOKEN = '_BEGIN_UNIONS' 942 _BEGIN_DEFINES_TOKEN = '_BEGIN_DEFINES' 943 _END_TOKEN = '_END' 944 _OLD_TYPE_RE = re.compile(r'^_OLD_TYPE\s+(\w+)$') 945 _NEW_TYPE_RE = re.compile(r'^_NEW_TYPE\s+(\w+)$') 946 _CONSTANTS_SECTION_RE = re.compile(r'^_CONSTANTS.* (\w+)$') 947 _STRUCTURE_SECTION_RE = re.compile(r'^_STRUCTURE\s+(\w+)$') 948 _UNION_SECTION_RE = re.compile(r'^_UNION\s+(\w+)$') 949 _TYPE_RE = re.compile(r'^_TYPE\s+(\w+)$') 950 _NAME_RE = re.compile(r'^_NAME\s+([a-zA-Z0-9_()\[\]/\*\+\-]+)$') 951 _VALUE_RE = re.compile(r'^_VALUE\s+(.+)$') 952 _SIZEOF_RE = re.compile(r'^.*sizeof\(([a-zA-Z0-9_]*)\).*$') 953 954 def __init__(self, in_file): 955 """Initializes a StructureParser instance. 956 957 Args: 958 in_file: A file as returned by open() which has been opened for reading. 959 """ 960 self._line = None 961 self._in_file = in_file 962 963 def _NextLine(self): 964 """Gets the next input line. 965 966 Returns: 967 The next input line if another line is available, None otherwise. 968 """ 969 try: 970 self._line = self._in_file.next() 971 except StopIteration: 972 self._line = None 973 974 def Parse(self): 975 """Parse everything in a structures file. 976 977 Returns: 978 Lists of objects and a type-map as described in the class documentation. 979 Returns these in the following order: types, constants, structs, defines, 980 typemap. 981 """ 982 self._NextLine() 983 types = [] 984 constants = [] 985 structs = [] 986 defines = [] 987 typemap = {} 988 while self._line: 989 if self._BEGIN_TYPES_TOKEN == self._line.rstrip(): 990 types += self._ParseTypes(typemap) 991 elif self._BEGIN_CONSTANTS_TOKEN == self._line.rstrip(): 992 constants += self._ParseConstants(types, typemap) 993 elif self._BEGIN_STRUCTURES_TOKEN == self._line.rstrip(): 994 structs += self._ParseStructures(self._STRUCTURE_SECTION_RE, typemap) 995 elif self._BEGIN_UNIONS_TOKEN == self._line.rstrip(): 996 structs += self._ParseStructures(self._UNION_SECTION_RE, typemap) 997 elif self._BEGIN_DEFINES_TOKEN == self._line.rstrip(): 998 defines += self._ParseDefines() 999 else: 1000 print('Invalid file format: %s' % self._line) 1001 break 1002 self._NextLine() 1003 # Empty structs not handled by the extractor. 1004 self._AddEmptyStruct('TPMU_SYM_DETAILS', True, structs, typemap) 1005 # Defines which are used in TPM 2.0 Part 2 but not defined there. 1006 defines.append(Define( 1007 'MAX_CAP_DATA', '(MAX_CAP_BUFFER-sizeof(TPM_CAP)-sizeof(UINT32))')) 1008 defines.append(Define( 1009 'MAX_CAP_ALGS', '(TPM_ALG_LAST - TPM_ALG_FIRST + 1)')) 1010 defines.append(Define( 1011 'MAX_CAP_HANDLES', '(MAX_CAP_DATA/sizeof(TPM_HANDLE))')) 1012 defines.append(Define( 1013 'MAX_CAP_CC', '((TPM_CC_LAST - TPM_CC_FIRST) + 1)')) 1014 defines.append(Define( 1015 'MAX_TPM_PROPERTIES', '(MAX_CAP_DATA/sizeof(TPMS_TAGGED_PROPERTY))')) 1016 defines.append(Define( 1017 'MAX_PCR_PROPERTIES', '(MAX_CAP_DATA/sizeof(TPMS_TAGGED_PCR_SELECT))')) 1018 defines.append(Define( 1019 'MAX_ECC_CURVES', '(MAX_CAP_DATA/sizeof(TPM_ECC_CURVE))')) 1020 defines.append(Define('HASH_COUNT', '3')) 1021 return types, constants, structs, defines, typemap 1022 1023 def _AddEmptyStruct(self, name, is_union, structs, typemap): 1024 """Adds an empty Structure object to |structs| and |typemap|. 1025 1026 Args: 1027 name: The name to assign the new structure. 1028 is_union: A boolean indicating whether the new structure is a union. 1029 structs: A list of structures to which the new object is appended. 1030 typemap: A map of type names to objects to which the new name and object 1031 are added. 1032 """ 1033 s = Structure(name, is_union) 1034 structs.append(s) 1035 typemap[name] = s 1036 return 1037 1038 def _ParseTypes(self, typemap): 1039 """Parses a typedefs section. 1040 1041 The current line should be _BEGIN_TYPES and the method will stop parsing 1042 when an _END line is found. 1043 1044 Args: 1045 typemap: A dictionary to which parsed types are added. 1046 1047 Returns: 1048 A list of Typedef objects. 1049 """ 1050 types = [] 1051 self._NextLine() 1052 while self._END_TOKEN != self._line.rstrip(): 1053 match = self._OLD_TYPE_RE.search(self._line) 1054 if not match: 1055 print('Invalid old type: %s' % self._line) 1056 return types 1057 old_type = match.group(1) 1058 self._NextLine() 1059 match = self._NEW_TYPE_RE.search(self._line) 1060 if not match: 1061 print('Invalid new type: %s' % self._line) 1062 return types 1063 new_type = match.group(1) 1064 t = Typedef(old_type, new_type) 1065 types.append(t) 1066 typemap[new_type] = t 1067 self._NextLine() 1068 return types 1069 1070 def _ParseConstants(self, types, typemap): 1071 """Parses a constants section. 1072 1073 The current line should be _BEGIN_CONSTANTS and the method will stop parsing 1074 when an _END line is found. Each group of constants has an associated type 1075 alias. A Typedef object is created for each of these aliases and added to 1076 both |types| and |typemap|. 1077 1078 Args: 1079 types: A list of Typedef objects. 1080 typemap: A dictionary to which parsed types are added. 1081 1082 Returns: 1083 A list of Constant objects. 1084 """ 1085 constants = [] 1086 self._NextLine() 1087 while self._END_TOKEN != self._line.rstrip(): 1088 match = self._CONSTANTS_SECTION_RE.search(self._line) 1089 if not match: 1090 print('Invalid constants section: %s' % self._line) 1091 return constants 1092 constant_typename = match.group(1) 1093 self._NextLine() 1094 match = self._TYPE_RE.search(self._line) 1095 if not match: 1096 print('Invalid constants type: %s' % self._line) 1097 return constants 1098 constant_type = match.group(1) 1099 # Create a typedef for the constant group name (e.g. TPM_RC). 1100 typedef = Typedef(constant_type, constant_typename) 1101 typemap[constant_typename] = typedef 1102 types.append(typedef) 1103 self._NextLine() 1104 match = self._NAME_RE.search(self._line) 1105 if not match: 1106 print('Invalid constant name: %s' % self._line) 1107 return constants 1108 while match: 1109 name = match.group(1) 1110 self._NextLine() 1111 match = self._VALUE_RE.search(self._line) 1112 if not match: 1113 print('Invalid constant value: %s' % self._line) 1114 return constants 1115 value = match.group(1) 1116 constants.append(Constant(constant_typename, name, value)) 1117 self._NextLine() 1118 match = self._NAME_RE.search(self._line) 1119 return constants 1120 1121 def _ParseStructures(self, section_re, typemap): 1122 """Parses structures and unions. 1123 1124 The current line should be _BEGIN_STRUCTURES or _BEGIN_UNIONS and the method 1125 will stop parsing when an _END line is found. 1126 1127 Args: 1128 section_re: The regular expression to use for matching section tokens. 1129 typemap: A dictionary to which parsed types are added. 1130 1131 Returns: 1132 A list of Structure objects. 1133 """ 1134 structures = [] 1135 is_union = section_re == self._UNION_SECTION_RE 1136 self._NextLine() 1137 while self._END_TOKEN != self._line.rstrip(): 1138 match = section_re.search(self._line) 1139 if not match: 1140 print('Invalid structure section: %s' % self._line) 1141 return structures 1142 current_structure_name = match.group(1) 1143 current_structure = Structure(current_structure_name, is_union) 1144 self._NextLine() 1145 match = self._TYPE_RE.search(self._line) 1146 if not match: 1147 print('Invalid field type: %s' % self._line) 1148 return structures 1149 while match: 1150 field_type = match.group(1) 1151 self._NextLine() 1152 match = self._NAME_RE.search(self._line) 1153 if not match: 1154 print('Invalid field name: %s' % self._line) 1155 return structures 1156 field_name = match.group(1) 1157 # If the field name includes 'sizeof(SOME_TYPE)', record the dependency 1158 # on SOME_TYPE. 1159 match = self._SIZEOF_RE.search(field_name) 1160 if match: 1161 current_structure.AddDependency(match.group(1)) 1162 # Manually change unfortunate names. 1163 if field_name == 'xor': 1164 field_name = 'xor_' 1165 current_structure.AddField(field_type, field_name) 1166 self._NextLine() 1167 match = self._TYPE_RE.search(self._line) 1168 structures.append(current_structure) 1169 typemap[current_structure_name] = current_structure 1170 return structures 1171 1172 def _ParseDefines(self): 1173 """Parses preprocessor defines. 1174 1175 The current line should be _BEGIN_DEFINES and the method will stop parsing 1176 when an _END line is found. 1177 1178 Returns: 1179 A list of Define objects. 1180 """ 1181 defines = [] 1182 self._NextLine() 1183 while self._END_TOKEN != self._line.rstrip(): 1184 match = self._NAME_RE.search(self._line) 1185 if not match: 1186 print('Invalid name: %s' % self._line) 1187 return defines 1188 name = match.group(1) 1189 self._NextLine() 1190 match = self._VALUE_RE.search(self._line) 1191 if not match: 1192 print('Invalid value: %s' % self._line) 1193 return defines 1194 value = match.group(1) 1195 defines.append(Define(name, value)) 1196 self._NextLine() 1197 return defines 1198 1199 1200class Command(object): 1201 """Represents a TPM command. 1202 1203 Attributes: 1204 name: The command name (e.g. 'TPM2_Startup'). 1205 command_code: The name of the command code constant (e.g. TPM2_CC_Startup). 1206 request_args: A list to hold command input arguments. Each element is a dict 1207 and has these keys: 1208 'type': The argument type. 1209 'name': The argument name. 1210 'command_code': The optional value of the command code constant. 1211 'description': Optional descriptive text for the argument. 1212 response_args: A list identical in form to request_args but to hold command 1213 output arguments. 1214 """ 1215 1216 _HANDLE_RE = re.compile(r'TPMI_.H_.*') 1217 _CALLBACK_ARG = """ 1218 const %(method_name)sResponse& callback""" 1219 _DELEGATE_ARG = """ 1220 AuthorizationDelegate* authorization_delegate""" 1221 _SERIALIZE_ARG = """ 1222 std::string* serialized_command""" 1223 _PARSE_ARG = """ 1224 const std::string& response""" 1225 _SERIALIZE_FUNCTION_START = """ 1226TPM_RC Tpm::SerializeCommand_%(method_name)s(%(method_args)s) { 1227 VLOG(3) << __func__; 1228 TPM_RC rc = TPM_RC_SUCCESS; 1229 TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS; 1230 UINT32 command_size = 10; // Header size. 1231 std::string handle_section_bytes; 1232 std::string parameter_section_bytes;""" 1233 _DECLARE_COMMAND_CODE = """ 1234 TPM_CC command_code = %(command_code)s;""" 1235 _DECLARE_BOOLEAN = """ 1236 bool %(var_name)s = %(value)s;""" 1237 _SERIALIZE_LOCAL_VAR = """ 1238 std::string %(var_name)s_bytes; 1239 rc = Serialize_%(var_type)s( 1240 %(var_name)s, 1241 &%(var_name)s_bytes); 1242 if (rc != TPM_RC_SUCCESS) { 1243 return rc; 1244 }""" 1245 _ENCRYPT_PARAMETER = """ 1246 if (authorization_delegate) { 1247 // Encrypt just the parameter data, not the size. 1248 std::string tmp = %(var_name)s_bytes.substr(2); 1249 if (!authorization_delegate->EncryptCommandParameter(&tmp)) { 1250 return TRUNKS_RC_ENCRYPTION_FAILED; 1251 } 1252 %(var_name)s_bytes.replace(2, std::string::npos, tmp); 1253 }""" 1254 _HASH_START = """ 1255 scoped_ptr<crypto::SecureHash> hash(crypto::SecureHash::Create( 1256 crypto::SecureHash::SHA256));""" 1257 _HASH_UPDATE = """ 1258 hash->Update(%(var_name)s.data(), 1259 %(var_name)s.size());""" 1260 _APPEND_COMMAND_HANDLE = """ 1261 handle_section_bytes += %(var_name)s_bytes; 1262 command_size += %(var_name)s_bytes.size();""" 1263 _APPEND_COMMAND_PARAMETER = """ 1264 parameter_section_bytes += %(var_name)s_bytes; 1265 command_size += %(var_name)s_bytes.size();""" 1266 _AUTHORIZE_COMMAND = """ 1267 std::string command_hash(32, 0); 1268 hash->Finish(string_as_array(&command_hash), command_hash.size()); 1269 std::string authorization_section_bytes; 1270 std::string authorization_size_bytes; 1271 if (authorization_delegate) { 1272 if (!authorization_delegate->GetCommandAuthorization( 1273 command_hash, 1274 is_command_parameter_encryption_possible, 1275 is_response_parameter_encryption_possible, 1276 &authorization_section_bytes)) { 1277 return TRUNKS_RC_AUTHORIZATION_FAILED; 1278 } 1279 if (!authorization_section_bytes.empty()) { 1280 tag = TPM_ST_SESSIONS; 1281 std::string tmp; 1282 rc = Serialize_UINT32(authorization_section_bytes.size(), 1283 &authorization_size_bytes); 1284 if (rc != TPM_RC_SUCCESS) { 1285 return rc; 1286 } 1287 command_size += authorization_size_bytes.size() + 1288 authorization_section_bytes.size(); 1289 } 1290 }""" 1291 _SERIALIZE_FUNCTION_END = """ 1292 *serialized_command = tag_bytes + 1293 command_size_bytes + 1294 command_code_bytes + 1295 handle_section_bytes + 1296 authorization_size_bytes + 1297 authorization_section_bytes + 1298 parameter_section_bytes; 1299 CHECK(serialized_command->size() == command_size) << "Command size mismatch!"; 1300 VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(), 1301 serialized_command->size()); 1302 return TPM_RC_SUCCESS; 1303} 1304""" 1305 _RESPONSE_PARSER_START = """ 1306TPM_RC Tpm::ParseResponse_%(method_name)s(%(method_args)s) { 1307 VLOG(3) << __func__; 1308 VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size()); 1309 TPM_RC rc = TPM_RC_SUCCESS; 1310 std::string buffer(response);""" 1311 _PARSE_LOCAL_VAR = """ 1312 %(var_type)s %(var_name)s; 1313 std::string %(var_name)s_bytes; 1314 rc = Parse_%(var_type)s( 1315 &buffer, 1316 &%(var_name)s, 1317 &%(var_name)s_bytes); 1318 if (rc != TPM_RC_SUCCESS) { 1319 return rc; 1320 }""" 1321 _PARSE_ARG_VAR = """ 1322 std::string %(var_name)s_bytes; 1323 rc = Parse_%(var_type)s( 1324 &buffer, 1325 %(var_name)s, 1326 &%(var_name)s_bytes); 1327 if (rc != TPM_RC_SUCCESS) { 1328 return rc; 1329 }""" 1330 _RESPONSE_ERROR_CHECK = """ 1331 if (response_size != response.size()) { 1332 return TPM_RC_SIZE; 1333 } 1334 if (response_code != TPM_RC_SUCCESS) { 1335 return response_code; 1336 }""" 1337 _RESPONSE_SECTION_SPLIT = """ 1338 std::string authorization_section_bytes; 1339 if (tag == TPM_ST_SESSIONS) { 1340 UINT32 parameter_section_size = buffer.size(); 1341 rc = Parse_UINT32(&buffer, ¶meter_section_size, nullptr); 1342 if (rc != TPM_RC_SUCCESS) { 1343 return rc; 1344 } 1345 if (parameter_section_size > buffer.size()) { 1346 return TPM_RC_INSUFFICIENT; 1347 } 1348 authorization_section_bytes = buffer.substr(parameter_section_size); 1349 // Keep the parameter section in |buffer|. 1350 buffer.erase(parameter_section_size); 1351 }""" 1352 _AUTHORIZE_RESPONSE = """ 1353 std::string response_hash(32, 0); 1354 hash->Finish(string_as_array(&response_hash), response_hash.size()); 1355 if (tag == TPM_ST_SESSIONS) { 1356 CHECK(authorization_delegate) << "Authorization delegate missing!"; 1357 if (!authorization_delegate->CheckResponseAuthorization( 1358 response_hash, 1359 authorization_section_bytes)) { 1360 return TRUNKS_RC_AUTHORIZATION_FAILED; 1361 } 1362 }""" 1363 _DECRYPT_PARAMETER = """ 1364 if (tag == TPM_ST_SESSIONS) { 1365 CHECK(authorization_delegate) << "Authorization delegate missing!"; 1366 // Decrypt just the parameter data, not the size. 1367 std::string tmp = %(var_name)s_bytes.substr(2); 1368 if (!authorization_delegate->DecryptResponseParameter(&tmp)) { 1369 return TRUNKS_RC_ENCRYPTION_FAILED; 1370 } 1371 %(var_name)s_bytes.replace(2, std::string::npos, tmp); 1372 rc = Parse_%(var_type)s( 1373 &%(var_name)s_bytes, 1374 %(var_name)s, 1375 nullptr); 1376 if (rc != TPM_RC_SUCCESS) { 1377 return rc; 1378 } 1379 }""" 1380 _RESPONSE_PARSER_END = """ 1381 return TPM_RC_SUCCESS; 1382} 1383""" 1384 _ERROR_CALLBACK_START = """ 1385void %(method_name)sErrorCallback( 1386 const Tpm::%(method_name)sResponse& callback, 1387 TPM_RC response_code) { 1388 VLOG(1) << __func__; 1389 callback.Run(response_code""" 1390 _ERROR_CALLBACK_ARG = """, 1391 %(arg_type)s()""" 1392 _ERROR_CALLBACK_END = """); 1393} 1394""" 1395 _RESPONSE_CALLBACK_START = """ 1396void %(method_name)sResponseParser( 1397 const Tpm::%(method_name)sResponse& callback, 1398 AuthorizationDelegate* authorization_delegate, 1399 const std::string& response) { 1400 VLOG(1) << __func__; 1401 base::Callback<void(TPM_RC)> error_reporter = 1402 base::Bind(%(method_name)sErrorCallback, callback);""" 1403 _DECLARE_ARG_VAR = """ 1404 %(var_type)s %(var_name)s;""" 1405 _RESPONSE_CALLBACK_END = """ 1406 TPM_RC rc = Tpm::ParseResponse_%(method_name)s( 1407 response,%(method_arg_names_out)s 1408 authorization_delegate); 1409 if (rc != TPM_RC_SUCCESS) { 1410 error_reporter.Run(rc); 1411 return; 1412 } 1413 callback.Run( 1414 rc%(method_arg_names_in)s); 1415} 1416""" 1417 _ASYNC_METHOD = """ 1418void Tpm::%(method_name)s(%(method_args)s) { 1419 VLOG(1) << __func__; 1420 base::Callback<void(TPM_RC)> error_reporter = 1421 base::Bind(%(method_name)sErrorCallback, callback); 1422 base::Callback<void(const std::string&)> parser = 1423 base::Bind(%(method_name)sResponseParser, 1424 callback, 1425 authorization_delegate); 1426 std::string command; 1427 TPM_RC rc = SerializeCommand_%(method_name)s(%(method_arg_names)s 1428 &command, 1429 authorization_delegate); 1430 if (rc != TPM_RC_SUCCESS) { 1431 error_reporter.Run(rc); 1432 return; 1433 } 1434 transceiver_->SendCommand(command, parser); 1435} 1436""" 1437 _SYNC_METHOD = """ 1438TPM_RC Tpm::%(method_name)sSync(%(method_args)s) { 1439 VLOG(1) << __func__; 1440 std::string command; 1441 TPM_RC rc = SerializeCommand_%(method_name)s(%(method_arg_names_in)s 1442 &command, 1443 authorization_delegate); 1444 if (rc != TPM_RC_SUCCESS) { 1445 return rc; 1446 } 1447 std::string response = transceiver_->SendCommandAndWait(command); 1448 rc = ParseResponse_%(method_name)s( 1449 response,%(method_arg_names_out)s 1450 authorization_delegate); 1451 return rc; 1452} 1453""" 1454 1455 def __init__(self, name): 1456 """Initializes a Command instance. 1457 1458 Initially the request_args and response_args attributes are not set. 1459 1460 Args: 1461 name: The command name (e.g. 'TPM2_Startup'). 1462 """ 1463 self.name = name 1464 self.command_code = '' 1465 self.request_args = None 1466 self.response_args = None 1467 1468 def OutputDeclarations(self, out_file): 1469 """Prints method and callback declaration statements for this command. 1470 1471 Args: 1472 out_file: The output file. 1473 """ 1474 self._OutputCallbackSignature(out_file) 1475 self._OutputMethodSignatures(out_file) 1476 1477 def OutputSerializeFunction(self, out_file): 1478 """Generates a serialize function for the command inputs. 1479 1480 Args: 1481 out_file: Generated code is written to this file. 1482 """ 1483 # Categorize arguments as either handles or parameters. 1484 handles, parameters = self._SplitArgs(self.request_args) 1485 response_parameters = self._SplitArgs(self.response_args)[1] 1486 out_file.write(self._SERIALIZE_FUNCTION_START % { 1487 'method_name': self._MethodName(), 1488 'method_args': self._SerializeArgs()}) 1489 out_file.write(self._DECLARE_COMMAND_CODE % {'command_code': 1490 self.command_code}) 1491 out_file.write(self._DECLARE_BOOLEAN % { 1492 'var_name': 'is_command_parameter_encryption_possible', 1493 'value': GetCppBool(parameters and IsTPM2B(parameters[0]['type']))}) 1494 out_file.write(self._DECLARE_BOOLEAN % { 1495 'var_name': 'is_response_parameter_encryption_possible', 1496 'value': GetCppBool(response_parameters and 1497 IsTPM2B(response_parameters[0]['type']))}) 1498 # Serialize the command code and all the handles and parameters. 1499 out_file.write(self._SERIALIZE_LOCAL_VAR % {'var_name': 'command_code', 1500 'var_type': 'TPM_CC'}) 1501 for arg in self.request_args: 1502 out_file.write(self._SERIALIZE_LOCAL_VAR % {'var_name': arg['name'], 1503 'var_type': arg['type']}) 1504 # Encrypt the first parameter (before doing authorization) if necessary. 1505 if parameters and IsTPM2B(parameters[0]['type']): 1506 out_file.write(self._ENCRYPT_PARAMETER % {'var_name': 1507 parameters[0]['name']}) 1508 # Compute the command hash and construct handle and parameter sections. 1509 out_file.write(self._HASH_START) 1510 out_file.write(self._HASH_UPDATE % {'var_name': 'command_code_bytes'}) 1511 for handle in handles: 1512 out_file.write(self._HASH_UPDATE % {'var_name': 1513 '%s_name' % handle['name']}) 1514 out_file.write(self._APPEND_COMMAND_HANDLE % {'var_name': 1515 handle['name']}) 1516 for parameter in parameters: 1517 out_file.write(self._HASH_UPDATE % {'var_name': 1518 '%s_bytes' % parameter['name']}) 1519 out_file.write(self._APPEND_COMMAND_PARAMETER % {'var_name': 1520 parameter['name']}) 1521 # Do authorization based on the hash. 1522 out_file.write(self._AUTHORIZE_COMMAND) 1523 # Now that the tag and size are finalized, serialize those. 1524 out_file.write(self._SERIALIZE_LOCAL_VAR % 1525 {'var_name': 'tag', 1526 'var_type': 'TPMI_ST_COMMAND_TAG'}) 1527 out_file.write(self._SERIALIZE_LOCAL_VAR % {'var_name': 'command_size', 1528 'var_type': 'UINT32'}) 1529 out_file.write(self._SERIALIZE_FUNCTION_END) 1530 1531 def OutputParseFunction(self, out_file): 1532 """Generates a parse function for the command outputs. 1533 1534 Args: 1535 out_file: Generated code is written to this file. 1536 """ 1537 out_file.write(self._RESPONSE_PARSER_START % { 1538 'method_name': self._MethodName(), 1539 'method_args': self._ParseArgs()}) 1540 # Parse the header -- this should always exist. 1541 out_file.write(self._PARSE_LOCAL_VAR % {'var_name': 'tag', 1542 'var_type': 'TPM_ST'}) 1543 out_file.write(self._PARSE_LOCAL_VAR % {'var_name': 'response_size', 1544 'var_type': 'UINT32'}) 1545 out_file.write(self._PARSE_LOCAL_VAR % {'var_name': 'response_code', 1546 'var_type': 'TPM_RC'}) 1547 # Handle the error case. 1548 out_file.write(self._RESPONSE_ERROR_CHECK) 1549 # Categorize arguments as either handles or parameters. 1550 handles, parameters = self._SplitArgs(self.response_args) 1551 # Parse any handles. 1552 for handle in handles: 1553 out_file.write(self._PARSE_ARG_VAR % {'var_name': handle['name'], 1554 'var_type': handle['type']}) 1555 # Setup a serialized command code which is needed for the response hash. 1556 out_file.write(self._DECLARE_COMMAND_CODE % {'command_code': 1557 self.command_code}) 1558 out_file.write(self._SERIALIZE_LOCAL_VAR % {'var_name': 'command_code', 1559 'var_type': 'TPM_CC'}) 1560 # Split out the authorization section. 1561 out_file.write(self._RESPONSE_SECTION_SPLIT) 1562 # Compute the response hash. 1563 out_file.write(self._HASH_START) 1564 out_file.write(self._HASH_UPDATE % {'var_name': 'response_code_bytes'}) 1565 out_file.write(self._HASH_UPDATE % {'var_name': 'command_code_bytes'}) 1566 out_file.write(self._HASH_UPDATE % {'var_name': 'buffer'}) 1567 # Do authorization related stuff. 1568 out_file.write(self._AUTHORIZE_RESPONSE) 1569 # Parse response parameters. 1570 for arg in parameters: 1571 out_file.write(self._PARSE_ARG_VAR % {'var_name': arg['name'], 1572 'var_type': arg['type']}) 1573 if parameters and IsTPM2B(parameters[0]['type']): 1574 out_file.write(self._DECRYPT_PARAMETER % {'var_name': 1575 parameters[0]['name'], 1576 'var_type': 1577 parameters[0]['type']}) 1578 out_file.write(self._RESPONSE_PARSER_END) 1579 1580 def OutputMethodImplementation(self, out_file): 1581 """Generates the implementation of a Tpm class method for this command. 1582 1583 The method assembles a command to be sent unmodified to the TPM and invokes 1584 the CommandTransceiver with the command. Errors are reported directly to the 1585 response callback via the error callback (see OutputErrorCallback). 1586 1587 Args: 1588 out_file: Generated code is written to this file. 1589 """ 1590 out_file.write(self._ASYNC_METHOD % { 1591 'method_name': self._MethodName(), 1592 'method_args': self._AsyncArgs(), 1593 'method_arg_names': self._ArgNameList(self._RequestArgs(), 1594 trailing_comma=True)}) 1595 out_file.write(self._SYNC_METHOD % { 1596 'method_name': self._MethodName(), 1597 'method_args': self._SyncArgs(), 1598 'method_arg_names_in': self._ArgNameList(self._RequestArgs(), 1599 trailing_comma=True), 1600 'method_arg_names_out': self._ArgNameList(self.response_args, 1601 trailing_comma=True)}) 1602 1603 def OutputErrorCallback(self, out_file): 1604 """Generates the implementation of an error callback for this command. 1605 1606 The error callback simply calls the command response callback with the error 1607 as the first argument and default values for all other arguments. 1608 1609 Args: 1610 out_file: Generated code is written to this file. 1611 """ 1612 out_file.write(self._ERROR_CALLBACK_START % {'method_name': 1613 self._MethodName()}) 1614 for arg in self.response_args: 1615 out_file.write(self._ERROR_CALLBACK_ARG % {'arg_type': arg['type']}) 1616 out_file.write(self._ERROR_CALLBACK_END) 1617 1618 def OutputResponseCallback(self, out_file): 1619 """Generates the implementation of a response callback for this command. 1620 1621 The response callback takes the unmodified response from the TPM, parses it, 1622 and invokes the original response callback with the parsed response args. 1623 Errors during parsing or from the TPM are reported directly to the response 1624 callback via the error callback (see OutputErrorCallback). 1625 1626 Args: 1627 out_file: Generated code is written to this file. 1628 """ 1629 out_file.write(self._RESPONSE_CALLBACK_START % {'method_name': 1630 self._MethodName()}) 1631 for arg in self.response_args: 1632 out_file.write(self._DECLARE_ARG_VAR % {'var_type': arg['type'], 1633 'var_name': arg['name']}) 1634 out_file.write(self._RESPONSE_CALLBACK_END % { 1635 'method_name': self._MethodName(), 1636 'method_arg_names_in': self._ArgNameList(self.response_args, 1637 leading_comma=True), 1638 'method_arg_names_out': self._ArgNameList(self.response_args, 1639 prefix='&', 1640 trailing_comma=True)}) 1641 1642 def GetNumberOfRequestHandles(self): 1643 """Returns the number of input handles for this command.""" 1644 return len(self._SplitArgs(self.request_args)[0]) 1645 1646 def GetNumberOfResponseHandles(self): 1647 """Returns the number of output handles for this command.""" 1648 return len(self._SplitArgs(self.response_args)[0]) 1649 1650 def _OutputMethodSignatures(self, out_file): 1651 """Prints method declaration statements for this command. 1652 1653 This includes a method to serialize a request, a method to parse a response, 1654 and methods for synchronous and asynchronous calls. 1655 1656 Args: 1657 out_file: The output file. 1658 """ 1659 out_file.write(' static TPM_RC SerializeCommand_%s(%s);\n' % ( 1660 self._MethodName(), self._SerializeArgs())) 1661 out_file.write(' static TPM_RC ParseResponse_%s(%s);\n' % ( 1662 self._MethodName(), self._ParseArgs())) 1663 out_file.write(' virtual void %s(%s);\n' % (self._MethodName(), 1664 self._AsyncArgs())) 1665 out_file.write(' virtual TPM_RC %sSync(%s);\n' % (self._MethodName(), 1666 self._SyncArgs())) 1667 1668 def _OutputCallbackSignature(self, out_file): 1669 """Prints a callback typedef for this command. 1670 1671 Args: 1672 out_file: The output file. 1673 """ 1674 args = self._InputArgList(self.response_args) 1675 if args: 1676 args = ',' + args 1677 args = '\n TPM_RC response_code' + args 1678 out_file.write(' typedef base::Callback<void(%s)> %sResponse;\n' % 1679 (args, self._MethodName())) 1680 1681 def _MethodName(self): 1682 """Creates an appropriate generated method name for the command. 1683 1684 We use the command name without the TPM2_ prefix. 1685 1686 Returns: 1687 The method name. 1688 """ 1689 if not self.name.startswith('TPM2_'): 1690 return self.name 1691 return self.name[5:] 1692 1693 def _InputArgList(self, args): 1694 """Formats a list of input arguments for use in a function declaration. 1695 1696 Args: 1697 args: An argument list in the same form as the request_args and 1698 response_args attributes. 1699 1700 Returns: 1701 A string which can be used in a function declaration. 1702 """ 1703 if args: 1704 arg_list = ['const %(type)s& %(name)s' % a for a in args] 1705 return '\n ' + ',\n '.join(arg_list) 1706 return '' 1707 1708 def _OutputArgList(self, args): 1709 """Formats a list of output arguments for use in a function declaration. 1710 1711 Args: 1712 args: An argument list in the same form as the request_args and 1713 response_args attributes. 1714 1715 Returns: 1716 A string which can be used in a function declaration. 1717 """ 1718 if args: 1719 arg_list = ['%(type)s* %(name)s' % a for a in args] 1720 return '\n ' + ',\n '.join(arg_list) 1721 return '' 1722 1723 def _ArgNameList(self, args, prefix='', leading_comma=False, 1724 trailing_comma=False): 1725 """Formats a list of arguments for use in a function call statement. 1726 1727 Args: 1728 args: An argument list in the same form as the request_args and 1729 response_args attributes. 1730 prefix: A prefix to be prepended to each argument. 1731 leading_comma: Whether to include a comma before the first argument. 1732 trailing_comma: Whether to include a comma after the last argument. 1733 1734 Returns: 1735 A string which can be used in a function call statement. 1736 """ 1737 if args: 1738 arg_list = [(prefix + a['name']) for a in args] 1739 header = '' 1740 if leading_comma: 1741 header = ',' 1742 trailer = '' 1743 if trailing_comma: 1744 trailer = ',' 1745 return header + '\n ' + ',\n '.join(arg_list) + trailer 1746 return '' 1747 1748 def _SplitArgs(self, args): 1749 """Splits a list of args into handles and parameters.""" 1750 handles = [] 1751 parameters = [] 1752 # These commands have handles that are serialized into the parameter 1753 # section. 1754 command_handle_parameters = { 1755 'TPM_CC_FlushContext': 'TPMI_DH_CONTEXT', 1756 'TPM_CC_Hash': 'TPMI_RH_HIERARCHY', 1757 'TPM_CC_LoadExternal': 'TPMI_RH_HIERARCHY', 1758 'TPM_CC_SequenceComplete': 'TPMI_RH_HIERARCHY', 1759 } 1760 # Handle type that appears in the handle section. 1761 always_handle = set(['TPM_HANDLE']) 1762 # Handle types that always appear as command parameters. 1763 always_parameter = set(['TPMI_RH_ENABLES', 'TPMI_DH_PERSISTENT']) 1764 if self.command_code in command_handle_parameters: 1765 always_parameter.add(command_handle_parameters[self.command_code]) 1766 for arg in args: 1767 if (arg['type'] in always_handle or 1768 (self._HANDLE_RE.search(arg['type']) and 1769 arg['type'] not in always_parameter)): 1770 handles.append(arg) 1771 else: 1772 parameters.append(arg) 1773 return handles, parameters 1774 1775 def _RequestArgs(self): 1776 """Computes the argument list for a Tpm request. 1777 1778 For every handle argument a handle name argument is added. 1779 """ 1780 handles, parameters = self._SplitArgs(self.request_args) 1781 args = [] 1782 # Add a name argument for every handle. We'll need it to compute cpHash. 1783 for handle in handles: 1784 args.append(handle) 1785 args.append({'type': 'std::string', 1786 'name': '%s_name' % handle['name']}) 1787 for parameter in parameters: 1788 args.append(parameter) 1789 return args 1790 1791 def _AsyncArgs(self): 1792 """Returns a formatted argument list for an asynchronous method.""" 1793 args = self._InputArgList(self._RequestArgs()) 1794 if args: 1795 args += ',' 1796 return (args + self._DELEGATE_ARG + ',' + 1797 self._CALLBACK_ARG % {'method_name': self._MethodName()}) 1798 1799 def _SyncArgs(self): 1800 """Returns a formatted argument list for a synchronous method.""" 1801 request_arg_list = self._InputArgList(self._RequestArgs()) 1802 if request_arg_list: 1803 request_arg_list += ',' 1804 response_arg_list = self._OutputArgList(self.response_args) 1805 if response_arg_list: 1806 response_arg_list += ',' 1807 return request_arg_list + response_arg_list + self._DELEGATE_ARG 1808 1809 def _SerializeArgs(self): 1810 """Returns a formatted argument list for a request-serialize method.""" 1811 args = self._InputArgList(self._RequestArgs()) 1812 if args: 1813 args += ',' 1814 return args + self._SERIALIZE_ARG + ',' + self._DELEGATE_ARG 1815 1816 def _ParseArgs(self): 1817 """Returns a formatted argument list for a response-parse method.""" 1818 args = self._OutputArgList(self.response_args) 1819 if args: 1820 args = ',' + args 1821 return self._PARSE_ARG + args + ',' + self._DELEGATE_ARG 1822 1823 1824class CommandParser(object): 1825 """Command definition parser. 1826 1827 The input text file is extracted from the PDF file containing the TPM 1828 command specification from the Trusted Computing Group. The syntax 1829 of the text file is defined by extract_commands.sh. 1830 """ 1831 1832 # Regular expressions to pull relevant bits from annotated lines. 1833 _INPUT_START_RE = re.compile(r'^_INPUT_START\s+(\w+)$') 1834 _OUTPUT_START_RE = re.compile(r'^_OUTPUT_START\s+(\w+)$') 1835 _TYPE_RE = re.compile(r'^_TYPE\s+(\w+)$') 1836 _NAME_RE = re.compile(r'^_NAME\s+(\w+)$') 1837 # Pull the command code from a comment like: _COMMENT TPM_CC_Startup {NV}. 1838 _COMMENT_CC_RE = re.compile(r'^_COMMENT\s+(TPM_CC_\w+).*$') 1839 _COMMENT_RE = re.compile(r'^_COMMENT\s+(.*)') 1840 # Args which are handled internally by the generated method. 1841 _INTERNAL_ARGS = ('tag', 'Tag', 'commandSize', 'commandCode', 'responseSize', 1842 'responseCode', 'returnCode') 1843 1844 def __init__(self, in_file): 1845 """Initializes a CommandParser instance. 1846 1847 Args: 1848 in_file: A file as returned by open() which has been opened for reading. 1849 """ 1850 self._line = None 1851 self._in_file = in_file 1852 1853 def _NextLine(self): 1854 """Gets the next input line. 1855 1856 Returns: 1857 The next input line if another line is available, None otherwise. 1858 """ 1859 try: 1860 self._line = self._in_file.next() 1861 except StopIteration: 1862 self._line = None 1863 1864 def Parse(self): 1865 """Parses everything in a commands file. 1866 1867 Returns: 1868 A list of extracted Command objects. 1869 """ 1870 commands = [] 1871 self._NextLine() 1872 if self._line != '_BEGIN\n': 1873 print('Invalid format for first line: %s\n' % self._line) 1874 return commands 1875 self._NextLine() 1876 1877 while self._line != '_END\n': 1878 cmd = self._ParseCommand() 1879 if not cmd: 1880 break 1881 commands.append(cmd) 1882 return commands 1883 1884 def _ParseCommand(self): 1885 """Parses inputs and outputs for a single TPM command. 1886 1887 Returns: 1888 A single Command object. 1889 """ 1890 match = self._INPUT_START_RE.search(self._line) 1891 if not match: 1892 print('Cannot match command input from line: %s\n' % self._line) 1893 return None 1894 name = match.group(1) 1895 cmd = Command(name) 1896 self._NextLine() 1897 cmd.request_args = self._ParseCommandArgs(cmd) 1898 match = self._OUTPUT_START_RE.search(self._line) 1899 if not match or match.group(1) != name: 1900 print('Cannot match command output from line: %s\n' % self._line) 1901 return None 1902 self._NextLine() 1903 cmd.response_args = self._ParseCommandArgs(cmd) 1904 request_var_names = set([arg['name'] for arg in cmd.request_args]) 1905 for arg in cmd.response_args: 1906 if arg['name'] in request_var_names: 1907 arg['name'] += '_out' 1908 if not cmd.command_code: 1909 print('Command code not found for %s' % name) 1910 return None 1911 return cmd 1912 1913 def _ParseCommandArgs(self, cmd): 1914 """Parses a set of arguments for a command. 1915 1916 The arguments may be input or output arguments. 1917 1918 Args: 1919 cmd: The current Command object. The command_code attribute will be set if 1920 such a constant is parsed. 1921 1922 Returns: 1923 A list of arguments in the same form as the Command.request_args and 1924 Command.response_args attributes. 1925 """ 1926 args = [] 1927 match = self._TYPE_RE.search(self._line) 1928 while match: 1929 arg_type = match.group(1) 1930 self._NextLine() 1931 match = self._NAME_RE.search(self._line) 1932 if not match: 1933 print('Cannot match argument name from line: %s\n' % self._line) 1934 break 1935 arg_name = match.group(1) 1936 self._NextLine() 1937 match = self._COMMENT_CC_RE.search(self._line) 1938 if match: 1939 cmd.command_code = match.group(1) 1940 match = self._COMMENT_RE.search(self._line) 1941 if match: 1942 self._NextLine() 1943 if arg_name not in self._INTERNAL_ARGS: 1944 args.append({'type': arg_type, 1945 'name': FixName(arg_name)}) 1946 match = self._TYPE_RE.search(self._line) 1947 return args 1948 1949 1950def GenerateHandleCountFunctions(commands, out_file): 1951 """Generates the GetNumberOf*Handles functions given a list of commands. 1952 1953 Args: 1954 commands: A list of Command objects. 1955 out_file: The output file. 1956 """ 1957 out_file.write(_HANDLE_COUNT_FUNCTION_START % {'handle_type': 'Request'}) 1958 for command in commands: 1959 out_file.write(_HANDLE_COUNT_FUNCTION_CASE % 1960 {'command_code': command.command_code, 1961 'handle_count': command.GetNumberOfRequestHandles()}) 1962 out_file.write(_HANDLE_COUNT_FUNCTION_END) 1963 out_file.write(_HANDLE_COUNT_FUNCTION_START % {'handle_type': 'Response'}) 1964 for command in commands: 1965 out_file.write(_HANDLE_COUNT_FUNCTION_CASE % 1966 {'command_code': command.command_code, 1967 'handle_count': command.GetNumberOfResponseHandles()}) 1968 out_file.write(_HANDLE_COUNT_FUNCTION_END) 1969 1970 1971def GenerateHeader(types, constants, structs, defines, typemap, commands): 1972 """Generates a header file with declarations for all given generator objects. 1973 1974 Args: 1975 types: A list of Typedef objects. 1976 constants: A list of Constant objects. 1977 structs: A list of Structure objects. 1978 defines: A list of Define objects. 1979 typemap: A dict mapping type names to the corresponding object. 1980 commands: A list of Command objects. 1981 """ 1982 out_file = open(_OUTPUT_FILE_H, 'w') 1983 out_file.write(_COPYRIGHT_HEADER) 1984 guard_name = 'TRUNKS_%s_' % _OUTPUT_FILE_H.upper().replace('.', '_') 1985 out_file.write(_HEADER_FILE_GUARD_HEADER % {'name': guard_name}) 1986 out_file.write(_HEADER_FILE_INCLUDES) 1987 out_file.write(_NAMESPACE_BEGIN) 1988 out_file.write(_FORWARD_DECLARATIONS) 1989 out_file.write('\n') 1990 # These types are built-in or defined by <stdint.h>; they serve as base cases 1991 # when defining type dependencies. 1992 defined_types = set(_BASIC_TYPES) 1993 # Generate defines. These must be generated before any other code. 1994 for define in defines: 1995 define.Output(out_file) 1996 out_file.write('\n') 1997 # Generate typedefs. These are declared before structs because they are not 1998 # likely to depend on structs and when they do a simple forward declaration 1999 # for the struct can be generated. This improves the readability of the 2000 # generated code. 2001 for typedef in types: 2002 typedef.Output(out_file, defined_types, typemap) 2003 out_file.write('\n') 2004 # Generate constant definitions. Again, generated before structs to improve 2005 # readability. 2006 for constant in constants: 2007 constant.Output(out_file, defined_types, typemap) 2008 out_file.write('\n') 2009 # Generate structs. All non-struct dependencies should be already declared. 2010 for struct in structs: 2011 struct.Output(out_file, defined_types, typemap) 2012 # Helper function declarations. 2013 out_file.write(_FUNCTION_DECLARATIONS) 2014 # Generate serialize / parse function declarations. 2015 for basic_type in _BASIC_TYPES: 2016 out_file.write(_SERIALIZE_DECLARATION % {'type': basic_type}) 2017 for typedef in types: 2018 out_file.write(_SERIALIZE_DECLARATION % {'type': typedef.new_type}) 2019 for struct in structs: 2020 out_file.write(_SERIALIZE_DECLARATION % {'type': struct.name}) 2021 if struct.IsSimpleTPM2B(): 2022 out_file.write(_SIMPLE_TPM2B_HELPERS_DECLARATION % {'type': struct.name}) 2023 elif struct.IsComplexTPM2B(): 2024 out_file.write(_COMPLEX_TPM2B_HELPERS_DECLARATION % { 2025 'type': struct.name, 2026 'inner_type': struct.fields[1][0]}) 2027 # Generate a declaration for a 'Tpm' class, which includes one method for 2028 # every TPM 2.0 command. 2029 out_file.write(_CLASS_BEGIN) 2030 for command in commands: 2031 command.OutputDeclarations(out_file) 2032 out_file.write(_CLASS_END) 2033 out_file.write(_NAMESPACE_END) 2034 out_file.write(_HEADER_FILE_GUARD_FOOTER % {'name': guard_name}) 2035 out_file.close() 2036 2037 2038def GenerateImplementation(types, structs, typemap, commands): 2039 """Generates implementation code for each command. 2040 2041 Args: 2042 types: A list of Typedef objects. 2043 structs: A list of Structure objects. 2044 typemap: A dict mapping type names to the corresponding object. 2045 commands: A list of Command objects. 2046 """ 2047 out_file = open(_OUTPUT_FILE_CC, 'w') 2048 out_file.write(_COPYRIGHT_HEADER) 2049 out_file.write(_LOCAL_INCLUDE % {'filename': _OUTPUT_FILE_H}) 2050 out_file.write(_IMPLEMENTATION_FILE_INCLUDES) 2051 out_file.write(_NAMESPACE_BEGIN) 2052 GenerateHandleCountFunctions(commands, out_file) 2053 serialized_types = set(_BASIC_TYPES) 2054 for basic_type in _BASIC_TYPES: 2055 out_file.write(_SERIALIZE_BASIC_TYPE % {'type': basic_type}) 2056 for typedef in types: 2057 typedef.OutputSerialize(out_file, serialized_types, typemap) 2058 for struct in structs: 2059 struct.OutputSerialize(out_file, serialized_types, typemap) 2060 for command in commands: 2061 command.OutputSerializeFunction(out_file) 2062 command.OutputParseFunction(out_file) 2063 command.OutputErrorCallback(out_file) 2064 command.OutputResponseCallback(out_file) 2065 command.OutputMethodImplementation(out_file) 2066 out_file.write(_NAMESPACE_END) 2067 out_file.close() 2068 2069 2070def FormatFile(filename): 2071 subprocess.call(['clang-format', '-i', '-style=file', filename]) 2072 2073 2074def main(): 2075 """A main function. 2076 2077 Both a TPM structures file and commands file are parsed and C++ header and C++ 2078 implementation file are generated. 2079 2080 Positional Args: 2081 structures_file: The extracted TPM structures file. 2082 commands_file: The extracted TPM commands file. 2083 """ 2084 parser = argparse.ArgumentParser(description='TPM 2.0 code generator') 2085 parser.add_argument('structures_file') 2086 parser.add_argument('commands_file') 2087 args = parser.parse_args() 2088 structure_parser = StructureParser(open(args.structures_file)) 2089 types, constants, structs, defines, typemap = structure_parser.Parse() 2090 command_parser = CommandParser(open(args.commands_file)) 2091 commands = command_parser.Parse() 2092 GenerateHeader(types, constants, structs, defines, typemap, commands) 2093 GenerateImplementation(types, structs, typemap, commands) 2094 FormatFile(_OUTPUT_FILE_H) 2095 FormatFile(_OUTPUT_FILE_CC) 2096 print('Processed %d commands.' % len(commands)) 2097 2098 2099if __name__ == '__main__': 2100 main() 2101