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