blob: ff00dd471ffa8c5dde1df7c89fb3005d769ee320 [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 Venture2bc23fe2018-12-13 10:16:36 -080022#include "tool_errors.hpp"
Patrick Venturebf58cd62018-12-11 09:05:46 -080023#include "updater.hpp"
24
25/* Use CLI11 argument parser once in openbmc/meta-oe or whatever. */
26#include <getopt.h>
27
Patrick Venturea6586362018-12-11 18:47:13 -080028#include <algorithm>
Patrick Venturebf58cd62018-12-11 09:05:46 -080029#include <cstdio>
Patrick Venture8104a522019-06-19 19:04:36 -070030#include <cstdlib>
Patrick Venturee564d5b2019-05-14 12:30:06 -070031#include <exception>
Patrick Ventureaa107a62018-12-12 15:16:25 -080032#include <iostream>
Patrick Venture664c5bc2019-03-07 08:09:45 -080033#include <ipmiblob/blob_handler.hpp>
34#include <ipmiblob/ipmi_handler.hpp>
Patrick Ventureaa107a62018-12-12 15:16:25 -080035#include <iterator>
Patrick Venture00887592018-12-11 10:57:06 -080036#include <memory>
Patrick Venturebf58cd62018-12-11 09:05:46 -080037#include <string>
Patrick Venturea6586362018-12-11 18:47:13 -080038#include <vector>
39
40#define IPMILPC "ipmilpc"
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070041#define IPMIPCI "ipmipci"
Patrick Venturea6586362018-12-11 18:47:13 -080042#define IPMIBT "ipmibt"
43
44namespace
45{
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070046const std::vector<std::string> interfaceList = {IPMIBT, IPMILPC, IPMIPCI};
Patrick Venturea6586362018-12-11 18:47:13 -080047}
Patrick Venturebf58cd62018-12-11 09:05:46 -080048
49void usage(const char* program)
50{
Patrick Venture7ae5dde2018-12-14 10:03:35 -080051 std::fprintf(
52 stderr,
53 "Usage: %s --command <command> --interface <interface> --image "
54 "<image file> --sig <signature file>\n",
55 program);
Patrick Venturea6586362018-12-11 18:47:13 -080056
Patrick Venture7ae5dde2018-12-14 10:03:35 -080057 std::fprintf(stderr, "interfaces: ");
Patrick Ventureaa107a62018-12-12 15:16:25 -080058 std::copy(interfaceList.begin(), interfaceList.end(),
59 std::ostream_iterator<std::string>(std::cerr, ", "));
60 std::fprintf(stderr, "\n");
Patrick Venturebf58cd62018-12-11 09:05:46 -080061}
62
63bool checkCommand(const std::string& command)
64{
65 return (command == "update");
66}
67
68bool checkInterface(const std::string& interface)
69{
Patrick Venturea6586362018-12-11 18:47:13 -080070 auto intf =
71 std::find(interfaceList.begin(), interfaceList.end(), interface);
72 return (intf != interfaceList.end());
Patrick Venturebf58cd62018-12-11 09:05:46 -080073}
74
75int main(int argc, char* argv[])
76{
77 std::string command, interface, imagePath, signaturePath;
Patrick Venture8104a522019-06-19 19:04:36 -070078 char* valueEnd = nullptr;
79 long address = 0;
80 long length = 0;
Patrick Venturebf58cd62018-12-11 09:05:46 -080081
82 while (1)
83 {
84 // clang-format off
85 static struct option long_options[] = {
86 {"command", required_argument, 0, 'c'},
87 {"interface", required_argument, 0, 'i'},
88 {"image", required_argument, 0, 'm'},
89 {"sig", required_argument, 0, 's'},
Patrick Venture8104a522019-06-19 19:04:36 -070090 {"address", required_argument, 0, 'a'},
91 {"length", required_argument, 0, 'l'},
Patrick Venturebf58cd62018-12-11 09:05:46 -080092 {0, 0, 0, 0}
93 };
94 // clang-format on
95
96 int option_index = 0;
97 int c =
Patrick Venture8104a522019-06-19 19:04:36 -070098 getopt_long(argc, argv, "c:i:m:s:a:l", long_options, &option_index);
Patrick Venturebf58cd62018-12-11 09:05:46 -080099 if (c == -1)
100 {
101 break;
102 }
103
104 switch (c)
105 {
106 case 'c':
107 command = std::string{optarg};
108 if (!checkCommand(command))
109 {
110 usage(argv[0]);
111 exit(EXIT_FAILURE);
112 }
113
114 break;
115 case 'i':
116 interface = std::string{optarg};
117 if (!checkInterface(interface))
118 {
119 usage(argv[0]);
120 exit(EXIT_FAILURE);
121 }
122 break;
123 case 'm':
124 imagePath = std::string{optarg};
125 break;
126 case 's':
127 signaturePath = std::string{optarg};
128 break;
Patrick Venture8104a522019-06-19 19:04:36 -0700129 case 'a':
130 address = std::strtol(&optarg[0], &valueEnd, 0);
131 if (valueEnd == nullptr)
132 {
133 usage(argv[0]);
134 exit(EXIT_FAILURE);
135 }
136 break;
137 case 'l':
138 length = std::strtol(&optarg[0], &valueEnd, 0);
139 if (valueEnd == nullptr)
140 {
141 usage(argv[0]);
142 exit(EXIT_FAILURE);
143 }
144 break;
Patrick Venturebf58cd62018-12-11 09:05:46 -0800145 default:
146 usage(argv[0]);
147 exit(EXIT_FAILURE);
148 }
149 }
150
Patrick Venture361bd5a2018-12-14 09:49:47 -0800151 if (command.empty())
152 {
153 usage(argv[0]);
154 exit(EXIT_FAILURE);
155 }
156
Patrick Venturebf58cd62018-12-11 09:05:46 -0800157 /* They want to update the firmware. */
158 if (command == "update")
159 {
160 if (interface.empty() || imagePath.empty() || signaturePath.empty())
161 {
162 usage(argv[0]);
163 exit(EXIT_FAILURE);
164 }
165
Patrick Venture866d4482019-05-13 09:26:52 -0700166 auto ipmi = ipmiblob::IpmiHandler::CreateIpmiHandler();
167 ipmiblob::BlobHandler blob(std::move(ipmi));
Patrick Venture46bdadc2019-01-18 09:04:16 -0800168 host_tool::DevMemDevice devmem;
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -0700169 host_tool::PciUtilImpl pci;
Patrick Venture00887592018-12-11 10:57:06 -0800170
Patrick Venture9b534f02018-12-13 16:10:02 -0800171 std::unique_ptr<host_tool::DataInterface> handler;
Patrick Venturea6586362018-12-11 18:47:13 -0800172
173 /* Input has already been validated in this case. */
174 if (interface == IPMIBT)
175 {
Patrick Venture9b534f02018-12-13 16:10:02 -0800176 handler = std::make_unique<host_tool::BtDataHandler>(&blob);
Patrick Venturea6586362018-12-11 18:47:13 -0800177 }
178 else if (interface == IPMILPC)
179 {
Patrick Venture8104a522019-06-19 19:04:36 -0700180 if (address == 0 || length == 0)
181 {
182 std::fprintf(stderr, "Address or Length were 0\n");
183 exit(EXIT_FAILURE);
184 }
185 handler = std::make_unique<host_tool::LpcDataHandler>(
186 &blob, &devmem, address, length);
Patrick Venturea6586362018-12-11 18:47:13 -0800187 }
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -0700188 else if (interface == IPMIPCI)
189 {
190 handler = std::make_unique<host_tool::P2aDataHandler>(
191 &blob, &devmem, &pci);
192 }
Patrick Venturea6586362018-12-11 18:47:13 -0800193
194 if (!handler)
195 {
196 /* TODO(venture): use a custom exception. */
197 std::fprintf(stderr, "Interface %s is unavailable\n",
198 interface.c_str());
199 exit(EXIT_FAILURE);
200 }
201
Patrick Venturebf58cd62018-12-11 09:05:46 -0800202 /* The parameters are all filled out. */
Patrick Venture2bc23fe2018-12-13 10:16:36 -0800203 try
204 {
Patrick Venture55646de2019-05-16 10:06:26 -0700205 host_tool::UpdateHandler updater(&blob, handler.get());
206 host_tool::updaterMain(&updater, imagePath, signaturePath);
Patrick Venture2bc23fe2018-12-13 10:16:36 -0800207 }
Patrick Venture9b534f02018-12-13 16:10:02 -0800208 catch (const host_tool::ToolException& e)
Patrick Venture2bc23fe2018-12-13 10:16:36 -0800209 {
210 std::fprintf(stderr, "Exception received: %s\n", e.what());
211 return -1;
212 }
Patrick Venturee564d5b2019-05-14 12:30:06 -0700213 catch (const std::exception& e)
214 {
215 std::fprintf(stderr, "Unexpected exception received: %s\n",
216 e.what());
217 return -1;
218 }
Patrick Venturebf58cd62018-12-11 09:05:46 -0800219 }
220
221 return 0;
222}