1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdio.h>
18
19 #include <android-base/endian.h>
20 #include <gflags/gflags.h>
21 #include <android-base/logging.h>
22
23 #include "host/libs/config/cuttlefish_config.h"
24 #include "host/libs/config/logging.h"
25 #include "common/libs/fs/shared_buf.h"
26 #include "common/libs/fs/shared_fd.h"
27 #include "common/libs/utils/subprocess.h"
28
29 DEFINE_int32(port, 0, "The port to run the TPM simulator on. Consumes the next "
30 "port as well for platform commands.");
31
32 namespace {
33
HasSubstrings(const std::string & string,const std::vector<std::string> & substrings)34 bool HasSubstrings(const std::string& string, const std::vector<std::string>& substrings) {
35 for (const auto& substr : substrings) {
36 if (string.find(substr) == std::string::npos) {
37 return false;
38 }
39 }
40 return true;
41 }
42
43 } // namespace
44
main(int argc,char ** argv)45 int main(int argc, char** argv) {
46 cuttlefish::DefaultSubprocessLogging(argv);
47 google::ParseCommandLineFlags(&argc, &argv, true);
48
49 CHECK(FLAGS_port > 0) << "A port must be set";
50 auto config = cuttlefish::CuttlefishConfig::Get();
51 CHECK(config) << "Unable to get config object";
52
53 // Assumes linked on the host with glibc
54 cuttlefish::Command simulator_cmd("/usr/bin/stdbuf");
55 simulator_cmd.AddParameter("-oL");
56 simulator_cmd.AddParameter(config->tpm_binary());
57 simulator_cmd.AddParameter(FLAGS_port);
58
59 cuttlefish::SharedFD sim_stdout_in, sim_stdout_out;
60 CHECK(cuttlefish::SharedFD::Pipe(&sim_stdout_out, &sim_stdout_in))
61 << "Unable to open pipe for stdout: " << strerror(errno);
62 simulator_cmd.RedirectStdIO(cuttlefish::Subprocess::StdIOChannel::kStdOut, sim_stdout_in);
63
64 auto tpm_subprocess = simulator_cmd.Start();
65
66 sim_stdout_in->Close();
67
68 std::unique_ptr<FILE, int(*)(FILE*)> stdout_file(
69 fdopen(sim_stdout_out->UNMANAGED_Dup(), "r"), &fclose);
70 sim_stdout_out->Close();
71
72 bool command_server = false;
73 bool platform_server = false;
74 bool sent_init = false;
75
76 cuttlefish::SharedFD client; // Hold this connection open for the process lifetime.
77
78 char* lineptr = nullptr;
79 size_t size = 0;
80 while (getline(&lineptr, &size, stdout_file.get()) >= 0) {
81 std::string line(lineptr);
82 line = line.substr(0, line.size() - 1);
83 if (HasSubstrings(line, {"TPM", "command", "server", "listening", "on", "port"})) {
84 command_server = true;
85 }
86 if (HasSubstrings(line, {"Platform", "server", "listening", "on", "port"})) {
87 platform_server = true;
88 }
89 if (command_server && platform_server && !sent_init) {
90 client = cuttlefish::SharedFD::SocketLocalClient(FLAGS_port + 1, SOCK_STREAM);
91 std::uint32_t command = htobe32(1); // TPM_SIGNAL_POWER_ON
92 CHECK(cuttlefish::WriteAllBinary(client, &command) == 4)
93 << "Could not send TPM_SIGNAL_POWER_ON";
94 std::uint32_t response;
95 CHECK(cuttlefish::ReadExactBinary(client, &response) == 4)
96 << "Could not read parity response";
97
98 command = htobe32(11); // TPM_SIGNAL_NV_ON
99 CHECK(cuttlefish::WriteAllBinary(client, &command) == 4)
100 << "Could not send TPM_SIGNAL_NV_ON";
101 CHECK(cuttlefish::ReadExactBinary(client, &response) == 4)
102 << "Could not read parity response";
103
104 sent_init = true;
105 }
106 LOG(INFO) << "TPM2SIM: " << line;
107 }
108 free(lineptr);
109
110 return tpm_subprocess.Wait() ? 0 : 1;
111 }
112