1*c538727dSKevin Tung #include "tpm2.hpp"
2*c538727dSKevin Tung
3*c538727dSKevin Tung #include "common/include/utils.hpp"
4*c538727dSKevin Tung
5*c538727dSKevin Tung #include <phosphor-logging/lg2.hpp>
6*c538727dSKevin Tung
7*c538727dSKevin Tung #include <cstdio>
8*c538727dSKevin Tung #include <regex>
9*c538727dSKevin Tung #include <sstream>
10*c538727dSKevin Tung
11*c538727dSKevin Tung PHOSPHOR_LOG2_USING;
12*c538727dSKevin Tung
13*c538727dSKevin Tung static constexpr std::string_view getCapPropertiesCmd =
14*c538727dSKevin Tung "/usr/bin/tpm2_getcap properties-fixed";
15*c538727dSKevin Tung static constexpr std::string_view fwVer1Property = "TPM2_PT_FIRMWARE_VERSION_1";
16*c538727dSKevin Tung static constexpr std::string_view fwVer2Property = "TPM2_PT_FIRMWARE_VERSION_2";
17*c538727dSKevin Tung static constexpr std::string_view manufacturerProperty = "TPM2_PT_MANUFACTURER";
18*c538727dSKevin Tung
19*c538727dSKevin Tung static constexpr std::string_view hexPattern = R"(^\s*raw:\s+0x([0-9a-fA-F]+))";
20*c538727dSKevin Tung
21*c538727dSKevin Tung enum class Tpm2Vendor
22*c538727dSKevin Tung {
23*c538727dSKevin Tung IFX,
24*c538727dSKevin Tung Nuvoton
25*c538727dSKevin Tung };
26*c538727dSKevin Tung
27*c538727dSKevin Tung // Reference: https://trustedcomputinggroup.org/resource/vendor-id-registry/
28*c538727dSKevin Tung static const std::unordered_map<uint32_t, Tpm2Vendor> validManufactureIDs = {
29*c538727dSKevin Tung {0x49465800, Tpm2Vendor::IFX}, {0x4E544300, Tpm2Vendor::Nuvoton}};
30*c538727dSKevin Tung
getTPMResourceManagerPath(uint8_t tpmIndex)31*c538727dSKevin Tung static std::string getTPMResourceManagerPath(uint8_t tpmIndex)
32*c538727dSKevin Tung {
33*c538727dSKevin Tung return "/dev/tpmrm" + std::to_string(tpmIndex);
34*c538727dSKevin Tung }
35*c538727dSKevin Tung
getProperty(std::string_view property,uint32_t & value)36*c538727dSKevin Tung sdbusplus::async::task<bool> TPM2Interface::getProperty(
37*c538727dSKevin Tung std::string_view property, uint32_t& value)
38*c538727dSKevin Tung {
39*c538727dSKevin Tung // Reference: https://tpm2-tools.readthedocs.io/en/latest/man/common/tcti/
40*c538727dSKevin Tung // The TCTI or "Transmission Interface" is the communication mechanism
41*c538727dSKevin Tung // with the TPM. TCTIs can be changed for communication with TPMs across
42*c538727dSKevin Tung // different mediums.
43*c538727dSKevin Tung auto tcti = "device:" + getTPMResourceManagerPath(tpmIndex);
44*c538727dSKevin Tung auto cmd = std::string(getCapPropertiesCmd) + " --tcti " + tcti +
45*c538727dSKevin Tung " | grep -A1 " + std::string(property);
46*c538727dSKevin Tung
47*c538727dSKevin Tung std::string output;
48*c538727dSKevin Tung if (!co_await asyncSystem(ctx, cmd, output))
49*c538727dSKevin Tung {
50*c538727dSKevin Tung error("Failed to run command: {CMD}", "CMD", cmd);
51*c538727dSKevin Tung co_return false;
52*c538727dSKevin Tung }
53*c538727dSKevin Tung
54*c538727dSKevin Tung const std::regex regexPattern{std::string(hexPattern)};
55*c538727dSKevin Tung std::smatch match;
56*c538727dSKevin Tung std::istringstream stream(output);
57*c538727dSKevin Tung std::string line;
58*c538727dSKevin Tung
59*c538727dSKevin Tung while (std::getline(stream, line))
60*c538727dSKevin Tung {
61*c538727dSKevin Tung if (std::regex_search(line, match, regexPattern) && match.size() >= 2)
62*c538727dSKevin Tung {
63*c538727dSKevin Tung try
64*c538727dSKevin Tung {
65*c538727dSKevin Tung value = std::stoul(match[1].str(), nullptr, 16);
66*c538727dSKevin Tung co_return true;
67*c538727dSKevin Tung }
68*c538727dSKevin Tung catch (const std::exception& e)
69*c538727dSKevin Tung {
70*c538727dSKevin Tung error("Failed to parse hex value for property {PT}: {ERR}",
71*c538727dSKevin Tung "PT", property, "ERR", e.what());
72*c538727dSKevin Tung co_return false;
73*c538727dSKevin Tung }
74*c538727dSKevin Tung }
75*c538727dSKevin Tung }
76*c538727dSKevin Tung
77*c538727dSKevin Tung error("No matching hex value found for property: {PT}", "PT", property);
78*c538727dSKevin Tung co_return false;
79*c538727dSKevin Tung }
80*c538727dSKevin Tung
updateFirmware(const uint8_t * image,size_t image_size)81*c538727dSKevin Tung sdbusplus::async::task<bool> TPM2Interface::updateFirmware(const uint8_t* image,
82*c538727dSKevin Tung size_t image_size)
83*c538727dSKevin Tung {
84*c538727dSKevin Tung (void)image;
85*c538727dSKevin Tung (void)image_size;
86*c538727dSKevin Tung
87*c538727dSKevin Tung error("TPM2 firmware update is not supported");
88*c538727dSKevin Tung co_return false;
89*c538727dSKevin Tung }
90*c538727dSKevin Tung
getVersion(std::string & version)91*c538727dSKevin Tung sdbusplus::async::task<bool> TPM2Interface::getVersion(std::string& version)
92*c538727dSKevin Tung {
93*c538727dSKevin Tung uint32_t manufacturerId = 0;
94*c538727dSKevin Tung uint32_t fwVer = 0;
95*c538727dSKevin Tung std::string tpmVer1;
96*c538727dSKevin Tung std::string tpmVer2;
97*c538727dSKevin Tung
98*c538727dSKevin Tung if (!co_await getProperty(manufacturerProperty, manufacturerId))
99*c538727dSKevin Tung {
100*c538727dSKevin Tung error("Failed to retrieve TPM manufacturer ID");
101*c538727dSKevin Tung co_return false;
102*c538727dSKevin Tung }
103*c538727dSKevin Tung
104*c538727dSKevin Tung auto it = validManufactureIDs.find(manufacturerId);
105*c538727dSKevin Tung
106*c538727dSKevin Tung if (it == validManufactureIDs.end())
107*c538727dSKevin Tung {
108*c538727dSKevin Tung error("Invalid TPM manufacturer ID: {ID}", "ID", lg2::hex,
109*c538727dSKevin Tung manufacturerId);
110*c538727dSKevin Tung co_return false;
111*c538727dSKevin Tung }
112*c538727dSKevin Tung
113*c538727dSKevin Tung auto vendor = it->second;
114*c538727dSKevin Tung
115*c538727dSKevin Tung if (!co_await getProperty(fwVer1Property, fwVer))
116*c538727dSKevin Tung {
117*c538727dSKevin Tung error("Failed to retrieve TPM firmware version 1");
118*c538727dSKevin Tung co_return false;
119*c538727dSKevin Tung }
120*c538727dSKevin Tung
121*c538727dSKevin Tung tpmVer1 = std::to_string(fwVer >> 16) + "." +
122*c538727dSKevin Tung std::to_string(fwVer & 0xFFFF);
123*c538727dSKevin Tung
124*c538727dSKevin Tung if (vendor == Tpm2Vendor::Nuvoton)
125*c538727dSKevin Tung {
126*c538727dSKevin Tung if (!co_await getProperty(fwVer2Property, fwVer))
127*c538727dSKevin Tung {
128*c538727dSKevin Tung error("Failed to retrieve TPM firmware version 2");
129*c538727dSKevin Tung co_return false;
130*c538727dSKevin Tung }
131*c538727dSKevin Tung
132*c538727dSKevin Tung tpmVer2 = std::to_string(fwVer >> 16) + "." +
133*c538727dSKevin Tung std::to_string(fwVer & 0xFFFF);
134*c538727dSKevin Tung version = tpmVer1 + "." + tpmVer2;
135*c538727dSKevin Tung }
136*c538727dSKevin Tung else
137*c538727dSKevin Tung {
138*c538727dSKevin Tung version = tpmVer1;
139*c538727dSKevin Tung }
140*c538727dSKevin Tung
141*c538727dSKevin Tung co_return true;
142*c538727dSKevin Tung }
143