blob: 50726e228bd9797236bb5173a81b7f49f57b6b04 [file] [log] [blame]
Vernon Mauery52ce6622019-05-22 09:19:46 -07001#include <ipmid/api.h>
2#include <openssl/evp.h>
3#include <openssl/sha.h>
4#include <sys/mman.h>
5#include <sys/stat.h>
6#include <sys/types.h>
7#include <unistd.h>
8
9#include <boost/algorithm/string.hpp>
10#include <boost/asio.hpp>
11#include <boost/process/child.hpp>
12#include <boost/uuid/random_generator.hpp>
13#include <boost/uuid/uuid_io.hpp>
14#include <chrono>
15#include <commandutils.hpp>
16#include <cstdint>
17#include <filesystem>
18#include <fstream>
19#include <iostream>
anil kumar appana6c7d9382019-05-31 14:33:13 +000020#include <ipmid/api.hpp>
Vernon Mauery52ce6622019-05-22 09:19:46 -070021#include <map>
22#include <random>
23#include <sdbusplus/bus.hpp>
24#include <sdbusplus/bus/match.hpp>
25#include <sdbusplus/server/object.hpp>
26#include <sdbusplus/timer.hpp>
27#include <sstream>
28
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +053029#ifdef INTEL_PFR_ENABLED
30uint32_t imgLength = 0;
31uint32_t imgType = 0;
32bool block0Mapped = false;
33static constexpr uint32_t perBlock0MagicNum = 0xB6EAFD19;
34#endif
35
James Feistbeaa2eb2019-08-22 10:59:24 -070036static constexpr const char *secondaryFitImageStartAddr = "22480000";
anil kumar appana31f88872019-08-02 15:16:27 +000037static uint8_t getActiveBootImage(void);
Vernon Mauery52ce6622019-05-22 09:19:46 -070038static void register_netfn_firmware_functions() __attribute__((constructor));
39
40// oem return code for firmware update control
41constexpr ipmi_ret_t IPMI_CC_REQ_INVALID_PHASE = 0xd5;
42constexpr ipmi_ret_t IPMI_CC_USB_ATTACH_FAIL = 0x80;
43
Vernon Mauery52ce6622019-05-22 09:19:46 -070044static constexpr bool DEBUG = false;
45
46static constexpr char FW_UPDATE_SERVER_DBUS_NAME[] =
47 "xyz.openbmc_project.fwupdate1.server";
48
49static constexpr char FW_UPDATE_SERVER_PATH[] =
50 "/xyz/openbmc_project/fwupdate1";
51static constexpr char FW_UPDATE_SERVER_INFO_PATH[] =
52 "/xyz/openbmc_project/fwupdate1/info";
53static constexpr char FW_UPDATE_ACTIVE_INFO_PATH[] =
54 "/xyz/openbmc_project/fwupdate1/info/bmc_active";
55static constexpr char FW_UPDATE_BACKUP_INFO_PATH[] =
56 "/xyz/openbmc_project/fwupdate1/info/bmc_backup";
57
58static constexpr char FW_UPDATE_INTERFACE[] = "xyz.openbmc_project.fwupdate1";
59static constexpr char FW_UPDATE_INFO_INTERFACE[] =
60 "xyz.openbmc_project.fwupdate1.fwinfo";
61static constexpr char FW_UPDATE_SECURITY_INTERFACE[] =
62 "xyz.openbmc_project.fwupdate1.security";
63
64constexpr std::size_t operator""_MB(unsigned long long v)
65{
66 return 1024u * 1024u * v;
67}
68static constexpr int FIRMWARE_BUFFER_MAX_SIZE = 32_MB;
69
70static constexpr char FIRMWARE_BUFFER_FILE[] = "/tmp/fw-download.bin";
71static bool local_download_is_active(void)
72{
73 struct stat sb;
74 if (stat(FIRMWARE_BUFFER_FILE, &sb) < 0)
75 return false;
76 return true;
77}
78
79class fw_update_status_cache
80{
81 public:
82 enum
83 {
84 FW_STATE_INIT = 0,
85 FW_STATE_IDLE,
86 FW_STATE_DOWNLOAD,
87 FW_STATE_VERIFY,
88 FW_STATE_WRITE,
89 FW_STATE_READY,
90 FW_STATE_ERROR = 0x0f,
91 FW_STATE_AC_CYCLE_REQUIRED = 0x83,
92 };
Vernon Mauery52ce6622019-05-22 09:19:46 -070093 uint8_t state()
94 {
95 if (DEBUG)
96 std::cerr << "fw-state: 0x" << std::hex << (int)_state << '\n';
97 if ((_state == FW_STATE_IDLE || _state == FW_STATE_INIT) &&
98 local_download_is_active())
99 {
100 _state = FW_STATE_DOWNLOAD;
101 _percent = 0;
102 }
103 return _state;
104 }
105 uint8_t percent()
106 {
107 return _percent;
108 }
109 std::string msg()
110 {
111 return _msg;
112 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700113 std::string get_software_obj_path()
114 {
115 return _software_obj_path;
116 }
117 void set_software_obj_path(std::string &obj_path)
118 {
119 _software_obj_path = obj_path;
120 _state = FW_STATE_WRITE;
121 _percent = 0;
122 _match = std::make_shared<sdbusplus::bus::match::match>(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700123 *_bus,
Vernon Mauery52ce6622019-05-22 09:19:46 -0700124 sdbusplus::bus::match::rules::propertiesChanged(
125 _software_obj_path,
126 "xyz.openbmc_project.Software.ActivationProgress"),
127 [&](sdbusplus::message::message &msg) {
128 if (DEBUG)
129 std::cerr << "propertiesChanged lambda\n";
130 std::map<std::string, ipmi::DbusVariant> props;
131 std::vector<std::string> inval;
132 std::string iface;
133 msg.read(iface, props, inval);
134 _parse_props(props);
135 });
136 }
137 uint8_t activation_timer_timeout()
138 {
139 std::cerr << "activation_timer_timout(): increase percentage...\n";
140 _percent = _percent + 5;
anil kumar appana31f88872019-08-02 15:16:27 +0000141 if (_percent >= 95)
142 {
143 /*changing the state to ready to update firmware utility */
144 _state = FW_STATE_READY;
145 }
146 std::cerr << " _percent = " << (int)_percent << "\n";
Vernon Mauery52ce6622019-05-22 09:19:46 -0700147 return _percent;
148 }
anil kumar appana31f88872019-08-02 15:16:27 +0000149 /* API for changing state to ERROR */
150 void firmwareUpdateAbortState()
151 {
152 unlink(FIRMWARE_BUFFER_FILE);
153 // changing the state to error
154 _state = FW_STATE_ERROR;
155 }
156 void setDeferRestart(bool deferRestart)
157 {
158 _deferRestart = deferRestart;
159 }
160 void setInhibitDowngrade(bool inhibitDowngrade)
161 {
162 _inhibitDowngrade = inhibitDowngrade;
163 }
164 bool getDeferRestart()
165 {
166 return _deferRestart;
167 }
168 bool getInhibitDowngrade()
169 {
170 return _inhibitDowngrade;
171 }
172
Vernon Mauery52ce6622019-05-22 09:19:46 -0700173 protected:
174 void _parse_props(std::map<std::string, ipmi::DbusVariant> &properties)
175 {
176 if (DEBUG)
177 std::cerr << "propertiesChanged (" << properties.size()
178 << " elements)";
179 for (const auto &t : properties)
180 {
181 auto key = t.first;
182 auto value = t.second;
183 if (key == "state")
184 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700185 auto state = std::get<std::string>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700186 if (DEBUG)
187 std::cerr << ", state=" << state;
188 if (state == "INIT")
189 _state = FW_STATE_INIT;
190 else if (state == "IDLE")
191 _state = FW_STATE_IDLE;
192 else if (state == "DOWNLOAD")
193 _state = FW_STATE_DOWNLOAD;
194 else if (state == "VERIFY")
195 _state = FW_STATE_VERIFY;
196 else if (state == "WRITE")
197 _state = FW_STATE_WRITE;
198 else if (state == "READY")
199 _state = FW_STATE_READY;
200 else if (state == "ERROR")
201 _state = FW_STATE_ERROR;
202 else if (state == "AC_CYCLE_REQUIRED")
203 _state = FW_STATE_AC_CYCLE_REQUIRED;
204 else
205 {
206 _state = FW_STATE_ERROR;
207 _msg = "internal error";
208 }
209 }
210 else if (key == "percent")
211 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700212 _percent = std::get<int32_t>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700213 if (DEBUG)
214 std::cerr << ", pct=" << (int)_percent;
215 }
216 else if (key == "msg")
217 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700218 _msg = std::get<std::string>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700219 if (DEBUG)
220 std::cerr << ", msg='" << _msg << '\'';
221 }
222 else if (key == "Progress")
223 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700224 _percent = std::get<uint8_t>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700225 ;
226 if (_percent == 100)
227 _state = FW_STATE_READY;
228 }
229 }
230 if ((_state == FW_STATE_IDLE || _state == FW_STATE_INIT) &&
231 local_download_is_active())
232 {
233 _state = FW_STATE_DOWNLOAD;
234 _percent = 0;
235 }
236 if (DEBUG)
237 std::cerr << '\n';
238 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700239
Vernon Mauery15419dd2019-05-24 09:40:30 -0700240 std::shared_ptr<sdbusplus::asio::connection> _bus;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700241 std::shared_ptr<sdbusplus::bus::match::match> _match;
242 uint8_t _state = 0;
243 uint8_t _percent = 0;
anil kumar appana31f88872019-08-02 15:16:27 +0000244 bool _deferRestart = false;
245 bool _inhibitDowngrade = false;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700246 std::string _msg;
247
248 private:
249 std::string _software_obj_path;
250};
251
252static fw_update_status_cache fw_update_status;
253
254static std::chrono::steady_clock::time_point fw_random_number_timestamp;
255static constexpr int FW_RANDOM_NUMBER_LENGTH = 8;
256static constexpr auto FW_RANDOM_NUMBER_TTL = std::chrono::seconds(30);
257static uint8_t fw_random_number[FW_RANDOM_NUMBER_LENGTH];
258
259static ipmi_ret_t ipmi_firmware_get_fw_random_number(
260 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
261 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
262{
263 std::random_device rd;
264 std::default_random_engine gen(rd());
265 std::uniform_int_distribution<> dist{0, 255};
266
267 if (*data_len != 0)
268 {
269 *data_len = 0;
270 return IPMI_CC_REQ_DATA_LEN_INVALID;
271 }
272
273 fw_random_number_timestamp = std::chrono::steady_clock::now();
274
275 uint8_t *msg_reply = static_cast<uint8_t *>(response);
276 for (int i = 0; i < FW_RANDOM_NUMBER_LENGTH; i++)
277 fw_random_number[i] = msg_reply[i] = dist(gen);
278
279 if (DEBUG)
280 std::cerr << "FW Rand Num: 0x" << std::hex << (int)msg_reply[0] << " 0x"
281 << (int)msg_reply[1] << " 0x" << (int)msg_reply[2] << " 0x"
282 << (int)msg_reply[3] << " 0x" << (int)msg_reply[4] << " 0x"
283 << (int)msg_reply[5] << " 0x" << (int)msg_reply[6] << " 0x"
284 << (int)msg_reply[7] << '\n';
285
286 *data_len = FW_RANDOM_NUMBER_LENGTH;
287
288 return IPMI_CC_OK;
289}
290
AppaRao Puli4b3e1c72019-10-16 20:53:09 +0530291/** @brief Set Firmware Update Mode
292 *
293 * This function sets BMC into firmware update mode
294 * after validating Random number obtained from the Get
295 * Firmware Update Random Number command
296 *
297 * @parameter
298 * - randNum - Random number(token)
299 * @returns IPMI completion code
300 **/
301ipmi::RspType<> ipmiSetFirmwareUpdateMode(
302 std::array<uint8_t, FW_RANDOM_NUMBER_LENGTH> &randNum)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700303{
AppaRao Puli4b3e1c72019-10-16 20:53:09 +0530304 /* Firmware Update Random number is valid for 30 seconds only */
305 auto timeElapsed =
306 (std::chrono::steady_clock::now() - fw_random_number_timestamp);
307 if (std::chrono::duration_cast<std::chrono::microseconds>(timeElapsed)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700308 .count() > std::chrono::duration_cast<std::chrono::microseconds>(
309 FW_RANDOM_NUMBER_TTL)
310 .count())
311 {
AppaRao Puli4b3e1c72019-10-16 20:53:09 +0530312 phosphor::logging::log<phosphor::logging::level::INFO>(
313 "Firmware update random number expired.");
314 return ipmi::responseInvalidFieldRequest();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700315 }
316
AppaRao Puli4b3e1c72019-10-16 20:53:09 +0530317 /* Validate random number */
Vernon Mauery52ce6622019-05-22 09:19:46 -0700318 for (int i = 0; i < FW_RANDOM_NUMBER_LENGTH; i++)
319 {
AppaRao Puli4b3e1c72019-10-16 20:53:09 +0530320 if (fw_random_number[i] != randNum[i])
Vernon Mauery52ce6622019-05-22 09:19:46 -0700321 {
AppaRao Puli4b3e1c72019-10-16 20:53:09 +0530322 phosphor::logging::log<phosphor::logging::level::INFO>(
323 "Invalid random number specified.");
324 return ipmi::responseInvalidFieldRequest();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700325 }
326 }
327
328 if (fw_update_status.state() != fw_update_status_cache::FW_STATE_IDLE
329 // TODO: Allowing FW_STATE_INIT here to let image activation available
330 // without being in FW_STATE_IDLE, need to fix/adjust the state machine
331 // to match xyz.openbmc_project.Software.BMC.Updater service activation
332 // mechanism at finer grain
333 && fw_update_status.state() != fw_update_status_cache::FW_STATE_INIT)
334 {
AppaRao Puli4b3e1c72019-10-16 20:53:09 +0530335 phosphor::logging::log<phosphor::logging::level::INFO>(
336 "Already firmware update is in progress.");
337 return ipmi::responseBusy();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700338 }
339 // FIXME? c++ doesn't off an option for exclusive file creation
340 FILE *fp = fopen(FIRMWARE_BUFFER_FILE, "wx");
341 if (!fp)
342 {
AppaRao Puli4b3e1c72019-10-16 20:53:09 +0530343 phosphor::logging::log<phosphor::logging::level::INFO>(
344 "Unable to open file.");
345 return ipmi::responseUnspecifiedError();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700346 }
347 fclose(fp);
348
AppaRao Puli4b3e1c72019-10-16 20:53:09 +0530349 return ipmi::responseSuccess();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700350}
351
anil kumar appanab57098a2019-05-28 16:22:33 +0000352/** @brief implements exit firmware update mode command
353 * @param None
354 *
355 * @returns IPMI completion code
356 */
357ipmi::RspType<> ipmiFirmwareExitFwUpdateMode()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700358{
Vernon Mauery52ce6622019-05-22 09:19:46 -0700359
anil kumar appanab57098a2019-05-28 16:22:33 +0000360 if (DEBUG)
361 {
362 std::cerr << "Exit FW update mode \n";
363 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700364 switch (fw_update_status.state())
365 {
366 case fw_update_status_cache::FW_STATE_INIT:
367 case fw_update_status_cache::FW_STATE_IDLE:
anil kumar appanab57098a2019-05-28 16:22:33 +0000368 return ipmi::responseInvalidFieldRequest();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700369 break;
370 case fw_update_status_cache::FW_STATE_DOWNLOAD:
Vernon Mauery52ce6622019-05-22 09:19:46 -0700371 case fw_update_status_cache::FW_STATE_VERIFY:
372 break;
373 case fw_update_status_cache::FW_STATE_WRITE:
Vernon Mauery52ce6622019-05-22 09:19:46 -0700374 break;
375 case fw_update_status_cache::FW_STATE_READY:
376 case fw_update_status_cache::FW_STATE_ERROR:
Vernon Mauery52ce6622019-05-22 09:19:46 -0700377 break;
378 case fw_update_status_cache::FW_STATE_AC_CYCLE_REQUIRED:
anil kumar appanab57098a2019-05-28 16:22:33 +0000379 return ipmi::responseInvalidFieldRequest();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700380 break;
381 }
anil kumar appanab57098a2019-05-28 16:22:33 +0000382 fw_update_status.firmwareUpdateAbortState();
383 return ipmi::responseSuccess();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700384}
385
386static void post_transfer_complete_handler(
387 std::unique_ptr<sdbusplus::bus::match::match> &fw_update_matcher);
388static bool request_start_firmware_update(const std::string &uri)
389{
390 if (DEBUG)
391 std::cerr << "request start firmware update()\n";
392
Vernon Mauery52ce6622019-05-22 09:19:46 -0700393 // fwupdate URIs start with file:// or usb:// or tftp:// etc. By the time
394 // the code gets to this point, the file should be transferred start the
395 // request (creating a new file in /tmp/images causes the update manager to
396 // check if it is ready for activation)
397 static std::unique_ptr<sdbusplus::bus::match::match> fw_update_matcher;
398 post_transfer_complete_handler(fw_update_matcher);
399 std::filesystem::rename(
400 uri, "/tmp/images/" +
401 boost::uuids::to_string(boost::uuids::random_generator()()));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700402 return true;
403}
404
405class transfer_hash_check
406{
407 public:
408 enum hash_check
409 {
410 CHECK_NOT_REQUESTED = 0,
411 CHECK_REQUESTED,
412 CHECK_PASSED_SHA2,
413 CHECK_RESVD1,
414 CHECK_FAILED_SHA2 = 0xe2,
415 CHECK_RESVD2 = 0xe3,
416 };
417
418 protected:
419 EVP_MD_CTX *_ctx;
420 std::vector<uint8_t> _expected;
421 enum hash_check _check;
422 bool _started;
423
424 public:
425 transfer_hash_check() : _check(CHECK_NOT_REQUESTED), _started(false)
426 {
427 }
428 ~transfer_hash_check()
429 {
430 if (_ctx)
431 {
432 EVP_MD_CTX_destroy(_ctx);
433 _ctx = NULL;
434 }
435 }
436 void init(const std::vector<uint8_t> &expected)
437 {
438 _expected = expected;
439 _check = CHECK_REQUESTED;
440 _ctx = EVP_MD_CTX_create();
441 EVP_DigestInit(_ctx, EVP_sha256());
442 }
443 void hash(const std::vector<uint8_t> &data)
444 {
445 if (!_started)
446 _started = true;
447 EVP_DigestUpdate(_ctx, data.data(), data.size());
448 }
449 void clear()
450 {
451 // if not started, nothing to clear
452 if (_started)
453 {
454 if (_ctx)
455 EVP_MD_CTX_destroy(_ctx);
456 if (_check != CHECK_NOT_REQUESTED)
457 _check = CHECK_REQUESTED;
458 _ctx = EVP_MD_CTX_create();
459 EVP_DigestInit(_ctx, EVP_sha256());
460 }
461 }
462 enum hash_check check()
463 {
464 if (_check == CHECK_REQUESTED)
465 {
466 unsigned int len;
467 std::vector<uint8_t> digest(EVP_MD_size(EVP_sha256()));
468 EVP_DigestFinal(_ctx, digest.data(), &len);
469 if (digest == _expected)
470 {
471 if (DEBUG)
472 std::cerr << "transfer sha2 check passed\n";
473 _check = CHECK_PASSED_SHA2;
474 }
475 else
476 {
477 if (DEBUG)
478 std::cerr << "transfer sha2 check failed\n";
479 _check = CHECK_FAILED_SHA2;
480 }
481 }
482 return _check;
483 }
484 uint8_t status() const
485 {
486 return static_cast<uint8_t>(_check);
487 }
488};
489
490std::shared_ptr<transfer_hash_check> xfer_hash_check;
491
Vernon Mauery52ce6622019-05-22 09:19:46 -0700492static void activate_image(const char *obj_path)
493{
anil kumar appana31f88872019-08-02 15:16:27 +0000494 // If flag is false means to reboot
495 if (fw_update_status.getDeferRestart() == false)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700496 {
Vernon Mauery52ce6622019-05-22 09:19:46 -0700497
anil kumar appana31f88872019-08-02 15:16:27 +0000498 if (DEBUG)
499 {
500 std::cerr << "activateImage()...\n";
501 std::cerr << "obj_path = " << obj_path << "\n";
502 }
503 phosphor::logging::log<phosphor::logging::level::INFO>(
504 "activating Image: ",
505 phosphor::logging::entry("OBJPATH =%s", obj_path));
506 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
507 bus->async_method_call(
508 [](const boost::system::error_code ec) {
509 if (ec)
510 {
511 phosphor::logging::log<phosphor::logging::level::ERR>(
512 "async_method_call error: activate_image failed");
513 return;
514 }
515 },
516 "xyz.openbmc_project.Software.BMC.Updater", obj_path,
517 "org.freedesktop.DBus.Properties", "Set",
518 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
519 std::variant<std::string>("xyz.openbmc_project.Software.Activation."
520 "RequestedActivations.Active"));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700521 }
anil kumar appana31f88872019-08-02 15:16:27 +0000522 else
Vernon Mauery52ce6622019-05-22 09:19:46 -0700523 {
anil kumar appana31f88872019-08-02 15:16:27 +0000524 phosphor::logging::log<phosphor::logging::level::INFO>(
525 "Firmware image activation is deferred.");
Vernon Mauery52ce6622019-05-22 09:19:46 -0700526 }
527}
528
529static void post_transfer_complete_handler(
530 std::unique_ptr<sdbusplus::bus::match::match> &fw_update_matcher)
531{
532 // Setup timer for watching signal
533 static phosphor::Timer timer(
534 [&fw_update_matcher]() { fw_update_matcher = nullptr; });
535
536 static phosphor::Timer activation_status_timer([]() {
537 if (fw_update_status.activation_timer_timeout() >= 95)
538 {
539 activation_status_timer.stop();
540 }
541 });
542
543 timer.start(std::chrono::microseconds(5000000), false);
544
545 // callback function for capturing signal
546 auto callback = [&fw_update_matcher](sdbusplus::message::message &m) {
547 if (DEBUG)
548 std::cerr << "[complete] Match fired\n";
549 bool flag = false;
550
551 std::vector<std::pair<
552 std::string,
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700553 std::vector<std::pair<std::string, std::variant<std::string>>>>>
Vernon Mauery52ce6622019-05-22 09:19:46 -0700554 interfaces_properties;
555
556 sdbusplus::message::object_path obj_path;
557
558 try
559 {
560 m.read(obj_path, interfaces_properties); // Read in the object path
561 // that was just created
562 }
563 catch (std::exception &e)
564 {
565 std::cerr
566 << "[complete] Failed at post_transfer_complete-handler : "
567 << e.what() << "\n";
568 }
569 // constructing response message
570 if (DEBUG)
571 std::cerr << "[complete] obj path = " << obj_path.str << "\n";
572 for (auto &interface : interfaces_properties)
573 {
574 if (DEBUG)
575 std::cerr << "[complete] interface = " << interface.first
576 << "\n";
577
578 if (interface.first == "xyz.openbmc_project.Software.Activation")
579 {
580 // cancel timer only when
581 // xyz.openbmc_project.Software.Activation interface is
582 // added
583
584 if (DEBUG)
585 std::cerr << "[complete] Attempt to cancel timer...\n";
586 try
587 {
588 timer.stop();
589 activation_status_timer.start(
590 std::chrono::microseconds(3000000), true);
591 }
592 catch (std::exception &e)
593 {
594 std::cerr << "[complete] cancel timer error: " << e.what()
595 << "\n";
596 }
597
598 fw_update_status.set_software_obj_path(obj_path.str);
599 activate_image(obj_path.str.c_str());
600 if (DEBUG)
601 std::cerr << "[complete] returned from activeImage()\n";
602
603 fw_update_matcher = nullptr;
604 }
605 }
606 };
607
608 // Adding matcher
609 fw_update_matcher = std::make_unique<sdbusplus::bus::match::match>(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700610 *getSdBus(),
Vernon Mauery52ce6622019-05-22 09:19:46 -0700611 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
612 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
613 callback);
614}
Vernon Mauery52ce6622019-05-22 09:19:46 -0700615
616class MappedFile
617{
618 public:
619 MappedFile(const std::string &fname) : addr(nullptr), fsize(0)
620 {
621 std::error_code ec;
622 size_t sz = std::filesystem::file_size(fname, ec);
623 int fd = open(fname.c_str(), O_RDONLY);
624 if (!ec || fd < 0)
625 {
626 return;
627 }
628 void *tmp = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
629 close(fd);
630 if (tmp == MAP_FAILED)
631 {
632 return;
633 }
634 addr = tmp;
635 fsize = sz;
636 }
637
638 ~MappedFile()
639 {
640 if (addr)
641 {
642 munmap(addr, fsize);
643 }
644 }
645 const uint8_t *data() const
646 {
647 return static_cast<const uint8_t *>(addr);
648 }
649 size_t size() const
650 {
651 return fsize;
652 }
653
654 private:
655 size_t fsize;
656 void *addr;
657};
658
659static int transfer_from_file(const std::string &uri, bool move = true)
660{
661 std::error_code ec;
662 if (DEBUG)
663 std::cerr << "transfer_from_file(" << uri << ")\n";
664 if (move)
665 {
666 std::filesystem::rename(uri, FIRMWARE_BUFFER_FILE, ec);
667 }
668 else
669 {
670 std::filesystem::copy(uri, FIRMWARE_BUFFER_FILE,
671 std::filesystem::copy_options::overwrite_existing,
672 ec);
673 }
674 if (xfer_hash_check)
675 {
676 MappedFile mappedfw(uri);
677 xfer_hash_check->hash(
678 {mappedfw.data(), mappedfw.data() + mappedfw.size()});
679 }
680 if (ec.value())
681 {
682 std::cerr << "cp/mv returns: " << ec.message() << "(" << ec.value()
683 << ")\n";
684 }
685 return ec.value();
686}
687
688template <typename... ArgTypes>
689static int executeCmd(const char *path, ArgTypes &&... tArgs)
690{
691 boost::process::child execProg(path, const_cast<char *>(tArgs)...);
692 execProg.wait();
693 return execProg.exit_code();
694}
695
696constexpr char USB_CTRL_PATH[] = "/usr/bin/usb-ctrl";
697constexpr char FWUPDATE_MOUNT_POINT[] = "/tmp/usb-fwupd.mnt";
698constexpr char FWUPDATE_USB_VOL_IMG[] = "/tmp/usb-fwupd.img";
699constexpr char FWUPDATE_USB_DEV_NAME[] = "fw-usb-mass-storage-dev";
700constexpr size_t fwPathMaxLength = 255;
701static int transfer_from_usb(const std::string &uri)
702{
703 int ret, sysret;
704 char fwpath[fwPathMaxLength];
705 if (DEBUG)
706 std::cerr << "transfer_from_usb(" << uri << ")\n";
707 ret = executeCmd(USB_CTRL_PATH, "mount", FWUPDATE_USB_VOL_IMG,
708 FWUPDATE_MOUNT_POINT);
709 if (ret)
710 {
711 return ret;
712 }
713
714 std::string usb_path = std::string(FWUPDATE_MOUNT_POINT) + "/" + uri;
715 ret = transfer_from_file(usb_path, false);
716
717 executeCmd(USB_CTRL_PATH, "cleanup", FWUPDATE_USB_VOL_IMG,
718 FWUPDATE_MOUNT_POINT);
719 return ret;
720}
721
722static bool transfer_firmware_from_uri(const std::string &uri)
723{
724 static constexpr char FW_URI_FILE[] = "file://";
725 static constexpr char FW_URI_USB[] = "usb://";
726 if (DEBUG)
727 std::cerr << "transfer_firmware_from_uri(" << uri << ")\n";
728 if (boost::algorithm::starts_with(uri, FW_URI_FILE))
729 {
730 std::string fname = uri.substr(sizeof(FW_URI_FILE) - 1);
731 if (fname != FIRMWARE_BUFFER_FILE)
732 {
733 return 0 == transfer_from_file(fname);
734 }
735 return true;
736 }
737 if (boost::algorithm::starts_with(uri, FW_URI_USB))
738 {
739 std::string fname = uri.substr(sizeof(FW_URI_USB) - 1);
740 return 0 == transfer_from_usb(fname);
741 }
742 return false;
743}
744
745/* Get USB-mass-storage device status: inserted => true, ejected => false */
746static int usb_get_status()
747{
748 static constexpr char usb_gadget_base[] = "/sys/kernel/config/usb_gadget/";
749 auto usb_device =
750 std::filesystem::path(usb_gadget_base) / FWUPDATE_USB_DEV_NAME;
751 std::error_code ec;
752 return std::filesystem::exists(usb_device, ec) && !ec;
753}
754
755/* Insert the USB-mass-storage device status: success => 0, failure => non-0 */
756static int usb_attach_device()
757{
758 if (usb_get_status())
759 {
760 return 1;
761 }
762 int ret =
763 executeCmd(USB_CTRL_PATH, "setup", FWUPDATE_USB_VOL_IMG,
764 std::to_string(FIRMWARE_BUFFER_MAX_SIZE / 1_MB).c_str());
765 if (!ret)
766 {
767 ret = executeCmd(USB_CTRL_PATH, "insert", FWUPDATE_USB_DEV_NAME,
768 FWUPDATE_USB_VOL_IMG);
769 }
770 return ret;
771}
772
773/* Eject the USB-mass-storage device status: success => 0, failure => non-0 */
774static int usb_detach_device()
775{
776 if (!usb_get_status())
777 {
778 return 1;
779 }
780 return executeCmd(USB_CTRL_PATH, "eject", FWUPDATE_USB_DEV_NAME);
781}
782
783constexpr uint8_t controls_init = 0x00;
784constexpr uint8_t controls_transfer_started = 0x01;
785constexpr uint8_t controls_transfer_completed = 0x02;
786constexpr uint8_t controls_transfer_aborted = 0x04;
787constexpr uint8_t controls_usb_attached = 0x08;
788
789struct fw_update_control_request
790{
791 enum knob
792 {
793 CTRL_GET = 0,
794 CTRL_XFER_START,
795 CTRL_XFER_COMPLETE,
796 CTRL_XFER_ABORT,
797 CTRL_SET_FILENAME,
798 CTRL_USB_ATTACH,
799 CTRL_USB_DETACH,
800 } __attribute__((packed));
801 enum knob control;
802 uint8_t nlen;
803 char filename[fwPathMaxLength];
804} __attribute__((packed));
805
806static ipmi_ret_t ipmi_firmware_control(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
807 ipmi_request_t request,
808 ipmi_response_t response,
809 ipmi_data_len_t data_len,
810 ipmi_context_t context)
811{
812 static std::string fw_xfer_uri;
813
814 if (DEBUG)
815 std::cerr << "FW update control\n";
816 *data_len = 0;
817
818 static uint8_t controls = controls_init;
819 ipmi_ret_t rc = IPMI_CC_OK;
820 auto ctrl_req = reinterpret_cast<fw_update_control_request *>(request);
821 auto ctrl_resp = reinterpret_cast<uint8_t *>(response);
822
823 if (usb_get_status())
824 {
825 controls |= controls_usb_attached;
826 }
827 else
828 {
829 controls &= ~controls_usb_attached;
830 }
831
832 switch (ctrl_req->control)
833 {
834 case fw_update_control_request::CTRL_GET:
835 break;
836 case fw_update_control_request::CTRL_XFER_START:
837 {
838 controls |= controls_transfer_started;
839 // reset buffer to empty (truncate file)
840 std::ofstream out(FIRMWARE_BUFFER_FILE,
841 std::ofstream::binary | std::ofstream::trunc);
842 fw_xfer_uri = std::string("file://") + FIRMWARE_BUFFER_FILE;
843 if (xfer_hash_check)
844 {
845 xfer_hash_check->clear();
846 }
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +0530847#ifdef INTEL_PFR_ENABLED
848 imgLength = 0;
849 imgType = 0;
850 block0Mapped = false;
851#endif
Vernon Mauery52ce6622019-05-22 09:19:46 -0700852 if (DEBUG)
853 std::cerr << "transfer start\n";
854 }
855 break;
856 case fw_update_control_request::CTRL_XFER_COMPLETE:
857 {
858 if (usb_get_status())
859 {
860 rc = IPMI_CC_REQ_INVALID_PHASE;
861 }
862 // finish transfer based on URI
863 if (!transfer_firmware_from_uri(fw_xfer_uri))
864 {
865 rc = IPMI_CC_UNSPECIFIED_ERROR;
866 break;
867 }
868 // transfer complete
869 if (xfer_hash_check)
870 {
871 if (transfer_hash_check::CHECK_PASSED_SHA2 !=
872 xfer_hash_check->check())
873 {
874 if (DEBUG)
875 std::cerr << "xfer_hash_check returns not "
876 "CHECK_PASSED_SHA2\n";
877 rc = IPMI_CC_UNSPECIFIED_ERROR;
878 break;
879 }
880 }
881 // start the request
882 if (!request_start_firmware_update(FIRMWARE_BUFFER_FILE))
883 {
884 if (DEBUG)
885 std::cerr
886 << "request_start_firmware_update returns failure\n";
887 rc = IPMI_CC_UNSPECIFIED_ERROR;
888 }
889 if (rc == IPMI_CC_OK)
890 {
891 controls |= controls_transfer_completed;
892 }
893 }
894 break;
895 case fw_update_control_request::CTRL_XFER_ABORT:
896 if (DEBUG)
897 std::cerr << "send abort request\n";
898 if (usb_get_status())
899 {
900 if (0 != usb_detach_device())
901 {
902 rc = IPMI_CC_USB_ATTACH_FAIL;
903 }
904 }
anil kumar appana31f88872019-08-02 15:16:27 +0000905 fw_update_status.firmwareUpdateAbortState();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700906 controls |= controls_transfer_aborted;
907 break;
908 case fw_update_control_request::CTRL_SET_FILENAME:
909 fw_xfer_uri.clear();
910 fw_xfer_uri.insert(0, ctrl_req->filename, ctrl_req->nlen);
911 break;
912 case fw_update_control_request::CTRL_USB_ATTACH:
913 if (usb_get_status())
914 {
915 rc = IPMI_CC_INVALID_FIELD_REQUEST;
916 }
917 else if (0 != usb_attach_device())
918 {
919 rc = IPMI_CC_USB_ATTACH_FAIL;
920 }
921 else
922 {
923 rc = IPMI_CC_OK;
924 }
925 break;
926 case fw_update_control_request::CTRL_USB_DETACH:
927 if (!usb_get_status())
928 {
929 rc = IPMI_CC_INVALID_FIELD_REQUEST;
930 }
931 if (0 != usb_detach_device())
932 {
933 rc = IPMI_CC_USB_ATTACH_FAIL;
934 }
935 else
936 {
937 rc = IPMI_CC_OK;
938 }
939 break;
940 default:
941 if (DEBUG)
942 std::cerr << "control byte " << std::hex << ctrl_req->control
943 << " unknown\n";
944 rc = IPMI_CC_INVALID_FIELD_REQUEST;
945 break;
946 }
947
948 if (rc == IPMI_CC_OK)
949 {
950 *ctrl_resp = controls;
951 *data_len = sizeof(*ctrl_resp);
952 }
953
954 return rc;
955}
956
957struct fw_version_info
958{
959 uint8_t id_tag;
960 uint8_t major;
961 uint8_t minor;
962 uint32_t build;
963 uint32_t build_time;
964 uint32_t update_time;
965} __attribute__((packed));
966
967static ipmi_ret_t ipmi_firmware_get_fw_version_info(
968 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
969 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
970{
971 if (DEBUG)
972 std::cerr << "Get FW Version Info\n";
973
974 // Byte 1 - Count (N) Number of devices data is being returned for.
975 // Byte 2 - ID Tag 00 – reserved 01 – BMC Active Image 02 – BBU Active Image
976 // 03 – BMC Backup Image 04 – BBU Backup Image 05 – BBR
977 // Image
978 // Byte 3 - Major Version Number
979 // Byte 4 - Minor Version Number
980 // Bytes 5:8 - Build Number
981 // Bytes 9:12 - Build Timestamp Format: LSB first, same format as SEL
982 // timestamp
983 // Bytes 13:16 - Update Timestamp
984 // Bytes - 17:(15xN) - Repeat of 2 through 16
985
986 uint8_t count = 0;
987 auto ret_count = reinterpret_cast<uint8_t *>(response);
988 auto info = reinterpret_cast<struct fw_version_info *>(ret_count + 1);
989
990 for (uint8_t id_tag = 1; id_tag < 6; id_tag++)
991 {
992 const char *fw_path;
993 switch (id_tag)
994 {
995 case 1:
996 fw_path = FW_UPDATE_ACTIVE_INFO_PATH;
997 break;
998 case 2:
999 fw_path = FW_UPDATE_BACKUP_INFO_PATH;
1000 break;
1001 case 3:
1002 case 4:
1003 case 5:
1004 continue; // skip for now
1005 break;
1006 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001007 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001008 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001009 bus->new_method_call(FW_UPDATE_SERVER_DBUS_NAME, fw_path,
Vernon Mauery52ce6622019-05-22 09:19:46 -07001010 "org.freedesktop.DBus.Properties", "GetAll");
1011 method.append(FW_UPDATE_INFO_INTERFACE);
1012 std::vector<std::pair<std::string, ipmi::DbusVariant>> properties;
1013 try
1014 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001015 auto reply = bus->call(method);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001016
1017 if (reply.is_method_error())
1018 continue;
1019
1020 reply.read(properties);
1021 }
1022 catch (sdbusplus::exception::SdBusError &e)
1023 {
1024 std::cerr << "SDBus Error: " << e.what();
1025 return IPMI_CC_UNSPECIFIED_ERROR;
1026 }
1027 uint8_t major = 0;
1028 uint8_t minor = 0;
1029 uint32_t build = 0;
1030 int32_t build_time = 0;
1031 int32_t update_time = 0;
1032 for (const auto &t : properties)
1033 {
1034 auto key = t.first;
1035 auto value = t.second;
1036 if (key == "version")
1037 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001038 auto strver = std::get<std::string>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001039 std::stringstream ss;
1040 ss << std::hex << strver;
1041 uint32_t t;
1042 ss >> t;
1043 major = t;
1044 ss.ignore();
1045 ss >> t;
1046 minor = t;
1047 ss.ignore();
1048 ss >> build;
1049 }
1050 else if (key == "build_time")
1051 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001052 build_time = std::get<int32_t>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001053 }
1054 else if (key == "update_time")
1055 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001056 update_time = std::get<int32_t>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001057 }
1058 }
1059
1060 info->id_tag = id_tag;
1061 info->major = major;
1062 info->minor = minor;
1063 info->build = build;
1064 info->build_time = build_time;
1065 info->update_time = update_time;
1066 count++;
1067 info++;
1068 }
1069 *ret_count = count;
1070
1071 // Status code.
1072 ipmi_ret_t rc = IPMI_CC_OK;
1073 *data_len = sizeof(count) + count * sizeof(*info);
1074
1075 return rc;
1076}
1077
1078struct fw_security_revision_info
1079{
1080 uint8_t id_tag;
1081 uint16_t sec_rev;
1082} __attribute__((packed));
1083
1084static ipmi_ret_t ipmi_firmware_get_fw_security_revision(
1085 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
1086 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
1087{
1088 if (DEBUG)
1089 std::cerr << "Get FW security revision info\n";
1090
1091 // Byte 1 - Count (N) Number of devices data is being returned for.
1092 // Byte 2 - ID Tag 00 – reserved 01 – BMC Active Image 02 – BBU Active Image
1093 // 03 – BMC Backup Image 04 – BBU Backup Image 05 – BBR
1094 // Image
1095 // Byte 3 - Major Version Number
1096 // Byte 4 - Minor Version Number
1097 // Bytes 5:8 - Build Number
1098 // Bytes 9:12 - Build Timestamp Format: LSB first, same format as SEL
1099 // timestamp
1100 // Bytes 13:16 - Update Timestamp
1101 // Bytes - 17:(15xN) - Repeat of 2 through 16
1102
1103 uint8_t count = 0;
1104 auto ret_count = reinterpret_cast<uint8_t *>(response);
1105 auto info =
1106 reinterpret_cast<struct fw_security_revision_info *>(ret_count + 1);
1107
Vernon Mauery15419dd2019-05-24 09:40:30 -07001108 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001109 for (uint8_t id_tag = 1; id_tag < 6; id_tag++)
1110 {
1111 const char *fw_path;
1112 switch (id_tag)
1113 {
1114 case 1:
1115 fw_path = FW_UPDATE_ACTIVE_INFO_PATH;
1116 break;
1117 case 2:
1118 fw_path = FW_UPDATE_BACKUP_INFO_PATH;
1119 break;
1120 case 3:
1121 case 4:
1122 case 5:
1123 continue; // skip for now
1124 break;
1125 }
1126 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001127 bus->new_method_call(FW_UPDATE_SERVER_DBUS_NAME, fw_path,
Vernon Mauery52ce6622019-05-22 09:19:46 -07001128 "org.freedesktop.DBus.Properties", "GetAll");
1129 method.append(FW_UPDATE_INFO_INTERFACE, "security_version");
1130 ipmi::DbusVariant sec_rev;
1131 try
1132 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001133 auto reply = bus->call(method);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001134
1135 if (reply.is_method_error())
1136 continue;
1137
1138 reply.read(sec_rev);
1139 }
1140 catch (sdbusplus::exception::SdBusError &e)
1141 {
1142 std::cerr << "SDBus Error: " << e.what();
1143 return IPMI_CC_UNSPECIFIED_ERROR;
1144 }
1145
1146 info->id_tag = id_tag;
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001147 info->sec_rev = std::get<int>(sec_rev);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001148 count++;
1149 info++;
1150 }
1151 *ret_count = count;
1152
1153 // Status code.
1154 ipmi_ret_t rc = IPMI_CC_OK;
1155 *data_len = sizeof(count) + count * sizeof(*info);
1156
1157 return rc;
1158}
1159
1160struct fw_channel_size
1161{
1162 uint8_t channel_id;
1163 uint32_t channel_size;
1164} __attribute__((packed));
1165
1166enum
1167{
1168 CHANNEL_RESVD = 0,
1169 CHANNEL_KCS,
1170 CHANNEL_RMCP_PLUS,
1171 CHANNEL_USB_DATA,
1172 CHANNEL_USB_MASS_STORAGE,
1173} channel_transfer_type;
1174
anil kumar appana159547c2019-05-31 16:08:34 +00001175static constexpr uint8_t channelListSize = 2;
1176/** @brief implements Maximum Firmware Transfer size command
1177 * @parameter
1178 * - none
1179 * @returns IPMI completion code plus response data
1180 * - count - channel count
1181 * - channelList - channel list information
1182 */
1183ipmi::RspType<uint8_t, // channel count
1184 std::array<std::tuple<uint8_t, uint32_t>,
1185 channelListSize> // channel
1186 // list
1187 >
1188 ipmiFirmwareMaxTransferSize()
Vernon Mauery52ce6622019-05-22 09:19:46 -07001189{
anil kumar appana159547c2019-05-31 16:08:34 +00001190 constexpr uint8_t KCSMaxBufSize = 128;
1191 constexpr uint32_t RMCPPLUSMaxBufSize = 50 * 1024;
Vernon Mauery52ce6622019-05-22 09:19:46 -07001192 if (DEBUG)
1193 std::cerr << "Get FW max transfer size\n";
Vernon Mauery52ce6622019-05-22 09:19:46 -07001194 // Byte 1 - Count (N) Number of devices data is being returned for.
1195 // Byte 2 - ID Tag 00 – reserved 01 – kcs 02 – rmcp+,
1196 // 03 – usb data, 04 – usb mass storage
1197 // Byte 3-6 - transfer size (little endian)
1198 // Bytes - 7:(5xN) - Repeat of 2 through 6
anil kumar appana159547c2019-05-31 16:08:34 +00001199 constexpr std::array<std::tuple<uint8_t, uint32_t>, channelListSize>
1200 channelList = {{{CHANNEL_KCS, KCSMaxBufSize},
1201 {CHANNEL_RMCP_PLUS, RMCPPLUSMaxBufSize}}};
1202 return ipmi::responseSuccess(channelListSize, channelList);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001203}
1204
1205enum
1206{
1207 EXEC_CTX_RESVD = 0,
1208 EXEC_CTX_FULL_LINUX = 0x10,
1209 EXEC_CTX_SAFE_MODE_LINUX = 0x11,
1210} bmc_execution_context;
1211
1212struct fw_execution_context
1213{
1214 uint8_t context;
1215 uint8_t image_selection;
1216} __attribute__((packed));
1217
1218static ipmi_ret_t ipmi_firmware_get_fw_execution_context(
1219 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
1220 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
1221{
1222 if (DEBUG)
1223 std::cerr << "Get FW execution context\n";
1224
1225 // Byte 1 - execution context
1226 // 0x10 - full linux stack, 0x11 - safe-mode linux stack
1227 // Byte 2 - current image selection
1228 // 1 - primary, 2 - secondary
1229
1230 auto info = reinterpret_cast<struct fw_execution_context *>(response);
anil kumar appana31f88872019-08-02 15:16:27 +00001231 info->context = EXEC_CTX_FULL_LINUX;
Vernon Mauery52ce6622019-05-22 09:19:46 -07001232
anil kumar appana31f88872019-08-02 15:16:27 +00001233 info->image_selection = getActiveBootImage();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001234
1235 // Status code.
1236 ipmi_ret_t rc = IPMI_CC_OK;
1237 *data_len = sizeof(*info);
1238
1239 return rc;
1240}
1241
anil kumar appana31f88872019-08-02 15:16:27 +00001242uint8_t getActiveBootImage(void)
1243{
1244 // 0x01 - primaryImage
1245 constexpr uint8_t primaryImage = 0x01;
1246 // 0x02 - secondaryImage
1247 constexpr uint8_t secondaryImage = 0x02;
1248 uint8_t bootImage = primaryImage;
1249
1250 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
1251 auto method = bus->new_method_call(
1252 "xyz.openbmc_project.U_Boot.Environment.Manager",
1253 "/xyz/openbmc_project/u_boot/environment/mgr",
1254 "xyz.openbmc_project.U_Boot.Environment.Manager", "Read");
1255 method.append("bootcmd");
1256 std::string value;
1257 try
1258 {
1259 auto reply = bus->call(method);
1260 reply.read(value);
1261 }
1262 catch (sdbusplus::exception::SdBusError &e)
1263 {
1264 std::cerr << "SDBus Error: " << e.what();
1265 return IPMI_CC_UNSPECIFIED_ERROR;
1266 }
1267 /* cheking for secondary FitImage Address 22480000 */
1268 if (value.find(secondaryFitImageStartAddr) != std::string::npos)
1269 {
1270 bootImage = secondaryImage;
1271 }
1272 else
1273 {
1274 bootImage = primaryImage;
1275 }
1276
1277 return bootImage;
1278}
anil kumar appana6c7d9382019-05-31 14:33:13 +00001279/** @brief implements firmware get status command
1280 * @parameter
1281 * - none
1282 * @returns IPMI completion code plus response data
1283 * - status - processing status
1284 * - percentage - percentage completion
1285 * - check - channel integrity check status
1286 **/
1287ipmi::RspType<uint8_t, // status
1288 uint8_t, // percentage
1289 uint8_t // check
1290 >
1291 ipmiFrmwareGetStatus()
Vernon Mauery52ce6622019-05-22 09:19:46 -07001292
Vernon Mauery52ce6622019-05-22 09:19:46 -07001293{
1294 if (DEBUG)
1295 std::cerr << "Get FW update status\n";
Vernon Mauery52ce6622019-05-22 09:19:46 -07001296 // Byte 1 - status (0=init, 1=idle, 2=download, 3=validate, 4=write,
1297 // 5=ready, f=error, 83=ac cycle required)
1298 // Byte 2 - percent
1299 // Byte 3 - integrity check status (0=none, 1=req, 2=sha2ok, e2=sha2fail)
anil kumar appana6c7d9382019-05-31 14:33:13 +00001300 uint8_t status = fw_update_status.state();
1301 uint8_t percent = fw_update_status.percent();
1302 uint8_t check = xfer_hash_check ? xfer_hash_check->status() : 0;
Vernon Mauery52ce6622019-05-22 09:19:46 -07001303
1304 // Status code.
anil kumar appana6c7d9382019-05-31 14:33:13 +00001305 return ipmi::responseSuccess(status, percent, check);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001306}
1307
1308static constexpr uint8_t FW_UPDATE_OPTIONS_NO_DOWNREV = (1 << 0);
1309static constexpr uint8_t FW_UPDATE_OPTIONS_DEFER_RESTART = (1 << 1);
1310static constexpr uint8_t FW_UPDATE_OPTIONS_SHA2_CHECK = (1 << 2);
1311static constexpr uint8_t FW_UPDATE_OPTIONS_RESVD1 = (1 << 3);
1312struct fw_update_options_request
1313{
1314 uint8_t mask;
1315 uint8_t options;
1316} __attribute__((packed));
1317
Vernon Mauery52ce6622019-05-22 09:19:46 -07001318uint32_t fw_update_options = 0;
1319static ipmi_ret_t ipmi_firmware_update_options(
1320 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
1321 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
1322{
1323 if (DEBUG)
1324 std::cerr << "Get/set FW update options\n";
1325
1326 // request:
1327 // Byte 1 - mask
1328 // Byte 2 - options
1329 // Byte 3-34 - optional integrity check expected value
1330 // response:
1331 // Byte 1 - set options
1332
1333 auto fw_options =
1334 reinterpret_cast<struct fw_update_options_request *>(request);
1335
1336 const char *path = FW_UPDATE_SERVER_INFO_PATH;
1337 const char *iface = FW_UPDATE_SECURITY_INTERFACE;
1338 if ((fw_options->mask & FW_UPDATE_OPTIONS_NO_DOWNREV) &&
1339 (fw_options->options & FW_UPDATE_OPTIONS_NO_DOWNREV) !=
1340 (fw_update_options & FW_UPDATE_OPTIONS_NO_DOWNREV))
1341 {
1342 if (fw_options->options & FW_UPDATE_OPTIONS_NO_DOWNREV)
1343 {
1344 fw_update_options |= FW_UPDATE_OPTIONS_NO_DOWNREV;
anil kumar appana31f88872019-08-02 15:16:27 +00001345 /*setting flag to flase for deferring downgrade support*/
1346 fw_update_status.setInhibitDowngrade(true);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001347 }
1348 else
1349 {
1350 fw_update_options &= ~FW_UPDATE_OPTIONS_NO_DOWNREV;
anil kumar appana31f88872019-08-02 15:16:27 +00001351 /*setting flag to true for downgrade support*/
1352 fw_update_status.setInhibitDowngrade(false);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001353 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001354 }
1355 if ((fw_options->mask & FW_UPDATE_OPTIONS_DEFER_RESTART) &&
1356 (fw_options->options & FW_UPDATE_OPTIONS_DEFER_RESTART) !=
1357 (fw_update_options & FW_UPDATE_OPTIONS_DEFER_RESTART))
1358 {
1359 if (fw_options->options & FW_UPDATE_OPTIONS_DEFER_RESTART)
1360 {
1361 fw_update_options |= FW_UPDATE_OPTIONS_DEFER_RESTART;
anil kumar appana31f88872019-08-02 15:16:27 +00001362 /* setting flag to true to stop image activation */
1363 fw_update_status.setDeferRestart(true);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001364 }
1365 else
1366 {
anil kumar appana31f88872019-08-02 15:16:27 +00001367 /* setting flag to false for image activation */
Vernon Mauery52ce6622019-05-22 09:19:46 -07001368 fw_update_options &= ~FW_UPDATE_OPTIONS_DEFER_RESTART;
anil kumar appana31f88872019-08-02 15:16:27 +00001369 fw_update_status.setDeferRestart(false);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001370 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001371 }
1372 if (fw_options->mask & FW_UPDATE_OPTIONS_SHA2_CHECK)
1373 {
1374 auto hash_size = EVP_MD_size(EVP_sha256());
1375 if (fw_options->options & FW_UPDATE_OPTIONS_SHA2_CHECK)
1376 {
1377 if (*data_len != (sizeof(*fw_options) + hash_size))
1378 {
1379 *data_len = 0;
1380 return IPMI_CC_REQ_DATA_LEN_INVALID;
1381 }
1382 xfer_hash_check = std::make_shared<transfer_hash_check>();
1383 auto exp_hash = reinterpret_cast<uint8_t *>(fw_options + 1);
1384 xfer_hash_check->init({exp_hash, exp_hash + hash_size});
1385 fw_update_options |= FW_UPDATE_OPTIONS_SHA2_CHECK;
1386 }
1387 else
1388 {
1389 fw_update_options &= ~FW_UPDATE_OPTIONS_SHA2_CHECK;
1390 // delete the xfer_hash_check object
1391 xfer_hash_check.reset();
1392 }
1393 }
1394 auto options_rsp = reinterpret_cast<uint8_t *>(response);
1395 *options_rsp = fw_update_options;
1396
1397 if (DEBUG)
1398 std::cerr << "current fw_update_options = " << std::hex
1399 << fw_update_options << '\n';
1400 // Status code.
1401 *data_len = sizeof(*options_rsp);
1402 return IPMI_CC_OK;
1403}
1404
1405struct fw_cert_info
1406{
1407 uint16_t cert_len;
1408 uint64_t serial;
1409 uint8_t subject_len;
1410 char subject[255];
1411} __attribute__((packed));
1412
1413static ipmi_ret_t ipmi_firmware_get_root_cert_info(
1414 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
1415 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
1416{
1417 if (DEBUG)
1418 std::cerr << "Get FW root cert info\n";
1419
1420 // request:
1421 // Byte 1 - certificate ID: request which certificate (ignored)
1422
1423 // response:
1424 // Byte 1-2 - certificate length (little endian)
1425 // Byte 3-10 - serial number (little endian)
1426 // Byte 11 - subject length
1427 // Byte 12-N - subject data
1428
1429 auto cert_info = reinterpret_cast<struct fw_cert_info *>(response);
Vernon Mauery15419dd2019-05-24 09:40:30 -07001430 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
1431 auto method = bus->new_method_call(
Vernon Mauery52ce6622019-05-22 09:19:46 -07001432 FW_UPDATE_SERVER_DBUS_NAME, FW_UPDATE_SERVER_INFO_PATH,
1433 "org.freedesktop.DBus.Properties", "GetAll");
1434 method.append(FW_UPDATE_SECURITY_INTERFACE);
1435 std::string subject;
1436 uint64_t serial;
1437 std::string cert;
1438 try
1439 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001440 auto reply = bus->call(method);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001441
1442 std::vector<std::pair<std::string, ipmi::DbusVariant>> properties;
1443 reply.read(properties);
1444
1445 for (const auto &t : properties)
1446 {
1447 auto key = t.first;
1448 auto value = t.second;
1449 if (key == "certificate_subject")
1450 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001451 subject = std::get<std::string>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001452 }
1453 else if (key == "cetificate_serial")
1454 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001455 serial = std::get<uint64_t>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001456 }
1457 else if (key == "certificate")
1458 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001459 cert = std::get<std::string>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001460 }
1461 }
1462 }
1463 catch (sdbusplus::exception::SdBusError &e)
1464 {
1465 std::cerr << "SDBus Error: " << e.what();
1466 return IPMI_CC_UNSPECIFIED_ERROR;
1467 }
1468
1469 cert_info->cert_len = cert.size();
1470 cert_info->serial = serial;
1471 // truncate subject so it fits in the 255-byte array (if necessary)
1472 if (subject.size() > sizeof(cert_info->subject))
1473 subject.resize(sizeof(cert_info->subject));
1474 cert_info->subject_len = subject.size();
1475 std::copy(subject.begin(), subject.end(), cert_info->subject);
1476
1477 // Status code.
1478 ipmi_ret_t rc = IPMI_CC_OK;
1479 // make sure to account for the *actual* size of the subject
1480 *data_len = sizeof(*cert_info) - sizeof(cert_info->subject) +
1481 cert_info->subject_len;
1482
1483 return rc;
1484}
1485
1486struct fw_cert_data_req
1487{
1488 uint8_t cert_id;
1489 uint16_t offset;
1490 uint16_t count;
1491} __attribute__((packed));
1492
1493static ipmi_ret_t ipmi_firmware_get_root_cert_data(
1494 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
1495 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
1496{
1497 if (DEBUG)
1498 std::cerr << "Get FW root cert data\n";
1499
1500 // request:
1501 // Byte 1 - certificate ID: request which certificate (ignored)
1502 // Byte 2-3 - offset within cert to start at
1503 // Byte 4-5 - number of bytes to return
1504
1505 // response:
1506 // Byte 1-N - certificate data
1507
1508 if (*data_len != sizeof(fw_cert_data_req))
1509 return IPMI_CC_REQ_DATA_LEN_INVALID;
1510
1511 auto cert_data_req = reinterpret_cast<struct fw_cert_data_req *>(request);
Vernon Mauery15419dd2019-05-24 09:40:30 -07001512 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
1513 auto method = bus->new_method_call(
Vernon Mauery52ce6622019-05-22 09:19:46 -07001514 FW_UPDATE_SERVER_DBUS_NAME, FW_UPDATE_SERVER_INFO_PATH,
1515 "org.freedesktop.DBus.Properties", "Get");
1516 method.append(FW_UPDATE_SECURITY_INTERFACE, "certificate");
1517 ipmi::DbusVariant cert;
1518 try
1519 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001520 auto reply = bus->call(method);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001521 reply.read(cert);
1522 }
1523 catch (sdbusplus::exception::SdBusError &e)
1524 {
1525 std::cerr << "SDBus Error: " << e.what();
1526 return IPMI_CC_UNSPECIFIED_ERROR;
1527 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001528 auto cert_data = std::get<std::string>(cert);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001529
1530 if (cert_data_req->offset >= cert_data.size())
1531 {
1532 *data_len = 0;
1533 return IPMI_CC_INVALID_FIELD_REQUEST;
1534 }
1535 auto first = cert_data.begin() + cert_data_req->offset;
1536 auto last = first + cert_data_req->count;
1537 if (last > cert_data.end())
1538 last = cert_data.end();
1539
1540 auto data_out = reinterpret_cast<char *>(response);
1541 std::copy(first, last, data_out);
1542
1543 // Status code.
1544 ipmi_ret_t rc = IPMI_CC_OK;
1545 *data_len = (last - first);
1546
1547 return rc;
1548}
1549
1550static ipmi_ret_t ipmi_firmware_write_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1551 ipmi_request_t request,
1552 ipmi_response_t response,
1553 ipmi_data_len_t data_len,
1554 ipmi_context_t context)
1555{
1556 if (DEBUG)
1557 std::cerr << "write fw data (" << *data_len << " bytes)\n";
1558
1559 auto bytes_in = *data_len;
1560 *data_len = 0;
1561 if (fw_update_status.state() != fw_update_status_cache::FW_STATE_DOWNLOAD)
1562 return IPMI_CC_INVALID;
1563
1564 std::ofstream out(FIRMWARE_BUFFER_FILE,
1565 std::ofstream::binary | std::ofstream::app);
1566 if (!out)
1567 {
1568 return IPMI_CC_UNSPECIFIED_ERROR;
1569 }
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301570
1571 uint64_t fileDataLen = out.tellp();
1572 if (fileDataLen > FIRMWARE_BUFFER_MAX_SIZE)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001573 {
1574 return IPMI_CC_INVALID_FIELD_REQUEST;
1575 }
1576 auto data = reinterpret_cast<uint8_t *>(request);
1577 out.write(reinterpret_cast<char *>(data), bytes_in);
1578 out.close();
1579 if (xfer_hash_check)
1580 {
1581 xfer_hash_check->hash({data, data + bytes_in});
1582 }
1583
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301584#ifdef INTEL_PFR_ENABLED
1585 /* PFR image block 0 - As defined in HAS */
1586 struct PFRImageBlock0
1587 {
1588 uint32_t tag;
1589 uint32_t pcLength;
1590 uint32_t pcType;
1591 uint32_t reserved1;
1592 uint8_t hash256[32];
1593 uint8_t hash384[48];
1594 uint8_t reserved2[32];
1595 } __attribute__((packed));
1596
1597 /* Get the PFR block 0 data and read the uploaded image
1598 * information( Image type, length etc) */
1599 if ((fileDataLen >= sizeof(PFRImageBlock0)) && (!block0Mapped))
1600 {
1601 struct PFRImageBlock0 block0Data = {0};
1602
1603 std::ifstream inFile(FIRMWARE_BUFFER_FILE,
1604 std::ios::binary | std::ios::in);
1605 inFile.read(reinterpret_cast<char *>(&block0Data), sizeof(block0Data));
1606 inFile.close();
1607
1608 uint32_t magicNum = block0Data.tag;
1609
1610 /* Validate the magic number */
1611 if (magicNum != perBlock0MagicNum)
1612 {
1613 return IPMI_CC_INVALID_FIELD_REQUEST;
1614 }
1615 // Note:imgLength, imgType and block0Mapped are in global scope, as
1616 // these are used in cascaded updates.
1617 imgLength = block0Data.pcLength;
1618 imgType = block0Data.pcType;
1619 block0Mapped = true;
1620 }
1621#endif // end of INTEL_PFR_ENABLED
Vernon Mauery52ce6622019-05-22 09:19:46 -07001622 return IPMI_CC_OK;
1623}
1624
Vernon Mauery52ce6622019-05-22 09:19:46 -07001625struct intc_app_get_buffer_size_resp
1626{
1627 uint8_t kcs_size;
1628 uint8_t ipmb_size;
1629} __attribute__((packed));
1630
1631static constexpr int KCS_MAX_BUFFER_SIZE = 63;
1632static constexpr int IPMB_MAX_BUFFER_SIZE = 128;
1633static ipmi_ret_t ipmi_intel_app_get_buffer_size(
1634 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
1635 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
1636{
1637 auto msg_reply =
1638 reinterpret_cast<intc_app_get_buffer_size_resp *>(response);
1639 // for now this is hard coded; really this number is dependent on
1640 // the BMC kcs driver as well as the host kcs driver....
1641 // we can't know the latter.
1642 msg_reply->kcs_size = KCS_MAX_BUFFER_SIZE / 4;
1643 msg_reply->ipmb_size = IPMB_MAX_BUFFER_SIZE / 4;
1644 *data_len = sizeof(*msg_reply);
1645
1646 return IPMI_CC_OK;
1647}
1648
1649static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_FW_VERSION_INFO = 0x20;
1650static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_FW_SEC_VERSION_INFO = 0x21;
1651static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_FW_UPD_CHAN_INFO = 0x22;
1652static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_BMC_EXEC_CTX = 0x23;
1653static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_ROOT_CERT_INFO = 0x24;
1654static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_ROOT_CERT_DATA = 0x25;
1655static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_FW_UPDATE_RAND_NUM = 0x26;
1656static constexpr ipmi_cmd_t IPMI_CMD_FW_SET_FW_UPDATE_MODE = 0x27;
anil kumar appanab57098a2019-05-28 16:22:33 +00001657static constexpr ipmi_cmd_t cmdFirmwareExitFirmwareUpdateMode = 0x28;
Vernon Mauery52ce6622019-05-22 09:19:46 -07001658static constexpr ipmi_cmd_t IPMI_CMD_FW_UPDATE_CONTROL = 0x29;
1659static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_STATUS = 0x2a;
1660static constexpr ipmi_cmd_t IPMI_CMD_FW_SET_FW_UPDATE_OPTIONS = 0x2b;
1661static constexpr ipmi_cmd_t IPMI_CMD_FW_IMAGE_WRITE = 0x2c;
1662static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_TIMESTAMP = 0x2d;
1663static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_UPDATE_ERR_MSG = 0xe0;
1664static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_REMOTE_FW_INFO = 0xf0;
1665
1666static constexpr ipmi_netfn_t NETFUN_INTC_APP = 0x30;
1667static constexpr ipmi_cmd_t IPMI_CMD_INTC_GET_BUFFER_SIZE = 0x66;
1668
1669static void register_netfn_firmware_functions()
1670{
1671 // guarantee that we start with an already timed out timestamp
1672 fw_random_number_timestamp =
1673 std::chrono::steady_clock::now() - FW_RANDOM_NUMBER_TTL;
1674
1675 unlink(FIRMWARE_BUFFER_FILE);
1676
1677 // <Get BT Interface Capabilities>
1678 if (DEBUG)
1679 std::cerr << "Registering firmware update commands\n";
1680
1681 // get firmware version information
1682 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_GET_FW_VERSION_INFO,
1683 NULL, ipmi_firmware_get_fw_version_info,
1684 PRIVILEGE_ADMIN);
1685
1686 // get firmware security version information
1687 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_GET_FW_SEC_VERSION_INFO,
1688 NULL, ipmi_firmware_get_fw_security_revision,
1689 PRIVILEGE_ADMIN);
1690
1691 // get channel information (max transfer sizes)
anil kumar appana159547c2019-05-31 16:08:34 +00001692 ipmi::registerHandler(ipmi::prioOemBase, NETFUN_FIRMWARE,
1693 IPMI_CMD_FW_GET_FW_UPD_CHAN_INFO,
1694 ipmi::Privilege::Admin, ipmiFirmwareMaxTransferSize);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001695
1696 // get bmc execution context
1697 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_GET_BMC_EXEC_CTX, NULL,
1698 ipmi_firmware_get_fw_execution_context,
1699 PRIVILEGE_ADMIN);
1700
1701 // get root certificate information
1702 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_GET_ROOT_CERT_INFO,
1703 NULL, ipmi_firmware_get_root_cert_info,
1704 PRIVILEGE_ADMIN);
1705
1706 // get root certificate data
1707 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_GET_ROOT_CERT_DATA,
1708 NULL, ipmi_firmware_get_root_cert_data,
1709 PRIVILEGE_ADMIN);
1710
1711 // generate bmc fw update random number (for enter fw tranfer mode)
1712 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_GET_FW_UPDATE_RAND_NUM,
1713 NULL, ipmi_firmware_get_fw_random_number,
1714 PRIVILEGE_ADMIN);
1715
AppaRao Puli4b3e1c72019-10-16 20:53:09 +05301716 // Set Firmware Update Mode(0x27)
1717 ipmi::registerHandler(ipmi::prioOemBase, NETFUN_FIRMWARE,
1718 IPMI_CMD_FW_SET_FW_UPDATE_MODE,
1719 ipmi::Privilege::Admin, ipmiSetFirmwareUpdateMode);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001720
1721 // exit firmware update mode
anil kumar appanab57098a2019-05-28 16:22:33 +00001722 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1723 cmdFirmwareExitFirmwareUpdateMode,
1724 ipmi::Privilege::Admin, ipmiFirmwareExitFwUpdateMode);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001725
1726 // firmware control mechanism (set filename, usb, etc.)
1727 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_UPDATE_CONTROL, NULL,
1728 ipmi_firmware_control, PRIVILEGE_ADMIN);
1729
1730 // get firmware update status
anil kumar appana6c7d9382019-05-31 14:33:13 +00001731 ipmi::registerHandler(ipmi::prioOemBase, NETFUN_FIRMWARE,
1732 IPMI_CMD_FW_GET_STATUS, ipmi::Privilege::Admin,
1733 ipmiFrmwareGetStatus);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001734 // set firmware update options (no downgrade, etc.)
1735 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_SET_FW_UPDATE_OPTIONS,
1736 NULL, ipmi_firmware_update_options, PRIVILEGE_ADMIN);
1737
1738 // write image data
1739 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_IMAGE_WRITE, NULL,
1740 ipmi_firmware_write_data, PRIVILEGE_ADMIN);
1741
Vernon Mauery52ce6622019-05-22 09:19:46 -07001742 // get buffer size is used by fw update (exclusively?)
1743 ipmi_register_callback(NETFUN_INTC_APP, IPMI_CMD_INTC_GET_BUFFER_SIZE, NULL,
1744 ipmi_intel_app_get_buffer_size, PRIVILEGE_USER);
1745 return;
1746}