1 /* 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 17 #include "bt.hpp" 18 #include "io.hpp" 19 #include "lpc.hpp" 20 #include "p2a.hpp" 21 #include "pci.hpp" 22 #include "progress.hpp" 23 #include "tool_errors.hpp" 24 #include "updater.hpp" 25 26 /* Use CLI11 argument parser once in openbmc/meta-oe or whatever. */ 27 #include <getopt.h> 28 29 #include <algorithm> 30 #include <cstdio> 31 #include <cstdlib> 32 #include <exception> 33 #include <iostream> 34 #include <ipmiblob/blob_handler.hpp> 35 #include <ipmiblob/ipmi_handler.hpp> 36 #include <iterator> 37 #include <limits> 38 #include <memory> 39 #include <string> 40 #include <vector> 41 42 #define IPMILPC "ipmilpc" 43 #define IPMIPCI "ipmipci" 44 #define IPMIBT "ipmibt" 45 46 namespace 47 { 48 const std::vector<std::string> interfaceList = {IPMIBT, IPMILPC, IPMIPCI}; 49 } // namespace 50 51 void usage(const char* program) 52 { 53 std::fprintf( 54 stderr, 55 "Usage: %s --command <command> --interface <interface> --image " 56 "<image file> --sig <signature file> --type <layout> " 57 "[--ignore-update]\n", 58 program); 59 60 std::fprintf(stderr, "interfaces: "); 61 std::copy(interfaceList.begin(), interfaceList.end(), 62 std::ostream_iterator<std::string>(std::cerr, ", ")); 63 std::fprintf(stderr, "\n"); 64 65 std::fprintf(stderr, "layouts examples: image, bios\n"); 66 std::fprintf(stderr, 67 "the type field specifies '/flash/{layout}' for a handler\n"); 68 } 69 70 bool checkCommand(const std::string& command) 71 { 72 return (command == "update"); 73 } 74 75 bool checkInterface(const std::string& interface) 76 { 77 auto intf = 78 std::find(interfaceList.begin(), interfaceList.end(), interface); 79 return (intf != interfaceList.end()); 80 } 81 82 int main(int argc, char* argv[]) 83 { 84 std::string command, interface, imagePath, signaturePath, type; 85 char* valueEnd = nullptr; 86 long address = 0; 87 long length = 0; 88 std::uint32_t hostAddress = 0; 89 std::uint32_t hostLength = 0; 90 bool ignoreUpdate = false; 91 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'}, 100 {"address", required_argument, 0, 'a'}, 101 {"length", required_argument, 0, 'l'}, 102 {"type", required_argument, 0, 't'}, 103 {"ignore-update", no_argument, 0, 'u'}, 104 {0, 0, 0, 0} 105 }; 106 // clang-format on 107 108 int option_index = 0; 109 int c = getopt_long(argc, argv, "c:i:m:s:a:l:t:u", long_options, 110 &option_index); 111 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; 141 case 'a': 142 address = std::strtol(&optarg[0], &valueEnd, 0); 143 if (valueEnd == nullptr) 144 { 145 usage(argv[0]); 146 exit(EXIT_FAILURE); 147 } 148 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); 155 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 } 163 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); 170 break; 171 case 't': 172 type = std::string{optarg}; 173 break; 174 case 'u': 175 ignoreUpdate = true; 176 break; 177 default: 178 usage(argv[0]); 179 exit(EXIT_FAILURE); 180 } 181 } 182 183 if (command.empty()) 184 { 185 usage(argv[0]); 186 exit(EXIT_FAILURE); 187 } 188 189 /* They want to update the firmware. */ 190 if (command == "update") 191 { 192 if (interface.empty() || imagePath.empty() || signaturePath.empty() || 193 type.empty()) 194 { 195 usage(argv[0]); 196 exit(EXIT_FAILURE); 197 } 198 199 auto ipmi = ipmiblob::IpmiHandler::CreateIpmiHandler(); 200 ipmiblob::BlobHandler blob(std::move(ipmi)); 201 host_tool::DevMemDevice devmem; 202 host_tool::PciUtilImpl pci; 203 host_tool::ProgressStdoutIndicator progress; 204 205 std::unique_ptr<host_tool::DataInterface> handler; 206 207 /* Input has already been validated in this case. */ 208 if (interface == IPMIBT) 209 { 210 handler = 211 std::make_unique<host_tool::BtDataHandler>(&blob, &progress); 212 } 213 else if (interface == IPMILPC) 214 { 215 if (hostAddress == 0 || hostLength == 0) 216 { 217 std::fprintf(stderr, "Address or Length were 0\n"); 218 exit(EXIT_FAILURE); 219 } 220 handler = std::make_unique<host_tool::LpcDataHandler>( 221 &blob, &devmem, hostAddress, hostLength, &progress); 222 } 223 else if (interface == IPMIPCI) 224 { 225 handler = std::make_unique<host_tool::P2aDataHandler>( 226 &blob, &devmem, &pci, &progress); 227 } 228 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 237 /* The parameters are all filled out. */ 238 try 239 { 240 host_tool::UpdateHandler updater(&blob, handler.get()); 241 host_tool::updaterMain(&updater, imagePath, signaturePath, type, 242 ignoreUpdate); 243 } 244 catch (const host_tool::ToolException& e) 245 { 246 std::fprintf(stderr, "Exception received: %s\n", e.what()); 247 return -1; 248 } 249 catch (const std::exception& e) 250 { 251 std::fprintf(stderr, "Unexpected exception received: %s\n", 252 e.what()); 253 return -1; 254 } 255 } 256 257 return 0; 258 } 259