blob: f749e3b5805a0c8b219746f08aca127a95577601 [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"
Benjamin Faire5aafa52020-06-05 21:04:24 -070023#include "pciaccess.hpp"
Patrick Venturecf9b2192019-06-27 12:09:52 -070024#include "progress.hpp"
Patrick Venture2bc23fe2018-12-13 10:16:36 -080025#include "tool_errors.hpp"
Patrick Venturebf58cd62018-12-11 09:05:46 -080026#include "updater.hpp"
27
28/* Use CLI11 argument parser once in openbmc/meta-oe or whatever. */
29#include <getopt.h>
30
Patrick Venture9b37b092020-05-28 20:58:57 -070031#include <ipmiblob/blob_handler.hpp>
32#include <ipmiblob/ipmi_handler.hpp>
33
Patrick Venturea6586362018-12-11 18:47:13 -080034#include <algorithm>
Patrick Venturebf58cd62018-12-11 09:05:46 -080035#include <cstdio>
Patrick Venture8104a522019-06-19 19:04:36 -070036#include <cstdlib>
Patrick Venturee564d5b2019-05-14 12:30:06 -070037#include <exception>
Patrick Ventureaa107a62018-12-12 15:16:25 -080038#include <iostream>
39#include <iterator>
Patrick Venture03db87e2019-06-20 07:56:06 -070040#include <limits>
Patrick Venture00887592018-12-11 10:57:06 -080041#include <memory>
Patrick Venturebf58cd62018-12-11 09:05:46 -080042#include <string>
Patrick Venturea6586362018-12-11 18:47:13 -080043#include <vector>
44
45#define IPMILPC "ipmilpc"
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070046#define IPMIPCI "ipmipci"
Willy Tu8a9de242020-10-30 11:00:21 -070047#define IPMIPCI_SKIP_BRIDGE_DISABLE "ipmipci-skip-bridge-disable"
Patrick Venturea6586362018-12-11 18:47:13 -080048#define IPMIBT "ipmibt"
Benjamin Fair30d09a32019-10-11 16:57:47 -070049#define IPMINET "ipminet"
Patrick Venturea6586362018-12-11 18:47:13 -080050
51namespace
52{
Willy Tu8a9de242020-10-30 11:00:21 -070053const std::vector<std::string> interfaceList = {
54 IPMINET, IPMIBT, IPMILPC, IPMIPCI, IPMIPCI_SKIP_BRIDGE_DISABLE};
Patrick Venture9f937c42019-06-21 07:55:54 -070055} // namespace
Patrick Venturebf58cd62018-12-11 09:05:46 -080056
57void usage(const char* program)
58{
Patrick Venture7ae5dde2018-12-14 10:03:35 -080059 std::fprintf(
60 stderr,
61 "Usage: %s --command <command> --interface <interface> --image "
Brandon Kim6749ba12019-09-19 13:31:37 -070062 "<image file> --sig <signature file> --type <layout> "
63 "[--ignore-update]\n",
Patrick Venture7ae5dde2018-12-14 10:03:35 -080064 program);
Patrick Venturea6586362018-12-11 18:47:13 -080065
Patrick Venture7ae5dde2018-12-14 10:03:35 -080066 std::fprintf(stderr, "interfaces: ");
Patrick Ventureaa107a62018-12-12 15:16:25 -080067 std::copy(interfaceList.begin(), interfaceList.end(),
68 std::ostream_iterator<std::string>(std::cerr, ", "));
69 std::fprintf(stderr, "\n");
Patrick Venture9f937c42019-06-21 07:55:54 -070070
Patrick Venturec498caa2019-08-15 10:12:50 -070071 std::fprintf(stderr, "layouts examples: image, bios\n");
72 std::fprintf(stderr,
73 "the type field specifies '/flash/{layout}' for a handler\n");
Patrick Venturebf58cd62018-12-11 09:05:46 -080074}
75
76bool checkCommand(const std::string& command)
77{
78 return (command == "update");
79}
80
81bool checkInterface(const std::string& interface)
82{
Patrick Venturea6586362018-12-11 18:47:13 -080083 auto intf =
84 std::find(interfaceList.begin(), interfaceList.end(), interface);
85 return (intf != interfaceList.end());
Patrick Venturebf58cd62018-12-11 09:05:46 -080086}
87
88int main(int argc, char* argv[])
89{
Benjamin Fair30d09a32019-10-11 16:57:47 -070090 std::string command, interface, imagePath, signaturePath, type, host;
91 std::string port = "623";
Patrick Venture8104a522019-06-19 19:04:36 -070092 char* valueEnd = nullptr;
93 long address = 0;
94 long length = 0;
Patrick Venture03db87e2019-06-20 07:56:06 -070095 std::uint32_t hostAddress = 0;
96 std::uint32_t hostLength = 0;
Brandon Kim6749ba12019-09-19 13:31:37 -070097 bool ignoreUpdate = false;
Patrick Venturebf58cd62018-12-11 09:05:46 -080098
99 while (1)
100 {
101 // clang-format off
102 static struct option long_options[] = {
103 {"command", required_argument, 0, 'c'},
104 {"interface", required_argument, 0, 'i'},
105 {"image", required_argument, 0, 'm'},
106 {"sig", required_argument, 0, 's'},
Patrick Venture8104a522019-06-19 19:04:36 -0700107 {"address", required_argument, 0, 'a'},
108 {"length", required_argument, 0, 'l'},
Patrick Venture9f937c42019-06-21 07:55:54 -0700109 {"type", required_argument, 0, 't'},
Brandon Kim6749ba12019-09-19 13:31:37 -0700110 {"ignore-update", no_argument, 0, 'u'},
Benjamin Fair30d09a32019-10-11 16:57:47 -0700111 {"host", required_argument, 0, 'H'},
112 {"port", optional_argument, 0, 'p'},
Patrick Venturebf58cd62018-12-11 09:05:46 -0800113 {0, 0, 0, 0}
114 };
115 // clang-format on
116
117 int option_index = 0;
Benjamin Fair30d09a32019-10-11 16:57:47 -0700118 int c = getopt_long(argc, argv, "c:i:m:s:a:l:t:uH:p:", long_options,
Patrick Venture9f937c42019-06-21 07:55:54 -0700119 &option_index);
Patrick Venturebf58cd62018-12-11 09:05:46 -0800120 if (c == -1)
121 {
122 break;
123 }
124
125 switch (c)
126 {
127 case 'c':
128 command = std::string{optarg};
129 if (!checkCommand(command))
130 {
131 usage(argv[0]);
132 exit(EXIT_FAILURE);
133 }
134
135 break;
136 case 'i':
137 interface = std::string{optarg};
138 if (!checkInterface(interface))
139 {
140 usage(argv[0]);
141 exit(EXIT_FAILURE);
142 }
143 break;
144 case 'm':
145 imagePath = std::string{optarg};
146 break;
147 case 's':
148 signaturePath = std::string{optarg};
149 break;
Patrick Venture8104a522019-06-19 19:04:36 -0700150 case 'a':
151 address = std::strtol(&optarg[0], &valueEnd, 0);
152 if (valueEnd == nullptr)
153 {
154 usage(argv[0]);
155 exit(EXIT_FAILURE);
156 }
Patrick Venture03db87e2019-06-20 07:56:06 -0700157 if (address > std::numeric_limits<std::uint32_t>::max())
158 {
159 std::fprintf(stderr, "Address beyond 32-bit limit.\n");
160 usage(argv[0]);
161 exit(EXIT_FAILURE);
162 }
163 hostAddress = static_cast<std::uint32_t>(address);
Patrick Venture8104a522019-06-19 19:04:36 -0700164 break;
165 case 'l':
166 length = std::strtol(&optarg[0], &valueEnd, 0);
167 if (valueEnd == nullptr)
168 {
169 usage(argv[0]);
170 exit(EXIT_FAILURE);
171 }
Patrick Venture03db87e2019-06-20 07:56:06 -0700172 if (length > std::numeric_limits<std::uint32_t>::max())
173 {
174 std::fprintf(stderr, "Length beyond 32-bit limit.\n");
175 usage(argv[0]);
176 exit(EXIT_FAILURE);
177 }
178 hostLength = static_cast<std::uint32_t>(length);
Patrick Venture8104a522019-06-19 19:04:36 -0700179 break;
Patrick Venture9f937c42019-06-21 07:55:54 -0700180 case 't':
181 type = std::string{optarg};
Patrick Venture9f937c42019-06-21 07:55:54 -0700182 break;
Brandon Kim6749ba12019-09-19 13:31:37 -0700183 case 'u':
184 ignoreUpdate = true;
185 break;
Benjamin Fair30d09a32019-10-11 16:57:47 -0700186 case 'H':
187 host = std::string{optarg};
188 break;
189 case 'p':
190 port = std::string{optarg};
191 break;
Patrick Venturebf58cd62018-12-11 09:05:46 -0800192 default:
193 usage(argv[0]);
194 exit(EXIT_FAILURE);
195 }
196 }
197
Patrick Venture361bd5a2018-12-14 09:49:47 -0800198 if (command.empty())
199 {
200 usage(argv[0]);
201 exit(EXIT_FAILURE);
202 }
203
Patrick Venturebf58cd62018-12-11 09:05:46 -0800204 /* They want to update the firmware. */
205 if (command == "update")
206 {
Patrick Venturec498caa2019-08-15 10:12:50 -0700207 if (interface.empty() || imagePath.empty() || signaturePath.empty() ||
208 type.empty())
Patrick Venturebf58cd62018-12-11 09:05:46 -0800209 {
210 usage(argv[0]);
211 exit(EXIT_FAILURE);
212 }
213
Patrick Venture866d4482019-05-13 09:26:52 -0700214 auto ipmi = ipmiblob::IpmiHandler::CreateIpmiHandler();
215 ipmiblob::BlobHandler blob(std::move(ipmi));
Rui Zhangd8515a62020-03-24 16:46:44 -0700216#ifdef ENABLE_PPC
217 const std::string ppcMemPath = "/sys/kernel/debug/powerpc/lpc/fw";
218 host_tool::PpcMemDevice devmem(ppcMemPath);
219#else
Patrick Venture46bdadc2019-01-18 09:04:16 -0800220 host_tool::DevMemDevice devmem;
Rui Zhangd8515a62020-03-24 16:46:44 -0700221#endif
Patrick Venturecf9b2192019-06-27 12:09:52 -0700222 host_tool::ProgressStdoutIndicator progress;
Patrick Venture00887592018-12-11 10:57:06 -0800223
Patrick Venture9b534f02018-12-13 16:10:02 -0800224 std::unique_ptr<host_tool::DataInterface> handler;
Patrick Venturea6586362018-12-11 18:47:13 -0800225
226 /* Input has already been validated in this case. */
227 if (interface == IPMIBT)
228 {
Patrick Venturecf9b2192019-06-27 12:09:52 -0700229 handler =
230 std::make_unique<host_tool::BtDataHandler>(&blob, &progress);
Patrick Venturea6586362018-12-11 18:47:13 -0800231 }
Benjamin Fair30d09a32019-10-11 16:57:47 -0700232 else if (interface == IPMINET)
233 {
234 if (host.empty())
235 {
236 std::fprintf(stderr, "Host not specified\n");
237 exit(EXIT_FAILURE);
238 }
239 handler = std::make_unique<host_tool::NetDataHandler>(
240 &blob, &progress, host, port);
241 }
Patrick Venturea6586362018-12-11 18:47:13 -0800242 else if (interface == IPMILPC)
243 {
Patrick Venture03db87e2019-06-20 07:56:06 -0700244 if (hostAddress == 0 || hostLength == 0)
Patrick Venture8104a522019-06-19 19:04:36 -0700245 {
246 std::fprintf(stderr, "Address or Length were 0\n");
247 exit(EXIT_FAILURE);
248 }
249 handler = std::make_unique<host_tool::LpcDataHandler>(
Patrick Venturecf9b2192019-06-27 12:09:52 -0700250 &blob, &devmem, hostAddress, hostLength, &progress);
Patrick Venturea6586362018-12-11 18:47:13 -0800251 }
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -0700252 else if (interface == IPMIPCI)
253 {
Benjamin Faire5aafa52020-06-05 21:04:24 -0700254 auto& pci = host_tool::PciAccessImpl::getInstance();
255 handler = std::make_unique<host_tool::P2aDataHandler>(&blob, &pci,
256 &progress);
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -0700257 }
Willy Tu8a9de242020-10-30 11:00:21 -0700258 else if (interface == IPMIPCI_SKIP_BRIDGE_DISABLE)
259 {
260 auto& pci = host_tool::PciAccessImpl::getInstance();
261 handler = std::make_unique<host_tool::P2aDataHandler>(
262 &blob, &pci, &progress, true);
263 }
Patrick Venturea6586362018-12-11 18:47:13 -0800264
265 if (!handler)
266 {
267 /* TODO(venture): use a custom exception. */
268 std::fprintf(stderr, "Interface %s is unavailable\n",
269 interface.c_str());
270 exit(EXIT_FAILURE);
271 }
272
Patrick Venturebf58cd62018-12-11 09:05:46 -0800273 /* The parameters are all filled out. */
Patrick Venture2bc23fe2018-12-13 10:16:36 -0800274 try
275 {
Patrick Venture55646de2019-05-16 10:06:26 -0700276 host_tool::UpdateHandler updater(&blob, handler.get());
Brandon Kim6749ba12019-09-19 13:31:37 -0700277 host_tool::updaterMain(&updater, imagePath, signaturePath, type,
278 ignoreUpdate);
Patrick Venture2bc23fe2018-12-13 10:16:36 -0800279 }
Patrick Venture9b534f02018-12-13 16:10:02 -0800280 catch (const host_tool::ToolException& e)
Patrick Venture2bc23fe2018-12-13 10:16:36 -0800281 {
282 std::fprintf(stderr, "Exception received: %s\n", e.what());
283 return -1;
284 }
Patrick Venturee564d5b2019-05-14 12:30:06 -0700285 catch (const std::exception& e)
286 {
287 std::fprintf(stderr, "Unexpected exception received: %s\n",
288 e.what());
289 return -1;
290 }
Patrick Venturebf58cd62018-12-11 09:05:46 -0800291 }
292
293 return 0;
294}