1# Copyright (C) 2021-2022 Intel Corporation.
2#
3# SPDX-License-Identifier: BSD-3-Clause
4#
5
6import ctypes
7import logging
8
9import inspectorlib.cdata as cdata
10from acpiparser._utils import TableHeader
11
12def tpm2_optional_data(data_len):
13    start_method_data_len = 0
14    has_log_area = False
15    if data_len <= 12:
16        start_method_data_len = data_len
17    elif data_len == 24:
18        start_method_data_len = 12
19        has_log_area = True
20    else:
21        start_method_data_len = 12
22        logging.debug(f"TPM2 data length: {data_len + 52} is greater than 64 bytes but less than 76 bytes.")
23        logging.debug(f"The TPM2 data is still processed but the 65 to {data_len + 52} bytes are discard.")
24    return start_method_data_len, has_log_area
25
26def tpm2_factory(start_method_data_len, has_log_area):
27    class TPM2(cdata.Struct):
28        _pack_ = 1
29        _fields_ = [
30            ('header', TableHeader),
31            ('platform_class', ctypes.c_uint16),
32            ('reserved', ctypes.c_uint16),
33            ('address_of_control_area', ctypes.c_uint64),
34            ('start_method', ctypes.c_uint32),
35            ('start_method_specific_parameters', ctypes.c_ubyte * start_method_data_len),
36        ] + ([
37            ('log_area_minimum_length', ctypes.c_uint32),
38            ('log_area_start_address', ctypes.c_uint64),
39        ] if has_log_area else [])
40
41    return TPM2
42
43def TPM2(val):
44    """Create class based on decode of a TPM2 table from filename."""
45    if isinstance(val, str):
46        base_length = 52
47        data = open(val, mode='rb').read()
48        start_method_data_len, has_log_area = tpm2_optional_data(len(data) - base_length)
49        return tpm2_factory(start_method_data_len, has_log_area).from_buffer_copy(data)
50    elif isinstance(val, bytearray):
51        return tpm2_factory(12, True).from_buffer(val) if len(val) > 64 else tpm2_factory(12, False).from_buffer(val)
52