blob: f73bcadc5910a3c0a09968ca204a166a7eb52415 [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"
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070020#include "p2a.hpp"
21#include "pci.hpp"
Patrick Venturecf9b2192019-06-27 12:09:52 -070022#include "progress.hpp"
Patrick Venture2bc23fe2018-12-13 10:16:36 -080023#include "tool_errors.hpp"
Patrick Venturebf58cd62018-12-11 09:05:46 -080024#include "updater.hpp"
25
26/* Use CLI11 argument parser once in openbmc/meta-oe or whatever. */
27#include <getopt.h>
28
Patrick Venturea6586362018-12-11 18:47:13 -080029#include <algorithm>
Patrick Venturebf58cd62018-12-11 09:05:46 -080030#include <cstdio>
Patrick Venture8104a522019-06-19 19:04:36 -070031#include <cstdlib>
Patrick Venturee564d5b2019-05-14 12:30:06 -070032#include <exception>
Patrick Ventureaa107a62018-12-12 15:16:25 -080033#include <iostream>
Patrick Venture664c5bc2019-03-07 08:09:45 -080034#include <ipmiblob/blob_handler.hpp>
35#include <ipmiblob/ipmi_handler.hpp>
Patrick Ventureaa107a62018-12-12 15:16:25 -080036#include <iterator>
Patrick Venture03db87e2019-06-20 07:56:06 -070037#include <limits>
Patrick Venture00887592018-12-11 10:57:06 -080038#include <memory>
Patrick Venturebf58cd62018-12-11 09:05:46 -080039#include <string>
Patrick Venturea6586362018-12-11 18:47:13 -080040#include <vector>
41
42#define IPMILPC "ipmilpc"
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070043#define IPMIPCI "ipmipci"
Patrick Venturea6586362018-12-11 18:47:13 -080044#define IPMIBT "ipmibt"
45
46namespace
47{
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070048const std::vector<std::string> interfaceList = {IPMIBT, IPMILPC, IPMIPCI};
Patrick Venture9f937c42019-06-21 07:55:54 -070049} // namespace
Patrick Venturebf58cd62018-12-11 09:05:46 -080050
51void usage(const char* program)
52{
Patrick Venture7ae5dde2018-12-14 10:03:35 -080053 std::fprintf(
54 stderr,
55 "Usage: %s --command <command> --interface <interface> --image "
Brandon Kim6749ba12019-09-19 13:31:37 -070056 "<image file> --sig <signature file> --type <layout> "
57 "[--ignore-update]\n",
Patrick Venture7ae5dde2018-12-14 10:03:35 -080058 program);
Patrick Venturea6586362018-12-11 18:47:13 -080059
Patrick Venture7ae5dde2018-12-14 10:03:35 -080060 std::fprintf(stderr, "interfaces: ");
Patrick Ventureaa107a62018-12-12 15:16:25 -080061 std::copy(interfaceList.begin(), interfaceList.end(),
62 std::ostream_iterator<std::string>(std::cerr, ", "));
63 std::fprintf(stderr, "\n");
Patrick Venture9f937c42019-06-21 07:55:54 -070064
Patrick Venturec498caa2019-08-15 10:12:50 -070065 std::fprintf(stderr, "layouts examples: image, bios\n");
66 std::fprintf(stderr,
67 "the type field specifies '/flash/{layout}' for a handler\n");
Patrick Venturebf58cd62018-12-11 09:05:46 -080068}
69
70bool checkCommand(const std::string& command)
71{
72 return (command == "update");
73}
74
75bool checkInterface(const std::string& interface)
76{
Patrick Venturea6586362018-12-11 18:47:13 -080077 auto intf =
78 std::find(interfaceList.begin(), interfaceList.end(), interface);
79 return (intf != interfaceList.end());
Patrick Venturebf58cd62018-12-11 09:05:46 -080080}
81
82int main(int argc, char* argv[])
83{
Patrick Venture9f937c42019-06-21 07:55:54 -070084 std::string command, interface, imagePath, signaturePath, type;
Patrick Venture8104a522019-06-19 19:04:36 -070085 char* valueEnd = nullptr;
86 long address = 0;
87 long length = 0;
Patrick Venture03db87e2019-06-20 07:56:06 -070088 std::uint32_t hostAddress = 0;
89 std::uint32_t hostLength = 0;
Brandon Kim6749ba12019-09-19 13:31:37 -070090 bool ignoreUpdate = false;
Patrick Venturebf58cd62018-12-11 09:05:46 -080091
92 while (1)
93 {
94 // clang-format off
95 static struct option long_options[] = {
96 {"command", required_argument, 0, 'c'},
97 {"interface", required_argument, 0, 'i'},
98 {"image", required_argument, 0, 'm'},
99 {"sig", required_argument, 0, 's'},
Patrick Venture8104a522019-06-19 19:04:36 -0700100 {"address", required_argument, 0, 'a'},
101 {"length", required_argument, 0, 'l'},
Patrick Venture9f937c42019-06-21 07:55:54 -0700102 {"type", required_argument, 0, 't'},
Brandon Kim6749ba12019-09-19 13:31:37 -0700103 {"ignore-update", no_argument, 0, 'u'},
Patrick Venturebf58cd62018-12-11 09:05:46 -0800104 {0, 0, 0, 0}
105 };
106 // clang-format on
107
108 int option_index = 0;
Brandon Kim6749ba12019-09-19 13:31:37 -0700109 int c = getopt_long(argc, argv, "c:i:m:s:a:l:t:u", long_options,
Patrick Venture9f937c42019-06-21 07:55:54 -0700110 &option_index);
Patrick Venturebf58cd62018-12-11 09:05:46 -0800111 if (c == -1)
112 {
113 break;
114 }
115
116 switch (c)
117 {
118 case 'c':
119 command = std::string{optarg};
120 if (!checkCommand(command))
121 {
122 usage(argv[0]);
123 exit(EXIT_FAILURE);
124 }
125
126 break;
127 case 'i':
128 interface = std::string{optarg};
129 if (!checkInterface(interface))
130 {
131 usage(argv[0]);
132 exit(EXIT_FAILURE);
133 }
134 break;
135 case 'm':
136 imagePath = std::string{optarg};
137 break;
138 case 's':
139 signaturePath = std::string{optarg};
140 break;
Patrick Venture8104a522019-06-19 19:04:36 -0700141 case 'a':
142 address = std::strtol(&optarg[0], &valueEnd, 0);
143 if (valueEnd == nullptr)
144 {
145 usage(argv[0]);
146 exit(EXIT_FAILURE);
147 }
Patrick Venture03db87e2019-06-20 07:56:06 -0700148 if (address > std::numeric_limits<std::uint32_t>::max())
149 {
150 std::fprintf(stderr, "Address beyond 32-bit limit.\n");
151 usage(argv[0]);
152 exit(EXIT_FAILURE);
153 }
154 hostAddress = static_cast<std::uint32_t>(address);
Patrick Venture8104a522019-06-19 19:04:36 -0700155 break;
156 case 'l':
157 length = std::strtol(&optarg[0], &valueEnd, 0);
158 if (valueEnd == nullptr)
159 {
160 usage(argv[0]);
161 exit(EXIT_FAILURE);
162 }
Patrick Venture03db87e2019-06-20 07:56:06 -0700163 if (length > std::numeric_limits<std::uint32_t>::max())
164 {
165 std::fprintf(stderr, "Length beyond 32-bit limit.\n");
166 usage(argv[0]);
167 exit(EXIT_FAILURE);
168 }
169 hostLength = static_cast<std::uint32_t>(length);
Patrick Venture8104a522019-06-19 19:04:36 -0700170 break;
Patrick Venture9f937c42019-06-21 07:55:54 -0700171 case 't':
172 type = std::string{optarg};
Patrick Venture9f937c42019-06-21 07:55:54 -0700173 break;
Brandon Kim6749ba12019-09-19 13:31:37 -0700174 case 'u':
175 ignoreUpdate = true;
176 break;
Patrick Venturebf58cd62018-12-11 09:05:46 -0800177 default:
178 usage(argv[0]);
179 exit(EXIT_FAILURE);
180 }
181 }
182
Patrick Venture361bd5a2018-12-14 09:49:47 -0800183 if (command.empty())
184 {
185 usage(argv[0]);
186 exit(EXIT_FAILURE);
187 }
188
Patrick Venturebf58cd62018-12-11 09:05:46 -0800189 /* They want to update the firmware. */
190 if (command == "update")
191 {
Patrick Venturec498caa2019-08-15 10:12:50 -0700192 if (interface.empty() || imagePath.empty() || signaturePath.empty() ||
193 type.empty())
Patrick Venturebf58cd62018-12-11 09:05:46 -0800194 {
195 usage(argv[0]);
196 exit(EXIT_FAILURE);
197 }
198
Patrick Venture866d4482019-05-13 09:26:52 -0700199 auto ipmi = ipmiblob::IpmiHandler::CreateIpmiHandler();
200 ipmiblob::BlobHandler blob(std::move(ipmi));
Patrick Venture46bdadc2019-01-18 09:04:16 -0800201 host_tool::DevMemDevice devmem;
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -0700202 host_tool::PciUtilImpl pci;
Patrick Venturecf9b2192019-06-27 12:09:52 -0700203 host_tool::ProgressStdoutIndicator progress;
Patrick Venture00887592018-12-11 10:57:06 -0800204
Patrick Venture9b534f02018-12-13 16:10:02 -0800205 std::unique_ptr<host_tool::DataInterface> handler;
Patrick Venturea6586362018-12-11 18:47:13 -0800206
207 /* Input has already been validated in this case. */
208 if (interface == IPMIBT)
209 {
Patrick Venturecf9b2192019-06-27 12:09:52 -0700210 handler =
211 std::make_unique<host_tool::BtDataHandler>(&blob, &progress);
Patrick Venturea6586362018-12-11 18:47:13 -0800212 }
213 else if (interface == IPMILPC)
214 {
Patrick Venture03db87e2019-06-20 07:56:06 -0700215 if (hostAddress == 0 || hostLength == 0)
Patrick Venture8104a522019-06-19 19:04:36 -0700216 {
217 std::fprintf(stderr, "Address or Length were 0\n");
218 exit(EXIT_FAILURE);
219 }
220 handler = std::make_unique<host_tool::LpcDataHandler>(
Patrick Venturecf9b2192019-06-27 12:09:52 -0700221 &blob, &devmem, hostAddress, hostLength, &progress);
Patrick Venturea6586362018-12-11 18:47:13 -0800222 }
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -0700223 else if (interface == IPMIPCI)
224 {
225 handler = std::make_unique<host_tool::P2aDataHandler>(
Patrick Venturecf9b2192019-06-27 12:09:52 -0700226 &blob, &devmem, &pci, &progress);
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -0700227 }
Patrick Venturea6586362018-12-11 18:47:13 -0800228
229 if (!handler)
230 {
231 /* TODO(venture): use a custom exception. */
232 std::fprintf(stderr, "Interface %s is unavailable\n",
233 interface.c_str());
234 exit(EXIT_FAILURE);
235 }
236
Patrick Venturebf58cd62018-12-11 09:05:46 -0800237 /* The parameters are all filled out. */
Patrick Venture2bc23fe2018-12-13 10:16:36 -0800238 try
239 {
Patrick Venture55646de2019-05-16 10:06:26 -0700240 host_tool::UpdateHandler updater(&blob, handler.get());
Brandon Kim6749ba12019-09-19 13:31:37 -0700241 host_tool::updaterMain(&updater, imagePath, signaturePath, type,
242 ignoreUpdate);
Patrick Venture2bc23fe2018-12-13 10:16:36 -0800243 }
Patrick Venture9b534f02018-12-13 16:10:02 -0800244 catch (const host_tool::ToolException& e)
Patrick Venture2bc23fe2018-12-13 10:16:36 -0800245 {
246 std::fprintf(stderr, "Exception received: %s\n", e.what());
247 return -1;
248 }
Patrick Venturee564d5b2019-05-14 12:30:06 -0700249 catch (const std::exception& e)
250 {
251 std::fprintf(stderr, "Unexpected exception received: %s\n",
252 e.what());
253 return -1;
254 }
Patrick Venturebf58cd62018-12-11 09:05:46 -0800255 }
256
257 return 0;
258}