blob: f9cd153840bc8e55eecf260c418e854cb01cf319 [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
352static ipmi_ret_t ipmi_firmware_exit_fw_update_mode(
353 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
354 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
355{
356 if (DEBUG)
357 std::cerr << "Exit FW update mode\n";
358 *data_len = 0;
359
360 ipmi_ret_t rc = IPMI_CC_OK;
361 switch (fw_update_status.state())
362 {
363 case fw_update_status_cache::FW_STATE_INIT:
364 case fw_update_status_cache::FW_STATE_IDLE:
365 rc = IPMI_CC_INVALID_FIELD_REQUEST;
366 break;
367 case fw_update_status_cache::FW_STATE_DOWNLOAD:
Vernon Mauery52ce6622019-05-22 09:19:46 -0700368 case fw_update_status_cache::FW_STATE_VERIFY:
369 break;
370 case fw_update_status_cache::FW_STATE_WRITE:
Vernon Mauery52ce6622019-05-22 09:19:46 -0700371 break;
372 case fw_update_status_cache::FW_STATE_READY:
373 case fw_update_status_cache::FW_STATE_ERROR:
Vernon Mauery52ce6622019-05-22 09:19:46 -0700374 break;
375 case fw_update_status_cache::FW_STATE_AC_CYCLE_REQUIRED:
376 rc = IPMI_CC_INVALID_FIELD_REQUEST;
377 break;
378 }
379 if (rc == IPMI_CC_OK)
380 {
anil kumar appana31f88872019-08-02 15:16:27 +0000381 fw_update_status.firmwareUpdateAbortState();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700382 }
383
384 return rc;
385}
386
387static void post_transfer_complete_handler(
388 std::unique_ptr<sdbusplus::bus::match::match> &fw_update_matcher);
389static bool request_start_firmware_update(const std::string &uri)
390{
391 if (DEBUG)
392 std::cerr << "request start firmware update()\n";
393
Vernon Mauery52ce6622019-05-22 09:19:46 -0700394 // fwupdate URIs start with file:// or usb:// or tftp:// etc. By the time
395 // the code gets to this point, the file should be transferred start the
396 // request (creating a new file in /tmp/images causes the update manager to
397 // check if it is ready for activation)
398 static std::unique_ptr<sdbusplus::bus::match::match> fw_update_matcher;
399 post_transfer_complete_handler(fw_update_matcher);
400 std::filesystem::rename(
401 uri, "/tmp/images/" +
402 boost::uuids::to_string(boost::uuids::random_generator()()));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700403 return true;
404}
405
406class transfer_hash_check
407{
408 public:
409 enum hash_check
410 {
411 CHECK_NOT_REQUESTED = 0,
412 CHECK_REQUESTED,
413 CHECK_PASSED_SHA2,
414 CHECK_RESVD1,
415 CHECK_FAILED_SHA2 = 0xe2,
416 CHECK_RESVD2 = 0xe3,
417 };
418
419 protected:
420 EVP_MD_CTX *_ctx;
421 std::vector<uint8_t> _expected;
422 enum hash_check _check;
423 bool _started;
424
425 public:
426 transfer_hash_check() : _check(CHECK_NOT_REQUESTED), _started(false)
427 {
428 }
429 ~transfer_hash_check()
430 {
431 if (_ctx)
432 {
433 EVP_MD_CTX_destroy(_ctx);
434 _ctx = NULL;
435 }
436 }
437 void init(const std::vector<uint8_t> &expected)
438 {
439 _expected = expected;
440 _check = CHECK_REQUESTED;
441 _ctx = EVP_MD_CTX_create();
442 EVP_DigestInit(_ctx, EVP_sha256());
443 }
444 void hash(const std::vector<uint8_t> &data)
445 {
446 if (!_started)
447 _started = true;
448 EVP_DigestUpdate(_ctx, data.data(), data.size());
449 }
450 void clear()
451 {
452 // if not started, nothing to clear
453 if (_started)
454 {
455 if (_ctx)
456 EVP_MD_CTX_destroy(_ctx);
457 if (_check != CHECK_NOT_REQUESTED)
458 _check = CHECK_REQUESTED;
459 _ctx = EVP_MD_CTX_create();
460 EVP_DigestInit(_ctx, EVP_sha256());
461 }
462 }
463 enum hash_check check()
464 {
465 if (_check == CHECK_REQUESTED)
466 {
467 unsigned int len;
468 std::vector<uint8_t> digest(EVP_MD_size(EVP_sha256()));
469 EVP_DigestFinal(_ctx, digest.data(), &len);
470 if (digest == _expected)
471 {
472 if (DEBUG)
473 std::cerr << "transfer sha2 check passed\n";
474 _check = CHECK_PASSED_SHA2;
475 }
476 else
477 {
478 if (DEBUG)
479 std::cerr << "transfer sha2 check failed\n";
480 _check = CHECK_FAILED_SHA2;
481 }
482 }
483 return _check;
484 }
485 uint8_t status() const
486 {
487 return static_cast<uint8_t>(_check);
488 }
489};
490
491std::shared_ptr<transfer_hash_check> xfer_hash_check;
492
Vernon Mauery52ce6622019-05-22 09:19:46 -0700493static void activate_image(const char *obj_path)
494{
anil kumar appana31f88872019-08-02 15:16:27 +0000495 // If flag is false means to reboot
496 if (fw_update_status.getDeferRestart() == false)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700497 {
Vernon Mauery52ce6622019-05-22 09:19:46 -0700498
anil kumar appana31f88872019-08-02 15:16:27 +0000499 if (DEBUG)
500 {
501 std::cerr << "activateImage()...\n";
502 std::cerr << "obj_path = " << obj_path << "\n";
503 }
504 phosphor::logging::log<phosphor::logging::level::INFO>(
505 "activating Image: ",
506 phosphor::logging::entry("OBJPATH =%s", obj_path));
507 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
508 bus->async_method_call(
509 [](const boost::system::error_code ec) {
510 if (ec)
511 {
512 phosphor::logging::log<phosphor::logging::level::ERR>(
513 "async_method_call error: activate_image failed");
514 return;
515 }
516 },
517 "xyz.openbmc_project.Software.BMC.Updater", obj_path,
518 "org.freedesktop.DBus.Properties", "Set",
519 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
520 std::variant<std::string>("xyz.openbmc_project.Software.Activation."
521 "RequestedActivations.Active"));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700522 }
anil kumar appana31f88872019-08-02 15:16:27 +0000523 else
Vernon Mauery52ce6622019-05-22 09:19:46 -0700524 {
anil kumar appana31f88872019-08-02 15:16:27 +0000525 phosphor::logging::log<phosphor::logging::level::INFO>(
526 "Firmware image activation is deferred.");
Vernon Mauery52ce6622019-05-22 09:19:46 -0700527 }
528}
529
530static void post_transfer_complete_handler(
531 std::unique_ptr<sdbusplus::bus::match::match> &fw_update_matcher)
532{
533 // Setup timer for watching signal
534 static phosphor::Timer timer(
535 [&fw_update_matcher]() { fw_update_matcher = nullptr; });
536
537 static phosphor::Timer activation_status_timer([]() {
538 if (fw_update_status.activation_timer_timeout() >= 95)
539 {
540 activation_status_timer.stop();
541 }
542 });
543
544 timer.start(std::chrono::microseconds(5000000), false);
545
546 // callback function for capturing signal
547 auto callback = [&fw_update_matcher](sdbusplus::message::message &m) {
548 if (DEBUG)
549 std::cerr << "[complete] Match fired\n";
550 bool flag = false;
551
552 std::vector<std::pair<
553 std::string,
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700554 std::vector<std::pair<std::string, std::variant<std::string>>>>>
Vernon Mauery52ce6622019-05-22 09:19:46 -0700555 interfaces_properties;
556
557 sdbusplus::message::object_path obj_path;
558
559 try
560 {
561 m.read(obj_path, interfaces_properties); // Read in the object path
562 // that was just created
563 }
564 catch (std::exception &e)
565 {
566 std::cerr
567 << "[complete] Failed at post_transfer_complete-handler : "
568 << e.what() << "\n";
569 }
570 // constructing response message
571 if (DEBUG)
572 std::cerr << "[complete] obj path = " << obj_path.str << "\n";
573 for (auto &interface : interfaces_properties)
574 {
575 if (DEBUG)
576 std::cerr << "[complete] interface = " << interface.first
577 << "\n";
578
579 if (interface.first == "xyz.openbmc_project.Software.Activation")
580 {
581 // cancel timer only when
582 // xyz.openbmc_project.Software.Activation interface is
583 // added
584
585 if (DEBUG)
586 std::cerr << "[complete] Attempt to cancel timer...\n";
587 try
588 {
589 timer.stop();
590 activation_status_timer.start(
591 std::chrono::microseconds(3000000), true);
592 }
593 catch (std::exception &e)
594 {
595 std::cerr << "[complete] cancel timer error: " << e.what()
596 << "\n";
597 }
598
599 fw_update_status.set_software_obj_path(obj_path.str);
600 activate_image(obj_path.str.c_str());
601 if (DEBUG)
602 std::cerr << "[complete] returned from activeImage()\n";
603
604 fw_update_matcher = nullptr;
605 }
606 }
607 };
608
609 // Adding matcher
610 fw_update_matcher = std::make_unique<sdbusplus::bus::match::match>(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700611 *getSdBus(),
Vernon Mauery52ce6622019-05-22 09:19:46 -0700612 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
613 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
614 callback);
615}
Vernon Mauery52ce6622019-05-22 09:19:46 -0700616
617class MappedFile
618{
619 public:
620 MappedFile(const std::string &fname) : addr(nullptr), fsize(0)
621 {
622 std::error_code ec;
623 size_t sz = std::filesystem::file_size(fname, ec);
624 int fd = open(fname.c_str(), O_RDONLY);
625 if (!ec || fd < 0)
626 {
627 return;
628 }
629 void *tmp = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
630 close(fd);
631 if (tmp == MAP_FAILED)
632 {
633 return;
634 }
635 addr = tmp;
636 fsize = sz;
637 }
638
639 ~MappedFile()
640 {
641 if (addr)
642 {
643 munmap(addr, fsize);
644 }
645 }
646 const uint8_t *data() const
647 {
648 return static_cast<const uint8_t *>(addr);
649 }
650 size_t size() const
651 {
652 return fsize;
653 }
654
655 private:
656 size_t fsize;
657 void *addr;
658};
659
660static int transfer_from_file(const std::string &uri, bool move = true)
661{
662 std::error_code ec;
663 if (DEBUG)
664 std::cerr << "transfer_from_file(" << uri << ")\n";
665 if (move)
666 {
667 std::filesystem::rename(uri, FIRMWARE_BUFFER_FILE, ec);
668 }
669 else
670 {
671 std::filesystem::copy(uri, FIRMWARE_BUFFER_FILE,
672 std::filesystem::copy_options::overwrite_existing,
673 ec);
674 }
675 if (xfer_hash_check)
676 {
677 MappedFile mappedfw(uri);
678 xfer_hash_check->hash(
679 {mappedfw.data(), mappedfw.data() + mappedfw.size()});
680 }
681 if (ec.value())
682 {
683 std::cerr << "cp/mv returns: " << ec.message() << "(" << ec.value()
684 << ")\n";
685 }
686 return ec.value();
687}
688
689template <typename... ArgTypes>
690static int executeCmd(const char *path, ArgTypes &&... tArgs)
691{
692 boost::process::child execProg(path, const_cast<char *>(tArgs)...);
693 execProg.wait();
694 return execProg.exit_code();
695}
696
697constexpr char USB_CTRL_PATH[] = "/usr/bin/usb-ctrl";
698constexpr char FWUPDATE_MOUNT_POINT[] = "/tmp/usb-fwupd.mnt";
699constexpr char FWUPDATE_USB_VOL_IMG[] = "/tmp/usb-fwupd.img";
700constexpr char FWUPDATE_USB_DEV_NAME[] = "fw-usb-mass-storage-dev";
701constexpr size_t fwPathMaxLength = 255;
702static int transfer_from_usb(const std::string &uri)
703{
704 int ret, sysret;
705 char fwpath[fwPathMaxLength];
706 if (DEBUG)
707 std::cerr << "transfer_from_usb(" << uri << ")\n";
708 ret = executeCmd(USB_CTRL_PATH, "mount", FWUPDATE_USB_VOL_IMG,
709 FWUPDATE_MOUNT_POINT);
710 if (ret)
711 {
712 return ret;
713 }
714
715 std::string usb_path = std::string(FWUPDATE_MOUNT_POINT) + "/" + uri;
716 ret = transfer_from_file(usb_path, false);
717
718 executeCmd(USB_CTRL_PATH, "cleanup", FWUPDATE_USB_VOL_IMG,
719 FWUPDATE_MOUNT_POINT);
720 return ret;
721}
722
723static bool transfer_firmware_from_uri(const std::string &uri)
724{
725 static constexpr char FW_URI_FILE[] = "file://";
726 static constexpr char FW_URI_USB[] = "usb://";
727 if (DEBUG)
728 std::cerr << "transfer_firmware_from_uri(" << uri << ")\n";
729 if (boost::algorithm::starts_with(uri, FW_URI_FILE))
730 {
731 std::string fname = uri.substr(sizeof(FW_URI_FILE) - 1);
732 if (fname != FIRMWARE_BUFFER_FILE)
733 {
734 return 0 == transfer_from_file(fname);
735 }
736 return true;
737 }
738 if (boost::algorithm::starts_with(uri, FW_URI_USB))
739 {
740 std::string fname = uri.substr(sizeof(FW_URI_USB) - 1);
741 return 0 == transfer_from_usb(fname);
742 }
743 return false;
744}
745
746/* Get USB-mass-storage device status: inserted => true, ejected => false */
747static int usb_get_status()
748{
749 static constexpr char usb_gadget_base[] = "/sys/kernel/config/usb_gadget/";
750 auto usb_device =
751 std::filesystem::path(usb_gadget_base) / FWUPDATE_USB_DEV_NAME;
752 std::error_code ec;
753 return std::filesystem::exists(usb_device, ec) && !ec;
754}
755
756/* Insert the USB-mass-storage device status: success => 0, failure => non-0 */
757static int usb_attach_device()
758{
759 if (usb_get_status())
760 {
761 return 1;
762 }
763 int ret =
764 executeCmd(USB_CTRL_PATH, "setup", FWUPDATE_USB_VOL_IMG,
765 std::to_string(FIRMWARE_BUFFER_MAX_SIZE / 1_MB).c_str());
766 if (!ret)
767 {
768 ret = executeCmd(USB_CTRL_PATH, "insert", FWUPDATE_USB_DEV_NAME,
769 FWUPDATE_USB_VOL_IMG);
770 }
771 return ret;
772}
773
774/* Eject the USB-mass-storage device status: success => 0, failure => non-0 */
775static int usb_detach_device()
776{
777 if (!usb_get_status())
778 {
779 return 1;
780 }
781 return executeCmd(USB_CTRL_PATH, "eject", FWUPDATE_USB_DEV_NAME);
782}
783
784constexpr uint8_t controls_init = 0x00;
785constexpr uint8_t controls_transfer_started = 0x01;
786constexpr uint8_t controls_transfer_completed = 0x02;
787constexpr uint8_t controls_transfer_aborted = 0x04;
788constexpr uint8_t controls_usb_attached = 0x08;
789
790struct fw_update_control_request
791{
792 enum knob
793 {
794 CTRL_GET = 0,
795 CTRL_XFER_START,
796 CTRL_XFER_COMPLETE,
797 CTRL_XFER_ABORT,
798 CTRL_SET_FILENAME,
799 CTRL_USB_ATTACH,
800 CTRL_USB_DETACH,
801 } __attribute__((packed));
802 enum knob control;
803 uint8_t nlen;
804 char filename[fwPathMaxLength];
805} __attribute__((packed));
806
807static ipmi_ret_t ipmi_firmware_control(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
808 ipmi_request_t request,
809 ipmi_response_t response,
810 ipmi_data_len_t data_len,
811 ipmi_context_t context)
812{
813 static std::string fw_xfer_uri;
814
815 if (DEBUG)
816 std::cerr << "FW update control\n";
817 *data_len = 0;
818
819 static uint8_t controls = controls_init;
820 ipmi_ret_t rc = IPMI_CC_OK;
821 auto ctrl_req = reinterpret_cast<fw_update_control_request *>(request);
822 auto ctrl_resp = reinterpret_cast<uint8_t *>(response);
823
824 if (usb_get_status())
825 {
826 controls |= controls_usb_attached;
827 }
828 else
829 {
830 controls &= ~controls_usb_attached;
831 }
832
833 switch (ctrl_req->control)
834 {
835 case fw_update_control_request::CTRL_GET:
836 break;
837 case fw_update_control_request::CTRL_XFER_START:
838 {
839 controls |= controls_transfer_started;
840 // reset buffer to empty (truncate file)
841 std::ofstream out(FIRMWARE_BUFFER_FILE,
842 std::ofstream::binary | std::ofstream::trunc);
843 fw_xfer_uri = std::string("file://") + FIRMWARE_BUFFER_FILE;
844 if (xfer_hash_check)
845 {
846 xfer_hash_check->clear();
847 }
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +0530848#ifdef INTEL_PFR_ENABLED
849 imgLength = 0;
850 imgType = 0;
851 block0Mapped = false;
852#endif
Vernon Mauery52ce6622019-05-22 09:19:46 -0700853 if (DEBUG)
854 std::cerr << "transfer start\n";
855 }
856 break;
857 case fw_update_control_request::CTRL_XFER_COMPLETE:
858 {
859 if (usb_get_status())
860 {
861 rc = IPMI_CC_REQ_INVALID_PHASE;
862 }
863 // finish transfer based on URI
864 if (!transfer_firmware_from_uri(fw_xfer_uri))
865 {
866 rc = IPMI_CC_UNSPECIFIED_ERROR;
867 break;
868 }
869 // transfer complete
870 if (xfer_hash_check)
871 {
872 if (transfer_hash_check::CHECK_PASSED_SHA2 !=
873 xfer_hash_check->check())
874 {
875 if (DEBUG)
876 std::cerr << "xfer_hash_check returns not "
877 "CHECK_PASSED_SHA2\n";
878 rc = IPMI_CC_UNSPECIFIED_ERROR;
879 break;
880 }
881 }
882 // start the request
883 if (!request_start_firmware_update(FIRMWARE_BUFFER_FILE))
884 {
885 if (DEBUG)
886 std::cerr
887 << "request_start_firmware_update returns failure\n";
888 rc = IPMI_CC_UNSPECIFIED_ERROR;
889 }
890 if (rc == IPMI_CC_OK)
891 {
892 controls |= controls_transfer_completed;
893 }
894 }
895 break;
896 case fw_update_control_request::CTRL_XFER_ABORT:
897 if (DEBUG)
898 std::cerr << "send abort request\n";
899 if (usb_get_status())
900 {
901 if (0 != usb_detach_device())
902 {
903 rc = IPMI_CC_USB_ATTACH_FAIL;
904 }
905 }
anil kumar appana31f88872019-08-02 15:16:27 +0000906 fw_update_status.firmwareUpdateAbortState();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700907 controls |= controls_transfer_aborted;
908 break;
909 case fw_update_control_request::CTRL_SET_FILENAME:
910 fw_xfer_uri.clear();
911 fw_xfer_uri.insert(0, ctrl_req->filename, ctrl_req->nlen);
912 break;
913 case fw_update_control_request::CTRL_USB_ATTACH:
914 if (usb_get_status())
915 {
916 rc = IPMI_CC_INVALID_FIELD_REQUEST;
917 }
918 else if (0 != usb_attach_device())
919 {
920 rc = IPMI_CC_USB_ATTACH_FAIL;
921 }
922 else
923 {
924 rc = IPMI_CC_OK;
925 }
926 break;
927 case fw_update_control_request::CTRL_USB_DETACH:
928 if (!usb_get_status())
929 {
930 rc = IPMI_CC_INVALID_FIELD_REQUEST;
931 }
932 if (0 != usb_detach_device())
933 {
934 rc = IPMI_CC_USB_ATTACH_FAIL;
935 }
936 else
937 {
938 rc = IPMI_CC_OK;
939 }
940 break;
941 default:
942 if (DEBUG)
943 std::cerr << "control byte " << std::hex << ctrl_req->control
944 << " unknown\n";
945 rc = IPMI_CC_INVALID_FIELD_REQUEST;
946 break;
947 }
948
949 if (rc == IPMI_CC_OK)
950 {
951 *ctrl_resp = controls;
952 *data_len = sizeof(*ctrl_resp);
953 }
954
955 return rc;
956}
957
958struct fw_version_info
959{
960 uint8_t id_tag;
961 uint8_t major;
962 uint8_t minor;
963 uint32_t build;
964 uint32_t build_time;
965 uint32_t update_time;
966} __attribute__((packed));
967
968static ipmi_ret_t ipmi_firmware_get_fw_version_info(
969 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
970 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
971{
972 if (DEBUG)
973 std::cerr << "Get FW Version Info\n";
974
975 // Byte 1 - Count (N) Number of devices data is being returned for.
976 // Byte 2 - ID Tag 00 – reserved 01 – BMC Active Image 02 – BBU Active Image
977 // 03 – BMC Backup Image 04 – BBU Backup Image 05 – BBR
978 // Image
979 // Byte 3 - Major Version Number
980 // Byte 4 - Minor Version Number
981 // Bytes 5:8 - Build Number
982 // Bytes 9:12 - Build Timestamp Format: LSB first, same format as SEL
983 // timestamp
984 // Bytes 13:16 - Update Timestamp
985 // Bytes - 17:(15xN) - Repeat of 2 through 16
986
987 uint8_t count = 0;
988 auto ret_count = reinterpret_cast<uint8_t *>(response);
989 auto info = reinterpret_cast<struct fw_version_info *>(ret_count + 1);
990
991 for (uint8_t id_tag = 1; id_tag < 6; id_tag++)
992 {
993 const char *fw_path;
994 switch (id_tag)
995 {
996 case 1:
997 fw_path = FW_UPDATE_ACTIVE_INFO_PATH;
998 break;
999 case 2:
1000 fw_path = FW_UPDATE_BACKUP_INFO_PATH;
1001 break;
1002 case 3:
1003 case 4:
1004 case 5:
1005 continue; // skip for now
1006 break;
1007 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001008 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001009 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001010 bus->new_method_call(FW_UPDATE_SERVER_DBUS_NAME, fw_path,
Vernon Mauery52ce6622019-05-22 09:19:46 -07001011 "org.freedesktop.DBus.Properties", "GetAll");
1012 method.append(FW_UPDATE_INFO_INTERFACE);
1013 std::vector<std::pair<std::string, ipmi::DbusVariant>> properties;
1014 try
1015 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001016 auto reply = bus->call(method);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001017
1018 if (reply.is_method_error())
1019 continue;
1020
1021 reply.read(properties);
1022 }
1023 catch (sdbusplus::exception::SdBusError &e)
1024 {
1025 std::cerr << "SDBus Error: " << e.what();
1026 return IPMI_CC_UNSPECIFIED_ERROR;
1027 }
1028 uint8_t major = 0;
1029 uint8_t minor = 0;
1030 uint32_t build = 0;
1031 int32_t build_time = 0;
1032 int32_t update_time = 0;
1033 for (const auto &t : properties)
1034 {
1035 auto key = t.first;
1036 auto value = t.second;
1037 if (key == "version")
1038 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001039 auto strver = std::get<std::string>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001040 std::stringstream ss;
1041 ss << std::hex << strver;
1042 uint32_t t;
1043 ss >> t;
1044 major = t;
1045 ss.ignore();
1046 ss >> t;
1047 minor = t;
1048 ss.ignore();
1049 ss >> build;
1050 }
1051 else if (key == "build_time")
1052 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001053 build_time = std::get<int32_t>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001054 }
1055 else if (key == "update_time")
1056 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001057 update_time = std::get<int32_t>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001058 }
1059 }
1060
1061 info->id_tag = id_tag;
1062 info->major = major;
1063 info->minor = minor;
1064 info->build = build;
1065 info->build_time = build_time;
1066 info->update_time = update_time;
1067 count++;
1068 info++;
1069 }
1070 *ret_count = count;
1071
1072 // Status code.
1073 ipmi_ret_t rc = IPMI_CC_OK;
1074 *data_len = sizeof(count) + count * sizeof(*info);
1075
1076 return rc;
1077}
1078
1079struct fw_security_revision_info
1080{
1081 uint8_t id_tag;
1082 uint16_t sec_rev;
1083} __attribute__((packed));
1084
1085static ipmi_ret_t ipmi_firmware_get_fw_security_revision(
1086 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
1087 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
1088{
1089 if (DEBUG)
1090 std::cerr << "Get FW security revision info\n";
1091
1092 // Byte 1 - Count (N) Number of devices data is being returned for.
1093 // Byte 2 - ID Tag 00 – reserved 01 – BMC Active Image 02 – BBU Active Image
1094 // 03 – BMC Backup Image 04 – BBU Backup Image 05 – BBR
1095 // Image
1096 // Byte 3 - Major Version Number
1097 // Byte 4 - Minor Version Number
1098 // Bytes 5:8 - Build Number
1099 // Bytes 9:12 - Build Timestamp Format: LSB first, same format as SEL
1100 // timestamp
1101 // Bytes 13:16 - Update Timestamp
1102 // Bytes - 17:(15xN) - Repeat of 2 through 16
1103
1104 uint8_t count = 0;
1105 auto ret_count = reinterpret_cast<uint8_t *>(response);
1106 auto info =
1107 reinterpret_cast<struct fw_security_revision_info *>(ret_count + 1);
1108
Vernon Mauery15419dd2019-05-24 09:40:30 -07001109 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001110 for (uint8_t id_tag = 1; id_tag < 6; id_tag++)
1111 {
1112 const char *fw_path;
1113 switch (id_tag)
1114 {
1115 case 1:
1116 fw_path = FW_UPDATE_ACTIVE_INFO_PATH;
1117 break;
1118 case 2:
1119 fw_path = FW_UPDATE_BACKUP_INFO_PATH;
1120 break;
1121 case 3:
1122 case 4:
1123 case 5:
1124 continue; // skip for now
1125 break;
1126 }
1127 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001128 bus->new_method_call(FW_UPDATE_SERVER_DBUS_NAME, fw_path,
Vernon Mauery52ce6622019-05-22 09:19:46 -07001129 "org.freedesktop.DBus.Properties", "GetAll");
1130 method.append(FW_UPDATE_INFO_INTERFACE, "security_version");
1131 ipmi::DbusVariant sec_rev;
1132 try
1133 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001134 auto reply = bus->call(method);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001135
1136 if (reply.is_method_error())
1137 continue;
1138
1139 reply.read(sec_rev);
1140 }
1141 catch (sdbusplus::exception::SdBusError &e)
1142 {
1143 std::cerr << "SDBus Error: " << e.what();
1144 return IPMI_CC_UNSPECIFIED_ERROR;
1145 }
1146
1147 info->id_tag = id_tag;
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001148 info->sec_rev = std::get<int>(sec_rev);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001149 count++;
1150 info++;
1151 }
1152 *ret_count = count;
1153
1154 // Status code.
1155 ipmi_ret_t rc = IPMI_CC_OK;
1156 *data_len = sizeof(count) + count * sizeof(*info);
1157
1158 return rc;
1159}
1160
1161struct fw_channel_size
1162{
1163 uint8_t channel_id;
1164 uint32_t channel_size;
1165} __attribute__((packed));
1166
1167enum
1168{
1169 CHANNEL_RESVD = 0,
1170 CHANNEL_KCS,
1171 CHANNEL_RMCP_PLUS,
1172 CHANNEL_USB_DATA,
1173 CHANNEL_USB_MASS_STORAGE,
1174} channel_transfer_type;
1175
anil kumar appana159547c2019-05-31 16:08:34 +00001176static constexpr uint8_t channelListSize = 2;
1177/** @brief implements Maximum Firmware Transfer size command
1178 * @parameter
1179 * - none
1180 * @returns IPMI completion code plus response data
1181 * - count - channel count
1182 * - channelList - channel list information
1183 */
1184ipmi::RspType<uint8_t, // channel count
1185 std::array<std::tuple<uint8_t, uint32_t>,
1186 channelListSize> // channel
1187 // list
1188 >
1189 ipmiFirmwareMaxTransferSize()
Vernon Mauery52ce6622019-05-22 09:19:46 -07001190{
anil kumar appana159547c2019-05-31 16:08:34 +00001191 constexpr uint8_t KCSMaxBufSize = 128;
1192 constexpr uint32_t RMCPPLUSMaxBufSize = 50 * 1024;
Vernon Mauery52ce6622019-05-22 09:19:46 -07001193 if (DEBUG)
1194 std::cerr << "Get FW max transfer size\n";
Vernon Mauery52ce6622019-05-22 09:19:46 -07001195 // Byte 1 - Count (N) Number of devices data is being returned for.
1196 // Byte 2 - ID Tag 00 – reserved 01 – kcs 02 – rmcp+,
1197 // 03 – usb data, 04 – usb mass storage
1198 // Byte 3-6 - transfer size (little endian)
1199 // Bytes - 7:(5xN) - Repeat of 2 through 6
anil kumar appana159547c2019-05-31 16:08:34 +00001200 constexpr std::array<std::tuple<uint8_t, uint32_t>, channelListSize>
1201 channelList = {{{CHANNEL_KCS, KCSMaxBufSize},
1202 {CHANNEL_RMCP_PLUS, RMCPPLUSMaxBufSize}}};
1203 return ipmi::responseSuccess(channelListSize, channelList);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001204}
1205
1206enum
1207{
1208 EXEC_CTX_RESVD = 0,
1209 EXEC_CTX_FULL_LINUX = 0x10,
1210 EXEC_CTX_SAFE_MODE_LINUX = 0x11,
1211} bmc_execution_context;
1212
1213struct fw_execution_context
1214{
1215 uint8_t context;
1216 uint8_t image_selection;
1217} __attribute__((packed));
1218
1219static ipmi_ret_t ipmi_firmware_get_fw_execution_context(
1220 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
1221 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
1222{
1223 if (DEBUG)
1224 std::cerr << "Get FW execution context\n";
1225
1226 // Byte 1 - execution context
1227 // 0x10 - full linux stack, 0x11 - safe-mode linux stack
1228 // Byte 2 - current image selection
1229 // 1 - primary, 2 - secondary
1230
1231 auto info = reinterpret_cast<struct fw_execution_context *>(response);
anil kumar appana31f88872019-08-02 15:16:27 +00001232 info->context = EXEC_CTX_FULL_LINUX;
Vernon Mauery52ce6622019-05-22 09:19:46 -07001233
anil kumar appana31f88872019-08-02 15:16:27 +00001234 info->image_selection = getActiveBootImage();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001235
1236 // Status code.
1237 ipmi_ret_t rc = IPMI_CC_OK;
1238 *data_len = sizeof(*info);
1239
1240 return rc;
1241}
1242
anil kumar appana31f88872019-08-02 15:16:27 +00001243uint8_t getActiveBootImage(void)
1244{
1245 // 0x01 - primaryImage
1246 constexpr uint8_t primaryImage = 0x01;
1247 // 0x02 - secondaryImage
1248 constexpr uint8_t secondaryImage = 0x02;
1249 uint8_t bootImage = primaryImage;
1250
1251 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
1252 auto method = bus->new_method_call(
1253 "xyz.openbmc_project.U_Boot.Environment.Manager",
1254 "/xyz/openbmc_project/u_boot/environment/mgr",
1255 "xyz.openbmc_project.U_Boot.Environment.Manager", "Read");
1256 method.append("bootcmd");
1257 std::string value;
1258 try
1259 {
1260 auto reply = bus->call(method);
1261 reply.read(value);
1262 }
1263 catch (sdbusplus::exception::SdBusError &e)
1264 {
1265 std::cerr << "SDBus Error: " << e.what();
1266 return IPMI_CC_UNSPECIFIED_ERROR;
1267 }
1268 /* cheking for secondary FitImage Address 22480000 */
1269 if (value.find(secondaryFitImageStartAddr) != std::string::npos)
1270 {
1271 bootImage = secondaryImage;
1272 }
1273 else
1274 {
1275 bootImage = primaryImage;
1276 }
1277
1278 return bootImage;
1279}
anil kumar appana6c7d9382019-05-31 14:33:13 +00001280/** @brief implements firmware get status command
1281 * @parameter
1282 * - none
1283 * @returns IPMI completion code plus response data
1284 * - status - processing status
1285 * - percentage - percentage completion
1286 * - check - channel integrity check status
1287 **/
1288ipmi::RspType<uint8_t, // status
1289 uint8_t, // percentage
1290 uint8_t // check
1291 >
1292 ipmiFrmwareGetStatus()
Vernon Mauery52ce6622019-05-22 09:19:46 -07001293
Vernon Mauery52ce6622019-05-22 09:19:46 -07001294{
1295 if (DEBUG)
1296 std::cerr << "Get FW update status\n";
Vernon Mauery52ce6622019-05-22 09:19:46 -07001297 // Byte 1 - status (0=init, 1=idle, 2=download, 3=validate, 4=write,
1298 // 5=ready, f=error, 83=ac cycle required)
1299 // Byte 2 - percent
1300 // Byte 3 - integrity check status (0=none, 1=req, 2=sha2ok, e2=sha2fail)
anil kumar appana6c7d9382019-05-31 14:33:13 +00001301 uint8_t status = fw_update_status.state();
1302 uint8_t percent = fw_update_status.percent();
1303 uint8_t check = xfer_hash_check ? xfer_hash_check->status() : 0;
Vernon Mauery52ce6622019-05-22 09:19:46 -07001304
1305 // Status code.
anil kumar appana6c7d9382019-05-31 14:33:13 +00001306 return ipmi::responseSuccess(status, percent, check);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001307}
1308
1309static constexpr uint8_t FW_UPDATE_OPTIONS_NO_DOWNREV = (1 << 0);
1310static constexpr uint8_t FW_UPDATE_OPTIONS_DEFER_RESTART = (1 << 1);
1311static constexpr uint8_t FW_UPDATE_OPTIONS_SHA2_CHECK = (1 << 2);
1312static constexpr uint8_t FW_UPDATE_OPTIONS_RESVD1 = (1 << 3);
1313struct fw_update_options_request
1314{
1315 uint8_t mask;
1316 uint8_t options;
1317} __attribute__((packed));
1318
Vernon Mauery52ce6622019-05-22 09:19:46 -07001319uint32_t fw_update_options = 0;
1320static ipmi_ret_t ipmi_firmware_update_options(
1321 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
1322 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
1323{
1324 if (DEBUG)
1325 std::cerr << "Get/set FW update options\n";
1326
1327 // request:
1328 // Byte 1 - mask
1329 // Byte 2 - options
1330 // Byte 3-34 - optional integrity check expected value
1331 // response:
1332 // Byte 1 - set options
1333
1334 auto fw_options =
1335 reinterpret_cast<struct fw_update_options_request *>(request);
1336
1337 const char *path = FW_UPDATE_SERVER_INFO_PATH;
1338 const char *iface = FW_UPDATE_SECURITY_INTERFACE;
1339 if ((fw_options->mask & FW_UPDATE_OPTIONS_NO_DOWNREV) &&
1340 (fw_options->options & FW_UPDATE_OPTIONS_NO_DOWNREV) !=
1341 (fw_update_options & FW_UPDATE_OPTIONS_NO_DOWNREV))
1342 {
1343 if (fw_options->options & FW_UPDATE_OPTIONS_NO_DOWNREV)
1344 {
1345 fw_update_options |= FW_UPDATE_OPTIONS_NO_DOWNREV;
anil kumar appana31f88872019-08-02 15:16:27 +00001346 /*setting flag to flase for deferring downgrade support*/
1347 fw_update_status.setInhibitDowngrade(true);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001348 }
1349 else
1350 {
1351 fw_update_options &= ~FW_UPDATE_OPTIONS_NO_DOWNREV;
anil kumar appana31f88872019-08-02 15:16:27 +00001352 /*setting flag to true for downgrade support*/
1353 fw_update_status.setInhibitDowngrade(false);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001354 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001355 }
1356 if ((fw_options->mask & FW_UPDATE_OPTIONS_DEFER_RESTART) &&
1357 (fw_options->options & FW_UPDATE_OPTIONS_DEFER_RESTART) !=
1358 (fw_update_options & FW_UPDATE_OPTIONS_DEFER_RESTART))
1359 {
1360 if (fw_options->options & FW_UPDATE_OPTIONS_DEFER_RESTART)
1361 {
1362 fw_update_options |= FW_UPDATE_OPTIONS_DEFER_RESTART;
anil kumar appana31f88872019-08-02 15:16:27 +00001363 /* setting flag to true to stop image activation */
1364 fw_update_status.setDeferRestart(true);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001365 }
1366 else
1367 {
anil kumar appana31f88872019-08-02 15:16:27 +00001368 /* setting flag to false for image activation */
Vernon Mauery52ce6622019-05-22 09:19:46 -07001369 fw_update_options &= ~FW_UPDATE_OPTIONS_DEFER_RESTART;
anil kumar appana31f88872019-08-02 15:16:27 +00001370 fw_update_status.setDeferRestart(false);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001371 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001372 }
1373 if (fw_options->mask & FW_UPDATE_OPTIONS_SHA2_CHECK)
1374 {
1375 auto hash_size = EVP_MD_size(EVP_sha256());
1376 if (fw_options->options & FW_UPDATE_OPTIONS_SHA2_CHECK)
1377 {
1378 if (*data_len != (sizeof(*fw_options) + hash_size))
1379 {
1380 *data_len = 0;
1381 return IPMI_CC_REQ_DATA_LEN_INVALID;
1382 }
1383 xfer_hash_check = std::make_shared<transfer_hash_check>();
1384 auto exp_hash = reinterpret_cast<uint8_t *>(fw_options + 1);
1385 xfer_hash_check->init({exp_hash, exp_hash + hash_size});
1386 fw_update_options |= FW_UPDATE_OPTIONS_SHA2_CHECK;
1387 }
1388 else
1389 {
1390 fw_update_options &= ~FW_UPDATE_OPTIONS_SHA2_CHECK;
1391 // delete the xfer_hash_check object
1392 xfer_hash_check.reset();
1393 }
1394 }
1395 auto options_rsp = reinterpret_cast<uint8_t *>(response);
1396 *options_rsp = fw_update_options;
1397
1398 if (DEBUG)
1399 std::cerr << "current fw_update_options = " << std::hex
1400 << fw_update_options << '\n';
1401 // Status code.
1402 *data_len = sizeof(*options_rsp);
1403 return IPMI_CC_OK;
1404}
1405
1406struct fw_cert_info
1407{
1408 uint16_t cert_len;
1409 uint64_t serial;
1410 uint8_t subject_len;
1411 char subject[255];
1412} __attribute__((packed));
1413
1414static ipmi_ret_t ipmi_firmware_get_root_cert_info(
1415 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
1416 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
1417{
1418 if (DEBUG)
1419 std::cerr << "Get FW root cert info\n";
1420
1421 // request:
1422 // Byte 1 - certificate ID: request which certificate (ignored)
1423
1424 // response:
1425 // Byte 1-2 - certificate length (little endian)
1426 // Byte 3-10 - serial number (little endian)
1427 // Byte 11 - subject length
1428 // Byte 12-N - subject data
1429
1430 auto cert_info = reinterpret_cast<struct fw_cert_info *>(response);
Vernon Mauery15419dd2019-05-24 09:40:30 -07001431 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
1432 auto method = bus->new_method_call(
Vernon Mauery52ce6622019-05-22 09:19:46 -07001433 FW_UPDATE_SERVER_DBUS_NAME, FW_UPDATE_SERVER_INFO_PATH,
1434 "org.freedesktop.DBus.Properties", "GetAll");
1435 method.append(FW_UPDATE_SECURITY_INTERFACE);
1436 std::string subject;
1437 uint64_t serial;
1438 std::string cert;
1439 try
1440 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001441 auto reply = bus->call(method);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001442
1443 std::vector<std::pair<std::string, ipmi::DbusVariant>> properties;
1444 reply.read(properties);
1445
1446 for (const auto &t : properties)
1447 {
1448 auto key = t.first;
1449 auto value = t.second;
1450 if (key == "certificate_subject")
1451 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001452 subject = std::get<std::string>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001453 }
1454 else if (key == "cetificate_serial")
1455 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001456 serial = std::get<uint64_t>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001457 }
1458 else if (key == "certificate")
1459 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001460 cert = std::get<std::string>(value);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001461 }
1462 }
1463 }
1464 catch (sdbusplus::exception::SdBusError &e)
1465 {
1466 std::cerr << "SDBus Error: " << e.what();
1467 return IPMI_CC_UNSPECIFIED_ERROR;
1468 }
1469
1470 cert_info->cert_len = cert.size();
1471 cert_info->serial = serial;
1472 // truncate subject so it fits in the 255-byte array (if necessary)
1473 if (subject.size() > sizeof(cert_info->subject))
1474 subject.resize(sizeof(cert_info->subject));
1475 cert_info->subject_len = subject.size();
1476 std::copy(subject.begin(), subject.end(), cert_info->subject);
1477
1478 // Status code.
1479 ipmi_ret_t rc = IPMI_CC_OK;
1480 // make sure to account for the *actual* size of the subject
1481 *data_len = sizeof(*cert_info) - sizeof(cert_info->subject) +
1482 cert_info->subject_len;
1483
1484 return rc;
1485}
1486
1487struct fw_cert_data_req
1488{
1489 uint8_t cert_id;
1490 uint16_t offset;
1491 uint16_t count;
1492} __attribute__((packed));
1493
1494static ipmi_ret_t ipmi_firmware_get_root_cert_data(
1495 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
1496 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
1497{
1498 if (DEBUG)
1499 std::cerr << "Get FW root cert data\n";
1500
1501 // request:
1502 // Byte 1 - certificate ID: request which certificate (ignored)
1503 // Byte 2-3 - offset within cert to start at
1504 // Byte 4-5 - number of bytes to return
1505
1506 // response:
1507 // Byte 1-N - certificate data
1508
1509 if (*data_len != sizeof(fw_cert_data_req))
1510 return IPMI_CC_REQ_DATA_LEN_INVALID;
1511
1512 auto cert_data_req = reinterpret_cast<struct fw_cert_data_req *>(request);
Vernon Mauery15419dd2019-05-24 09:40:30 -07001513 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
1514 auto method = bus->new_method_call(
Vernon Mauery52ce6622019-05-22 09:19:46 -07001515 FW_UPDATE_SERVER_DBUS_NAME, FW_UPDATE_SERVER_INFO_PATH,
1516 "org.freedesktop.DBus.Properties", "Get");
1517 method.append(FW_UPDATE_SECURITY_INTERFACE, "certificate");
1518 ipmi::DbusVariant cert;
1519 try
1520 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001521 auto reply = bus->call(method);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001522 reply.read(cert);
1523 }
1524 catch (sdbusplus::exception::SdBusError &e)
1525 {
1526 std::cerr << "SDBus Error: " << e.what();
1527 return IPMI_CC_UNSPECIFIED_ERROR;
1528 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001529 auto cert_data = std::get<std::string>(cert);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001530
1531 if (cert_data_req->offset >= cert_data.size())
1532 {
1533 *data_len = 0;
1534 return IPMI_CC_INVALID_FIELD_REQUEST;
1535 }
1536 auto first = cert_data.begin() + cert_data_req->offset;
1537 auto last = first + cert_data_req->count;
1538 if (last > cert_data.end())
1539 last = cert_data.end();
1540
1541 auto data_out = reinterpret_cast<char *>(response);
1542 std::copy(first, last, data_out);
1543
1544 // Status code.
1545 ipmi_ret_t rc = IPMI_CC_OK;
1546 *data_len = (last - first);
1547
1548 return rc;
1549}
1550
1551static ipmi_ret_t ipmi_firmware_write_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1552 ipmi_request_t request,
1553 ipmi_response_t response,
1554 ipmi_data_len_t data_len,
1555 ipmi_context_t context)
1556{
1557 if (DEBUG)
1558 std::cerr << "write fw data (" << *data_len << " bytes)\n";
1559
1560 auto bytes_in = *data_len;
1561 *data_len = 0;
1562 if (fw_update_status.state() != fw_update_status_cache::FW_STATE_DOWNLOAD)
1563 return IPMI_CC_INVALID;
1564
1565 std::ofstream out(FIRMWARE_BUFFER_FILE,
1566 std::ofstream::binary | std::ofstream::app);
1567 if (!out)
1568 {
1569 return IPMI_CC_UNSPECIFIED_ERROR;
1570 }
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301571
1572 uint64_t fileDataLen = out.tellp();
1573 if (fileDataLen > FIRMWARE_BUFFER_MAX_SIZE)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001574 {
1575 return IPMI_CC_INVALID_FIELD_REQUEST;
1576 }
1577 auto data = reinterpret_cast<uint8_t *>(request);
1578 out.write(reinterpret_cast<char *>(data), bytes_in);
1579 out.close();
1580 if (xfer_hash_check)
1581 {
1582 xfer_hash_check->hash({data, data + bytes_in});
1583 }
1584
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301585#ifdef INTEL_PFR_ENABLED
1586 /* PFR image block 0 - As defined in HAS */
1587 struct PFRImageBlock0
1588 {
1589 uint32_t tag;
1590 uint32_t pcLength;
1591 uint32_t pcType;
1592 uint32_t reserved1;
1593 uint8_t hash256[32];
1594 uint8_t hash384[48];
1595 uint8_t reserved2[32];
1596 } __attribute__((packed));
1597
1598 /* Get the PFR block 0 data and read the uploaded image
1599 * information( Image type, length etc) */
1600 if ((fileDataLen >= sizeof(PFRImageBlock0)) && (!block0Mapped))
1601 {
1602 struct PFRImageBlock0 block0Data = {0};
1603
1604 std::ifstream inFile(FIRMWARE_BUFFER_FILE,
1605 std::ios::binary | std::ios::in);
1606 inFile.read(reinterpret_cast<char *>(&block0Data), sizeof(block0Data));
1607 inFile.close();
1608
1609 uint32_t magicNum = block0Data.tag;
1610
1611 /* Validate the magic number */
1612 if (magicNum != perBlock0MagicNum)
1613 {
1614 return IPMI_CC_INVALID_FIELD_REQUEST;
1615 }
1616 // Note:imgLength, imgType and block0Mapped are in global scope, as
1617 // these are used in cascaded updates.
1618 imgLength = block0Data.pcLength;
1619 imgType = block0Data.pcType;
1620 block0Mapped = true;
1621 }
1622#endif // end of INTEL_PFR_ENABLED
Vernon Mauery52ce6622019-05-22 09:19:46 -07001623 return IPMI_CC_OK;
1624}
1625
Vernon Mauery52ce6622019-05-22 09:19:46 -07001626struct intc_app_get_buffer_size_resp
1627{
1628 uint8_t kcs_size;
1629 uint8_t ipmb_size;
1630} __attribute__((packed));
1631
1632static constexpr int KCS_MAX_BUFFER_SIZE = 63;
1633static constexpr int IPMB_MAX_BUFFER_SIZE = 128;
1634static ipmi_ret_t ipmi_intel_app_get_buffer_size(
1635 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
1636 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
1637{
1638 auto msg_reply =
1639 reinterpret_cast<intc_app_get_buffer_size_resp *>(response);
1640 // for now this is hard coded; really this number is dependent on
1641 // the BMC kcs driver as well as the host kcs driver....
1642 // we can't know the latter.
1643 msg_reply->kcs_size = KCS_MAX_BUFFER_SIZE / 4;
1644 msg_reply->ipmb_size = IPMB_MAX_BUFFER_SIZE / 4;
1645 *data_len = sizeof(*msg_reply);
1646
1647 return IPMI_CC_OK;
1648}
1649
1650static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_FW_VERSION_INFO = 0x20;
1651static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_FW_SEC_VERSION_INFO = 0x21;
1652static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_FW_UPD_CHAN_INFO = 0x22;
1653static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_BMC_EXEC_CTX = 0x23;
1654static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_ROOT_CERT_INFO = 0x24;
1655static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_ROOT_CERT_DATA = 0x25;
1656static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_FW_UPDATE_RAND_NUM = 0x26;
1657static constexpr ipmi_cmd_t IPMI_CMD_FW_SET_FW_UPDATE_MODE = 0x27;
1658static constexpr ipmi_cmd_t IPMI_CMD_FW_EXIT_FW_UPDATE_MODE = 0x28;
1659static constexpr ipmi_cmd_t IPMI_CMD_FW_UPDATE_CONTROL = 0x29;
1660static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_STATUS = 0x2a;
1661static constexpr ipmi_cmd_t IPMI_CMD_FW_SET_FW_UPDATE_OPTIONS = 0x2b;
1662static constexpr ipmi_cmd_t IPMI_CMD_FW_IMAGE_WRITE = 0x2c;
1663static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_TIMESTAMP = 0x2d;
1664static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_UPDATE_ERR_MSG = 0xe0;
1665static constexpr ipmi_cmd_t IPMI_CMD_FW_GET_REMOTE_FW_INFO = 0xf0;
1666
1667static constexpr ipmi_netfn_t NETFUN_INTC_APP = 0x30;
1668static constexpr ipmi_cmd_t IPMI_CMD_INTC_GET_BUFFER_SIZE = 0x66;
1669
1670static void register_netfn_firmware_functions()
1671{
1672 // guarantee that we start with an already timed out timestamp
1673 fw_random_number_timestamp =
1674 std::chrono::steady_clock::now() - FW_RANDOM_NUMBER_TTL;
1675
1676 unlink(FIRMWARE_BUFFER_FILE);
1677
1678 // <Get BT Interface Capabilities>
1679 if (DEBUG)
1680 std::cerr << "Registering firmware update commands\n";
1681
1682 // get firmware version information
1683 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_GET_FW_VERSION_INFO,
1684 NULL, ipmi_firmware_get_fw_version_info,
1685 PRIVILEGE_ADMIN);
1686
1687 // get firmware security version information
1688 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_GET_FW_SEC_VERSION_INFO,
1689 NULL, ipmi_firmware_get_fw_security_revision,
1690 PRIVILEGE_ADMIN);
1691
1692 // get channel information (max transfer sizes)
anil kumar appana159547c2019-05-31 16:08:34 +00001693 ipmi::registerHandler(ipmi::prioOemBase, NETFUN_FIRMWARE,
1694 IPMI_CMD_FW_GET_FW_UPD_CHAN_INFO,
1695 ipmi::Privilege::Admin, ipmiFirmwareMaxTransferSize);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001696
1697 // get bmc execution context
1698 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_GET_BMC_EXEC_CTX, NULL,
1699 ipmi_firmware_get_fw_execution_context,
1700 PRIVILEGE_ADMIN);
1701
1702 // get root certificate information
1703 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_GET_ROOT_CERT_INFO,
1704 NULL, ipmi_firmware_get_root_cert_info,
1705 PRIVILEGE_ADMIN);
1706
1707 // get root certificate data
1708 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_GET_ROOT_CERT_DATA,
1709 NULL, ipmi_firmware_get_root_cert_data,
1710 PRIVILEGE_ADMIN);
1711
1712 // generate bmc fw update random number (for enter fw tranfer mode)
1713 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_GET_FW_UPDATE_RAND_NUM,
1714 NULL, ipmi_firmware_get_fw_random_number,
1715 PRIVILEGE_ADMIN);
1716
AppaRao Puli4b3e1c72019-10-16 20:53:09 +05301717 // Set Firmware Update Mode(0x27)
1718 ipmi::registerHandler(ipmi::prioOemBase, NETFUN_FIRMWARE,
1719 IPMI_CMD_FW_SET_FW_UPDATE_MODE,
1720 ipmi::Privilege::Admin, ipmiSetFirmwareUpdateMode);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001721
1722 // exit firmware update mode
1723 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_EXIT_FW_UPDATE_MODE,
1724 NULL, ipmi_firmware_exit_fw_update_mode,
1725 PRIVILEGE_ADMIN);
1726
1727 // firmware control mechanism (set filename, usb, etc.)
1728 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_UPDATE_CONTROL, NULL,
1729 ipmi_firmware_control, PRIVILEGE_ADMIN);
1730
1731 // get firmware update status
anil kumar appana6c7d9382019-05-31 14:33:13 +00001732 ipmi::registerHandler(ipmi::prioOemBase, NETFUN_FIRMWARE,
1733 IPMI_CMD_FW_GET_STATUS, ipmi::Privilege::Admin,
1734 ipmiFrmwareGetStatus);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001735 // set firmware update options (no downgrade, etc.)
1736 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_SET_FW_UPDATE_OPTIONS,
1737 NULL, ipmi_firmware_update_options, PRIVILEGE_ADMIN);
1738
1739 // write image data
1740 ipmi_register_callback(NETFUN_FIRMWARE, IPMI_CMD_FW_IMAGE_WRITE, NULL,
1741 ipmi_firmware_write_data, PRIVILEGE_ADMIN);
1742
Vernon Mauery52ce6622019-05-22 09:19:46 -07001743 // get buffer size is used by fw update (exclusively?)
1744 ipmi_register_callback(NETFUN_INTC_APP, IPMI_CMD_INTC_GET_BUFFER_SIZE, NULL,
1745 ipmi_intel_app_get_buffer_size, PRIVILEGE_USER);
1746 return;
1747}