blob: 9746a6d092a4e4303af80389fc28b36580020fa6 [file] [log] [blame]
Patrick Venturebf58cd62018-12-11 09:05:46 -08001/*
2 * Copyright 2018 Google Inc.
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
Patrick Venturea6586362018-12-11 18:47:13 -080017#include "bt.hpp"
Patrick Venture46bdadc2019-01-18 09:04:16 -080018#include "io.hpp"
Patrick Venturea6586362018-12-11 18:47:13 -080019#include "lpc.hpp"
Benjamin Fair30d09a32019-10-11 16:57:47 -070020#include "net.hpp"
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070021#include "p2a.hpp"
22#include "pci.hpp"
Patrick Venturecf9b2192019-06-27 12:09:52 -070023#include "progress.hpp"
Patrick Venture2bc23fe2018-12-13 10:16:36 -080024#include "tool_errors.hpp"
Patrick Venturebf58cd62018-12-11 09:05:46 -080025#include "updater.hpp"
26
27/* Use CLI11 argument parser once in openbmc/meta-oe or whatever. */
28#include <getopt.h>
29
Patrick Venturea6586362018-12-11 18:47:13 -080030#include <algorithm>
Patrick Venturebf58cd62018-12-11 09:05:46 -080031#include <cstdio>
Patrick Venture8104a522019-06-19 19:04:36 -070032#include <cstdlib>
Patrick Venturee564d5b2019-05-14 12:30:06 -070033#include <exception>
Patrick Ventureaa107a62018-12-12 15:16:25 -080034#include <iostream>
Patrick Venture664c5bc2019-03-07 08:09:45 -080035#include <ipmiblob/blob_handler.hpp>
36#include <ipmiblob/ipmi_handler.hpp>
Patrick Ventureaa107a62018-12-12 15:16:25 -080037#include <iterator>
Patrick Venture03db87e2019-06-20 07:56:06 -070038#include <limits>
Patrick Venture00887592018-12-11 10:57:06 -080039#include <memory>
Patrick Venturebf58cd62018-12-11 09:05:46 -080040#include <string>
Patrick Venturea6586362018-12-11 18:47:13 -080041#include <vector>
42
43#define IPMILPC "ipmilpc"
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070044#define IPMIPCI "ipmipci"
Patrick Venturea6586362018-12-11 18:47:13 -080045#define IPMIBT "ipmibt"
Benjamin Fair30d09a32019-10-11 16:57:47 -070046#define IPMINET "ipminet"
Patrick Venturea6586362018-12-11 18:47:13 -080047
48namespace
49{
Benjamin Fair30d09a32019-10-11 16:57:47 -070050const std::vector<std::string> interfaceList = {IPMINET, IPMIBT, IPMILPC,
51 IPMIPCI};
Patrick Venture9f937c42019-06-21 07:55:54 -070052} // namespace
Patrick Venturebf58cd62018-12-11 09:05:46 -080053
54void usage(const char* program)
55{
Patrick Venture7ae5dde2018-12-14 10:03:35 -080056 std::fprintf(
57 stderr,
58 "Usage: %s --command <command> --interface <interface> --image "
Brandon Kim6749ba12019-09-19 13:31:37 -070059 "<image file> --sig <signature file> --type <layout> "
60 "[--ignore-update]\n",
Patrick Venture7ae5dde2018-12-14 10:03:35 -080061 program);
Patrick Venturea6586362018-12-11 18:47:13 -080062
Patrick Venture7ae5dde2018-12-14 10:03:35 -080063 std::fprintf(stderr, "interfaces: ");
Patrick Ventureaa107a62018-12-12 15:16:25 -080064 std::copy(interfaceList.begin(), interfaceList.end(),
65 std::ostream_iterator<std::string>(std::cerr, ", "));
66 std::fprintf(stderr, "\n");
Patrick Venture9f937c42019-06-21 07:55:54 -070067
Patrick Venturec498caa2019-08-15 10:12:50 -070068 std::fprintf(stderr, "layouts examples: image, bios\n");
69 std::fprintf(stderr,
70 "the type field specifies '/flash/{layout}' for a handler\n");
Patrick Venturebf58cd62018-12-11 09:05:46 -080071}
72
73bool checkCommand(const std::string& command)
74{
75 return (command == "update");
76}
77
78bool checkInterface(const std::string& interface)
79{
Patrick Venturea6586362018-12-11 18:47:13 -080080 auto intf =
81 std::find(interfaceList.begin(), interfaceList.end(), interface);
82 return (intf != interfaceList.end());
Patrick Venturebf58cd62018-12-11 09:05:46 -080083}
84
85int main(int argc, char* argv[])
86{
Benjamin Fair30d09a32019-10-11 16:57:47 -070087 std::string command, interface, imagePath, signaturePath, type, host;
88 std::string port = "623";
Patrick Venture8104a522019-06-19 19:04:36 -070089 char* valueEnd = nullptr;
90 long address = 0;
91 long length = 0;
Patrick Venture03db87e2019-06-20 07:56:06 -070092 std::uint32_t hostAddress = 0;
93 std::uint32_t hostLength = 0;
Brandon Kim6749ba12019-09-19 13:31:37 -070094 bool ignoreUpdate = false;
Patrick Venturebf58cd62018-12-11 09:05:46 -080095
96 while (1)
97 {
98 // clang-format off
99 static struct option long_options[] = {
100 {"command", required_argument, 0, 'c'},
101 {"interface", required_argument, 0, 'i'},
102 {"image", required_argument, 0, 'm'},
103 {"sig", required_argument, 0, 's'},
Patrick Venture8104a522019-06-19 19:04:36 -0700104 {"address", required_argument, 0, 'a'},
105 {"length", required_argument, 0, 'l'},
Patrick Venture9f937c42019-06-21 07:55:54 -0700106 {"type", required_argument, 0, 't'},
Brandon Kim6749ba12019-09-19 13:31:37 -0700107 {"ignore-update", no_argument, 0, 'u'},
Benjamin Fair30d09a32019-10-11 16:57:47 -0700108 {"host", required_argument, 0, 'H'},
109 {"port", optional_argument, 0, 'p'},
Patrick Venturebf58cd62018-12-11 09:05:46 -0800110 {0, 0, 0, 0}
111 };
112 // clang-format on
113
114 int option_index = 0;
Benjamin Fair30d09a32019-10-11 16:57:47 -0700115 int c = getopt_long(argc, argv, "c:i:m:s:a:l:t:uH:p:", long_options,
Patrick Venture9f937c42019-06-21 07:55:54 -0700116 &option_index);
Patrick Venturebf58cd62018-12-11 09:05:46 -0800117 if (c == -1)
118 {
119 break;
120 }
121
122 switch (c)
123 {
124 case 'c':
125 command = std::string{optarg};
126 if (!checkCommand(command))
127 {
128 usage(argv[0]);
129 exit(EXIT_FAILURE);
130 }
131
132 break;
133 case 'i':
134 interface = std::string{optarg};
135 if (!checkInterface(interface))
136 {
137 usage(argv[0]);
138 exit(EXIT_FAILURE);
139 }
140 break;
141 case 'm':
142 imagePath = std::string{optarg};
143 break;
144 case 's':
145 signaturePath = std::string{optarg};
146 break;
Patrick Venture8104a522019-06-19 19:04:36 -0700147 case 'a':
148 address = std::strtol(&optarg[0], &valueEnd, 0);
149 if (valueEnd == nullptr)
150 {
151 usage(argv[0]);
152 exit(EXIT_FAILURE);
153 }
Patrick Venture03db87e2019-06-20 07:56:06 -0700154 if (address > std::numeric_limits<std::uint32_t>::max())
155 {
156 std::fprintf(stderr, "Address beyond 32-bit limit.\n");
157 usage(argv[0]);
158 exit(EXIT_FAILURE);
159 }
160 hostAddress = static_cast<std::uint32_t>(address);
Patrick Venture8104a522019-06-19 19:04:36 -0700161 break;
162 case 'l':
163 length = std::strtol(&optarg[0], &valueEnd, 0);
164 if (valueEnd == nullptr)
165 {
166 usage(argv[0]);
167 exit(EXIT_FAILURE);
168 }
Patrick Venture03db87e2019-06-20 07:56:06 -0700169 if (length > std::numeric_limits<std::uint32_t>::max())
170 {
171 std::fprintf(stderr, "Length beyond 32-bit limit.\n");
172 usage(argv[0]);
173 exit(EXIT_FAILURE);
174 }
175 hostLength = static_cast<std::uint32_t>(length);
Patrick Venture8104a522019-06-19 19:04:36 -0700176 break;
Patrick Venture9f937c42019-06-21 07:55:54 -0700177 case 't':
178 type = std::string{optarg};
Patrick Venture9f937c42019-06-21 07:55:54 -0700179 break;
Brandon Kim6749ba12019-09-19 13:31:37 -0700180 case 'u':
181 ignoreUpdate = true;
182 break;
Benjamin Fair30d09a32019-10-11 16:57:47 -0700183 case 'H':
184 host = std::string{optarg};
185 break;
186 case 'p':
187 port = std::string{optarg};
188 break;
Patrick Venturebf58cd62018-12-11 09:05:46 -0800189 default:
190 usage(argv[0]);
191 exit(EXIT_FAILURE);
192 }
193 }
194
Patrick Venture361bd5a2018-12-14 09:49:47 -0800195 if (command.empty())
196 {
197 usage(argv[0]);
198 exit(EXIT_FAILURE);
199 }
200
Patrick Venturebf58cd62018-12-11 09:05:46 -0800201 /* They want to update the firmware. */
202 if (command == "update")
203 {
Patrick Venturec498caa2019-08-15 10:12:50 -0700204 if (interface.empty() || imagePath.empty() || signaturePath.empty() ||
205 type.empty())
Patrick Venturebf58cd62018-12-11 09:05:46 -0800206 {
207 usage(argv[0]);
208 exit(EXIT_FAILURE);
209 }
210
Patrick Venture866d4482019-05-13 09:26:52 -0700211 auto ipmi = ipmiblob::IpmiHandler::CreateIpmiHandler();
212 ipmiblob::BlobHandler blob(std::move(ipmi));
Patrick Venture46bdadc2019-01-18 09:04:16 -0800213 host_tool::DevMemDevice devmem;
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -0700214 host_tool::PciUtilImpl pci;
Patrick Venturecf9b2192019-06-27 12:09:52 -0700215 host_tool::ProgressStdoutIndicator progress;
Patrick Venture00887592018-12-11 10:57:06 -0800216
Patrick Venture9b534f02018-12-13 16:10:02 -0800217 std::unique_ptr<host_tool::DataInterface> handler;
Patrick Venturea6586362018-12-11 18:47:13 -0800218
219 /* Input has already been validated in this case. */
220 if (interface == IPMIBT)
221 {
Patrick Venturecf9b2192019-06-27 12:09:52 -0700222 handler =
223 std::make_unique<host_tool::BtDataHandler>(&blob, &progress);
Patrick Venturea6586362018-12-11 18:47:13 -0800224 }
Benjamin Fair30d09a32019-10-11 16:57:47 -0700225 else if (interface == IPMINET)
226 {
227 if (host.empty())
228 {
229 std::fprintf(stderr, "Host not specified\n");
230 exit(EXIT_FAILURE);
231 }
232 handler = std::make_unique<host_tool::NetDataHandler>(
233 &blob, &progress, host, port);
234 }
Patrick Venturea6586362018-12-11 18:47:13 -0800235 else if (interface == IPMILPC)
236 {
Patrick Venture03db87e2019-06-20 07:56:06 -0700237 if (hostAddress == 0 || hostLength == 0)
Patrick Venture8104a522019-06-19 19:04:36 -0700238 {
239 std::fprintf(stderr, "Address or Length were 0\n");
240 exit(EXIT_FAILURE);
241 }
242 handler = std::make_unique<host_tool::LpcDataHandler>(
Patrick Venturecf9b2192019-06-27 12:09:52 -0700243 &blob, &devmem, hostAddress, hostLength, &progress);
Patrick Venturea6586362018-12-11 18:47:13 -0800244 }
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -0700245 else if (interface == IPMIPCI)
246 {
247 handler = std::make_unique<host_tool::P2aDataHandler>(
Patrick Venturecf9b2192019-06-27 12:09:52 -0700248 &blob, &devmem, &pci, &progress);
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -0700249 }
Patrick Venturea6586362018-12-11 18:47:13 -0800250
251 if (!handler)
252 {
253 /* TODO(venture): use a custom exception. */
254 std::fprintf(stderr, "Interface %s is unavailable\n",
255 interface.c_str());
256 exit(EXIT_FAILURE);
257 }
258
Patrick Venturebf58cd62018-12-11 09:05:46 -0800259 /* The parameters are all filled out. */
Patrick Venture2bc23fe2018-12-13 10:16:36 -0800260 try
261 {
Patrick Venture55646de2019-05-16 10:06:26 -0700262 host_tool::UpdateHandler updater(&blob, handler.get());
Brandon Kim6749ba12019-09-19 13:31:37 -0700263 host_tool::updaterMain(&updater, imagePath, signaturePath, type,
264 ignoreUpdate);
Patrick Venture2bc23fe2018-12-13 10:16:36 -0800265 }
Patrick Venture9b534f02018-12-13 16:10:02 -0800266 catch (const host_tool::ToolException& e)
Patrick Venture2bc23fe2018-12-13 10:16:36 -0800267 {
268 std::fprintf(stderr, "Exception received: %s\n", e.what());
269 return -1;
270 }
Patrick Venturee564d5b2019-05-14 12:30:06 -0700271 catch (const std::exception& e)
272 {
273 std::fprintf(stderr, "Unexpected exception received: %s\n",
274 e.what());
275 return -1;
276 }
Patrick Venturebf58cd62018-12-11 09:05:46 -0800277 }
278
279 return 0;
280}